15dfecf96Smrg/* 25dfecf96Smrg * Copyright (c) 2001 by The XFree86 Project, Inc. 35dfecf96Smrg * 45dfecf96Smrg * Permission is hereby granted, free of charge, to any person obtaining a 55dfecf96Smrg * copy of this software and associated documentation files (the "Software"), 65dfecf96Smrg * to deal in the Software without restriction, including without limitation 75dfecf96Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 85dfecf96Smrg * and/or sell copies of the Software, and to permit persons to whom the 95dfecf96Smrg * Software is furnished to do so, subject to the following conditions: 105dfecf96Smrg * 115dfecf96Smrg * The above copyright notice and this permission notice shall be included in 125dfecf96Smrg * all copies or substantial portions of the Software. 135dfecf96Smrg * 145dfecf96Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 155dfecf96Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 165dfecf96Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 175dfecf96Smrg * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 185dfecf96Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 195dfecf96Smrg * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 205dfecf96Smrg * SOFTWARE. 215dfecf96Smrg * 225dfecf96Smrg * Except as contained in this notice, the name of the XFree86 Project shall 235dfecf96Smrg * not be used in advertising or otherwise to promote the sale, use or other 245dfecf96Smrg * dealings in this Software without prior written authorization from the 255dfecf96Smrg * XFree86 Project. 265dfecf96Smrg * 275dfecf96Smrg * Author: Paulo César Pereira de Andrade 285dfecf96Smrg */ 295dfecf96Smrg 305dfecf96Smrg/* $XFree86: xc/programs/xedit/lisp/pathname.c,v 1.17tsi Exp $ */ 315dfecf96Smrg 325dfecf96Smrg#include <stdio.h> /* including dirent.h first may cause problems */ 335dfecf96Smrg#include <sys/types.h> 345dfecf96Smrg#include <dirent.h> 355dfecf96Smrg#include <errno.h> 365dfecf96Smrg#include <sys/stat.h> 375dfecf96Smrg#include "lisp/pathname.h" 385dfecf96Smrg#include "lisp/private.h" 395dfecf96Smrg 405dfecf96Smrg#define NOREAD_SKIP 0 415dfecf96Smrg#define NOREAD_ERROR 1 425dfecf96Smrg 435dfecf96Smrg/* 445dfecf96Smrg * Initialization 455dfecf96Smrg */ 465dfecf96SmrgLispObj *Oparse_namestring, *Kerror, *Kabsolute, *Krelative, *Kskip; 475dfecf96Smrg 485dfecf96Smrg/* 495dfecf96Smrg * Implementation 505dfecf96Smrg */ 515dfecf96Smrgvoid 525dfecf96SmrgLispPathnameInit(void) 535dfecf96Smrg{ 545dfecf96Smrg Kerror = KEYWORD("ERROR"); 555dfecf96Smrg Oparse_namestring = STATIC_ATOM("PARSE-NAMESTRING"); 565dfecf96Smrg Kabsolute = KEYWORD("ABSOLUTE"); 575dfecf96Smrg Krelative = KEYWORD("RELATIVE"); 585dfecf96Smrg} 595dfecf96Smrg 605dfecf96Smrgstatic int 615dfecf96Smrgglob_match(char *cmp1, char *cmp2) 625dfecf96Smrg/* 635dfecf96Smrg * Note: this code was written from scratch, and may generate incorrect 645dfecf96Smrg * results for very complex glob masks. 655dfecf96Smrg */ 665dfecf96Smrg{ 675dfecf96Smrg for (;;) { 685dfecf96Smrg while (*cmp1 && *cmp1 == *cmp2) { 695dfecf96Smrg ++cmp1; 705dfecf96Smrg ++cmp2; 715dfecf96Smrg } 725dfecf96Smrg if (*cmp2) { 735dfecf96Smrg if (*cmp1 == '*') { 745dfecf96Smrg while (*cmp1 == '*') 755dfecf96Smrg ++cmp1; 765dfecf96Smrg if (*cmp1) { 775dfecf96Smrg int count = 0, settmp = 1; 785dfecf96Smrg char *tmp = cmp2, *sav2; 795dfecf96Smrg 805dfecf96Smrg while (*cmp1 && *cmp1 == '?') { 815dfecf96Smrg ++cmp1; 825dfecf96Smrg ++count; 835dfecf96Smrg } 845dfecf96Smrg 855dfecf96Smrg /* need to recurse here to make sure 865dfecf96Smrg * all cases are tested. 875dfecf96Smrg */ 885dfecf96Smrg while (*cmp2 && *cmp2 != *cmp1) 895dfecf96Smrg ++cmp2; 905dfecf96Smrg if (!*cmp1 && cmp2 - tmp < count) 915dfecf96Smrg return (0); 925dfecf96Smrg sav2 = cmp2; 935dfecf96Smrg 945dfecf96Smrg /* if recursive calls fails, make sure all '?' 955dfecf96Smrg * following '*' are processed */ 965dfecf96Smrg while (*sav2 && sav2 - tmp < count) 975dfecf96Smrg ++sav2; 985dfecf96Smrg 995dfecf96Smrg for (; *cmp2;) { 1005dfecf96Smrg if (settmp) /* repeated letters: *?o? => boot, root */ 1015dfecf96Smrg tmp = cmp2; 1025dfecf96Smrg else 1035dfecf96Smrg settmp = 1; 1045dfecf96Smrg while (*cmp2 && *cmp2 != *cmp1) 1055dfecf96Smrg ++cmp2; 1065dfecf96Smrg if (cmp2 - tmp < count) { 1075dfecf96Smrg if (*cmp2) 1085dfecf96Smrg ++cmp2; 1095dfecf96Smrg settmp = 0; 1105dfecf96Smrg continue; 1115dfecf96Smrg } 1125dfecf96Smrg if (*cmp2) { 1135dfecf96Smrg if (glob_match(cmp1, cmp2)) 1145dfecf96Smrg return (1); 1155dfecf96Smrg ++cmp2; 1165dfecf96Smrg } 1175dfecf96Smrg } 1185dfecf96Smrg cmp2 = sav2; 1195dfecf96Smrg } 1205dfecf96Smrg else { 1215dfecf96Smrg while (*cmp2) 1225dfecf96Smrg ++cmp2; 1235dfecf96Smrg break; 1245dfecf96Smrg } 1255dfecf96Smrg } 1265dfecf96Smrg else if (*cmp1 == '?') { 1275dfecf96Smrg while (*cmp1 == '?' && *cmp2) { 1285dfecf96Smrg ++cmp1; 1295dfecf96Smrg ++cmp2; 1305dfecf96Smrg } 1315dfecf96Smrg continue; 1325dfecf96Smrg } 1335dfecf96Smrg else 1345dfecf96Smrg break; 1355dfecf96Smrg } 1365dfecf96Smrg else { 1375dfecf96Smrg while (*cmp1 == '*') 1385dfecf96Smrg ++cmp1; 1395dfecf96Smrg break; 1405dfecf96Smrg } 1415dfecf96Smrg } 1425dfecf96Smrg 1435dfecf96Smrg return (*cmp1 == '\0' && *cmp2 == '\0'); 1445dfecf96Smrg} 1455dfecf96Smrg 1465dfecf96Smrg/* 1475dfecf96Smrg * Since directory is a function to be extended by the implementation, 1485dfecf96Smrg * current extensions are: 1495dfecf96Smrg * all => list files and directories 1505dfecf96Smrg * it is an error to call 1515dfecf96Smrg * (directory "<pathname-spec>/" :all t) 1525dfecf96Smrg * if non nil, it is like the shell command 1535dfecf96Smrg * echo <pathname-spec>, but normally, not in the 1545dfecf96Smrg * same order, as the code does not sort the result. 1555dfecf96Smrg * !=nil => list files and directories 1565dfecf96Smrg * (default) nil => list only files, or only directories if 1575dfecf96Smrg * <pathname-spec> ends with PATH_SEP char. 1585dfecf96Smrg * if-cannot-read => if opendir fails on a directory 1595dfecf96Smrg * :error => generate an error 1605dfecf96Smrg * (default) :skip => skip search in this directory 1615dfecf96Smrg */ 1625dfecf96SmrgLispObj * 1635dfecf96SmrgLisp_Directory(LispBuiltin *builtin) 1645dfecf96Smrg/* 1655dfecf96Smrg directory pathname &key all if-cannot-read 1665dfecf96Smrg */ 1675dfecf96Smrg{ 1685dfecf96Smrg GC_ENTER(); 1695dfecf96Smrg DIR *dir; 1705dfecf96Smrg struct stat st; 1715dfecf96Smrg struct dirent *ent; 1725dfecf96Smrg int length, listdirs, i, ndirs, nmatches; 1735dfecf96Smrg char name[PATH_MAX + 1], path[PATH_MAX + 2], directory[PATH_MAX + 2]; 1745dfecf96Smrg char *sep, *base, *ptr, **dirs, **matches, 1755dfecf96Smrg dot[] = {'.', PATH_SEP, '\0'}, 1765dfecf96Smrg dotdot[] = {'.', '.', PATH_SEP, '\0'}; 1775dfecf96Smrg int cannot_read; 1785dfecf96Smrg 1795dfecf96Smrg LispObj *pathname, *all, *if_cannot_read, *result, *cons, *object; 1805dfecf96Smrg 1815dfecf96Smrg if_cannot_read = ARGUMENT(2); 1825dfecf96Smrg all = ARGUMENT(1); 1835dfecf96Smrg pathname = ARGUMENT(0); 1845dfecf96Smrg result = NIL; 1855dfecf96Smrg 1865dfecf96Smrg cons = NIL; 1875dfecf96Smrg 1885dfecf96Smrg if (if_cannot_read != UNSPEC) { 1895dfecf96Smrg if (!KEYWORDP(if_cannot_read) || 1905dfecf96Smrg (if_cannot_read != Kskip && 1915dfecf96Smrg if_cannot_read != Kerror)) 1925dfecf96Smrg LispDestroy("%s: bad :IF-CANNOT-READ %s", 1935dfecf96Smrg STRFUN(builtin), STROBJ(if_cannot_read)); 1945dfecf96Smrg if (if_cannot_read != Kskip) 1955dfecf96Smrg cannot_read = NOREAD_SKIP; 1965dfecf96Smrg else 1975dfecf96Smrg cannot_read = NOREAD_ERROR; 1985dfecf96Smrg } 1995dfecf96Smrg else 2005dfecf96Smrg cannot_read = NOREAD_SKIP; 2015dfecf96Smrg 2025dfecf96Smrg if (PATHNAMEP(pathname)) 2035dfecf96Smrg pathname = CAR(pathname->data.pathname); 2045dfecf96Smrg else if (STREAMP(pathname) && pathname->data.stream.type == LispStreamFile) 2055dfecf96Smrg pathname = CAR(pathname->data.stream.pathname->data.pathname); 2065dfecf96Smrg else if (!STRINGP(pathname)) 2075dfecf96Smrg LispDestroy("%s: %s is not a pathname", 2085dfecf96Smrg STRFUN(builtin), STROBJ(pathname)); 2095dfecf96Smrg 2105dfecf96Smrg strncpy(name, THESTR(pathname), sizeof(name) - 1); 2115dfecf96Smrg name[sizeof(name) - 1] = '\0'; 2125dfecf96Smrg length = strlen(name); 2135dfecf96Smrg if (length < STRLEN(pathname)) 2145dfecf96Smrg LispDestroy("%s: pathname too long %s", 2155dfecf96Smrg STRFUN(builtin), name); 2165dfecf96Smrg 2175dfecf96Smrg if (length == 0) { 2185dfecf96Smrg if (getcwd(path, sizeof(path) - 2) == NULL) 2195dfecf96Smrg LispDestroy("%s: getcwd(): %s", STRFUN(builtin), strerror(errno)); 2205dfecf96Smrg length = strlen(path); 2215dfecf96Smrg if (!length || path[length - 1] != PATH_SEP) { 2225dfecf96Smrg path[length++] = PATH_SEP; 2235dfecf96Smrg path[length] = '\0'; 2245dfecf96Smrg } 2255dfecf96Smrg result = APPLY1(Oparse_namestring, LSTRING(path, length)); 2265dfecf96Smrg GC_LEAVE(); 2275dfecf96Smrg 2285dfecf96Smrg return (result); 2295dfecf96Smrg } 2305dfecf96Smrg 2315dfecf96Smrg if (name[length - 1] == PATH_SEP) { 2325dfecf96Smrg listdirs = 1; 2335dfecf96Smrg if (length > 1) { 2345dfecf96Smrg --length; 2355dfecf96Smrg name[length] = '\0'; 2365dfecf96Smrg } 2375dfecf96Smrg } 2385dfecf96Smrg else 2395dfecf96Smrg listdirs = 0; 2405dfecf96Smrg 2415dfecf96Smrg if (name[0] != PATH_SEP) { 2425dfecf96Smrg if (getcwd(path, sizeof(path) - 2) == NULL) 2435dfecf96Smrg LispDestroy("%s: getcwd(): %s", STRFUN(builtin), strerror(errno)); 2445dfecf96Smrg length = strlen(path); 2455dfecf96Smrg if (!length || path[length - 1] != PATH_SEP) { 2465dfecf96Smrg path[length++] = PATH_SEP; 2475dfecf96Smrg path[length] = '\0'; 2485dfecf96Smrg } 2495dfecf96Smrg } 2505dfecf96Smrg else 2515dfecf96Smrg path[0] = '\0'; 2525dfecf96Smrg 2535dfecf96Smrg result = NIL; 2545dfecf96Smrg 2555dfecf96Smrg /* list intermediate directories */ 2565dfecf96Smrg matches = NULL; 2575dfecf96Smrg nmatches = 0; 2585dfecf96Smrg dirs = LispMalloc(sizeof(char*)); 2595dfecf96Smrg ndirs = 1; 2605dfecf96Smrg if (snprintf(directory, sizeof(directory), "%s%s%c", 2615dfecf96Smrg path, name, PATH_SEP) > PATH_MAX) 2625dfecf96Smrg LispDestroy("%s: pathname too long %s", STRFUN(builtin), directory); 2635dfecf96Smrg 2645dfecf96Smrg /* Remove ../ */ 2655dfecf96Smrg sep = directory; 2665dfecf96Smrg for (sep = strstr(sep, dotdot); sep; sep = strstr(sep, dotdot)) { 2675dfecf96Smrg if (sep <= directory + 1) 2685dfecf96Smrg strcpy(directory, sep + 2); 2695dfecf96Smrg else if (sep[-1] == PATH_SEP) { 2705dfecf96Smrg for (base = sep - 2; base > directory; base--) 2715dfecf96Smrg if (*base == PATH_SEP) 2725dfecf96Smrg break; 2735dfecf96Smrg strcpy(base, sep + 2); 2745dfecf96Smrg sep = base; 2755dfecf96Smrg } 2765dfecf96Smrg else 2775dfecf96Smrg ++sep; 2785dfecf96Smrg } 2795dfecf96Smrg 2805dfecf96Smrg /* Remove "./" */ 2815dfecf96Smrg sep = directory; 2825dfecf96Smrg for (sep = strstr(sep, dot); sep; sep = strstr(sep, dot)) { 2835dfecf96Smrg if (sep == directory || sep[-1] == PATH_SEP) 2845dfecf96Smrg strcpy(sep, sep + 2); 2855dfecf96Smrg else 2865dfecf96Smrg ++sep; 2875dfecf96Smrg } 2885dfecf96Smrg 2895dfecf96Smrg /* This will happen when there are too many '../' in the path */ 2905dfecf96Smrg if (directory[1] == '\0') { 2915dfecf96Smrg directory[1] = PATH_SEP; 2925dfecf96Smrg directory[2] = '\0'; 2935dfecf96Smrg } 2945dfecf96Smrg 2955dfecf96Smrg base = directory; 2965dfecf96Smrg sep = strchr(base + 1, PATH_SEP); 2975dfecf96Smrg dirs[0] = LispMalloc(2); 2985dfecf96Smrg dirs[0][0] = PATH_SEP; 2995dfecf96Smrg dirs[0][1] = '\0'; 3005dfecf96Smrg 3015dfecf96Smrg for (base = directory + 1, sep = strchr(base, PATH_SEP); ; 3025dfecf96Smrg base = sep + 1, sep = strchr(base, PATH_SEP)) { 3035dfecf96Smrg *sep = '\0'; 3045dfecf96Smrg if (sep[1] == '\0') 3055dfecf96Smrg sep = NULL; 3065dfecf96Smrg length = strlen(base); 3075dfecf96Smrg if (length == 0) { 3085dfecf96Smrg if (sep) 3095dfecf96Smrg *sep = PATH_SEP; 3105dfecf96Smrg else 3115dfecf96Smrg break; 3125dfecf96Smrg continue; 3135dfecf96Smrg } 3145dfecf96Smrg 3155dfecf96Smrg for (i = 0; i < ndirs; i++) { 3165dfecf96Smrg length = strlen(dirs[i]); 3175dfecf96Smrg if (length > 1) 3185dfecf96Smrg dirs[i][length - 1] = '\0'; /* remove trailing / */ 3195dfecf96Smrg if ((dir = opendir(dirs[i])) != NULL) { 3205dfecf96Smrg (void)readdir(dir); /* "." */ 3215dfecf96Smrg (void)readdir(dir); /* ".." */ 3225dfecf96Smrg if (length > 1) 3235dfecf96Smrg dirs[i][length - 1] = PATH_SEP; /* add trailing / again */ 3245dfecf96Smrg 3255dfecf96Smrg snprintf(path, sizeof(path), "%s", dirs[i]); 3265dfecf96Smrg length = strlen(path); 3275dfecf96Smrg ptr = path + length; 3285dfecf96Smrg 3295dfecf96Smrg while ((ent = readdir(dir)) != NULL) { 3305dfecf96Smrg int isdir; 3315dfecf96Smrg unsigned d_namlen = strlen(ent->d_name); 3325dfecf96Smrg 3335dfecf96Smrg if (length + d_namlen + 2 < sizeof(path)) 3345dfecf96Smrg strcpy(ptr, ent->d_name); 3355dfecf96Smrg else { 3365dfecf96Smrg closedir(dir); 3375dfecf96Smrg LispDestroy("%s: pathname too long %s", 3385dfecf96Smrg STRFUN(builtin), dirs[i]); 3395dfecf96Smrg } 3405dfecf96Smrg 3415dfecf96Smrg if (stat(path, &st) != 0) 3425dfecf96Smrg isdir = 0; 3435dfecf96Smrg else 3445dfecf96Smrg isdir = S_ISDIR(st.st_mode); 3455dfecf96Smrg 3465dfecf96Smrg if (all != UNSPEC || ((isdir && (listdirs || sep)) || 3475dfecf96Smrg (!listdirs && !sep && !isdir))) { 3485dfecf96Smrg if (glob_match(base, ent->d_name)) { 3495dfecf96Smrg if (isdir) { 3505dfecf96Smrg length = strlen(ptr); 3515dfecf96Smrg ptr[length++] = PATH_SEP; 3525dfecf96Smrg ptr[length] = '\0'; 3535dfecf96Smrg } 3545dfecf96Smrg /* XXX won't closedir on memory allocation failure! */ 3555dfecf96Smrg matches = LispRealloc(matches, sizeof(char*) * 3565dfecf96Smrg nmatches + 1); 3575dfecf96Smrg matches[nmatches++] = LispStrdup(ptr); 3585dfecf96Smrg } 3595dfecf96Smrg } 3605dfecf96Smrg } 3615dfecf96Smrg closedir(dir); 3625dfecf96Smrg 3635dfecf96Smrg if (nmatches == 0) { 3645dfecf96Smrg if (sep || !listdirs || *base) { 3655dfecf96Smrg LispFree(dirs[i]); 3665dfecf96Smrg if (i + 1 < ndirs) 3675dfecf96Smrg memmove(dirs + i, dirs + i + 1, 3685dfecf96Smrg sizeof(char*) * (ndirs - (i + 1))); 3695dfecf96Smrg --ndirs; 3705dfecf96Smrg --i; /* XXX playing with for loop */ 3715dfecf96Smrg } 3725dfecf96Smrg } 3735dfecf96Smrg else { 3745dfecf96Smrg int j; 3755dfecf96Smrg 3765dfecf96Smrg length = strlen(dirs[i]); 3775dfecf96Smrg if (nmatches > 1) { 3785dfecf96Smrg dirs = LispRealloc(dirs, sizeof(char*) * 3795dfecf96Smrg (ndirs + nmatches)); 3805dfecf96Smrg if (i + 1 < ndirs) 3815dfecf96Smrg memmove(dirs + i + nmatches, dirs + i + 1, 3825dfecf96Smrg sizeof(char*) * (ndirs - (i + 1))); 3835dfecf96Smrg } 3845dfecf96Smrg for (j = 1; j < nmatches; j++) { 3855dfecf96Smrg dirs[i + j] = LispMalloc(length + 3865dfecf96Smrg strlen(matches[j]) + 1); 3875dfecf96Smrg sprintf(dirs[i + j], "%s%s", dirs[i], matches[j]); 3885dfecf96Smrg } 3895dfecf96Smrg dirs[i] = LispRealloc(dirs[i], 3905dfecf96Smrg length + strlen(matches[0]) + 1); 3915dfecf96Smrg strcpy(dirs[i] + length, matches[0]); 3925dfecf96Smrg i += nmatches - 1; /* XXX playing with for loop */ 3935dfecf96Smrg ndirs += nmatches - 1; 3945dfecf96Smrg 3955dfecf96Smrg for (j = 0; j < nmatches; j++) 3965dfecf96Smrg LispFree(matches[j]); 3975dfecf96Smrg LispFree(matches); 3985dfecf96Smrg matches = NULL; 3995dfecf96Smrg nmatches = 0; 4005dfecf96Smrg } 4015dfecf96Smrg } 4025dfecf96Smrg else { 4035dfecf96Smrg if (cannot_read == NOREAD_ERROR) 4045dfecf96Smrg LispDestroy("%s: opendir(%s): %s", 4055dfecf96Smrg STRFUN(builtin), dirs[i], strerror(errno)); 4065dfecf96Smrg else { 4075dfecf96Smrg LispFree(dirs[i]); 4085dfecf96Smrg if (i + 1 < ndirs) 4095dfecf96Smrg memmove(dirs + i, dirs + i + 1, 4105dfecf96Smrg sizeof(char*) * (ndirs - (i + 1))); 4115dfecf96Smrg --ndirs; 4125dfecf96Smrg --i; /* XXX playing with for loop */ 4135dfecf96Smrg } 4145dfecf96Smrg } 4155dfecf96Smrg } 4165dfecf96Smrg if (sep) 4175dfecf96Smrg *sep = PATH_SEP; 4185dfecf96Smrg else 4195dfecf96Smrg break; 4205dfecf96Smrg } 4215dfecf96Smrg 4225dfecf96Smrg for (i = 0; i < ndirs; i++) { 4235dfecf96Smrg object = APPLY1(Oparse_namestring, STRING2(dirs[i])); 4245dfecf96Smrg if (result == NIL) { 4255dfecf96Smrg result = cons = CONS(object, NIL); 4265dfecf96Smrg GC_PROTECT(result); 4275dfecf96Smrg } 4285dfecf96Smrg else { 4295dfecf96Smrg RPLACD(cons, CONS(object, NIL)); 4305dfecf96Smrg cons = CDR(cons); 4315dfecf96Smrg } 4325dfecf96Smrg } 4335dfecf96Smrg LispFree(dirs); 4345dfecf96Smrg GC_LEAVE(); 4355dfecf96Smrg 4365dfecf96Smrg return (result); 4375dfecf96Smrg} 4385dfecf96Smrg 4395dfecf96SmrgLispObj * 4405dfecf96SmrgLisp_ParseNamestring(LispBuiltin *builtin) 4415dfecf96Smrg/* 4425dfecf96Smrg parse-namestring object &optional host defaults &key start end junk-allowed 4435dfecf96Smrg */ 4445dfecf96Smrg{ 4455dfecf96Smrg GC_ENTER(); 4465dfecf96Smrg LispObj *result; 4475dfecf96Smrg 4485dfecf96Smrg LispObj *object, *host, *defaults, *ostart, *oend, *junk_allowed; 4495dfecf96Smrg 4505dfecf96Smrg junk_allowed = ARGUMENT(5); 4515dfecf96Smrg oend = ARGUMENT(4); 4525dfecf96Smrg ostart = ARGUMENT(3); 4535dfecf96Smrg defaults = ARGUMENT(2); 4545dfecf96Smrg host = ARGUMENT(1); 4555dfecf96Smrg object = ARGUMENT(0); 4565dfecf96Smrg 4575dfecf96Smrg if (host == UNSPEC) 4585dfecf96Smrg host = NIL; 4595dfecf96Smrg if (defaults == UNSPEC) 4605dfecf96Smrg defaults = NIL; 4615dfecf96Smrg 4625dfecf96Smrg RETURN_COUNT = 1; 4635dfecf96Smrg if (STREAMP(object)) { 4645dfecf96Smrg if (object->data.stream.type == LispStreamFile) 4655dfecf96Smrg object = object->data.stream.pathname; 4665dfecf96Smrg /* else just check for JUNK-ALLOWED... */ 4675dfecf96Smrg } 4685dfecf96Smrg if (PATHNAMEP(object)) { 4695dfecf96Smrg RETURN(0) = FIXNUM(0); 4705dfecf96Smrg return (object); 4715dfecf96Smrg } 4725dfecf96Smrg 4735dfecf96Smrg if (host != NIL) { 4745dfecf96Smrg CHECK_STRING(host); 4755dfecf96Smrg } 4765dfecf96Smrg if (defaults != NIL) { 4775dfecf96Smrg if (!PATHNAMEP(defaults)) { 4785dfecf96Smrg defaults = APPLY1(Oparse_namestring, defaults); 4795dfecf96Smrg GC_PROTECT(defaults); 4805dfecf96Smrg } 4815dfecf96Smrg } 4825dfecf96Smrg 4835dfecf96Smrg result = NIL; 4845dfecf96Smrg if (STRINGP(object)) { 4855dfecf96Smrg LispObj *cons, *cdr; 4865dfecf96Smrg char *name = THESTR(object), *ptr, *str, data[PATH_MAX + 1], 487f765521fSmrg string[PATH_MAX + 1], *send; 488f765521fSmrg const char *namestr, *typestr; 4895dfecf96Smrg long start, end, length, alength, namelen, typelen; 4905dfecf96Smrg 4915dfecf96Smrg LispCheckSequenceStartEnd(builtin, object, ostart, oend, 4925dfecf96Smrg &start, &end, &length); 4935dfecf96Smrg alength = end - start; 4945dfecf96Smrg 4955dfecf96Smrg if (alength > sizeof(data) - 1) 4965dfecf96Smrg LispDestroy("%s: string %s too large", 4975dfecf96Smrg STRFUN(builtin), STROBJ(object)); 4985dfecf96Smrg memcpy(data, name + start, alength); 4995dfecf96Smrg#ifndef KEEP_EXTRA_PATH_SEP 5005dfecf96Smrg ptr = data; 5015dfecf96Smrg send = ptr + alength; 5025dfecf96Smrg while (ptr < send) { 5035dfecf96Smrg if (*ptr++ == PATH_SEP) { 5045dfecf96Smrg for (str = ptr; str < send && *str == PATH_SEP; str++) 5055dfecf96Smrg ; 5065dfecf96Smrg if (str - ptr) { 5075dfecf96Smrg memmove(ptr, str, alength - (str - data)); 5085dfecf96Smrg alength -= str - ptr; 5095dfecf96Smrg send -= str - ptr; 5105dfecf96Smrg } 5115dfecf96Smrg } 5125dfecf96Smrg } 5135dfecf96Smrg#endif 5145dfecf96Smrg data[alength] = '\0'; 5155dfecf96Smrg memcpy(string, data, alength + 1); 5165dfecf96Smrg 5175dfecf96Smrg if (PATHNAMEP(defaults)) 5185dfecf96Smrg defaults = defaults->data.pathname; 5195dfecf96Smrg 5205dfecf96Smrg /* string name */ 5215dfecf96Smrg result = cons = CONS(NIL, NIL); 5225dfecf96Smrg GC_PROTECT(result); 5235dfecf96Smrg 5245dfecf96Smrg /* host */ 5255dfecf96Smrg if (defaults != NIL) 5265dfecf96Smrg defaults = CDR(defaults); 5275dfecf96Smrg cdr = defaults == NIL ? NIL : CAR(defaults); 5285dfecf96Smrg RPLACD(cons, CONS(cdr, NIL)); 5295dfecf96Smrg cons = CDR(cons); 5305dfecf96Smrg 5315dfecf96Smrg /* device */ 5325dfecf96Smrg if (defaults != NIL) 5335dfecf96Smrg defaults = CDR(defaults); 5345dfecf96Smrg cdr = defaults == NIL ? NIL : CAR(defaults); 5355dfecf96Smrg RPLACD(cons, CONS(cdr, NIL)); 5365dfecf96Smrg cons = CDR(cons); 5375dfecf96Smrg 5385dfecf96Smrg /* directory */ 5395dfecf96Smrg if (defaults != NIL) 5405dfecf96Smrg defaults = CDR(defaults); 5415dfecf96Smrg if (*data == PATH_SEP) 5425dfecf96Smrg cdr = CONS(Kabsolute, NIL); 5435dfecf96Smrg else 5445dfecf96Smrg cdr = CONS(Krelative, NIL); 5455dfecf96Smrg RPLACD(cons, CONS(cdr, NIL)); 5465dfecf96Smrg cons = CDR(cons); 5475dfecf96Smrg /* directory components */ 5485dfecf96Smrg ptr = data; 5495dfecf96Smrg send = data + alength; 5505dfecf96Smrg if (*ptr == PATH_SEP) 5515dfecf96Smrg ++ptr; 5525dfecf96Smrg for (str = ptr; str < send; str++) { 5535dfecf96Smrg if (*str == PATH_SEP) 5545dfecf96Smrg break; 5555dfecf96Smrg } 5565dfecf96Smrg while (str < send) { 5575dfecf96Smrg *str++ = '\0'; 5585dfecf96Smrg if (str - ptr > NAME_MAX) 5595dfecf96Smrg LispDestroy("%s: directory name too long %s", 5605dfecf96Smrg STRFUN(builtin), ptr); 5615dfecf96Smrg RPLACD(cdr, CONS(LSTRING(ptr, str - ptr - 1), NIL)); 5625dfecf96Smrg cdr = CDR(cdr); 5635dfecf96Smrg for (ptr = str; str < send; str++) { 5645dfecf96Smrg if (*str == PATH_SEP) 5655dfecf96Smrg break; 5665dfecf96Smrg } 5675dfecf96Smrg } 5685dfecf96Smrg if (str - ptr > NAME_MAX) 5695dfecf96Smrg LispDestroy("%s: file name too long %s", STRFUN(builtin), ptr); 5705dfecf96Smrg if (CAAR(cons) == Krelative && 5715dfecf96Smrg defaults != NIL && CAAR(defaults) == Kabsolute) { 5725dfecf96Smrg /* defaults specify directory and pathname doesn't */ 5735dfecf96Smrg char *tstring; 5745dfecf96Smrg long dlength, tlength; 5755dfecf96Smrg LispObj *dir = CDAR(defaults); 5765dfecf96Smrg 5775dfecf96Smrg for (dlength = 1; CONSP(dir); dir = CDR(dir)) 5785dfecf96Smrg dlength += STRLEN(CAR(dir)) + 1; 5795dfecf96Smrg if (alength + dlength < PATH_MAX) { 5805dfecf96Smrg memmove(data + dlength, data, alength + 1); 5815dfecf96Smrg memmove(string + dlength, string, alength + 1); 5825dfecf96Smrg alength += dlength; 5835dfecf96Smrg ptr += dlength; 5845dfecf96Smrg send += dlength; 5855dfecf96Smrg CAAR(cons) = Kabsolute; 5865dfecf96Smrg for (dir = CDAR(defaults), cdr = CAR(cons); 5875dfecf96Smrg CONSP(dir); 5885dfecf96Smrg dir = CDR(dir)) { 5895dfecf96Smrg RPLACD(cdr, CONS(CAR(dir), CDR(cdr))); 5905dfecf96Smrg cdr = CDR(cdr); 5915dfecf96Smrg } 5925dfecf96Smrg dir = CDAR(defaults); 5935dfecf96Smrg data[0] = string[0] = PATH_SEP; 5945dfecf96Smrg for (dlength = 1; CONSP(dir); dir = CDR(dir)) { 5955dfecf96Smrg tstring = THESTR(CAR(dir)); 5965dfecf96Smrg tlength = STRLEN(CAR(dir)); 5975dfecf96Smrg memcpy(data + dlength, tstring, tlength); 5985dfecf96Smrg memcpy(string + dlength, tstring, tlength); 5995dfecf96Smrg dlength += tlength; 6005dfecf96Smrg data[dlength] = string[dlength] = PATH_SEP; 6015dfecf96Smrg ++dlength; 6025dfecf96Smrg } 6035dfecf96Smrg } 6045dfecf96Smrg } 6055dfecf96Smrg 6065dfecf96Smrg /* name */ 6075dfecf96Smrg if (defaults != NIL) 6085dfecf96Smrg defaults = CDR(defaults); 6095dfecf96Smrg cdr = defaults == NIL ? NIL : CAR(defaults); 6105dfecf96Smrg for (typelen = 0, str = ptr; str < send; str++) { 6115dfecf96Smrg if (*str == PATH_TYPESEP) { 6125dfecf96Smrg typelen = 1; 6135dfecf96Smrg break; 6145dfecf96Smrg } 6155dfecf96Smrg } 6165dfecf96Smrg if (*ptr) 6175dfecf96Smrg cdr = LSTRING(ptr, str - ptr); 6185dfecf96Smrg if (STRINGP(cdr)) { 6195dfecf96Smrg namestr = THESTR(cdr); 6205dfecf96Smrg namelen = STRLEN(cdr); 6215dfecf96Smrg } 6225dfecf96Smrg else { 6235dfecf96Smrg namestr = ""; 6245dfecf96Smrg namelen = 0; 6255dfecf96Smrg } 6265dfecf96Smrg RPLACD(cons, CONS(cdr, NIL)); 6275dfecf96Smrg cons = CDR(cons); 6285dfecf96Smrg 6295dfecf96Smrg /* type */ 6305dfecf96Smrg if (defaults != NIL) 6315dfecf96Smrg defaults = CDR(defaults); 6325dfecf96Smrg cdr = defaults == NIL ? NIL : CAR(defaults); 6335dfecf96Smrg ptr = str + typelen; 6345dfecf96Smrg if (*ptr) 6355dfecf96Smrg cdr = LSTRING(ptr, send - ptr); 6365dfecf96Smrg if (STRINGP(cdr)) { 6375dfecf96Smrg typestr = THESTR(cdr); 6385dfecf96Smrg typelen = STRLEN(cdr); 6395dfecf96Smrg } 6405dfecf96Smrg else { 6415dfecf96Smrg typestr = ""; 6425dfecf96Smrg typelen = 0; 6435dfecf96Smrg } 6445dfecf96Smrg RPLACD(cons, CONS(cdr, NIL)); 6455dfecf96Smrg cons = CDR(cons); 6465dfecf96Smrg 6475dfecf96Smrg /* version */ 6485dfecf96Smrg if (defaults != NIL) 6495dfecf96Smrg defaults = CDR(defaults); 6505dfecf96Smrg cdr = defaults == NIL ? NIL : CAR(defaults); 6515dfecf96Smrg RPLACD(cons, CONS(cdr, NIL)); 6525dfecf96Smrg 6535dfecf96Smrg /* string representation, must be done here to use defaults */ 6545dfecf96Smrg for (ptr = string + alength; ptr >= string; ptr--) { 6555dfecf96Smrg if (*ptr == PATH_SEP) 6565dfecf96Smrg break; 6575dfecf96Smrg } 6585dfecf96Smrg if (ptr >= string) 6595dfecf96Smrg ++ptr; 6605dfecf96Smrg else 6615dfecf96Smrg ptr = string; 6625dfecf96Smrg *ptr = '\0'; 6635dfecf96Smrg 6645dfecf96Smrg length = ptr - string; 6655dfecf96Smrg 6665dfecf96Smrg alength = namelen; 6675dfecf96Smrg if (alength) { 6685dfecf96Smrg if (length + alength + 2 > sizeof(string)) 6695dfecf96Smrg alength = sizeof(string) - length - 2; 6705dfecf96Smrg memcpy(string + length, namestr, alength); 6715dfecf96Smrg length += alength; 6725dfecf96Smrg } 6735dfecf96Smrg 6745dfecf96Smrg alength = typelen; 6755dfecf96Smrg if (alength) { 6765dfecf96Smrg if (length + 2 < sizeof(string)) 6775dfecf96Smrg string[length++] = PATH_TYPESEP; 6785dfecf96Smrg if (length + alength + 2 > sizeof(string)) 6795dfecf96Smrg alength = sizeof(string) - length - 2; 6805dfecf96Smrg memcpy(string + length, typestr, alength); 6815dfecf96Smrg length += alength; 6825dfecf96Smrg } 6835dfecf96Smrg string[length] = '\0'; 6845dfecf96Smrg 6855dfecf96Smrg RPLACA(result, LSTRING(string, length)); 6865dfecf96Smrg RETURN(0) = FIXNUM(end); 6875dfecf96Smrg 6885dfecf96Smrg result = PATHNAME(result); 6895dfecf96Smrg } 6905dfecf96Smrg else if (junk_allowed == UNSPEC || junk_allowed == NIL) 6915dfecf96Smrg LispDestroy("%s: bad argument %s", STRFUN(builtin), STROBJ(object)); 6925dfecf96Smrg else 6935dfecf96Smrg RETURN(0) = NIL; 6945dfecf96Smrg 6955dfecf96Smrg GC_LEAVE(); 6965dfecf96Smrg 6975dfecf96Smrg return (result); 6985dfecf96Smrg} 6995dfecf96Smrg 7005dfecf96SmrgLispObj * 7015dfecf96SmrgLisp_MakePathname(LispBuiltin *builtin) 7025dfecf96Smrg/* 7035dfecf96Smrg make-pathname &key host device directory name type version defaults 7045dfecf96Smrg */ 7055dfecf96Smrg{ 7065dfecf96Smrg GC_ENTER(); 7075dfecf96Smrg int length, alength; 7085dfecf96Smrg char *string, pathname[PATH_MAX + 1]; 7095dfecf96Smrg LispObj *result, *cdr, *cons; 7105dfecf96Smrg 7115dfecf96Smrg LispObj *host, *device, *directory, *name, *type, *version, *defaults; 7125dfecf96Smrg 7135dfecf96Smrg defaults = ARGUMENT(6); 7145dfecf96Smrg version = ARGUMENT(5); 7155dfecf96Smrg type = ARGUMENT(4); 7165dfecf96Smrg name = ARGUMENT(3); 7175dfecf96Smrg directory = ARGUMENT(2); 7185dfecf96Smrg device = ARGUMENT(1); 7195dfecf96Smrg host = ARGUMENT(0); 7205dfecf96Smrg 7215dfecf96Smrg if (host != UNSPEC) { 7225dfecf96Smrg CHECK_STRING(host); 7235dfecf96Smrg } 7245dfecf96Smrg if (device != UNSPEC) { 7255dfecf96Smrg CHECK_STRING(device); 7265dfecf96Smrg } 7275dfecf96Smrg 7285dfecf96Smrg if (directory != UNSPEC) { 7295dfecf96Smrg LispObj *dir; 7305dfecf96Smrg 7315dfecf96Smrg CHECK_CONS(directory); 7325dfecf96Smrg dir = CAR(directory); 7335dfecf96Smrg CHECK_KEYWORD(dir); 7345dfecf96Smrg if (dir != Kabsolute && dir != Krelative) 7355dfecf96Smrg LispDestroy("%s: directory type %s unknown", 7365dfecf96Smrg STRFUN(builtin), STROBJ(dir)); 7375dfecf96Smrg } 7385dfecf96Smrg 7395dfecf96Smrg if (name != UNSPEC) { 7405dfecf96Smrg CHECK_STRING(name); 7415dfecf96Smrg } 7425dfecf96Smrg if (type != UNSPEC) { 7435dfecf96Smrg CHECK_STRING(type); 7445dfecf96Smrg } 7455dfecf96Smrg 7465dfecf96Smrg if (version != UNSPEC && version != NIL) { 7475dfecf96Smrg switch (OBJECT_TYPE(version)) { 7485dfecf96Smrg case LispFixnum_t: 7495dfecf96Smrg if (FIXNUM_VALUE(version) >= 0) 7505dfecf96Smrg goto version_ok; 7515dfecf96Smrg case LispInteger_t: 7525dfecf96Smrg if (INT_VALUE(version) >= 0) 7535dfecf96Smrg goto version_ok; 7545dfecf96Smrg break; 7555dfecf96Smrg case LispDFloat_t: 7565dfecf96Smrg if (DFLOAT_VALUE(version) >= 0.0) 7575dfecf96Smrg goto version_ok; 7585dfecf96Smrg break; 7595dfecf96Smrg default: 7605dfecf96Smrg break; 7615dfecf96Smrg } 7625dfecf96Smrg LispDestroy("%s: %s is not a positive real number", 7635dfecf96Smrg STRFUN(builtin), STROBJ(version)); 7645dfecf96Smrg } 7655dfecf96Smrgversion_ok: 7665dfecf96Smrg 7675dfecf96Smrg if (defaults != UNSPEC && !PATHNAMEP(defaults) && 7685dfecf96Smrg (host == UNSPEC || device == UNSPEC || directory == UNSPEC || 7695dfecf96Smrg name == UNSPEC || type == UNSPEC || version == UNSPEC)) { 7705dfecf96Smrg defaults = APPLY1(Oparse_namestring, defaults); 7715dfecf96Smrg GC_PROTECT(defaults); 7725dfecf96Smrg } 7735dfecf96Smrg 7745dfecf96Smrg if (defaults != UNSPEC) { 7755dfecf96Smrg defaults = defaults->data.pathname; 7765dfecf96Smrg defaults = CDR(defaults); /* host */ 7775dfecf96Smrg if (host == UNSPEC) 7785dfecf96Smrg host = CAR(defaults); 7795dfecf96Smrg defaults = CDR(defaults); /* device */ 7805dfecf96Smrg if (device == UNSPEC) 7815dfecf96Smrg device = CAR(defaults); 7825dfecf96Smrg defaults = CDR(defaults); /* directory */ 7835dfecf96Smrg if (directory == UNSPEC) 7845dfecf96Smrg directory = CAR(defaults); 7855dfecf96Smrg defaults = CDR(defaults); /* name */ 7865dfecf96Smrg if (name == UNSPEC) 7875dfecf96Smrg name = CAR(defaults); 7885dfecf96Smrg defaults = CDR(defaults); /* type */ 7895dfecf96Smrg if (type == UNSPEC) 7905dfecf96Smrg type = CAR(defaults); 7915dfecf96Smrg defaults = CDR(defaults); /* version */ 7925dfecf96Smrg if (version == UNSPEC) 7935dfecf96Smrg version = CAR(defaults); 7945dfecf96Smrg } 7955dfecf96Smrg 7965dfecf96Smrg /* string representation */ 7975dfecf96Smrg length = 0; 7985dfecf96Smrg if (CONSP(directory)) { 7995dfecf96Smrg if (CAR(directory) == Kabsolute) 8005dfecf96Smrg pathname[length++] = PATH_SEP; 8015dfecf96Smrg 8025dfecf96Smrg for (cdr = CDR(directory); CONSP(cdr); cdr = CDR(cdr)) { 8035dfecf96Smrg CHECK_STRING(CAR(cdr)); 8045dfecf96Smrg string = THESTR(CAR(cdr)); 8055dfecf96Smrg alength = STRLEN(CAR(cdr)); 8065dfecf96Smrg if (alength > NAME_MAX) 8075dfecf96Smrg LispDestroy("%s: directory name too long %s", 8085dfecf96Smrg STRFUN(builtin), string); 8095dfecf96Smrg if (length + alength + 2 > sizeof(pathname)) 8105dfecf96Smrg alength = sizeof(pathname) - length - 2; 8115dfecf96Smrg memcpy(pathname + length, string, alength); 8125dfecf96Smrg length += alength; 8135dfecf96Smrg pathname[length++] = PATH_SEP; 8145dfecf96Smrg } 8155dfecf96Smrg } 8165dfecf96Smrg if (STRINGP(name)) { 8175dfecf96Smrg int xlength = 0; 8185dfecf96Smrg 8195dfecf96Smrg if (STRINGP(type)) 8205dfecf96Smrg xlength = STRLEN(type) + 1; 8215dfecf96Smrg 8225dfecf96Smrg string = THESTR(name); 8235dfecf96Smrg alength = STRLEN(name); 8245dfecf96Smrg if (alength + xlength > NAME_MAX) 8255dfecf96Smrg LispDestroy("%s: file name too long %s", 8265dfecf96Smrg STRFUN(builtin), string); 8275dfecf96Smrg if (length + alength + 2 > sizeof(pathname)) 8285dfecf96Smrg alength = sizeof(pathname) - length - 2; 8295dfecf96Smrg memcpy(pathname + length, string, alength); 8305dfecf96Smrg length += alength; 8315dfecf96Smrg } 8325dfecf96Smrg if (STRINGP(type)) { 8335dfecf96Smrg if (length + 2 < sizeof(pathname)) 8345dfecf96Smrg pathname[length++] = PATH_TYPESEP; 8355dfecf96Smrg string = THESTR(type); 8365dfecf96Smrg alength = STRLEN(type); 8375dfecf96Smrg if (length + alength + 2 > sizeof(pathname)) 8385dfecf96Smrg alength = sizeof(pathname) - length - 2; 8395dfecf96Smrg memcpy(pathname + length, string, alength); 8405dfecf96Smrg length += alength; 8415dfecf96Smrg } 8425dfecf96Smrg pathname[length] = '\0'; 8435dfecf96Smrg result = cons = CONS(LSTRING(pathname, length), NIL); 8445dfecf96Smrg GC_PROTECT(result); 8455dfecf96Smrg 8465dfecf96Smrg /* host */ 8475dfecf96Smrg RPLACD(cons, CONS(host == UNSPEC ? NIL : host, NIL)); 8485dfecf96Smrg cons = CDR(cons); 8495dfecf96Smrg 8505dfecf96Smrg /* device */ 8515dfecf96Smrg RPLACD(cons, CONS(device == UNSPEC ? NIL : device, NIL)); 8525dfecf96Smrg cons = CDR(cons); 8535dfecf96Smrg 8545dfecf96Smrg /* directory */ 8555dfecf96Smrg if (directory == UNSPEC) 8565dfecf96Smrg cdr = CONS(Krelative, NIL); 8575dfecf96Smrg else 8585dfecf96Smrg cdr = directory; 8595dfecf96Smrg RPLACD(cons, CONS(cdr, NIL)); 8605dfecf96Smrg cons = CDR(cons); 8615dfecf96Smrg 8625dfecf96Smrg /* name */ 8635dfecf96Smrg RPLACD(cons, CONS(name == UNSPEC ? NIL : name, NIL)); 8645dfecf96Smrg cons = CDR(cons); 8655dfecf96Smrg 8665dfecf96Smrg /* type */ 8675dfecf96Smrg RPLACD(cons, CONS(type == UNSPEC ? NIL : type, NIL)); 8685dfecf96Smrg cons = CDR(cons); 8695dfecf96Smrg 8705dfecf96Smrg /* version */ 8715dfecf96Smrg RPLACD(cons, CONS(version == UNSPEC ? NIL : version, NIL)); 8725dfecf96Smrg 8735dfecf96Smrg GC_LEAVE(); 8745dfecf96Smrg 8755dfecf96Smrg return (PATHNAME(result)); 8765dfecf96Smrg} 8775dfecf96Smrg 8785dfecf96SmrgLispObj * 8795dfecf96SmrgLisp_PathnameHost(LispBuiltin *builtin) 8805dfecf96Smrg/* 8815dfecf96Smrg pathname-host pathname 8825dfecf96Smrg */ 8835dfecf96Smrg{ 8845dfecf96Smrg return (LispPathnameField(PATH_HOST, 0)); 8855dfecf96Smrg} 8865dfecf96Smrg 8875dfecf96SmrgLispObj * 8885dfecf96SmrgLisp_PathnameDevice(LispBuiltin *builtin) 8895dfecf96Smrg/* 8905dfecf96Smrg pathname-device pathname 8915dfecf96Smrg */ 8925dfecf96Smrg{ 8935dfecf96Smrg return (LispPathnameField(PATH_DEVICE, 0)); 8945dfecf96Smrg} 8955dfecf96Smrg 8965dfecf96SmrgLispObj * 8975dfecf96SmrgLisp_PathnameDirectory(LispBuiltin *builtin) 8985dfecf96Smrg/* 8995dfecf96Smrg pathname-device pathname 9005dfecf96Smrg */ 9015dfecf96Smrg{ 9025dfecf96Smrg return (LispPathnameField(PATH_DIRECTORY, 0)); 9035dfecf96Smrg} 9045dfecf96Smrg 9055dfecf96SmrgLispObj * 9065dfecf96SmrgLisp_PathnameName(LispBuiltin *builtin) 9075dfecf96Smrg/* 9085dfecf96Smrg pathname-name pathname 9095dfecf96Smrg */ 9105dfecf96Smrg{ 9115dfecf96Smrg return (LispPathnameField(PATH_NAME, 0)); 9125dfecf96Smrg} 9135dfecf96Smrg 9145dfecf96SmrgLispObj * 9155dfecf96SmrgLisp_PathnameType(LispBuiltin *builtin) 9165dfecf96Smrg/* 9175dfecf96Smrg pathname-type pathname 9185dfecf96Smrg */ 9195dfecf96Smrg{ 9205dfecf96Smrg return (LispPathnameField(PATH_TYPE, 0)); 9215dfecf96Smrg} 9225dfecf96Smrg 9235dfecf96SmrgLispObj * 9245dfecf96SmrgLisp_PathnameVersion(LispBuiltin *builtin) 9255dfecf96Smrg/* 9265dfecf96Smrg pathname-version pathname 9275dfecf96Smrg */ 9285dfecf96Smrg{ 9295dfecf96Smrg return (LispPathnameField(PATH_VERSION, 0)); 9305dfecf96Smrg} 9315dfecf96Smrg 9325dfecf96SmrgLispObj * 9335dfecf96SmrgLisp_FileNamestring(LispBuiltin *builtin) 9345dfecf96Smrg/* 9355dfecf96Smrg file-namestring pathname 9365dfecf96Smrg */ 9375dfecf96Smrg{ 9385dfecf96Smrg return (LispPathnameField(PATH_NAME, 1)); 9395dfecf96Smrg} 9405dfecf96Smrg 9415dfecf96SmrgLispObj * 9425dfecf96SmrgLisp_DirectoryNamestring(LispBuiltin *builtin) 9435dfecf96Smrg/* 9445dfecf96Smrg directory-namestring pathname 9455dfecf96Smrg */ 9465dfecf96Smrg{ 9475dfecf96Smrg return (LispPathnameField(PATH_DIRECTORY, 1)); 9485dfecf96Smrg} 9495dfecf96Smrg 9505dfecf96SmrgLispObj * 9515dfecf96SmrgLisp_EnoughNamestring(LispBuiltin *builtin) 9525dfecf96Smrg/* 9535dfecf96Smrg enough-pathname pathname &optional defaults 9545dfecf96Smrg */ 9555dfecf96Smrg{ 9565dfecf96Smrg LispObj *pathname, *defaults; 9575dfecf96Smrg 9585dfecf96Smrg defaults = ARGUMENT(1); 9595dfecf96Smrg pathname = ARGUMENT(0); 9605dfecf96Smrg 9615dfecf96Smrg if (defaults != UNSPEC && defaults != NIL) { 9625dfecf96Smrg char *ppathname, *pdefaults, *pp, *pd; 9635dfecf96Smrg 9645dfecf96Smrg if (!STRINGP(pathname)) { 9655dfecf96Smrg if (PATHNAMEP(pathname)) 9665dfecf96Smrg pathname = CAR(pathname->data.pathname); 9675dfecf96Smrg else if (STREAMP(pathname) && 9685dfecf96Smrg pathname->data.stream.type == LispStreamFile) 9695dfecf96Smrg pathname = CAR(pathname->data.stream.pathname->data.pathname); 9705dfecf96Smrg else 9715dfecf96Smrg LispDestroy("%s: bad PATHNAME %s", 9725dfecf96Smrg STRFUN(builtin), STROBJ(pathname)); 9735dfecf96Smrg } 9745dfecf96Smrg 9755dfecf96Smrg if (!STRINGP(defaults)) { 9765dfecf96Smrg if (PATHNAMEP(defaults)) 9775dfecf96Smrg defaults = CAR(defaults->data.pathname); 9785dfecf96Smrg else if (STREAMP(defaults) && 9795dfecf96Smrg defaults->data.stream.type == LispStreamFile) 9805dfecf96Smrg defaults = CAR(defaults->data.stream.pathname->data.pathname); 9815dfecf96Smrg else 9825dfecf96Smrg LispDestroy("%s: bad DEFAULTS %s", 9835dfecf96Smrg STRFUN(builtin), STROBJ(defaults)); 9845dfecf96Smrg } 9855dfecf96Smrg 9865dfecf96Smrg ppathname = pp = THESTR(pathname); 9875dfecf96Smrg pdefaults = pd = THESTR(defaults); 9885dfecf96Smrg while (*ppathname && *pdefaults && *ppathname == *pdefaults) { 9895dfecf96Smrg ppathname++; 9905dfecf96Smrg pdefaults++; 9915dfecf96Smrg } 9925dfecf96Smrg if (*pdefaults == '\0' && pdefaults > pd) 9935dfecf96Smrg --pdefaults; 9945dfecf96Smrg if (*ppathname && *pdefaults && *pdefaults != PATH_SEP) { 9955dfecf96Smrg --ppathname; 9965dfecf96Smrg while (*ppathname != PATH_SEP && ppathname > pp) 9975dfecf96Smrg --ppathname; 9985dfecf96Smrg if (*ppathname == PATH_SEP) 9995dfecf96Smrg ++ppathname; 10005dfecf96Smrg } 10015dfecf96Smrg 10025dfecf96Smrg return (STRING(ppathname)); 10035dfecf96Smrg } 10045dfecf96Smrg else { 10055dfecf96Smrg if (STRINGP(pathname)) 10065dfecf96Smrg return (pathname); 10075dfecf96Smrg else if (PATHNAMEP(pathname)) 10085dfecf96Smrg return (CAR(pathname->data.pathname)); 10095dfecf96Smrg else if (STREAMP(pathname)) { 10105dfecf96Smrg if (pathname->data.stream.type == LispStreamFile) 10115dfecf96Smrg return (CAR(pathname->data.stream.pathname->data.pathname)); 10125dfecf96Smrg } 10135dfecf96Smrg } 10145dfecf96Smrg LispDestroy("%s: bad PATHNAME %s", STRFUN(builtin), STROBJ(pathname)); 10155dfecf96Smrg 10165dfecf96Smrg return (NIL); 10175dfecf96Smrg} 10185dfecf96Smrg 10195dfecf96SmrgLispObj * 10205dfecf96SmrgLisp_Namestring(LispBuiltin *builtin) 10215dfecf96Smrg/* 10225dfecf96Smrg namestring pathname 10235dfecf96Smrg */ 10245dfecf96Smrg{ 10255dfecf96Smrg return (LispPathnameField(PATH_STRING, 1)); 10265dfecf96Smrg} 10275dfecf96Smrg 10285dfecf96SmrgLispObj * 10295dfecf96SmrgLisp_HostNamestring(LispBuiltin *builtin) 10305dfecf96Smrg/* 10315dfecf96Smrg host-namestring pathname 10325dfecf96Smrg */ 10335dfecf96Smrg{ 10345dfecf96Smrg return (LispPathnameField(PATH_HOST, 1)); 10355dfecf96Smrg} 10365dfecf96Smrg 10375dfecf96SmrgLispObj * 10385dfecf96SmrgLisp_Pathnamep(LispBuiltin *builtin) 10395dfecf96Smrg/* 10405dfecf96Smrg pathnamep object 10415dfecf96Smrg */ 10425dfecf96Smrg{ 10435dfecf96Smrg LispObj *object; 10445dfecf96Smrg 10455dfecf96Smrg object = ARGUMENT(0); 10465dfecf96Smrg 10475dfecf96Smrg return (PATHNAMEP(object) ? T : NIL); 10485dfecf96Smrg} 10495dfecf96Smrg 10505dfecf96Smrg/* XXX only checks if host is a string and only checks the HOME enviroment 10515dfecf96Smrg * variable */ 10525dfecf96SmrgLispObj * 10535dfecf96SmrgLisp_UserHomedirPathname(LispBuiltin *builtin) 10545dfecf96Smrg/* 10555dfecf96Smrg user-homedir-pathname &optional host 10565dfecf96Smrg */ 10575dfecf96Smrg{ 10585dfecf96Smrg GC_ENTER(); 10595dfecf96Smrg char *home = getenv("HOME"), data[PATH_MAX + 1]; 106097f927b5Skamil char sepstr[] = {PATH_SEP, '\0'}; 10615dfecf96Smrg LispObj *result; 10625dfecf96Smrg 10635dfecf96Smrg LispObj *host; 10645dfecf96Smrg 10655dfecf96Smrg host = ARGUMENT(0); 10665dfecf96Smrg 10675dfecf96Smrg if (host != UNSPEC && !STRINGP(host)) 10685dfecf96Smrg LispDestroy("%s: bad hostname %s", STRFUN(builtin), STROBJ(host)); 10695dfecf96Smrg 10705dfecf96Smrg if (home) { 107197f927b5Skamil strlcpy(data, home, sizeof(data)); 107297f927b5Skamil if (data[0] != '\0' && data[strlen(data) - 1] != PATH_SEP) 107397f927b5Skamil strlcat(data, sepstr, sizeof(data)); 107497f927b5Skamil } else { 107597f927b5Skamil data[0] = '\0'; 10765dfecf96Smrg } 10775dfecf96Smrg 107897f927b5Skamil result = STRING(data); 10795dfecf96Smrg GC_PROTECT(result); 10805dfecf96Smrg result = APPLY1(Oparse_namestring, result); 10815dfecf96Smrg GC_LEAVE(); 10825dfecf96Smrg 10835dfecf96Smrg return (result); 10845dfecf96Smrg} 10855dfecf96Smrg 10865dfecf96SmrgLispObj * 10875dfecf96SmrgLisp_Truename(LispBuiltin *builtin) 10885dfecf96Smrg{ 10895dfecf96Smrg return (LispProbeFile(builtin, 0)); 10905dfecf96Smrg} 10915dfecf96Smrg 10925dfecf96SmrgLispObj * 10935dfecf96SmrgLisp_ProbeFile(LispBuiltin *builtin) 10945dfecf96Smrg{ 10955dfecf96Smrg return (LispProbeFile(builtin, 1)); 10965dfecf96Smrg} 1097