/* * pathname.c * * path name management module */ #ifdef FD #include "fd.h" #else /* !FD */ #include "machine.h" #include #include #include # ifndef NOUNISTDH # include # endif # ifndef NOSTDLIBH # include # endif #include "printf.h" #include "kctype.h" #include "pathname.h" #endif /* !FD */ #if MSDOS #include #include "unixemu.h" # ifndef FD # include # include # include # define DS_IRDONLY 001 # define DS_IHIDDEN 002 # define DS_IFSYSTEM 004 # define DS_IFLABEL 010 # define DS_IFDIR 020 # define DS_IARCHIVE 040 # define SEARCHATTRS (DS_IRDONLY | DS_IHIDDEN | DS_IFSYSTEM \ | DS_IFDIR | DS_IARCHIVE) # endif /* !FD */ #define EXTWIDTH 4 # if defined (__TURBOC__) || (defined (DJGPP) && DJGPP < 2) # include # endif # if defined (DJGPP) && DJGPP < 2 # define find_t ffblk # define _dos_findfirst(p, a, f) findfirst(p, f, a) # define _dos_findnext findnext # define _ENOENT_ ENMFILE # else # define ff_attrib attrib # define ff_ftime wr_time # define ff_fdate wr_date # define ff_fsize size # define ff_name name # define _ENOENT_ ENOENT # endif #else /* !MSDOS */ #include #include #include #include #define EXTWIDTH 0 # ifdef USEDIRECT # include # define dirent direct # else # include # endif #endif /* !MSDOS */ #ifdef NOERRNO extern int errno; #endif #ifdef DEBUG extern char *_mtrace_file; #endif #ifdef FD extern char *getenv2 __P_((CONST char *)); extern char *malloc2 __P_((ALLOC_T)); extern char *realloc2 __P_((VOID_P, ALLOC_T)); extern char *c_realloc __P_((char *, ALLOC_T, ALLOC_T *)); extern char *strdup2 __P_((CONST char *)); extern char *strndup2 __P_((CONST char *, int)); extern char *strchr2 __P_((CONST char *, int)); extern char *strcpy2 __P_((char *, CONST char *)); extern char *strncpy2 __P_((char *, CONST char *, int)); # ifdef _USEDOSPATH extern int _dospath __P_((CONST char *)); # endif # if MSDOS extern int dospath3 __P_((CONST char *)); # else extern int dospath __P_((CONST char *, char *)); #define dospath3(path) dospath(path, NULL) # endif extern DIR *Xopendir __P_((CONST char *)); extern int Xclosedir __P_((DIR *)); extern struct dirent *Xreaddir __P_((DIR *)); extern char *Xgetwd __P_((char *)); extern int Xstat __P_((CONST char *, struct stat *)); extern int stat2 __P_((CONST char *, struct stat *)); extern int _chdir2 __P_((CONST char *)); extern int Xaccess __P_((CONST char *, int)); # ifndef _NODOSDRIVE extern int preparedrv __P_((int, int *)); extern VOID shutdrv __P_((int)); # endif # if MSDOS && !defined (_NOUSELFN) extern char *shortname __P_((CONST char *, char *)); # endif extern VOID demacroarg __P_((char **)); extern VOID lostcwd __P_((char *)); extern char *progpath; #else /* !FD */ #define getenv2 (char *)getenv VOID error __P_((CONST char *)); char *malloc2 __P_((ALLOC_T)); char *realloc2 __P_((VOID_P, ALLOC_T)); char *c_realloc __P_((char *, ALLOC_T, ALLOC_T *)); char *strdup2 __P_((CONST char *)); char *strndup2 __P_((CONST char *, int)); char *strchr2 __P_((CONST char *, int)); char *strcpy2 __P_((char *, CONST char *)); char *strncpy2 __P_((char *, CONST char *, int)); # if MSDOS int _dospath __P_((CONST char *)); extern int chdir2 __P_((CONST char *)); DIR *Xopendir __P_((CONST char *)); int Xclosedir __P_((DIR *)); struct dirent *Xreaddir __P_((DIR *)); static u_int NEAR getdosmode __P_((u_int)); static time_t NEAR getdostime __P_((u_int, u_int)); int Xstat __P_((CONST char *, struct stat *)); # ifndef NOSYMLINK # define Xlstat Xstat # endif # else /* !MSDOS */ # define chdir2(p) ((chdir(p)) ? -1 : 0) # define Xopendir opendir # define Xclosedir closedir # define Xreaddir readdir # define Xstat(p, s) ((stat(p, s)) ? -1 : 0) # ifndef NOSYMLINK # define Xlstat(p, s) ((lstat(p, s)) ? -1 : 0) # endif # endif /* !MSDOS */ # define _chdir2 chdir2 # ifdef NOSYMLINK # define stat2 Xstat # else int stat2 __P_((CONST char *, struct stat *)); # endif # ifdef DJGPP char *Xgetwd __P_((char *)); # else /* !DJGPP */ # ifdef USEGETWD # define Xgetwd (char *)getwd # else # define Xgetwd(p) (char *)getcwd(p, MAXPATHLEN) # endif # endif /* !DJGPP */ #define Xaccess(p, m) ((access(p, m)) ? -1 : 0) #endif /* !FD */ static char *NEAR getenvvar __P_((CONST char *, int)); static int NEAR setvar __P_((CONST char *, CONST char *, int)); static int NEAR isescape __P_((CONST char *, int, int, int, int)); #ifdef _NOORIGGLOB static char *NEAR cnvregexp __P_((CONST char *, int)); #else static int NEAR _regexp_exec __P_((CONST reg_t *, CONST char *)); #endif static void NEAR addstrbuf __P_((strbuf_t *, CONST char *, int)); static void NEAR duplwild __P_((wild_t *, CONST wild_t *)); static void NEAR freewild __P_((wild_t *)); static int NEAR _evalwild __P_((int, char ***, wild_t *)); #ifndef _NOUSEHASH static int NEAR calchash __P_((CONST char *)); static VOID NEAR inithash __P_((VOID_A)); static hashlist *NEAR newhash __P_((CONST char *, char *, int, hashlist *)); static VOID NEAR freehash __P_((hashlist **)); static hashlist *NEAR findhash __P_((CONST char *, int)); static VOID NEAR rmhash __P_((CONST char *, int)); #endif static int NEAR isexecute __P_((CONST char *, int, int)); #if MSDOS static int NEAR extaccess __P_((char *, CONST char *, int, int)); #endif #if !defined (FDSH) && !defined (_NOCOMPLETE) static int NEAR completefile __P_((CONST char *, int, int, char ***, CONST char *, int, int)); static int NEAR completeexe __P_((CONST char *, int, int, char ***)); #endif /* !FDSH && !_NOCOMPLETE */ static int NEAR addmeta __P_((char *, CONST char *, int)); static int NEAR skipvar __P_((CONST char **, int *, int *, int)); #ifdef MINIMUMSHELL static int NEAR skipvarvalue __P_((CONST char *, int *, CONST char *, int, int)); static char *NEAR evalshellparam __P_((int, int)); #else /* !MINIMUMSHELL */ static int NEAR skipvarvalue __P_((CONST char *, int *, CONST char *, int, int, int)); static char *NEAR removeword __P_((CONST char *, CONST char *, int, int)); static char **NEAR removevar __P_((char **, CONST char *, int, int)); static char *NEAR evalshellparam __P_((int, int, CONST char *, int, int *)); #endif /* !MINIMUMSHELL */ static int NEAR replacevar __P_((CONST char *, char **, int, int, int, int, int)); static char *NEAR insertarg __P_((char *, int, CONST char *, int, int)); static int NEAR evalvar __P_((char **, int, CONST char **, int)); static char *NEAR replacebackquote __P_((char *, int *, char *, int)); #define BUFUNIT 32 #define b_size(n, type) ((((n) / BUFUNIT) + 1) * BUFUNIT * sizeof(type)) #define b_realloc(ptr, n, type) \ (((n) % BUFUNIT) ? ((type *)(ptr)) \ : (type *)realloc2(ptr, b_size(n, type))) #define getconstvar(s) (getenvvar(s, sizeof(s) - 1)) #ifdef FD #define STRFD "FD" #endif CONST char nullstr[] = ""; CONST char rootpath[] = _SS_; CONST char curpath[] = "."; CONST char parentpath[] = ".."; char **argvar = NULL; #ifndef _NOUSEHASH hashlist **hashtable = NULL; #endif char *(*getvarfunc)__P_((CONST char *, int)) = NULL; int (*putvarfunc)__P_((char *, int)) = NULL; int (*getretvalfunc)__P_((VOID_A)) = NULL; p_id_t (*getpidfunc)__P_((VOID_A)) = NULL; p_id_t (*getlastpidfunc)__P_((VOID_A)) = NULL; char *(*getflagfunc)__P_((VOID_A)) = NULL; int (*checkundeffunc)__P_((CONST char *, CONST char *, int)) = NULL; VOID (*exitfunc)__P_((VOID_A)) = NULL; char *(*backquotefunc)__P_((CONST char *)) = NULL; #ifndef MINIMUMSHELL char *(*posixsubstfunc)__P_((CONST char *, int *)) = NULL; #endif #ifndef PATHNOCASE int pathignorecase = 0; #endif static int skipdotfile = 0; #if !defined (USEREGCMP) && !defined (USEREGCOMP) && !defined (USERE_COMP) static char *wildsymbol1 = "?"; static char *wildsymbol2 = "*"; #endif #if defined (FD) && !defined (NOUID) static uidtable *uidlist = NULL; static int maxuid = 0; static gidtable *gidlist = NULL; static int maxgid = 0; #endif /* FD && !NOUID */ #ifndef FD VOID error(s) CONST char *s; { fputs(s, stderr); fputs(": memory allocation error", stderr); fputnl(stderr); exit(2); } char *malloc2(size) ALLOC_T size; { char *tmp; if (!size || !(tmp = (char *)malloc(size))) { error("malloc()"); #ifdef FAKEUNINIT tmp = NULL; /* fake for -Wuninitialized */ #endif } return(tmp); } char *realloc2(ptr, size) VOID_P ptr; ALLOC_T size; { char *tmp; if (!size || !(tmp = (ptr) ? (char *)realloc(ptr, size) : (char *)malloc(size))) { error("realloc()"); #ifdef FAKEUNINIT tmp = NULL; /* fake for -Wuninitialized */ #endif } return(tmp); } char *c_realloc(ptr, n, sizep) char *ptr; ALLOC_T n, *sizep; { if (!ptr) { *sizep = BUFUNIT; return(malloc2(*sizep)); } while (n + 1 >= *sizep) *sizep *= 2; return(realloc2(ptr, *sizep)); } char *strdup2(s) CONST char *s; { char *tmp; int n; if (!s) return(NULL); n = strlen(s); if (!(tmp = (char *)malloc((ALLOC_T)n + 1))) error("malloc()"); memcpy(tmp, s, n + 1); return(tmp); } char *strndup2(s, n) CONST char *s; int n; { char *tmp; int i; if (!s) return(NULL); for (i = 0; i < n; i++) if (!s[i]) break; if (!(tmp = (char *)malloc((ALLOC_T)i + 1))) error("malloc()"); memcpy(tmp, s, i); tmp[i] = '\0'; return(tmp); } char *strchr2(s, c) CONST char *s; int c; { int i; for (i = 0; s[i]; i++) { if (s[i] == c) return((char *)&(s[i])); if (iskanji1(s, i)) i++; #ifdef CODEEUC else if (isekana(s, i)) i++; #endif } return(NULL); } char *strcpy2(s1, s2) char *s1; CONST char *s2; { int i; for (i = 0; s2[i]; i++) s1[i] = s2[i]; s1[i] = '\0'; return(&(s1[i])); } char *strncpy2(s1, s2, n) char *s1; CONST char *s2; int n; { int i; for (i = 0; i < n && s2[i]; i++) s1[i] = s2[i]; s1[i] = '\0'; return(&(s1[i])); } # if MSDOS int _dospath(path) CONST char *path; { return((isalpha2(*path) && path[1] == ':') ? *path : 0); } DIR *Xopendir(dir) CONST char *dir; { DIR *dirp; char *cp; int i; dirp = (DIR *)malloc2(sizeof(DIR)); dirp -> dd_off = 0; dirp -> dd_buf = malloc2(sizeof(struct find_t)); dirp -> dd_path = malloc2(strlen(dir) + 1 + 3 + 1); cp = strcatdelim2(dirp -> dd_path, dir, NULL); dirp -> dd_id = DID_IFNORMAL; strcpy(cp, "*.*"); if (cp - 1 > dir + 3) i = -1; else i = _dos_findfirst(dirp -> dd_path, DS_IFLABEL, (struct find_t *)(dirp -> dd_buf)); if (i == 0) dirp -> dd_id = DID_IFLABEL; else i = _dos_findfirst(dirp -> dd_path, (SEARCHATTRS | DS_IFLABEL), (struct find_t *)(dirp -> dd_buf)); if (i < 0) { if (!errno || errno == _ENOENT_) dirp -> dd_off = -1; else { free(dirp -> dd_path); free(dirp -> dd_buf); free(dirp); return(NULL); } } return(dirp); } int Xclosedir(dirp) DIR *dirp; { free(dirp -> dd_buf); free(dirp -> dd_path); free(dirp); return(0); } struct dirent *Xreaddir(dirp) DIR *dirp; { static struct dirent d; struct find_t *findp; int n; if (dirp -> dd_off < 0) return(NULL); d.d_off = dirp -> dd_off; findp = (struct find_t *)(dirp -> dd_buf); strcpy(d.d_name, findp -> ff_name); if (!(dirp -> dd_id & DID_IFLABEL)) n = _dos_findnext(findp); else n = _dos_findfirst(dirp -> dd_path, SEARCHATTRS, findp); if (n == 0) dirp -> dd_off++; else dirp -> dd_off = -1; dirp -> dd_id &= ~DID_IFLABEL; return(&d); } static u_int NEAR getdosmode(attr) u_int attr; { u_int mode; mode = 0; if (attr & DS_IARCHIVE) mode |= S_ISVTX; if (!(attr & DS_IHIDDEN)) mode |= S_IREAD; if (!(attr & DS_IRDONLY)) mode |= S_IWRITE; if (attr & DS_IFDIR) mode |= (S_IFDIR | S_IEXEC); else if (attr & DS_IFLABEL) mode |= S_IFIFO; else if (attr & DS_IFSYSTEM) mode |= S_IFSOCK; else mode |= S_IFREG; return(mode); } static time_t NEAR getdostime(d, t) u_int d, t; { struct tm tm; tm.tm_year = 1980 + ((d >> 9) & 0x7f); tm.tm_year -= 1900; tm.tm_mon = ((d >> 5) & 0x0f) - 1; tm.tm_mday = (d & 0x1f); tm.tm_hour = ((t >> 11) & 0x1f); tm.tm_min = ((t >> 5) & 0x3f); tm.tm_sec = ((t << 1) & 0x3e); tm.tm_isdst = -1; return(mktime(&tm)); } int Xstat(path, stp) CONST char *path; struct stat *stp; { struct find_t find; if (_dos_findfirst(path, SEARCHATTRS, &find) != 0) return(-1); stp -> st_mode = getdosmode(find.ff_attrib); stp -> st_mtime = getdostime(find.ff_fdate, find.ff_ftime); stp -> st_size = find.ff_fsize; stp -> st_ctime = stp -> st_atime = stp -> st_mtime; stp -> st_dev = stp -> st_ino = 0; stp -> st_nlink = 1; stp -> st_uid = stp -> st_gid = -1; return(0); } # endif /* MSDOS */ # ifndef NOSYMLINK int stat2(path, stp) CONST char *path; struct stat *stp; { int duperrno; if (Xstat(path, stp) < 0) { duperrno = errno; if (Xlstat(path, stp) < 0 || (stp -> st_mode & S_IFMT) != S_IFLNK) { errno = duperrno; return(-1); } stp -> st_mode &= ~S_IFMT; } return(0); } # endif /* !NOSYMLINK */ # ifdef DJGPP char *Xgetwd(path) char *path; { char *cp; int i; if (!(cp = (char *)getcwd(path, MAXPATHLEN))) return(NULL); for (i = 0; cp[i]; i++) if (cp[i] == '/') cp[i] = _SC_; return(cp); } # endif /* !DJGPP */ #endif /* !FD */ #if MSDOS || (defined (FD) && !defined (_NODOSDRIVE)) char *gendospath(path, drive, c) char *path; int drive, c; { *(path++) = drive; *(path++) = ':'; if (c) *(path++) = c; *path = '\0'; return(path); } char *strdelim(s, d) CONST char *s; int d; { int i; if (d && _dospath(s)) return((char *)&(s[1])); for (i = 0; s[i]; i++) { if (s[i] == _SC_) return((char *)&(s[i])); # ifdef BSPATHDELIM if (iskanji1(s, i)) i++; # endif } return(NULL); } char *strrdelim(s, d) CONST char *s; int d; { CONST char *cp; int i; if (d && _dospath(s)) cp = &(s[1]); else cp = NULL; for (i = 0; s[i]; i++) { if (s[i] == _SC_) cp = &(s[i]); # ifdef BSPATHDELIM if (iskanji1(s, i)) i++; # endif } return((char *)cp); } #endif /* MSDOS || (FD && !_NODOSDRIVE) */ #ifdef FD char *strrdelim2(s, eol) CONST char *s, *eol; { # ifdef BSPATHDELIM CONST char *cp; int i; cp = NULL; for (i = 0; s[i] && &(s[i]) < eol; i++) { if (s[i] == _SC_) cp = &(s[i]); if (iskanji1(s, i)) i++; } return((char *)cp); # else for (eol--; eol >= s; eol--) if (*eol == _SC_) return((char *)eol); return(NULL); # endif } #endif /* FD */ int isdelim(s, ptr) CONST char *s; int ptr; { #ifdef BSPATHDELIM int i; #endif if (ptr < 0 || s[ptr] != _SC_) return(0); #ifdef BSPATHDELIM if (--ptr < 0) return(1); if (!ptr) return(!iskanji1(s, 0)); for (i = 0; s[i] && i < ptr; i++) if (iskanji1(s, i)) i++; if (!s[i] || i > ptr) return(1); return(!iskanji1(s, i)); #else return(1); #endif } char *strcatdelim(s) char *s; { char *cp; int i; #if MSDOS || (defined (FD) && !defined (_NODOSDRIVE)) if (_dospath(s)) i = 2; else #endif #ifdef DOUBLESLASH if (isdslash(s)) i = 1; else #endif i = 0; if (!s[i]) return(&(s[i])); if (s[i] == _SC_ && !s[i + 1]) return(&(s[i + 1])); cp = NULL; for (; s[i]; i++) { if (s[i] == _SC_) { if (!cp) cp = &(s[i]); continue; } cp = NULL; #ifdef BSPATHDELIM if (iskanji1(s, i)) i++; #endif } if (!cp) { cp = &(s[i]); if (i >= MAXPATHLEN - 1) return(cp); *cp = _SC_; } *(++cp) = '\0'; return(cp); } char *strcatdelim2(buf, s1, s2) char *buf; CONST char *s1, *s2; { char *cp; int i, len; #if MSDOS || (defined (FD) && !defined (_NODOSDRIVE)) if (_dospath(s1)) { buf[0] = s1[0]; buf[1] = s1[1]; i = 2; } else #endif #ifdef DOUBLESLASH if (isdslash(s1)) { buf[0] = s1[0]; i = 1; } else #endif i = 0; if (!s1[i]) cp = &(buf[i]); else if (s1[i] == _SC_ && !s1[i + 1]) { cp = &(buf[i]); *(cp++) = _SC_; } else { cp = NULL; for (; s1[i]; i++) { if (i >= MAXPATHLEN - 1) { buf[i] = '\0'; return(&(buf[i])); } buf[i] = s1[i]; if (s1[i] == _SC_) { if (!cp) cp = &(buf[i]) + 1; continue; } cp = NULL; #ifdef BSPATHDELIM if (iskanji1(s1, i)) { if (!s1[++i]) break; buf[i] = s1[i]; } #endif } if (!cp) { cp = &(buf[i]); if (i >= MAXPATHLEN - 1) { *cp = '\0'; return(cp); } *(cp++) = _SC_; } } if (s2) { len = MAXPATHLEN - 1 - (cp - buf); for (i = 0; s2[i] && i < len; i++) *(cp++) = s2[i]; } *cp = '\0'; return(cp); } int strcasecmp2(s1, s2) CONST char *s1, *s2; { int c1, c2; for (;;) { c1 = toupper2(*s1); c2 = toupper2(*s2); if (c1 != c2) return(c1 - c2); #ifndef CODEEUC if (issjis1(*s1)) { s1++; s2++; if (*s1 != *s2) return((u_char)*s1 - (u_char)*s2); } #endif if (!*s1) break; s1++; s2++; } return(0); } int strncasecmp2(s1, s2, n) CONST char *s1, *s2; int n; { int c1, c2; while (n-- > 0) { c1 = toupper2(*s1); c2 = toupper2(*s2); if (c1 != c2) return(c1 - c2); #ifndef CODEEUC if (issjis1(*s1)) { if (n-- <= 0) break; s1++; s2++; if (*s1 != *s2) return((u_char)*s1 - (u_char)*s2); } #endif if (!*s1) break; s1++; s2++; } return(0); } #ifndef PATHNOCASE int strpathcmp2(s1, s2) CONST char *s1, *s2; { if (pathignorecase) return(strcasecmp2(s1, s2)); return(strcmp(s1, s2)); } int strnpathcmp2(s1, s2, n) CONST char *s1, *s2; int n; { if (pathignorecase) return(strncasecmp2(s1, s2, n)); return(strncmp(s1, s2, n)); } #endif /* !PATHNOCASE */ #ifdef FD char *underpath(path, dir, len) CONST char *path, *dir; int len; { char *cp; if (len < 0) len = strlen(dir); if ((cp = strrdelim2(dir, &(dir[len]))) && !cp[1]) len = cp - dir; if (len <= 0 || strnpathcmp(path, dir, len)) return(NULL); if (path[len] && path[len] != _SC_) return(NULL); return((char *)&(path[len])); } #endif /* FD */ static char *NEAR getenvvar(ident, len) CONST char *ident; int len; { #if (!defined (FD) && !defined (FDSH)) || defined (_NOORIGSHELL) char *cp, *env; #endif if (getvarfunc) return((*getvarfunc)(ident, len)); #if (defined (FD) || defined (FDSH)) && !defined (_NOORIGSHELL) return(NULL); #else if (len < 0) len = strlen(ident); cp = strndup2(ident, len); env = getenv2(cp); free(cp); return(env); #endif } static int NEAR setvar(ident, value, len) CONST char *ident, *value; int len; { char *cp; int ret, vlen; vlen = strlen(value); cp = malloc2(len + 1 + vlen + 1); strncpy(cp, ident, len); cp[len] = '='; strncpy2(&(cp[len + 1]), value, vlen); #if defined (FD) || defined (FDSH) ret = (putvarfunc) ? (*putvarfunc)(cp, len) : -1; #else ret = (putvarfunc) ? (*putvarfunc)(cp, len) : putenv(cp); #endif if (ret < 0) free(cp); return(ret); } int isidentchar(c) int c; { return(c == '_' || isalpha2(c)); } int isidentchar2(c) int c; { return(c == '_' || isalnum2(c)); } int isdotdir(s) CONST char *s; { if (s[0] != '.') /*EMPTY*/; else if (!s[1]) return(2); else if (s[1] != '.') /*EMPTY*/; else if (!s[2]) return(1); return(0); } char *isrootdir(s) CONST char *s; { #if MSDOS || (defined (FD) && !defined (_NODOSDRIVE)) if (_dospath(s)) s += 2; #endif if (*s != _SC_) return(NULL); return((char *)s); } int isrootpath(s) CONST char *s; { return((s[0] == _SC_ && !s[1]) ? 1 : 0); } VOID copyrootpath(s) char *s; { *(s++) = _SC_; *s = '\0'; } VOID copycurpath(s) char *s; { *(s++) = '.'; *s = '\0'; } #ifdef DOUBLESLASH int isdslash(s) CONST char *s; { # if MSDOS || defined (CYGWIN) char *cp; if (s[0] != _SC_ || s[1] != _SC_ || !s[2] || s[2] == _SC_) return(0); if ((cp = strdelim(&(s[2]), 0))) return(cp - s); return(strlen(s)); # else return((s[0] == _SC_ && s[1] == _SC_) ? 2 : 0); # endif } #endif /* DOUBLESLASH */ char *getbasename(s) CONST char *s; { char *cp; if ((cp = strrdelim(s, 1))) return(&(cp[1])); return((char *)s); } char *getshellname(s, loginp, restrictedp) CONST char *s; int *loginp, *restrictedp; { if (loginp) *loginp = 0; if (restrictedp) *restrictedp = 0; if (*s == '-') { s++; if (loginp) *loginp = 1; } #ifdef PATHNOCASE if (tolower2(*s) == 'r') #else if (*s == 'r') #endif { s++; if (restrictedp) *restrictedp = 1; } return((char *)s); } static int NEAR isescape(s, ptr, quote, len, flags) CONST char *s; int ptr, quote, len, flags; { #ifdef FAKEMETA return(0); #else /* !FAKEMETA */ if (s[ptr] != PMETA || quote == '\'') return(0); if (len >= 0) { if (!(flags & EA_EOLMETA) && ptr + 1 >= len) return(0); # ifndef BASHSTYLE /* bash does not treat "\" as \ */ if (quote == '"' && s[ptr + 1] == quote && ptr + 2 >= len) return(0); # endif } else { if (!(flags & EA_EOLMETA) && !s[ptr + 1]) return(0); # ifndef BASHSTYLE /* bash does not treat "\" as \ */ if (quote == '"' && s[ptr + 1] == quote && !s[ptr + 2]) return(0); # endif } # ifdef BSPATHDELIM if (quote == '"') { if (!strchr(DQ_METACHAR, s[ptr + 1])) return(0); } else { /* if (!quote || quote == '`') */ if (!strchr(METACHAR, s[ptr + 1])) return(0); } # endif return(1); #endif /* !FAKEMETA */ } #ifdef _NOORIGGLOB static char *NEAR cnvregexp(s, len) CONST char *s; int len; { char *re; ALLOC_T size; int i, j, paren; if (!*s) { s = "*"; len = 1; } if (len < 0) len = strlen(s); re = c_realloc(NULL, 0, &size); paren = j = 0; re[j++] = '^'; for (i = 0; i < len; i++) { re = c_realloc(re, j + 2, &size); if (paren) { if (s[i] == ']') paren = 0; re[j++] = s[i]; continue; } else if (isescape(s, i, '\0', len, 0)) { re[j++] = s[i++]; re[j++] = s[i]; } else switch (s[i]) { case '?': re[j++] = '.'; break; case '*': re[j++] = '.'; re[j++] = '*'; break; case '[': paren = 1; re[j++] = s[i]; break; case '^': case '$': case '.': re[j++] = '\\'; re[j++] = s[i]; break; default: re[j++] = s[i]; break; } } re[j++] = '$'; re[j++] = '\0'; return(re); } #endif /* _NOORIGGLOB */ #ifdef USERE_COMP extern char *re_comp __P_((CONST char *)); extern int re_exec __P_((CONST char *)); # ifdef PATHNOCASE extern int re_ignore_case; # endif reg_t *regexp_init(s, len) CONST char *s; int len; { char *new; # ifdef PATHNOCASE re_ignore_case = 1; # endif skipdotfile = (*s == '*' || *s == '?' || *s == '['); new = cnvregexp(s, len); re_comp(new); free(new); return((reg_t *)1); } /*ARGSUSED*/ int regexp_exec(re, s, fname) CONST reg_t *re; CONST char *s; int fname; { if (fname && skipdotfile && *s == '.') return(0); return(re_exec(s) > 0); } /*ARGSUSED*/ VOID regexp_free(re) reg_t *re; { return; } #else /* !USERE_COMP */ # ifdef USEREGCOMP reg_t *regexp_init(s, len) CONST char *s; int len; { reg_t *re; char *new; skipdotfile = (*s == '*' || *s == '?' || *s == '['); s = new = cnvregexp(s, len); re = (reg_t *)malloc2(sizeof(reg_t)); # ifdef PATHNOCASE if (regcomp(re, s, REG_EXTENDED | REG_ICASE)) { # else if (regcomp(re, s, REG_EXTENDED | (pathignorecase ? REG_ICASE : 0))) { # endif free(re); re = NULL; } free(new); return(re); } int regexp_exec(re, s, fname) CONST reg_t *re; CONST char *s; int fname; { if (!re || (fname && skipdotfile && *s == '.')) return(0); return(!regexec(re, s, 0, NULL, 0)); } VOID regexp_free(re) reg_t *re; { if (re) { regfree(re); free(re); } } # else /* !USEREGCOMP */ # ifdef USEREGCMP extern char *regcmp __P_((CONST char *, int)); extern char *regex __P_((CONST char *, CONST char *, ...)); reg_t *regexp_init(s, len) CONST char *s; int len; { reg_t *re; char *new; skipdotfile = (*s == '*' || *s == '?' || *s == '['); new = cnvregexp(s, len); re = regcmp(new, 0); free(new); return(re); } int regexp_exec(re, s, fname) CONST reg_t *re; CONST char *s; int fname; { if (!re || (fname && skipdotfile && *s == '.')) return(0); return(regex(re, s) ? 1 : 0); } VOID regexp_free(re) reg_t *re; { if (re) free(re); } # else /* !USEREGCMP */ reg_t *regexp_init(s, len) CONST char *s; int len; { reg_t *re; char *cp, *paren; ALLOC_T size; int i, j, n, pc, plen, metachar, quote; skipdotfile = 0; if (len < 0) len = strlen(s); re = NULL; paren = NULL; n = plen = size = 0; quote = '\0'; re = b_realloc(re, n, reg_t); re[n] = NULL; for (i = 0; i < len; i++) { cp = NULL; metachar = 0; pc = parsechar(&(s[i]), len - i, '\0', 0, "e, NULL); if (pc == PC_OPQUOTE || pc == PC_CLQUOTE) continue; else if (pc == PC_ESCAPE) { metachar = 1; i++; } if (paren) { paren = c_realloc(paren, plen + 1, &size); if (quote || metachar) { #ifdef BASHSTYLE /* bash treats a character quoted by \ in "[]" as a character itself */ paren[plen++] = PMETA; # ifndef PATHNOCASE if (!pathignorecase) paren[plen++] = s[i]; else # endif paren[plen++] = toupper2(s[i]); #endif } else if (s[i] == ']') { if (!plen) { free(paren); regexp_free(re); return(NULL); } #ifndef BASHSTYLE /* bash treats "[a-]]" as "[a-]" + "]" */ if (paren[plen - 1] == '-') { paren[plen++] = s[i]; continue; } #endif paren[plen] = '\0'; cp = realloc2(paren, plen + 1); paren = NULL; } #ifdef BASHSTYLE /* bash treats "[^abc]" as "[!abc]" */ else if (!plen && (s[i] == '!' || s[i] == '^')) paren[plen++] = '\0'; #else else if (!plen && s[i] == '!') paren[plen++] = '\0'; #endif else if (s[i] == '-') { if (i + 1 >= len) j = '\0'; #ifndef PATHNOCASE else if (!pathignorecase) j = s[i + 1]; #endif else j = toupper2(s[i + 1]); #ifdef BASHSTYLE /* bash does not allow "[b-a]" */ if (plen && j && j != ']' && j < paren[plen - 1]) { free(paren); regexp_free(re); return(NULL); } #else /* Bourne shell ignores "[b-a]" */ if (plen && j && j < paren[plen - 1]) { do { if (i + 1 >= len) break; i++; } while (s[i + 1] != ']'); } /* Bourne shell does not allow "[-a]" */ else if ((!plen && j != '-')) { free(paren); regexp_free(re); return(NULL); } #endif else paren[plen++] = s[i]; } else if (iskanji1(s, i)) { paren[plen++] = s[i++]; paren[plen++] = s[i]; } #ifdef CODEEUC else if (isekana(s, i)) { paren[plen++] = s[i++]; paren[plen++] = s[i]; } #endif #ifndef PATHNOCASE else if (!pathignorecase) paren[plen++] = s[i]; #endif else paren[plen++] = toupper2(s[i]); } else if (!quote && !metachar) switch (s[i]) { case '?': cp = wildsymbol1; if (!n) skipdotfile++; break; case '*': cp = wildsymbol2; if (!n) skipdotfile++; break; case '[': paren = c_realloc(NULL, 0, &size); plen = 0; if (!n) skipdotfile++; break; default: break; } if (paren) continue; if (!cp) { cp = malloc2(2 + 1); j = 0; if (iskanji1(s, i)) { cp[j++] = s[i++]; cp[j++] = s[i]; } #ifdef CODEEUC else if (isekana(s, i)) { cp[j++] = s[i++]; cp[j++] = s[i]; } #endif #ifndef PATHNOCASE else if (!pathignorecase) cp[j++] = s[i]; #endif else cp[j++] = toupper2(s[i]); cp[j] = '\0'; } re[n++] = cp; re = b_realloc(re, n, reg_t); re[n] = NULL; } if (paren) { free(paren); if (plen) { regexp_free(re); return(NULL); } cp = strdup2("["); re[n++] = cp; re = b_realloc(re, n, reg_t); re[n] = NULL; } return((reg_t *)realloc2(re, (n + 1) * sizeof(reg_t))); } static int NEAR _regexp_exec(re, s) CONST reg_t *re; CONST char *s; { int i, n1, n2, c1, c2, beg, rev; for (n1 = n2 = 0; re[n1] && s[n2]; n1++, n2++) { c1 = (u_char)(s[i = n2]); if (iskanji1(s, n2)) c1 = (c1 << 8) + (u_char)(s[++n2]); #ifdef CODEEUC else if (isekana(s, n2)) c1 = (c1 << 8) + (u_char)(s[++n2]); #endif #ifndef PATHNOCASE else if (!pathignorecase) /*EMPTY*/; #endif else c1 = toupper2(c1); if (re[n1] == wildsymbol1) continue; if (re[n1] == wildsymbol2) { if (_regexp_exec(&(re[n1 + 1]), &(s[i]))) return(1); n1--; continue; } i = rev = 0; if (!re[n1][i]) { rev = 1; i++; } beg = -1; c2 = '\0'; for (; re[n1][i]; i++) { #ifdef BASHSTYLE /* bash treats a character quoted by \ in "[]" as a character itself */ if (re[n1][i] == PMETA && re[n1][i + 1]) i++; /* bash treats "[a-]]" as "[a-]" + "]" */ else if (re[n1][i] == '-' && re[n1][i + 1] && c2) #else if (re[n1][i] == '-' && c2) #endif { beg = c2; i++; } c2 = (u_char)(re[n1][i]); if (iskanji1(re[n1], i)) c2 = (c2 << 8) + (u_char)(re[n1][++i]); #ifdef CODEEUC else if (isekana(re[n1], i)) c2 = (c2 << 8) + (u_char)(re[n1][++i]); #endif if (beg >= 0) { if (beg && c1 >= beg && c1 <= c2) break; beg = -1; } else if (c1 == c2) break; } if (rev) { if (re[n1][i]) return(0); } else { if (!re[n1][i]) return(0); } } while (re[n1] == wildsymbol2) n1++; if (re[n1] || s[n2]) return(0); return(1); } int regexp_exec(re, s, fname) CONST reg_t *re; CONST char *s; int fname; { if (!re || (fname && skipdotfile && *s == '.')) return(0); return(_regexp_exec(re, s)); } VOID regexp_free(re) reg_t *re; { int i; if (re) { for (i = 0; re[i]; i++) if (re[i] != wildsymbol1 && re[i] != wildsymbol2) free(re[i]); free(re); } } # endif /* !USEREGCMP */ # endif /* !USEREGCOMP */ #endif /* !USERE_COMP */ static void NEAR addstrbuf(sp, s, len) strbuf_t *sp; CONST char *s; int len; { sp -> s = c_realloc(sp -> s, sp -> len + len, &(sp -> size)); memcpy(&(sp -> s[sp -> len]), s, len); sp -> len += len; sp -> s[sp -> len] = '\0'; } static void NEAR duplwild(dst, src) wild_t *dst; CONST wild_t *src; { memcpy((char *)dst, (char *)src, sizeof(wild_t)); dst -> fixed.s = (char *)malloc2(src -> fixed.size); memcpy(dst -> fixed.s, src -> fixed.s, src -> fixed.len + 1); dst -> path.s = (char *)malloc2(src -> path.size); memcpy(dst -> path.s, src -> path.s, src -> path.len + 1); #ifndef NODIRLOOP if (src -> ino) { dst -> ino = (devino_t *)malloc2(src -> nino * sizeof(devino_t)); memcpy((char *)(dst -> ino), (char *)(src -> ino), src -> nino * sizeof(devino_t)); } #endif /* !NODIRLOOP */ } static void NEAR freewild(wp) wild_t *wp; { if (wp -> fixed.s) free(wp -> fixed.s); if (wp -> path.s) free(wp -> path.s); #ifndef NODIRLOOP if (wp -> ino) free(wp -> ino); #endif } static int NEAR _evalwild(argc, argvp, wp) int argc; char ***argvp; wild_t *wp; { #ifdef DOUBLESLASH int ds; #endif DIR *dirp; struct dirent *dp; struct stat st; reg_t *re; wild_t dupl; ALLOC_T flen, plen; CONST char *cp; char *new; int i, n, w, pc, quote, isdir; if (!*(wp -> s)) { if (!(wp -> fixed.len)) return(argc); *argvp = (char **)realloc2(*argvp, (argc + 2) * sizeof(char *)); (*argvp)[argc++] = wp -> fixed.s; wp -> fixed.s = NULL; return(argc); } flen = wp -> fixed.len; plen = wp -> path.len; quote = wp -> quote; if (wp -> fixed.len) addstrbuf(&(wp -> path), rootpath, 1); #ifdef DOUBLESLASH if (wp -> path.len) ds = 0; else if ((ds = isdslash(wp -> s))) { addstrbuf(&(wp -> fixed), wp -> s, ds); addstrbuf(&(wp -> path), wp -> s, ds); wp -> s += ds; } #endif for (i = w = 0; wp -> s[i] && wp -> s[i] != _SC_; i++) { pc = parsechar(&(wp -> s[i]), -1, '\0', 0, &(wp -> quote), NULL); if (pc == PC_OPQUOTE || pc == PC_CLQUOTE) { if (!(wp -> flags & EA_STRIPQ)) addstrbuf(&(wp -> fixed), &(wp -> s[i]), 1); continue; } else if (pc == PC_WORD) { addstrbuf(&(wp -> fixed), &(wp -> s[i]), 1); addstrbuf(&(wp -> path), &(wp -> s[i]), 1); i++; } else if (pc == PC_ESCAPE) { if (wp -> flags & EA_KEEPMETA) addstrbuf(&(wp -> fixed), &(wp -> s[i]), 1); if (wp -> s[i + 1] == _SC_) continue; if (wp -> quote == '\'' || (wp -> quote == '"' && !strchr(DQ_METACHAR, wp -> s[i + 1]))) { if (!(wp -> flags & EA_KEEPMETA)) addstrbuf(&(wp -> fixed), &(wp -> s[i]), 1); addstrbuf(&(wp -> path), &(wp -> s[i]), 1); } i++; } else if (pc == PC_NORMAL && strchr("?*[", wp -> s[i])) { if (w >= 0 && wp -> s[i] == '*') w++; else w = -1; } addstrbuf(&(wp -> fixed), &(wp -> s[i]), 1); addstrbuf(&(wp -> path), &(wp -> s[i]), 1); } if (!(wp -> s[i])) isdir = 0; else { isdir = 1; addstrbuf(&(wp -> fixed), rootpath, 1); } if (!w) { if (wp -> path.len <= plen) w++; #ifdef DOUBLESLASH else if (ds) st.st_mode = S_IFDIR; #endif else if (stat2(wp -> path.s, &st) < 0) return(argc); wp -> s += i; if (isdir) { if (!w && (st.st_mode & S_IFMT) != S_IFDIR) return(argc); (wp -> s)++; } #ifndef NODIRLOOP # ifdef DOUBLESLASH if (ds) /*EMPTY*/; else # endif if (!w) { wp -> ino = (devino_t *)realloc2(wp -> ino, (wp -> nino + 1) * sizeof(devino_t)); wp -> ino[wp -> nino].dev = st.st_dev; wp -> ino[(wp -> nino)++].ino = st.st_ino; } #endif /* !NODIRLOOP */ return(_evalwild(argc, argvp, wp)); } if (w != 2 || !isdir || strcmp(&(wp -> path.s[plen]), "**")) w = -1; wp -> fixed.len = flen; wp -> path.len = plen; wp -> fixed.s[flen] = wp -> path.s[plen] = '\0'; if (w > 0) { duplwild(&dupl, wp); dupl.s += i + 1; argc = _evalwild(argc, argvp, &dupl); freewild(&dupl); re = NULL; } else { new = malloc2(i + 2); n = 0; if (quote) new[n++] = quote; memcpy(&(new[n]), wp -> s, i); n += i; if (wp -> quote) new[n++] = wp -> quote; re = regexp_init(new, n); free(new); if (!re) return(argc); wp -> s += i + 1; } if (wp -> path.len) cp = wp -> path.s; else if (wp -> fixed.len) cp = rootpath; else cp = curpath; if (!(dirp = Xopendir(cp))) { regexp_free(re); return(argc); } if (wp -> path.len || wp -> fixed.len) addstrbuf(&(wp -> path), rootpath, 1); while ((dp = Xreaddir(dirp))) { if (isdotdir(dp -> d_name)) continue; duplwild(&dupl, wp); n = strlen(dp -> d_name); addstrbuf(&(dupl.fixed), dp -> d_name, n); addstrbuf(&(dupl.path), dp -> d_name, n); if (isdir) { if (re) n = regexp_exec(re, dp -> d_name, 1); else n = (*(dp -> d_name) == '.') ? 0 : 1; if (!n || Xstat(dupl.path.s, &st) < 0 || (st.st_mode & S_IFMT) != S_IFDIR) { freewild(&dupl); continue; } #ifndef NODIRLOOP if (!re) { for (n = 0; n < dupl.nino; n++) if (dupl.ino[n].dev == st.st_dev && dupl.ino[n].ino == st.st_ino) break; if (n < dupl.nino) { freewild(&dupl); continue; } } dupl.ino = (devino_t *)realloc2(dupl.ino, (dupl.nino + 1) * sizeof(devino_t)); dupl.ino[dupl.nino].dev = st.st_dev; dupl.ino[(dupl.nino)++].ino = st.st_ino; #endif addstrbuf(&(dupl.fixed), rootpath, 1); argc = _evalwild(argc, argvp, &dupl); } else if (regexp_exec(re, dp -> d_name, 1)) { *argvp = (char **)realloc2(*argvp, (argc + 2) * sizeof(char *)); (*argvp)[argc++] = dupl.fixed.s; dupl.fixed.s = NULL; } freewild(&dupl); } Xclosedir(dirp); regexp_free(re); return(argc); } int cmppath(vp1, vp2) CONST VOID_P vp1; CONST VOID_P vp2; { return(strpathcmp2(*((char **)vp1), *((char **)vp2))); } char **evalwild(s, flags) CONST char *s; int flags; { wild_t w; char **argv; int argc; argv = (char **)malloc2(1 * sizeof(char *)); w.s = s; w.fixed.s = c_realloc(NULL, 0, &(w.fixed.size)); w.path.s = c_realloc(NULL, 0, &(w.path.size)); w.fixed.len = w.path.len = (ALLOC_T)0; w.quote = '\0'; #ifndef NODIRLOOP w.nino = 0; w.ino = NULL; #endif w.flags = flags; argc = _evalwild(0, &argv, &w); freewild(&w); if (!argc) { free(argv); return(NULL); } argv[argc] = NULL; if (argc > 1) qsort(argv, argc, sizeof(char *), cmppath); return(argv); } #ifndef _NOUSEHASH static int NEAR calchash(s) CONST char *s; { u_int n; int i; for (i = n = 0; s[i]; i++) n += (u_char)(s[i]); return(n % MAXHASH); } static VOID NEAR inithash(VOID_A) { int i; if (hashtable) return; hashtable = (hashlist **)malloc2(MAXHASH * sizeof(hashlist *)); for (i = 0; i < MAXHASH; i++) hashtable[i] = NULL; } static hashlist *NEAR newhash(com, path, cost, next) CONST char *com; char *path; int cost; hashlist *next; { hashlist *new; new = (hashlist *)malloc2(sizeof(hashlist)); new -> command = strdup2(com); new -> path = path; new -> hits = 0; new -> cost = cost; new -> next = next; return(new); } static VOID NEAR freehash(htable) hashlist **htable; { hashlist *hp, *next; int i; if (!htable) { if (!hashtable) return; htable = hashtable; } for (i = 0; i < MAXHASH; i++) { next = NULL; for (hp = htable[i]; hp; hp = next) { next = hp -> next; free(hp -> command); free(hp -> path); free(hp); } htable[i] = NULL; } free(htable); if (htable == hashtable) hashtable = NULL; } hashlist **duplhash(htable) hashlist **htable; { CONST hashlist *hp; hashlist **nextp, **new; int i; if (!htable) return(NULL); new = (hashlist **)malloc2(MAXHASH * sizeof(hashlist *)); for (i = 0; i < MAXHASH; i++) { *(nextp = &(new[i])) = NULL; for (hp = htable[i]; hp; hp = hp -> next) { *nextp = newhash(hp -> command, strdup2(hp -> path), hp -> cost, NULL); (*nextp) -> type = hp -> type; (*nextp) -> hits = hp -> hits; nextp = &((*nextp) -> next); } } return(new); } static hashlist *NEAR findhash(com, n) CONST char *com; int n; { hashlist *hp; for (hp = hashtable[n]; hp; hp = hp -> next) if (!strpathcmp(com, hp -> command)) return(hp); return(NULL); } static VOID NEAR rmhash(com, n) CONST char *com; int n; { hashlist *hp, *prev; prev = NULL; for (hp = hashtable[n]; hp; hp = hp -> next) { if (!strpathcmp(com, hp -> command)) { if (!prev) hashtable[n] = hp -> next; else prev -> next = hp -> next; free(hp -> command); free(hp -> path); free(hp); return; } prev = hp; } } #endif /* !_NOUSEHASH */ static int NEAR isexecute(path, dirok, exe) CONST char *path; int dirok, exe; { struct stat st; int d; if (stat2(path, &st) < 0) return(-1); d = ((st.st_mode & S_IFMT) == S_IFDIR); if (!exe) return(d); if (d) return(dirok ? d : -1); return(Xaccess(path, X_OK)); } #if MSDOS static int NEAR extaccess(path, ext, len, exe) char *path; CONST char *ext; int len, exe; { if (ext) { if (isexecute(path, 0, exe) >= 0) { if (!(strpathcmp(ext, EXTCOM))) return(0); else if (!(strpathcmp(ext, EXTEXE))) return(CM_EXE); else if (!(strpathcmp(ext, EXTBAT))) return(CM_BATCH); } } else { path[len++] = '.'; strcpy(&(path[len]), EXTCOM); if (isexecute(path, 0, exe) >= 0) return(CM_ADDEXT); strcpy(&(path[len]), EXTEXE); if (isexecute(path, 0, exe) >= 0) return(CM_ADDEXT | CM_EXE); strcpy(&(path[len]), EXTBAT); if (isexecute(path, 0, exe) >= 0) return(CM_ADDEXT | CM_BATCH); } return(-1); } #endif /* MSDOS */ int searchhash(hpp, com, search) hashlist **hpp; CONST char *com, *search; { #if MSDOS char *ext; #endif CONST char *cp, *next; char *tmp, *path; int len, dlen, cost, size, ret; #ifndef _NOUSEHASH hashlist *hp; int n, recalc, duperrno; if (!hpp || (!com && !search)) { duperrno = errno; if (!com && !search) freehash(hpp); if (!hpp && hashtable) for (n = 0; n < MAXHASH; n++) { for (hp = hashtable[n]; hp; hp = hp -> next) if (hp -> type & CM_RECALC) hp -> type |= CM_REHASH; } errno = duperrno; return(CM_NOTFOUND); } #endif #if MSDOS if ((ext = strrchr(com, '.')) && strdelim(++ext, 0)) ext = NULL; #endif if (strdelim(com, 1)) { #if MSDOS len = strlen(com); path = malloc2(len + EXTWIDTH + 1); strcpy(path, com); ret = extaccess(path, ext, len, 0); free(path); if (ret >= 0) return(ret | CM_FULLPATH); #else if (isexecute(com, 0, 0) >= 0) return(CM_FULLPATH); #endif return(CM_NOTFOUND | CM_FULLPATH); } #ifndef _NOUSEHASH if (!hashtable) inithash(); n = calchash(com); if ((*hpp = findhash(com, n))) { if (!((*hpp) -> type & CM_REHASH) && isexecute((*hpp) -> path, 0, 1) >= 0) return((*hpp) -> type); rmhash(com, n); } #endif #ifdef CWDINPATH len = strlen(com); path = malloc2(len + 2 + EXTWIDTH + 1); path[0] = '.'; path[1] = _SC_; strcpy(&(path[2]), com); # if MSDOS if ((ret = extaccess(path, ext, len + 2, 1)) < 0) free(path); # else if ((ret = isexecute(path, 0, 0)) < 0) free(path); # endif else { # ifdef _NOUSEHASH *hpp = (hashlist *)path; # else *hpp = newhash(com, path, 0, hashtable[n]); hashtable[n] = *hpp; (*hpp) -> type = (ret |= (CM_HASH | CM_RECALC)); # endif return(ret); } #endif /* CWDINPATH */ #ifndef _NOUSEHASH recalc = 0; #endif if ((next = (search) ? search : getconstvar(ENVPATH))) { len = strlen(com); size = ret = 0; path = NULL; cost = 1; for (cp = next; cp; cp = next) { next = cp; #if MSDOS || (defined (FD) && !defined (_NODOSDRIVE)) if (_dospath(cp)) next += 2; #endif #ifndef _NOUSEHASH if (*next != _SC_) recalc = CM_RECALC; #endif next = strchr(next, PATHDELIM); dlen = (next) ? (next++) - cp : strlen(cp); if (!dlen) tmp = NULL; else { tmp = _evalpath(cp, &(cp[dlen]), 0); dlen = strlen(tmp); } if (dlen + len + 1 + EXTWIDTH + 1 > size) { size = dlen + len + 1 + EXTWIDTH + 1; path = realloc2(path, size); } if (tmp) { strncpy2(path, tmp, dlen); free(tmp); dlen = strcatdelim(path) - path; } strncpy2(&(path[dlen]), com, len); dlen += len; #if MSDOS if ((ret = extaccess(path, ext, dlen, 1)) >= 0) break; #else if (isexecute(path, 0, 1) >= 0) break; #endif cost++; } if (cp) { #ifdef _NOUSEHASH *hpp = (hashlist *)path; #else *hpp = newhash(com, path, cost, hashtable[n]); hashtable[n] = *hpp; (*hpp) -> type = (ret |= (CM_HASH | recalc)); #endif return(ret); } if (path) free(path); } return(CM_NOTFOUND); } #ifdef FD char *searchexecpath(path, search) CONST char *path, *search; { hashlist *hp; int type; if ((type = searchhash(&hp, path, search)) & CM_NOTFOUND) return(NULL); if (type & CM_FULLPATH) return(strdup2(path)); # ifdef _NOUSEHASH return((char *)hp); # else return(strdup2(hp -> path)); # endif } #endif /* FD */ #if !defined (FDSH) && !defined (_NOCOMPLETE) char *finddupl(target, argc, argv) CONST char *target; int argc; char *CONST *argv; { int i; for (i = 0; i < argc; i++) if (!strpathcmp(argv[i], target)) return(argv[i]); return(NULL); } # ifndef NOUID int completeuser(name, len, argc, argvp, home) CONST char *name; int len, argc; char ***argvp; int home; { struct passwd *pwd; char *new; ALLOC_T size; len = strlen(name); # ifdef DEBUG _mtrace_file = "setpwent(start)"; setpwent(); if (_mtrace_file) _mtrace_file = NULL; else { _mtrace_file = "setpwent(end)"; malloc(0); /* dummy alloc */ } for (;;) { _mtrace_file = "getpwent(start)"; pwd = getpwent(); if (_mtrace_file) _mtrace_file = NULL; else { _mtrace_file = "getpwent(end)"; malloc(0); /* dummy alloc */ } if (!pwd) break; if (strnpathcmp(name, pwd -> pw_name, len)) continue; if (!home) new = strdup2(pwd -> pw_name); else { size = strlen(pwd -> pw_name); new = malloc2(size + 2 + 1); new[0] = '~'; strcatdelim2(&(new[1]), pwd -> pw_name, NULL); } if (finddupl(new, argc, *argvp)) { free(new); continue; } *argvp = (char **)realloc2(*argvp, (argc + 1) * sizeof(char *)); (*argvp)[argc++] = new; } _mtrace_file = "endpwent(start)"; endpwent(); if (_mtrace_file) _mtrace_file = NULL; else { _mtrace_file = "endpwent(end)"; malloc(0); /* dummy alloc */ } # else /* !DEBUG */ setpwent(); while ((pwd = getpwent())) { if (strnpathcmp(name, pwd -> pw_name, len)) continue; if (!home) new = strdup2(pwd -> pw_name); else { size = strlen(pwd -> pw_name); new = malloc2(size + 2 + 1); new[0] = '~'; strcatdelim2(&(new[1]), pwd -> pw_name, NULL); } if (finddupl(new, argc, *argvp)) { free(new); continue; } *argvp = (char **)realloc2(*argvp, (argc + 1) * sizeof(char *)); (*argvp)[argc++] = new; } endpwent(); # endif /* !DEBUG */ return(argc); } int completegroup(name, len, argc, argvp) CONST char *name; int len, argc; char ***argvp; { struct group *grp; char *new; len = strlen(name); # ifdef DEBUG _mtrace_file = "setgrent(start)"; setgrent(); if (_mtrace_file) _mtrace_file = NULL; else { _mtrace_file = "setgrent(end)"; malloc(0); /* dummy alloc */ } for (;;) { _mtrace_file = "getgrent(start)"; grp = getgrent(); if (_mtrace_file) _mtrace_file = NULL; else { _mtrace_file = "getgrent(end)"; malloc(0); /* dummy alloc */ } if (!grp) break; if (strnpathcmp(name, grp -> gr_name, len)) continue; new = strdup2(grp -> gr_name); if (finddupl(new, argc, *argvp)) { free(new); continue; } *argvp = (char **)realloc2(*argvp, (argc + 1) * sizeof(char *)); (*argvp)[argc++] = new; } _mtrace_file = "endgrent(start)"; endgrent(); if (_mtrace_file) _mtrace_file = NULL; else { _mtrace_file = "endgrent(end)"; malloc(0); /* dummy alloc */ } # else /* !DEBUG */ setgrent(); while ((grp = getgrent())) { if (strnpathcmp(name, grp -> gr_name, len)) continue; new = strdup2(grp -> gr_name); if (finddupl(new, argc, *argvp)) { free(new); continue; } *argvp = (char **)realloc2(*argvp, (argc + 1) * sizeof(char *)); (*argvp)[argc++] = new; } endgrent(); # endif /* !DEBUG */ return(argc); } # endif /* !NOUID */ static int NEAR completefile(file, len, argc, argvp, dir, dlen, exe) CONST char *file; int len, argc; char ***argvp; CONST char *dir; int dlen, exe; { DIR *dirp; struct dirent *dp; char *cp, *new, path[MAXPATHLEN]; int d, size, dirok; if (dlen >= MAXPATHLEN - 2) return(argc); strncpy2(path, dir, dlen); if (!(dirp = Xopendir(path))) return(argc); cp = strcatdelim(path); dirok = (exe <= 1) ? 1 : 0; while ((dp = Xreaddir(dirp))) { if ((!len && isdotdir(dp -> d_name)) || strnpathcmp(file, dp -> d_name, len)) continue; size = strlen(dp -> d_name); if (size + (cp - path) >= MAXPATHLEN) continue; strncpy2(cp, dp -> d_name, size); if (isdotdir(dp -> d_name)) d = 1; else if ((d = isexecute(path, dirok, exe)) < 0) continue; new = malloc2(size + 1 + 1); strncpy(new, dp -> d_name, size); if (d) new[size++] = _SC_; new[size] = '\0'; if (finddupl(new, argc, *argvp)) { free(new); continue; } *argvp = (char **)realloc2(*argvp, (argc + 1) * sizeof(char *)); (*argvp)[argc++] = new; } Xclosedir(dirp); return(argc); } static int NEAR completeexe(file, len, argc, argvp) CONST char *file; int len, argc; char ***argvp; { char *cp, *tmp, *next; int dlen; # ifdef CWDINPATH argc = completefile(file, len, argc, argvp, curpath, 1, 2); # endif if (!(next = getconstvar(ENVPATH))) return(argc); for (cp = next; cp; cp = next) { # if MSDOS || (defined (FD) && !defined (_NODOSDRIVE)) if (_dospath(cp)) next = strchr(&(cp[2]), PATHDELIM); else # endif next = strchr(cp, PATHDELIM); dlen = (next) ? (next++) - cp : strlen(cp); tmp = _evalpath(cp, &(cp[dlen]), 0); dlen = strlen(tmp); argc = completefile(file, len, argc, argvp, tmp, dlen, 2); free(tmp); } return(argc); } int completepath(path, len, argc, argvp, exe) CONST char *path; int len, argc; char ***argvp; int exe; { # if MSDOS || (defined (FD) && !defined (_NODOSDRIVE)) char cwd[4]; # endif # ifdef DOUBLESLASH int n; # endif CONST char *dir, *file; int dlen; # if MSDOS || (defined (FD) && !defined (_NODOSDRIVE)) if (_dospath(path)) dlen = 2; else # endif dlen = 0; dir = &(path[dlen]); if ((file = strrdelim(dir, 0))) { if (file == dir) { dlen++; file++; } # ifdef DOUBLESLASH else if ((n = isdslash(path)) && file < &(path[n])) { if (path[n - 1] != _SC_) return(argc); dlen = n; file = &(path[n]); if (*file == _SC_) file++; } # endif else dlen += file++ - dir; return(completefile(file, strlen(file), argc, argvp, path, dlen, exe)); } # ifndef NOUID else if (*path == '~') return(completeuser(&(path[1]), len - 1, argc, argvp, 1)); # endif # if MSDOS || (defined (FD) && !defined (_NODOSDRIVE)) else if (dir != path) { len -= dlen; dlen = gendospath(cwd, *path, '.') - cwd; return(completefile(dir, len, argc, argvp, cwd, dlen, exe)); } # endif else if (exe) return(completeexe(path, len, argc, argvp)); return(completefile(path, len, argc, argvp, curpath, 1, exe)); } char *findcommon(argc, argv) int argc; char *CONST *argv; { char *common; int i, n; if (!argv || !argv[0]) return(NULL); common = strdup2(argv[0]); for (n = 1; n < argc; n++) { for (i = 0; common[i]; i++) if (common[i] != argv[n][i]) break; common[i] = '\0'; } if (!common[0]) { free(common); return(NULL); } return(common); } #endif /* !FDSH && !_NOCOMPLETE */ static int NEAR addmeta(s1, s2, quoted) char *s1; CONST char *s2; int quoted; { int i, j, pc, quote; if (!s2) return(0); for (i = j = 0; s2[i]; i++, j++) { quote = quoted; pc = parsechar(&(s2[i]), -1, '\0', EA_EOLMETA, "e, NULL); if (pc == PC_OPQUOTE || pc == PC_CLQUOTE || pc == PC_ESCAPE) { if (s1) s1[j] = PMETA; j++; } else if (pc == PC_WORD) { if (s1) s1[j] = s2[i]; j++; i++; } if (s1) s1[j] = s2[i]; } return(j); } char *catvar(argv, delim) char *CONST *argv; int delim; { char *cp; int i, len; if (!argv) return(NULL); for (i = len = 0; argv[i]; i++) len += strlen(argv[i]); if (i < 1) return(strdup2(nullstr)); len += (delim) ? i - 1 : 0; cp = malloc2(len + 1); len = strcpy2(cp, argv[0]) - cp; for (i = 1; argv[i]; i++) { if (delim) cp[len++] = delim; len = strcpy2(&(cp[len]), argv[i]) - cp; } return(cp); } int countvar(var) char *CONST *var; { int i; if (!var) return(0); for (i = 0; var[i]; i++); return(i); } VOID freevar(var) char **var; { int i, duperrno; duperrno = errno; if (var) { for (i = 0; var[i]; i++) free(var[i]); free(var); } errno = duperrno; } char **duplvar(var, margin) char *CONST *var; int margin; { char **dupl; int i, n; if (margin < 0) { if (!var) return(NULL); margin = 0; } n = countvar(var); dupl = (char **)malloc2((n + margin + 1) * sizeof(char *)); for (i = 0; i < n; i++) dupl[i] = strdup2(var[i]); dupl[i] = NULL; return(dupl); } int parsechar(s, len, spc, flags, qp, pqp) CONST char *s; int len, spc, flags, *qp, *pqp; { if (*s == *qp) { #ifdef FD if (flags & EA_FINDMETA) return((*qp == '\'') ? PC_EXMETA : PC_META); #endif if (!pqp) *qp = '\0'; else { *qp = *pqp; *pqp = '\0'; } return(PC_CLQUOTE); } else if (iskanji1(s, 0)) return(PC_WORD); #ifdef CODEEUC else if (isekana(s, 0)) return(PC_WORD); #endif else if (*qp == '\'') return(PC_SQUOTE); #ifdef FD else if ((flags & EA_FINDMETA) && strchr(DQ_METACHAR, *s)) return(PC_META); else if ((flags & EA_FINDDELIM) && strchr(CMDLINE_DELIM, *s)) return(PC_DELIM); #endif else if (isescape(s, 0, *qp, len, flags)) return(PC_ESCAPE); else if (*qp == '`') return(PC_BQUOTE); #ifdef NESTINGQUOTE else if ((flags & EA_BACKQ) && *s == '`') { if (pqp && *qp) *pqp = *qp; *qp = *s; return(PC_OPQUOTE); } #endif else if (spc && *s == spc) return(*s); else if (*qp) return(PC_DQUOTE); else if (!(flags & EA_NOEVALQ) && *s == '\'') { #ifdef FD if (flags & EA_FINDMETA) return(PC_META); #endif *qp = *s; return(PC_OPQUOTE); } else if (*s == '"') { *qp = *s; return(PC_OPQUOTE); } #ifndef NESTINGQUOTE else if ((flags & EA_BACKQ) && *s == '`') { if (pqp && *qp) *pqp = *qp; *qp = *s; return(PC_OPQUOTE); } #endif #ifdef FD else if ((flags & EA_FINDMETA) && strchr(METACHAR, *s)) return(PC_META); #endif return(PC_NORMAL); } static int NEAR skipvar(bufp, eolp, ptrp, qed) CONST char **bufp; int *eolp, *ptrp, qed; { int i, mode; mode = '\0'; *bufp += *ptrp; *ptrp = 0; if (isidentchar((*bufp)[*ptrp])) { while ((*bufp)[++(*ptrp)]) if (!isidentchar2((*bufp)[*ptrp])) break; if (eolp) *eolp = *ptrp; return(mode); } #ifndef MINIMUMSHELL if ((*bufp)[*ptrp] == '(') { if ((*bufp)[++(*ptrp)] != '(') { if (skipvarvalue(*bufp, ptrp, ")", qed, 0, 1) < 0) return(-1); } else { (*ptrp)++; if (skipvarvalue(*bufp, ptrp, "))", qed, 0, 1) < 0) return(-1); } if (eolp) *eolp = *ptrp; return('('); } #endif if ((*bufp)[*ptrp] != '{') { if ((*bufp)[*ptrp] != qed) (*ptrp)++; if (eolp) *eolp = *ptrp; return(mode); } (*bufp)++; #ifndef MINIMUMSHELL if ((*bufp)[*ptrp] == '#' && (*bufp)[*ptrp + 1] != '}') { (*bufp)++; mode = 'n'; } #endif if (isidentchar((*bufp)[*ptrp])) { while ((*bufp)[++(*ptrp)]) if (!isidentchar2((*bufp)[*ptrp])) break; } else (*ptrp)++; if (eolp) *eolp = *ptrp; if ((i = (*bufp)[(*ptrp)++]) == '}') return(mode); #ifndef MINIMUMSHELL if (mode) return(-1); #endif if (i == ':') { mode = (*bufp)[(*ptrp)++]; if (!strchr("-=?+", mode)) return(-1); mode |= 0x80; } else if (strchr("-=?+", i)) mode = i; #ifndef MINIMUMSHELL else if (i != RMSUFFIX && i != '#') return(-1); else if ((*bufp)[*ptrp] != i) mode = i; else { (*ptrp)++; mode = i | 0x80; } #endif /* !MINIMUMSHELL */ #ifdef BASHSTYLE /* bash treats any meta character in ${} as just a character */ # ifdef MINIMUMSHELL if (skipvarvalue(*bufp, ptrp, "}", qed, 0) < 0) return(-1); # else if (skipvarvalue(*bufp, ptrp, "}", qed, 0, 0) < 0) return(-1); # endif #else /* BASHSTYLE */ # ifdef MINIMUMSHELL if (skipvarvalue(*bufp, ptrp, "}", qed, 1) < 0) return(-1); # else if (skipvarvalue(*bufp, ptrp, "}", qed, 1, 0) < 0) return(-1); # endif #endif /* BASHSTYLE */ return(mode); } #ifdef MINIMUMSHELL static int NEAR skipvarvalue(s, ptrp, next, qed, nonl) CONST char *s; int *ptrp; CONST char *next; int qed, nonl; #else static int NEAR skipvarvalue(s, ptrp, next, qed, nonl, nest) CONST char *s; int *ptrp; CONST char *next; int qed, nonl, nest; #endif { #ifdef NESTINGQUOTE int pq; #endif CONST char *cp; int pc, q, len; #ifdef NESTINGQUOTE pq = '\0'; #endif q = '\0'; len = strlen(next); while (s[*ptrp]) { #ifdef NESTINGQUOTE pc = parsechar(&(s[*ptrp]), -1, '$', EA_BACKQ, &q, &pq); #else pc = parsechar(&(s[*ptrp]), -1, '$', EA_BACKQ, &q, NULL); #endif if (pc == PC_WORD || pc == PC_ESCAPE) (*ptrp)++; else if (pc == '$') { if (!s[++(*ptrp)]) return(0); cp = s; if (skipvar(&cp, NULL, ptrp, (q) ? q : qed) < 0) return(-1); *ptrp += (cp - s); continue; } else if (pc != PC_NORMAL) /*EMPTY*/; else if (nonl && s[*ptrp] == '\n') return(-1); #ifndef MINIMUMSHELL else if (nest && s[*ptrp] == '(') { int tmpq; tmpq = (q) ? q : qed; (*ptrp)++; if (skipvarvalue(s, ptrp, ")", tmpq, nonl, nest) < 0) return(-1); continue; } #endif else if (!strncmp(&(s[*ptrp]), next, len)) { *ptrp += len; return(0); } (*ptrp)++; } return(-1); } #ifndef MINIMUMSHELL static char *NEAR removeword(s, pattern, plen, mode) CONST char *s, *pattern; int plen, mode; { reg_t *re; CONST char *cp; char *ret, *tmp, *new; int c, n, len; if (!s || !*s) return(NULL); tmp = strndup2(pattern, plen); new = evalarg(tmp, '\0', EA_BACKQ); free(tmp); re = regexp_init(new, -1); free(new); if (!re) return(NULL); ret = NULL; len = strlen(s); n = -1; if ((mode & ~0x80) != '#') { if (mode & 0x80) for (cp = s; cp < &(s[len]); cp++) { if (regexp_exec(re, cp, 0)) { n = cp - s; break; } } else for (cp = &(s[len - 1]); cp >= s; cp--) { if (regexp_exec(re, cp, 0)) { n = cp - s; break; } } if (n >= 0) ret = strndup2(s, n); } else { new = strdup2(s); if (mode & 0x80) for (tmp = &(new[len]); tmp >= new; tmp--) { *tmp = '\0'; if (regexp_exec(re, new, 0)) { n = tmp - new; break; } } else for (tmp = &(new[1]); tmp <= &(new[len]); tmp++) { c = *tmp; *tmp = '\0'; if (regexp_exec(re, new, 0)) { n = tmp - new; break; } *tmp = c; } if (n >= 0) ret = strdup2(&(s[n])); free(new); } regexp_free(re); return(ret); } static char **NEAR removevar(var, pattern, plen, mode) char **var; CONST char *pattern; int plen, mode; { char *cp, **new; int i, n; n = countvar(var); new = (char **)malloc2((n + 1) * sizeof(char *)); for (i = 0; i < n; i++) { if ((cp = removeword(var[i], pattern, plen, mode))) new[i] = cp; else new[i] = strdup2(var[i]); } new[i] = NULL; return(new); } #endif /* !MINIMUMSHELL */ #ifdef MINIMUMSHELL static char *NEAR evalshellparam(c, quoted) int c, quoted; #else static char *NEAR evalshellparam(c, quoted, pattern, plen, modep) int c, quoted; CONST char *pattern; int plen, *modep; #endif { #ifndef MINIMUMSHELL char **new; #endif char *cp, **arglist, tmp[MAXLONGWIDTH + 1]; p_id_t pid; int i, j, sp; cp = NULL; #ifndef MINIMUMSHELL new = NULL; #endif switch (c) { case '@': if (!(arglist = argvar)) break; #ifndef MINIMUMSHELL if (modep) { new = removevar(arglist, pattern, plen, *modep); arglist = new; *modep = '\0'; } #endif sp = ' '; if (!quoted) { cp = catvar(&(arglist[1]), sp); break; } #ifdef BASHSTYLE /* bash uses IFS instead of a space as a separator */ if ((cp = getconstvar(ENVIFS)) && *cp) sp = *cp; #endif for (i = j = 0; arglist[i + 1]; i++) j += addmeta(NULL, arglist[i + 1], quoted); if (i <= 0) cp = strdup2(nullstr); else { j += (i - 1) * 3; cp = malloc2(j + 1); j = addmeta(cp, arglist[1], quoted); for (i = 2; arglist[i]; i++) { cp[j++] = quoted; cp[j++] = sp; cp[j++] = quoted; j += addmeta(&(cp[j]), arglist[i], quoted); } cp[j] = '\0'; } break; case '*': if (!(arglist = argvar)) break; #ifndef MINIMUMSHELL if (modep) { new = removevar(arglist, pattern, plen, *modep); arglist = new; *modep = '\0'; } #endif sp = ' '; #ifdef BASHSTYLE /* bash uses IFS instead of a space as a separator */ if (quoted && (cp = getconstvar(ENVIFS))) sp = (*cp) ? *cp : '\0'; #endif cp = catvar(&(arglist[1]), sp); break; case '#': if (!argvar) break; snprintf2(tmp, sizeof(tmp), "%d", countvar(argvar + 1)); cp = tmp; break; case '?': snprintf2(tmp, sizeof(tmp), "%d", (getretvalfunc) ? (*getretvalfunc)() : 0); cp = tmp; break; case '$': if (!getpidfunc) pid = getpid(); else pid = (*getpidfunc)(); snprintf2(tmp, sizeof(tmp), "%id", pid); cp = tmp; break; case '!': if (getlastpidfunc && (pid = (*getlastpidfunc)()) >= 0) { snprintf2(tmp, sizeof(tmp), "%id", pid); cp = tmp; } break; case '-': if (getflagfunc) cp = (*getflagfunc)(); break; default: break; } if (cp == tmp) cp = strdup2(tmp); #ifndef MINIMUMSHELL freevar(new); #endif return(cp); } static int NEAR replacevar(arg, cpp, s, len, vlen, mode, quoted) CONST char *arg; char **cpp; int s, len, vlen, mode, quoted; { char *val; int i; if (!mode) return(0); if (mode == '+') { if (!*cpp) return(0); } else if (*cpp) return(0); else if (mode == '=' && !isidentchar(*arg)) return(-1); val = strndup2(&(arg[s]), vlen); *cpp = evalarg(val, quoted, (mode == '=' || mode == '?') ? EA_STRIPQ | EA_BACKQ : EA_BACKQ); free(val); if (!*cpp) return(-1); if (mode == '=') { #ifdef FD demacroarg(cpp); #endif if (setvar(arg, *cpp, len) < 0) { free(*cpp); *cpp = NULL; return(-1); } #ifdef BASHSTYLE /* bash does not evaluates a quoted string in substitution itself */ free(*cpp); val = strndup2(&(arg[s]), vlen); *cpp = evalarg(val, quoted, EA_BACKQ); free(val); if (!*cpp) return(-1); # ifdef FD demacroarg(cpp); # endif #endif } else if (mode == '?') { #ifdef FD demacroarg(cpp); #endif for (i = 0; i < len; i++) fputc(arg[i], stderr); fprintf2(stderr, ": %k", (vlen > 0) ? *cpp : "parameter null or not set"); fputnl(stderr); free(*cpp); *cpp = NULL; if (exitfunc) (*exitfunc)(); return(-2); } return(mode); } static char *NEAR insertarg(buf, ptr, arg, olen, nlen) char *buf; int ptr; CONST char *arg; int olen, nlen; { if (nlen <= olen) return(buf); buf = realloc2(buf, ptr + nlen + (int)strlen(arg) - olen + 1); return(buf); } static int NEAR evalvar(bufp, ptr, argp, quoted) char **bufp; int ptr; CONST char **argp; int quoted; { #ifndef MINIMUMSHELL char tmp[MAXLONGWIDTH + 1]; #endif CONST char *arg, *top; char *cp, *new; int i, c, n, len, vlen, s, nul, mode; new = NULL; arg = *argp; top = &(arg[1]); n = 0; if ((mode = skipvar(&top, &s, &n, quoted)) < 0) return(-1); *argp = &(top[n - 1]); if (!(len = s)) { (*bufp)[ptr++] = '$'; return(ptr); } nul = (mode & 0x80); if (n > 0 && top[n - 1] == '}') n--; if (!mode) vlen = 0; else { s++; if (nul) s++; vlen = n - s; } #ifdef MINIMUMSHELL mode &= ~0x80; #else if (strchr("-=?+", mode & ~0x80)) mode &= ~0x80; else if (mode == '(') { if (!posixsubstfunc) return(-1); for (;;) { if ((new = (*posixsubstfunc)(top, &n))) break; if (n < 0 || !top[n]) return(-1); if (skipvarvalue(top, &n, ")", quoted, 0, 1) < 0) return(-1); *argp = top + n - 1; } mode = '\0'; } else if (mode == 'n') { if (len == 1 && (*top == '*' || *top == '@')) { top--; mode = '\0'; } } else nul = -1; #endif /* !MINIMUMSHELL */ c = '\0'; if ((cp = new)) /*EMPTY*/; else if (isidentchar(*top)) cp = getenvvar(top, len); else if (isdigit2(*top)) { if (len > 1) return(-1); if (!argvar) { (*bufp)[ptr++] = '$'; (*bufp)[ptr++] = *top; return(ptr); } i = *top - '0'; if (i < countvar(argvar)) cp = argvar[i]; } else if (len == 1) { c = *top; #ifdef MINIMUMSHELL cp = evalshellparam(c, quoted); #else cp = evalshellparam(c, quoted, top + s, vlen, (nul < 0) ? &mode : NULL); #endif if (cp) new = cp; else { (*bufp)[ptr++] = '$'; (*bufp)[ptr++] = *top; return(ptr); } } else return(-1); if (!mode && checkundeffunc && (*checkundeffunc)(cp, top, len) < 0) return(-1); if (cp && (nul == 0x80) && !*cp) cp = NULL; #ifndef MINIMUMSHELL if (mode == 'n') { snprintf2(tmp, sizeof(tmp), "%d", (cp) ? strlen(cp) : 0); cp = tmp; } else if (nul == -1) { new = removeword(cp, top + s, vlen, mode); if (new) cp = new; } else #endif /* !MINIMUMSHELL */ if ((mode = replacevar(top, &cp, s, len, vlen, mode, quoted)) < 0) { if (new) free(new); return(mode); } else if (mode) { if (new) free(new); new = cp; } if (!mode && (c != '@' || !quoted)) { vlen = addmeta(NULL, cp, quoted); *bufp = insertarg(*bufp, ptr, arg, *argp - arg + 1, vlen); addmeta(&((*bufp)[ptr]), cp, quoted); } else if (!cp) vlen = 0; else if (c == '@' && !*cp && quoted && ptr > 0 && (*bufp)[ptr - 1] == quoted && *(*argp + 1) == quoted) { vlen = 0; ptr--; (*argp)++; } else { vlen = strlen(cp); *bufp = insertarg(*bufp, ptr, arg, *argp - arg + 1, vlen); strncpy(&((*bufp)[ptr]), cp, vlen); } ptr += vlen; if (new) free(new); return(ptr); } #if defined (FD) && !defined (NOUID) uidtable *finduid(uid, name) uid_t uid; CONST char *name; { struct passwd *pwd; int i; if (name) { for (i = 0; i < maxuid; i++) if (!strpathcmp(name, uidlist[i].name)) return(&(uidlist[i])); # ifdef DEBUG _mtrace_file = "getpwnam(start)"; pwd = getpwnam(name); if (_mtrace_file) _mtrace_file = NULL; else { _mtrace_file = "getpwnam(end)"; malloc(0); /* dummy alloc */ } # else pwd = getpwnam(name); # endif } else { for (i = 0; i < maxuid; i++) if (uid == uidlist[i].uid) return(&(uidlist[i])); # ifdef DEBUG _mtrace_file = "getpwuid(start)"; pwd = getpwuid(uid); if (_mtrace_file) _mtrace_file = NULL; else { _mtrace_file = "getpwuid(end)"; malloc(0); /* dummy alloc */ } # else pwd = getpwuid(uid); # endif } if (!pwd) return(NULL); uidlist = b_realloc(uidlist, maxuid, uidtable); uidlist[maxuid].uid = pwd -> pw_uid; uidlist[maxuid].name = strdup2(pwd -> pw_name); uidlist[maxuid].home = strdup2(pwd -> pw_dir); return(&(uidlist[maxuid++])); } gidtable *findgid(gid, name) gid_t gid; CONST char *name; { struct group *grp; int i; if (name) { for (i = 0; i < maxgid; i++) if (!strpathcmp(name, gidlist[i].name)) return(&(gidlist[i])); # ifdef DEBUG _mtrace_file = "getgrnam(start)"; grp = getgrnam(name); if (_mtrace_file) _mtrace_file = NULL; else { _mtrace_file = "getgrnam(end)"; malloc(0); /* dummy alloc */ } # else grp = getgrnam(name); # endif } else { for (i = 0; i < maxgid; i++) if (gid == gidlist[i].gid) return(&(gidlist[i])); # ifdef DEBUG _mtrace_file = "getgrgid(start)"; grp = getgrgid(gid); if (_mtrace_file) _mtrace_file = NULL; else { _mtrace_file = "getgrgid(end)"; malloc(0); /* dummy alloc */ } # else grp = getgrgid(gid); # endif } if (!grp) return(NULL); gidlist = b_realloc(gidlist, maxgid, gidtable); gidlist[maxgid].gid = grp -> gr_gid; gidlist[maxgid].name = strdup2(grp -> gr_name); # ifndef USEGETGROUPS gidlist[maxgid].gr_mem = duplvar(grp -> gr_mem, -1); # endif gidlist[maxgid].ismem = 0; return(&(gidlist[maxgid++])); } int isgroupmember(gid) gid_t gid; { # ifdef USEGETGROUPS gid_t *gidset; int n; # else uidtable *up; # endif gidtable *gp; int i; if (!(gp = findgid(gid, NULL))) return(0); if (!(gp -> ismem)) { gp -> ismem++; # ifdef USEGETGROUPS if ((n = getgroups(0, NULL)) > 0) { gidset = (gid_t *)malloc2(n * sizeof(*gidset)); n = getgroups(n, gidset); for (i = 0; i < n; i++) if (gidset[i] == gp -> gid) { gp -> ismem++; break; } free(gidset); } # else /* !USEGETGROUPS */ if (gp -> gr_mem && (up = finduid(geteuid(), NULL))) for (i = 0; gp -> gr_mem[i]; i++) { if (!strpathcmp(up -> name, gp -> gr_mem[i])) { gp -> ismem++; break; } } freevar(gp -> gr_mem); gp -> gr_mem = NULL; # endif /* !USEGETGROUPS */ } return(gp -> ismem - 1); } # ifdef DEBUG VOID freeidlist(VOID_A) { int i; if (uidlist) { for (i = 0; i < maxuid; i++) { free(uidlist[i].name); free(uidlist[i].home); } free(uidlist); } if (gidlist) { for (i = 0; i < maxgid; i++) { free(gidlist[i].name); # ifndef USEGETGROUPS freevar(gidlist[i].gr_mem); # endif } free(gidlist); } uidlist = NULL; gidlist = NULL; maxuid = maxgid = 0; } # endif #endif /* FD && !NOUID */ static char *NEAR replacebackquote(buf, ptrp, bbuf, rest) char *buf; int *ptrp; char *bbuf; int rest; { char *tmp; int len, size; stripquote(bbuf, EA_BACKQ); if (!(tmp = (*backquotefunc)(bbuf))) return(buf); len = addmeta(NULL, tmp, '\0'); size = *ptrp + len + rest + 1; buf = realloc2(buf, size); addmeta(&(buf[*ptrp]), tmp, '\0'); *ptrp += len; free(tmp); return(buf); } char *gethomedir(VOID_A) { #ifndef NOUID # ifdef FD uidtable *up; # else struct passwd *pwd; # endif #endif /* !NOUID */ char *cp; if ((cp = getconstvar(ENVHOME))) return(cp); #ifndef NOUID # ifdef FD if ((up = finduid(getuid(), NULL))) return(up -> home); # else /* !FD */ # ifdef DEBUG _mtrace_file = "getpwuid(start)"; pwd = getpwuid(getuid()); if (_mtrace_file) _mtrace_file = NULL; else { _mtrace_file = "getpwuid(end)"; malloc(0); /* dummy alloc */ } # else pwd = getpwuid(getuid()); # endif if (pwd) return(pwd -> pw_dir); # endif /* !FD */ #endif /* !NOUID */ return(NULL); } CONST char *getrealpath(path, resolved, cwd) CONST char *path; char *resolved, *cwd; { #if defined (FD) && !defined (_NODOSDRIVE) int drv; #endif CONST char *err; char buf[MAXPATHLEN]; if (cwd) /*EMPTY*/; else if (!Xgetwd(buf)) return(NULL); else cwd = buf; #if defined (FD) && !defined (_NODOSDRIVE) if (preparedrv(dospath3(cwd), &drv) < 0) return(cwd); #endif if (_chdir2(path) < 0) err = path; else if (!Xgetwd(resolved)) err = NULL; else if (_chdir2(cwd) < 0) { #ifdef FD lostcwd(NULL); err = resolved; #else err = cwd; #endif } else err = resolved; #if defined (FD) && !defined (_NODOSDRIVE) shutdrv(drv); #endif return(err); } #ifndef MINIMUMSHELL int evalhome(bufp, ptr, argp) char **bufp; int ptr; CONST char **argp; { CONST char *top; char *cp; int len, vlen; top = &((*argp)[1]); len = ((cp = strdelim(top, 0))) ? (cp - top) : strlen(top); if (!len) cp = gethomedir(); # ifdef FD else if (len == strsize(STRFD) && !strnpathcmp(top, STRFD, len)) cp = progpath; # endif else { # ifdef NOUID cp = NULL; # else /* !NOUID */ # ifdef FD uidtable *up; cp = strndup2(top, len); up = finduid(0, cp); free(cp); cp = (up) ? up -> home : NULL; # else /* !FD */ struct passwd *pwd; cp = strndup2(top, len); # ifdef DEBUG _mtrace_file = "getpwnam(start)"; pwd = getpwnam(cp); if (_mtrace_file) _mtrace_file = NULL; else { _mtrace_file = "getpwnam(end)"; malloc(0); /* dummy alloc */ } # else pwd = getpwnam(cp); # endif free(cp); cp = (pwd) ? pwd -> pw_dir : NULL; # endif /* !FD */ # endif /* !NOUID */ } if (!cp) { vlen = len; (*bufp)[ptr++] = '~'; } else { top = cp; vlen = strlen(top); *bufp = insertarg(*bufp, ptr, *argp, len + 1, vlen); } strncpy(&((*bufp)[ptr]), top, vlen); ptr += vlen; *argp += len; return(ptr); } #endif /* !MINIMUMSHELL */ char *evalarg(arg, qed, flags) char *arg; int qed, flags; { #if MSDOS && defined (FD) && !defined (_NOUSELFN) char path[MAXPATHLEN], alias[MAXPATHLEN]; #endif #ifndef MINIMUMSHELL int prev; #endif #ifdef NESTINGQUOTE int pq; #endif CONST char *cp; char *buf, *bbuf; int i, j, pc, q; #if MSDOS && defined (FD) && !defined (_NOUSELFN) if (*arg == '"' && (i = strlen(arg)) > 2 && arg[i - 1] == '"') { strncpy2(path, &(arg[1]), i - 2); if (shortname(path, alias) == alias) { if (flags & (EA_STRIPQ | EA_STRIPQLATER)) return(strdup2(alias)); i = strlen(alias); buf = malloc2(i + 2 + 1); buf[0] = '"'; memcpy(&(buf[1]), alias, i); buf[++i] = '"'; buf[++i] = '\0'; return(buf); } } #endif i = strlen(arg) + 1; buf = malloc2(i); if (!backquotefunc) flags &= ~EA_BACKQ; bbuf = (flags & EA_BACKQ) ? malloc2(i) : NULL; #ifndef MINIMUMSHELL prev = #endif #ifdef NESTINGQUOTE pq = #endif q = '\0'; i = j = 0; cp = arg; while (*cp) { #ifdef NESTINGQUOTE pc = parsechar(cp, -1, '$', flags, &q, &pq); #else pc = parsechar(cp, -1, '$', flags, &q, NULL); #endif if (pc == PC_CLQUOTE) { if (*cp == '`') { bbuf[j] = '\0'; buf = replacebackquote(buf, &i, bbuf, strlen(&(cp[1]))); j = 0; } else if (!(flags & EA_STRIPQ)) buf[i++] = *cp; } else if (pc == PC_WORD) { if (q == '`') { bbuf[j++] = *cp++; bbuf[j++] = *cp; } else { buf[i++] = *cp++; buf[i++] = *cp; } } else if (pc == PC_BQUOTE) bbuf[j++] = *cp; else if (pc == PC_SQUOTE || pc == PC_DQUOTE) buf[i++] = *cp; else if (pc == '$') { int tmpq; tmpq = (q) ? q : qed; if (!cp[1]) buf[i++] = *cp; #ifdef FAKEMETA # ifdef MINIMUMSHELL else if (cp[1] == '$') cp++; # else else if (cp[1] == '$' || cp[1] == '~') cp++; # endif #endif /* FAKEMETA */ else if ((i = evalvar(&buf, i, &cp, tmpq)) < 0) { if (bbuf) free(bbuf); free(buf); if (i < -1) *arg = '\0'; return(NULL); } } else if (pc == PC_ESCAPE) { cp++; if (flags & EA_KEEPMETA) pc = PC_NORMAL; else if (*cp == '$') /*EMPTY*/; else if ((flags & EA_BACKQ) && *cp == '`') /*EMPTY*/; else if ((flags & EA_STRIPQ) && (*cp == '\'' || *cp == '"')) /*EMPTY*/; else pc = PC_NORMAL; if (q == '`') { bbuf[j++] = PMETA; bbuf[j++] = *cp; } else { if (pc != PC_ESCAPE) buf[i++] = PMETA; buf[i++] = *cp; } } else if (pc == PC_OPQUOTE) { if (*cp == '`') j = 0; else if (!(flags & EA_STRIPQ)) buf[i++] = *cp; } else if (pc != PC_NORMAL) /*EMPTY*/; #ifndef MINIMUMSHELL else if (*cp == '~' && (!prev || prev == ':' || prev == '=')) i = evalhome(&buf, i, &cp); #endif else buf[i++] = *cp; #ifdef MINIMUMSHELL cp++; #else prev = *(cp++); #endif } #ifndef BASHSTYLE /* bash does not allow unclosed quote */ if ((flags & EA_BACKQ) && q == '`') { bbuf[j] = '\0'; buf = replacebackquote(buf, &i, bbuf, 0); } #endif if (bbuf) free(bbuf); buf[i] = '\0'; if (flags & EA_STRIPQLATER) stripquote(buf, EA_STRIPQ); return(buf); } int evalifs(argc, argvp, ifs) int argc; char ***argvp; CONST char *ifs; { char *cp; int i, j, n, pc, quote; for (n = 0; n < argc; n++) { for (i = 0, quote = '\0'; (*argvp)[n][i]; i++) { pc = parsechar(&((*argvp)[n][i]), -1, '\0', 0, "e, NULL); if (pc == PC_WORD || pc == PC_ESCAPE) i++; else if (pc != PC_NORMAL) /*EMPTY*/; else if (strchr2(ifs, (*argvp)[n][i])) { for (j = i + 1; (*argvp)[n][j]; j++) if (!strchr2(ifs, (*argvp)[n][j])) break; if (!i) { for (i = 0; (*argvp)[n][i + j]; i++) (*argvp)[n][i] = (*argvp)[n][i + j]; (*argvp)[n][i] = '\0'; i = -1; continue; } (*argvp)[n][i] = '\0'; if (!(*argvp)[n][j]) break; cp = strdup2(&((*argvp)[n][j])); *argvp = (char **)realloc2(*argvp, (argc + 2) * sizeof(char *)); memmove((char *)(&((*argvp)[n + 2])), (char *)(&((*argvp)[n + 1])), (argc++ - n) * sizeof(char *)); (*argvp)[n + 1] = cp; break; } } if (!i) { free((*argvp)[n--]); memmove((char *)(&((*argvp)[n + 1])), (char *)(&((*argvp)[n + 2])), (argc-- - n) * sizeof(char *)); } } return(argc); } int evalglob(argc, argvp, flags) int argc; char ***argvp; int flags; { char **wild; int i, n; for (n = 0; n < argc; n++) { if (!(wild = evalwild((*argvp)[n], flags))) { stripquote((*argvp)[n], flags); continue; } i = countvar(wild); if (i > 1) { *argvp = (char **)realloc2(*argvp, (argc + i) * sizeof(char *)); memmove((char *)(&((*argvp)[n + i])), (char *)(&((*argvp)[n + 1])), (argc - n) * sizeof(char *)); argc += i - 1; } free((*argvp)[n]); memmove((char *)(&((*argvp)[n])), (char *)wild, i * sizeof(char *)); free(wild); n += i - 1; } return(argc); } int stripquote(arg, flags) char *arg; int flags; { int i, j, pc, quote, stripped; stripped = 0; if (!arg) return(stripped); for (i = j = 0, quote = '\0'; arg[i]; i++) { pc = parsechar(&(arg[i]), -1, '\0', 0, "e, NULL); if (pc == PC_OPQUOTE || pc == PC_CLQUOTE) { stripped++; if (flags & EA_STRIPQ) continue; } else if (pc == PC_WORD) arg[j++] = arg[i++]; else if (pc == PC_ESCAPE) { i++; if (flags & EA_KEEPMETA) pc = PC_NORMAL; else if (!quote && !(flags & EA_BACKQ)) /*EMPTY*/; else if (!strchr(DQ_METACHAR, arg[i])) pc = PC_NORMAL; if (pc != PC_ESCAPE) arg[j++] = PMETA; else stripped++; } arg[j++] = arg[i]; } arg[j] = '\0'; return(stripped); } char *_evalpath(path, eol, flags) CONST char *path, *eol; int flags; { #if MSDOS && defined (FD) && !defined (_NOUSELFN) char alias[MAXPATHLEN]; int top; #endif #ifdef DOUBLESLASH int ds; #endif char *cp, *tmp; int i, j, c, pc, size, quote; if (eol) i = eol - path; else i = strlen(path); cp = strndup2(path, i); if (!(tmp = evalarg(cp, '\'', EA_KEEPMETA))) { *cp = '\0'; return(cp); } free(cp); cp = tmp; #if MSDOS && defined (FD) && !defined (_NOUSELFN) top = -1; #endif #ifdef DOUBLESLASH ds = isdslash(cp); #endif size = strlen(cp) + 1; tmp = malloc2(size); quote = '\0'; for (i = j = c = 0; cp[i]; c = cp[i++]) { pc = parsechar(&(cp[i]), -1, '\0', 0, "e, NULL); if (pc == PC_CLQUOTE) { #if MSDOS && defined (FD) && !defined (_NOUSELFN) if ((flags & EA_NOEVALQ) && top >= 0 && ++top < j) { tmp[j] = '\0'; if (shortname(&(tmp[top]), alias) == alias) { int len; len = strlen(alias); size += top + len - j; j = top + len; tmp = realloc2(tmp, size); strncpy(&(tmp[top]), alias, len); } } top = -1; #endif if (!(flags & EA_NOEVALQ)) continue; } else if (pc == PC_WORD) tmp[j++] = cp[i++]; else if (pc == PC_ESCAPE) { i++; if ((flags & EA_KEEPMETA) || (quote && !strchr(DQ_METACHAR, cp[i]))) tmp[j++] = PMETA; } else if (pc == PC_OPQUOTE) { #if MSDOS && defined (FD) && !defined (_NOUSELFN) if (cp[i] == '"') top = j; #endif if (!(flags & EA_NOEVALQ)) continue; } else if (pc != PC_NORMAL) /*EMPTY*/; else if (flags & EA_NOUNIQDELIM) /*EMPTY*/; #ifdef DOUBLESLASH else if (ds && i == 1) /*EMPTY*/; #endif else if (cp[i] == _SC_ && c == _SC_) continue; tmp[j++] = cp[i]; } tmp[j] = '\0'; free(cp); return(tmp); } char *evalpath(path, flags) char *path; int flags; { char *cp; if (!path || !*path) return(path); for (cp = path; *cp == ' ' || *cp == '\t'; cp++); cp = _evalpath(cp, NULL, flags); free(path); return(cp); }