This is utils.c in view mode; [Download] [Up]
/* * $Id: utils.c,v 2.61 1996/10/15 20:16:35 hzoli Exp $ * * utils.c - miscellaneous utilities * * This file is part of zsh, the Z shell. * * Copyright (c) 1992-1996 Paul Falstad * All rights reserved. * * Permission is hereby granted, without written agreement and without * license or royalty fees, to use, copy, modify, and distribute this * software and to distribute modified versions of this software for any * purpose, provided that the above copyright notice and the following * two paragraphs appear in all copies of this software. * * In no event shall Paul Falstad or the Zsh Development Group be liable * to any party for direct, indirect, special, incidental, or consequential * damages arising out of the use of this software and its documentation, * even if Paul Falstad and the Zsh Development Group have been advised of * the possibility of such damage. * * Paul Falstad and the Zsh Development Group specifically disclaim any * warranties, including, but not limited to, the implied warranties of * merchantability and fitness for a particular purpose. The software * provided hereunder is on an "as is" basis, and Paul Falstad and the * Zsh Development Group have no obligation to provide maintenance, * support, updates, enhancements, or modifications. * */ #include "zsh.h" /* Print an error */ /**/ void zwarnnam(char *cmd, char *fmt, char *str, int num) { int waserr; waserr = errflag; zerrnam(cmd, fmt, str, num); errflag = waserr; } /**/ void zerr(char *fmt, char *str, int num) { if (errflag || noerrs) return; errflag = 1; trashzle(); /* * scriptname is set when sourcing scripts, so that we get the * correct name instead of the generic name of whatever * program/script is running. */ nicezputs(isset(SHINSTDIN) ? "zsh" : scriptname ? scriptname : argzero, stderr); fputs(": ", stderr); zerrnam(NULL, fmt, str, num); } /**/ void zerrnam(char *cmd, char *fmt, char *str, int num) { if (cmd) { if (errflag || noerrs) return; errflag = 1; trashzle(); if(unset(SHINSTDIN)) { nicezputs(scriptname ? scriptname : argzero, stderr); fputs(": ", stderr); } nicezputs(cmd, stderr); fputs(": ", stderr); } while (*fmt) if (*fmt == '%') { fmt++; switch (*fmt++) { case 's': nicezputs(str, stderr); break; case 'l': { char sav; num = metalen(str, num); sav = str[num]; str[num] = '\0'; nicezputs(str, stderr); str[num] = sav; break; } case 'd': fprintf(stderr, "%d", num); break; case '%': putc('%', stderr); break; case 'c': fputs(nicechar(num), stderr); break; case 'e': /* print the corresponding message for this errno */ if (num == EINTR) { fputs("interrupt\n", stderr); errflag = 1; return; } /* If the message is not about I/O problems, it looks better * * if we uncapitalize the first letter of the message */ if (num == EIO) fputs(strerror(num), stderr); else { char *errmsg = strerror(num); fputc(tulower(errmsg[0]), stderr); fputs(errmsg + 1, stderr); } break; } } else { putc(*fmt == Meta ? *++fmt ^ 32 : *fmt, stderr); fmt++; } if (unset(SHINSTDIN) && lineno) fprintf(stderr, " [%ld]\n", lineno); else putc('\n', stderr); fflush(stderr); } /* Output a single character, for the termcap routines. * * This is used instead of putchar since it can be a macro. */ /**/ int putraw(int c) { putc(c, stdout); return 0; } /* Output a single character, for the termcap routines. */ /**/ int putshout(int c) { putc(c, shout); return 0; } /* Turn a character into a visible representation thereof. The visible * * string is put together in a static buffer, and this function returns * * a pointer to it. Printable characters stand for themselves, DEL is * * represented as "^?", newline and tab are represented as "\n" and * * "\t", and normal control characters are represented in "^C" form. * * Characters with bit 7 set, if unprintable, are represented as "\M-" * * followed by the visible representation of the character with bit 7 * * stripped off. Tokens are interpreted, rather than being treated as * * literal characters. */ /**/ char * nicechar(int c) { static char buf[6]; char *s = buf; c &= 0xff; if (isprint(c)) goto done; if (c & 0x80) { *s++ = '\\'; *s++ = 'M'; *s++ = '-'; c &= 0x7f; if(isprint(c)) goto done; } if (c == 0x7f) { *s++ = '^'; c = '?'; } else if (c == '\n') { *s++ = '\\'; c = 'n'; } else if (c == '\t') { *s++ = '\\'; c = 't'; } else if (c < 0x20) { *s++ = '^'; c += 0x40; } done: *s++ = c; *s = 0; return buf; } #if 0 /* Output a string's visible representation. */ /**/ void nicefputs(char *s, FILE *f) { for (; *s; s++) fputs(nicechar(STOUC(*s)), f); } #endif /* Return the length of the visible representation of a string. */ /**/ size_t nicestrlen(char *s) { size_t l = 0; for (; *s; s++) l += strlen(nicechar(STOUC(*s))); return l; } /* get a symlink-free pathname for s relative to PWD */ /**/ char * findpwd(char *s) { char *t; if (*s == '/') return xsymlink(s); s = tricat((pwd[1]) ? pwd : "", "/", s); t = xsymlink(s); zsfree(s); return t; } /* Check whether a string contains the * * name of the present directory. */ /**/ int ispwd(char *s) { struct stat sbuf, tbuf; if (stat(unmeta(s), &sbuf) == 0 && stat(".", &tbuf) == 0) if (sbuf.st_dev == tbuf.st_dev && sbuf.st_ino == tbuf.st_ino) return 1; return 0; } static char xbuf[PATH_MAX*2]; /**/ char ** slashsplit(char *s) { char *t, **r, **q; int t0; if (!*s) return (char **) zcalloc(sizeof(char **)); for (t = s, t0 = 0; *t; t++) if (*t == '/') t0++; q = r = (char **) zalloc(sizeof(char **) * (t0 + 2)); while ((t = strchr(s, '/'))) { *q++ = ztrduppfx(s, t - s); while (*t == '/') t++; if (!*t) { *q = NULL; return r; } s = t; } *q++ = ztrdup(s); *q = NULL; return r; } /* expands symlinks and .. or . expressions */ /* if flag = 0, only expand .. and . expressions */ static int xsymlinks(char *s, int flag) { char **pp, **opp; char xbuf2[PATH_MAX*2], xbuf3[PATH_MAX*2]; int t0; opp = pp = slashsplit(s); for (; *pp; pp++) { if (!strcmp(*pp, ".")) { zsfree(*pp); continue; } if (!strcmp(*pp, "..")) { char *p; zsfree(*pp); if (!strcmp(xbuf, "/")) continue; p = xbuf + strlen(xbuf); while (*--p != '/'); *p = '\0'; continue; } if (unset(CHASELINKS)) { strcat(xbuf, "/"); strcat(xbuf, *pp); zsfree(*pp); continue; } sprintf(xbuf2, "%s/%s", xbuf, *pp); t0 = readlink(unmeta(xbuf2), xbuf3, PATH_MAX); if (t0 == -1 || !flag) { strcat(xbuf, "/"); strcat(xbuf, *pp); zsfree(*pp); } else { metafy(xbuf3, t0, META_NOALLOC); if (*xbuf3 == '/') { strcpy(xbuf, ""); if (xsymlinks(xbuf3 + 1, flag)) return 1; } else if (xsymlinks(xbuf3, flag)) return 1; zsfree(*pp); } } free(opp); return 0; } /* expand symlinks in s, and remove other weird things */ /**/ char * xsymlink(char *s) { if (unset(CHASELINKS)) return ztrdup(s); if (*s != '/') return NULL; *xbuf = '\0'; if (xsymlinks(s + 1, 1)) return ztrdup(s); if (!*xbuf) return ztrdup("/"); return ztrdup(xbuf); } /* print a directory */ /**/ void fprintdir(char *s, FILE *f) { Nameddir d = finddir(s); if (!d) fputs(unmeta(s), f); else { putc('~', f); fputs(unmeta(d->nam), f); fputs(unmeta(s + strlen(d->dir)), f); } } /* Returns the current username. It caches the username * * and uid to try to avoid requerying the password files * * or NIS/NIS+ database. */ /**/ char * get_username(void) { struct passwd *pswd; uid_t current_uid; current_uid = getuid(); if (current_uid != cached_uid) { cached_uid = current_uid; zsfree(cached_username); if ((pswd = getpwuid(current_uid))) cached_username = ztrdup(pswd->pw_name); else cached_username = ztrdup(""); } return cached_username; } /* static variables needed by finddir(). */ static char finddir_full[PATH_MAX]; static Nameddir finddir_last; static int finddir_best; /* ScanFunc used by finddir(). */ static void finddir_scan _((HashNode, int)); static void finddir_scan(HashNode hn, int flags) { Nameddir nd = (Nameddir) hn; if(nd->diff > finddir_best && !dircmp(nd->dir, finddir_full)) { finddir_last=nd; finddir_best=nd->diff; } } /* See if a path has a named directory as its prefix. * * If passed a NULL argument, it will invalidate any * * cached information. */ /**/ Nameddir finddir(char *s) { static struct nameddir homenode = { NULL, "", 0, NULL, 0 }; /* Invalidate directory cache if argument is NULL. This is called * * whenever a node is added to or removed from the hash table, and * * whenever the value of $HOME changes. (On startup, too.) */ if (!s) { homenode.dir = home; homenode.diff = strlen(home); if(homenode.diff==1 || homenode.diff>=PATH_MAX) homenode.diff = 0; finddir_full[0] = 0; return finddir_last = NULL; } if (!strcmp(s, finddir_full)) return finddir_last; strcpy(finddir_full, s); finddir_best=0; finddir_last=NULL; finddir_scan((HashNode)&homenode, 0); scanhashtable(nameddirtab, 0, 0, 0, finddir_scan, 0); return finddir_last; } /* add a named directory */ /**/ void adduserdir(char *s, char *t, int flags, int always) { Nameddir nd; /* We don't maintain a hash table in non-interactive shells. */ if (!interact) return; /* The ND_USERNAME flag means that this possible hash table * * entry is derived from a passwd entry. Such entries are * * subordinate to explicitly generated entries. */ if ((flags & ND_USERNAME) && nameddirtab->getnode2(nameddirtab, s)) return; /* Normal parameter assignments generate calls to this function, * * with always==0. Unless the AUTO_NAME_DIRS option is set, we * * don't let such assignments actually create directory names. * * Instead, a reference to the parameter as a directory name can * * cause the actual creation of the hash table entry. */ if (!always && unset(AUTONAMEDIRS) && !nameddirtab->getnode2(nameddirtab, s)) return; if (!t || *t != '/' || strlen(t) >= PATH_MAX) { /* We can't use this value as a directory, so simply remove * * the corresponding entry in the hash table, if any. */ HashNode hn = nameddirtab->removenode(nameddirtab, s); if(hn) nameddirtab->freenode(hn); return; } /* add the name */ nd = (Nameddir) zcalloc(sizeof *nd); nd->flags = flags; nd->dir = ztrdup(t); nameddirtab->addnode(nameddirtab, ztrdup(s), nd); } /* Get a named directory: this function can cause a directory name * * to be added to the hash table, if it isn't there already. */ /**/ char * getnameddir(char *name) { Param pm; char *str; struct passwd *pw; Nameddir nd; /* Check if it is already in the named directory table */ if ((nd = (Nameddir) nameddirtab->getnode(nameddirtab, name))) return dupstring(nd->dir); /* Check if there is a scalar parameter with this name whose value * * begins with a `/'. If there is, add it to the hash table and * * return the new value. */ if ((pm = (Param) paramtab->getnode(paramtab, name)) && (PM_TYPE(pm->flags) == PM_SCALAR) && (str = getsparam(name)) && *str == '/') { adduserdir(name, str, 0, 1); return str; } /* Retrieve an entry from the password table/database for this user. */ if ((pw = getpwnam(name))) { char *dir = xsymlink(pw->pw_dir); adduserdir(name, dir, ND_USERNAME, 1); str = dupstring(dir); zsfree(dir); return str; } /* There are no more possible sources of directory names, so give up. */ return NULL; } /**/ int dircmp(char *s, char *t) { if (s) { for (; *s == *t; s++, t++) if (!*s) return 0; if (!*s && *t == '/') return 0; } return 1; } /* do pre-prompt stuff */ /**/ void preprompt(void) { List list; struct schedcmd *sch, *schl; int period = getiparam("PERIOD"); int mailcheck = getiparam("MAILCHECK"); in_vared = 0; /* If NOTIFY is not set, then check for completed * * jobs before we print the prompt. */ if (unset(NOTIFY)) scanjobs(); if (errflag) return; /* If a shell function named "precmd" exists, * * then execute it. */ if ((list = getshfunc("precmd"))) doshfunc(list, NULL, 0, 1); if (errflag) return; /* If 1) the parameter PERIOD exists, 2) the shell function * * "periodic" exists, 3) it's been greater than PERIOD since we * * executed "periodic", then execute it now. */ if (period && (time(NULL) > lastperiodic + period) && (list = getshfunc("periodic"))) { doshfunc(list, NULL, 0, 1); lastperiodic = time(NULL); } if (errflag) return; /* If WATCH is set, then check for the * * specified login/logout events. */ if (watch) { if ((int) difftime(time(NULL), lastwatch) > getiparam("LOGCHECK")) { dowatch(); lastwatch = time(NULL); } } if (errflag) return; /* Check mail */ if (mailcheck && (int) difftime(time(NULL), lastmailcheck) > mailcheck) { char *mailfile; if (mailpath && *mailpath && **mailpath) checkmailpath(mailpath); else if ((mailfile = getsparam("MAIL")) && *mailfile) { char *x[2]; x[0] = mailfile; x[1] = NULL; checkmailpath(x); } lastmailcheck = time(NULL); } /* Check scheduled commands */ for (schl = (struct schedcmd *)&schedcmds, sch = schedcmds; sch; sch = (schl = sch)->next) { if (sch->time < time(NULL)) { execstring(sch->cmd, 0, 0); schl->next = sch->next; zsfree(sch->cmd); zfree(sch, sizeof(struct schedcmd)); sch = schl; } if (errflag) return; } } /**/ void checkmailpath(char **s) { struct stat st; char *v, *u, c; while (*s) { for (v = *s; *v && *v != '?'; v++); c = *v; *v = '\0'; if (c != '?') u = NULL; else u = v + 1; if (**s == 0) { *v = c; zerr("empty MAILPATH component: %s", *s, 0); } else if (stat(unmeta(*s), &st) == -1) { if (errno != ENOENT) zerr("%e: %s", *s, errno); } else if (S_ISDIR(st.st_mode)) { LinkList l; DIR *lock = opendir(unmeta(*s)); char buf[PATH_MAX * 2], **arr, **ap; int ct = 1; if (lock) { char *fn; HEAPALLOC { pushheap(); l = newlinklist(); while ((fn = zreaddir(lock))) { if (errflag) break; /* Ignore `.' and `..'. */ if (fn[0] == '.' && (fn[1] == '\0' || (fn[1] == '.' && fn[2] == '\0'))) continue; if (u) sprintf(buf, "%s/%s?%s", *s, fn, u); else sprintf(buf, "%s/%s", *s, fn); addlinknode(l, dupstring(buf)); ct++; } closedir(lock); ap = arr = (char **) alloc(ct * sizeof(char *)); while ((*ap++ = (char *)ugetnode(l))); checkmailpath(arr); popheap(); } LASTALLOC; } } else { if (st.st_size && st.st_atime <= st.st_mtime && st.st_mtime > lastmailcheck) if (!u) { fprintf(stderr, "You have new mail.\n"); fflush(stderr); } else { char *usav = underscore; underscore = *s; HEAPALLOC { u = dupstring(u); if (! parsestr(u)) { singsub(&u); zputs(u, stderr); fputc('\n', stderr); fflush(stderr); } underscore = usav; } LASTALLOC; } if (isset(MAILWARNING) && st.st_atime > st.st_mtime && st.st_atime > lastmailcheck && st.st_size) { fprintf(stderr, "The mail in %s has been read.\n", unmeta(*s)); fflush(stderr); } } *v = c; s++; } } /**/ void freecompcond(void *a) { Compcond cc = (Compcond) a; Compcond and, or, c; int n; for (c = cc; c; c = or) { or = c->or; for (; c; c = and) { and = c->and; if (c->type == CCT_POS || c->type == CCT_NUMWORDS) { free(c->u.r.a); free(c->u.r.b); } else if (c->type == CCT_CURSUF || c->type == CCT_CURPRE) { for (n = 0; n < c->n; n++) if (c->u.s.s[n]) zsfree(c->u.s.s[n]); free(c->u.s.s); } else if (c->type == CCT_RANGESTR || c->type == CCT_RANGEPAT) { for (n = 0; n < c->n; n++) if (c->u.l.a[n]) zsfree(c->u.l.a[n]); free(c->u.l.a); for (n = 0; n < c->n; n++) if (c->u.l.b[n]) zsfree(c->u.l.b[n]); free(c->u.l.b); } else { for (n = 0; n < c->n; n++) if (c->u.s.s[n]) zsfree(c->u.s.s[n]); free(c->u.s.p); free(c->u.s.s); } zfree(c, sizeof(struct compcond)); } } } /**/ void freestr(void *a) { zsfree(a); } /**/ void gettyinfo(struct ttyinfo *ti) { if (SHTTY != -1) { #ifdef HAVE_TERMIOS_H # ifdef HAVE_TCGETATTR if (tcgetattr(SHTTY, &ti->tio) == -1) # else if (ioctl(SHTTY, TCGETS, &ti->tio) == -1) # endif zerr("bad tcgets: %e", NULL, errno); #else # ifdef HAVE_TERMIO_H ioctl(SHTTY, TCGETA, &ti->tio); # else ioctl(SHTTY, TIOCGETP, &ti->sgttyb); ioctl(SHTTY, TIOCLGET, &ti->lmodes); ioctl(SHTTY, TIOCGETC, &ti->tchars); ioctl(SHTTY, TIOCGLTC, &ti->ltchars); # endif #endif } } /**/ void settyinfo(struct ttyinfo *ti) { if (SHTTY != -1) { #ifdef HAVE_TERMIOS_H # ifdef HAVE_TCGETATTR # ifndef TCSADRAIN # define TCSADRAIN 1 /* XXX Princeton's include files are screwed up */ # endif tcsetattr(SHTTY, TCSADRAIN, &ti->tio); /* if (tcsetattr(SHTTY, TCSADRAIN, &ti->tio) == -1) */ # else ioctl(SHTTY, TCSETS, &ti->tio); /* if (ioctl(SHTTY, TCSETS, &ti->tio) == -1) */ # endif /* zerr("settyinfo: %e",NULL,errno)*/ ; #else # ifdef HAVE_TERMIO_H ioctl(SHTTY, TCSETA, &ti->tio); # else ioctl(SHTTY, TIOCSETN, &ti->sgttyb); ioctl(SHTTY, TIOCLSET, &ti->lmodes); ioctl(SHTTY, TIOCSETC, &ti->tchars); ioctl(SHTTY, TIOCSLTC, &ti->ltchars); # endif #endif } } #ifdef TIOCGWINSZ extern winchanged; #endif /* check the size of the window and adjust if necessary. * * The value of from: * * 0: called from update_job or setupvals * * 1: called from the SIGWINCH handler * * 2: the user have just changed LINES manually * * 3: the user have just changed COLUMNS manually */ /**/ void adjustwinsize(int from) { int oldcols = columns, oldrows = lines; #ifdef TIOCGWINSZ static int userlines, usercols; if (SHTTY == -1) return; if (from == 2) userlines = lines > 0; if (from == 3) usercols = columns > 0; if (!ioctl(SHTTY, TIOCGWINSZ, (char *)&shttyinfo.winsize)) { if (!userlines) lines = shttyinfo.winsize.ws_row; if (!usercols) columns = shttyinfo.winsize.ws_col; } #endif /* TIOCGWINSZ */ if (lines <= 0) lines = tclines > 0 ? tclines : 24; if (columns <= 0) columns = tccolumns > 0 ? tccolumns : 80; if (lines > 2) termflags &= ~TERM_SHORT; else termflags |= TERM_SHORT; if (columns > 2) termflags &= ~TERM_NARROW; else termflags |= TERM_NARROW; #ifdef TIOCGWINSZ if (from >= 2) { shttyinfo.winsize.ws_row = lines; shttyinfo.winsize.ws_col = columns; ioctl(SHTTY, TIOCSWINSZ, (char *)&shttyinfo.winsize); } #endif if (zleactive && (from >= 2 || oldcols != columns || oldrows != lines)) { resetneeded = winchanged = 1; refresh(); } } /* Move a fd to a place >= 10 and mark the new fd in fdtable. If the fd * * is already >= 10, it is not moved. If it is invalid, -1 is returned. */ /**/ int movefd(int fd) { if(fd != -1 && fd < 10) { #ifdef F_DUPFD int fe = fcntl(fd, F_DUPFD, 10); #else int fe = movefd(dup(fd)); #endif zclose(fd); fd = fe; } if(fd != -1) { if (fd > max_zsh_fd) { while (fd >= fdtable_size) fdtable = zrealloc(fdtable, (fdtable_size *= 2)); max_zsh_fd = fd; } fdtable[fd] = 1; } return fd; } /* Move fd x to y. If x == -1, fd y is closed. */ /**/ void redup(int x, int y) { if(x < 0) zclose(y); else if (x != y) { while (y >= fdtable_size) fdtable = zrealloc(fdtable, (fdtable_size *= 2)); dup2(x, y); if ((fdtable[y] = fdtable[x]) && y > max_zsh_fd) max_zsh_fd = y; zclose(x); } } /* Close the given fd, and clear it from fdtable. */ /**/ int zclose(int fd) { if (fd >= 0) { fdtable[fd] = 0; while (max_zsh_fd > 0 && !fdtable[max_zsh_fd]) max_zsh_fd--; if (fd == coprocin) coprocin = -1; if (fd == coprocout) coprocout = -1; } return close(fd); } /* Get a file name relative to $TMPPREFIX which * * is unique, for use as a temporary file. */ /**/ char * gettempname(void) { char *s; if (!(s = getsparam("TMPPREFIX"))) s = DEFAULT_TMPPREFIX; return ((char *) mktemp(dyncat(unmeta(s), "XXXXXX"))); } /* Check if a string contains a token */ /**/ int has_token(const char *s) { while(*s) if(itok(*s++)) return 1; return 0; } /* Delete a character in a string */ /**/ void chuck(char *str) { while ((str[0] = str[1])) str++; } /**/ int tulower(int c) { c &= 0xff; return (isupper(c) ? tolower(c) : c); } /**/ int tuupper(int c) { c &= 0xff; return (islower(c) ? toupper(c) : c); } /* copy len chars from t into s, and null terminate */ /**/ void ztrncpy(char *s, char *t, int len) { while (len--) *s++ = *t++; *s = '\0'; } /* copy t into *s and update s */ /**/ void strucpy(char **s, char *t) { char *u = *s; while ((*u++ = *t++)); *s = u - 1; } /**/ void struncpy(char **s, char *t, int n) { char *u = *s; while (n--) *u++ = *t++; *s = u; *u = '\0'; } /* Return the number of elements in an array of pointers. * * It doesn't count the NULL pointer at the end. */ /**/ int arrlen(char **s) { int count; for (count = 0; *s; s++, count++); return count; } /* Skip over a balanced pair of parenthesis. */ /**/ int skipparens(char inpar, char outpar, char **s) { int level; if (**s != inpar) return -1; for (level = 1; *++*s && level;) if (**s == inpar) ++level; else if (**s == outpar) --level; return level; } /* Convert string to long. This function (without the z) * * is contained in the ANSI standard C library, but a lot * * of them seem to be broken. */ /**/ long zstrtol(const char *s, char **t, int base) { long ret = 0; int neg; while (inblank(*s)) s++; if ((neg = (*s == '-'))) s++; else if (*s == '+') s++; if (!base) if (*s != '0') base = 10; else if (*++s == 'x' || *s == 'X') base = 16, s++; else base = 8; if (base <= 10) for (; *s >= '0' && *s < ('0' + base); s++) ret = ret * base + *s - '0'; else for (; idigit(*s) || (*s >= 'a' && *s < ('a' + base - 10)) || (*s >= 'A' && *s < ('A' + base - 10)); s++) ret = ret * base + (idigit(*s) ? (*s - '0') : (*s & 0x1f) + 9); if (t) *t = (char *)s; return neg ? -ret : ret; } /* Convert string to quad_t. */ #if defined(RLIM_T_IS_QUAD_T) || defined(RLIM_T_IS_UNSIGNED) /**/ rlim_t zstrtorlimit(const char *s, char **t, int base) { rlim_t ret = 0; if (!base) if (*s != '0') base = 10; else if (*++s == 'x' || *s == 'X') base = 16, s++; else base = 8; if (base <= 10) for (; *s >= '0' && *s < ('0' + base); s++) ret = ret * base + *s - '0'; else for (; idigit(*s) || (*s >= 'a' && *s < ('a' + base - 10)) || (*s >= 'A' && *s < ('A' + base - 10)); s++) ret = ret * base + (idigit(*s) ? (*s - '0') : (*s & 0x1f) + 9); if (t) *t = (char *)s; return ret; } #endif /**/ int checkrmall(char *s) { fflush(stdin); fprintf(shout, "zsh: sure you want to delete all the files in "); if (*s != '/') { nicezputs(pwd[1] ? unmeta(pwd) : "", shout); fputc('/', shout); } nicezputs(s, shout); fputs(" [yn]? ", shout); fflush(shout); feep(); return (getquery("ny") == 'y'); } /**/ int setblock_stdin(void) { #ifdef O_NONBLOCK struct stat st; long mode; if (!fstat(0, &st) && !S_ISREG(st.st_mode)) { mode = fcntl(0, F_GETFL); if (mode != -1 && (mode & O_NONBLOCK) && !fcntl(0, F_SETFL, mode & ~O_NONBLOCK)) return 1; } #endif return 0; } /**/ int getquery(char *valid_chars) { char c, d; int isem = !strcmp(term, "emacs"); #ifdef FIONREAD int val = 0; #endif attachtty(mypgrp); if (!isem) setcbreak(); #ifdef FIONREAD ioctl(SHTTY, FIONREAD, (char *)&val); if (val) { if (!isem) settyinfo(&shttyinfo); write(SHTTY, "n\n", 2); return 'n'; } #endif while (read(SHTTY, &c, 1) == 1) { if (c == 'Y' || c == '\t') c = 'y'; else if (c == 'N') c = 'n'; if (!valid_chars) break; if (c == '\n') { c = *valid_chars; break; } if (strchr(valid_chars, c)) { write(2, "\n", 1); break; } feep(); if (icntrl(c)) write(2, "\b \b", 3); write(2, "\b \b", 3); } if (isem) { if (c != '\n') while (read(SHTTY, &d, 1) == 1 && d != '\n'); } else { settyinfo(&shttyinfo); if (c != '\n' && !valid_chars) write(2, "\n", 1); } return (int)c; } static int d; static char *guess, *best; /**/ void spscan(HashNode hn, int scanflags) { int nd; nd = spdist(hn->nam, guess, (int) strlen(guess) / 4 + 1); if (nd <= d) { best = hn->nam; d = nd; } } /* spellcheck a word */ /* fix s ; if hist is nonzero, fix the history list too */ /**/ void spckword(char **s, int hist, int cmd, int ask) { char *t, *u; int x; char ic = '\0'; int ne; int preflen = 0; if ((histdone & HISTFLAG_NOEXEC) || **s == '-' || **s == '%') return; if (!strcmp(*s, "in")) return; if (!(*s)[0] || !(*s)[1]) return; if (shfunctab->getnode(shfunctab, *s) || builtintab->getnode(builtintab, *s) || cmdnamtab->getnode(cmdnamtab, *s) || aliastab->getnode(aliastab, *s) || reswdtab->getnode(reswdtab, *s)) return; else if (isset(HASHLISTALL)) { cmdnamtab->filltable(cmdnamtab); if (cmdnamtab->getnode(cmdnamtab, *s)) return; } t = *s; if (*t == Tilde || *t == Equals || *t == String) t++; for (; *t; t++) if (itok(*t)) return; best = NULL; for (t = *s; *t; t++) if (*t == '/') break; if (**s == Tilde && !*t) return; if (**s == String && !*t) { guess = *s + 1; if (*t || !ialpha(*guess)) return; ic = String; d = 100; scanhashtable(paramtab, 1, 0, 0, spscan, 0); } else if (**s == Equals) { if (*t) return; if (hashcmd(guess = *s + 1, pathchecked)) return; d = 100; ic = Equals; scanhashtable(aliastab, 1, 0, 0, spscan, 0); scanhashtable(cmdnamtab, 1, 0, 0, spscan, 0); } else { guess = *s; if (*guess == Tilde || *guess == String) { ic = *guess; if (!*++t) return; guess = dupstring(guess); ne = noerrs; noerrs = 1; singsub(&guess); noerrs = ne; if (!guess) return; preflen = strlen(guess) - strlen(t); } if (access(unmeta(guess), F_OK) == 0) return; if ((u = spname(guess)) != guess) best = u; if (!*t && cmd) { if (hashcmd(guess, pathchecked)) return; d = 100; scanhashtable(reswdtab, 1, 0, 0, spscan, 0); scanhashtable(aliastab, 1, 0, 0, spscan, 0); scanhashtable(shfunctab, 1, 0, 0, spscan, 0); scanhashtable(builtintab, 1, 0, 0, spscan, 0); scanhashtable(cmdnamtab, 1, 0, 0, spscan, 0); } } if (errflag) return; if (best && (int)strlen(best) > 1 && strcmp(best, guess)) { if (ic) { if (preflen) { /* do not correct the result of an expansion */ if (strncmp(guess, best, preflen)) return; /* replace the temporarily expanded prefix with the original */ u = (char *) ncalloc(t - *s + strlen(best + preflen) + 1); strncpy(u, *s, t - *s); strcpy(u + (t - *s), best + preflen); } else { u = (char *) ncalloc(strlen(best) + 2); strcpy(u + 1, best); } best = u; guess = *s; *guess = *best = ztokens[ic - Pound]; } if (ask) { char *pptbuf; int pptlen; rstring = best; Rstring = guess; pptbuf = putprompt(sprompt, &pptlen, NULL, 1); fwrite(pptbuf, pptlen, 1, stderr); free(pptbuf); fflush(stderr); feep(); x = getquery("nyae "); } else x = 'y'; if (x == 'y' || x == ' ') { *s = dupstring(best); if (hist) hwrep(best); } else if (x == 'a') { histdone |= HISTFLAG_NOEXEC; } else if (x == 'e') { histdone |= HISTFLAG_NOEXEC | HISTFLAG_RECALL; } if (ic) **s = ic; } } /**/ int ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm) { #ifndef HAVE_STRFTIME static char *astr[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; static char *estr[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; #else char *origbuf = buf; #endif static char *lstr[] = {"12", " 1", " 2", " 3", " 4", " 5", " 6", " 7", " 8", " 9", "10", "11"}; char tmp[3]; tmp[0] = '%'; tmp[2] = '\0'; while (*fmt) if (*fmt == '%') { fmt++; switch (*fmt++) { case 'd': *buf++ = '0' + tm->tm_mday / 10; *buf++ = '0' + tm->tm_mday % 10; break; case 'e': if (tm->tm_mday > 9) *buf++ = '0' + tm->tm_mday / 10; *buf++ = '0' + tm->tm_mday % 10; break; case 'k': if (tm->tm_hour > 9) *buf++ = '0' + tm->tm_hour / 10; *buf++ = '0' + tm->tm_hour % 10; break; case 'l': strucpy(&buf, lstr[tm->tm_hour % 12]); break; case 'm': *buf++ = '0' + (tm->tm_mon + 1) / 10; *buf++ = '0' + (tm->tm_mon + 1) % 10; break; case 'M': *buf++ = '0' + tm->tm_min / 10; *buf++ = '0' + tm->tm_min % 10; break; case 'S': *buf++ = '0' + tm->tm_sec / 10; *buf++ = '0' + tm->tm_sec % 10; break; case 'y': *buf++ = '0' + tm->tm_year / 10; *buf++ = '0' + tm->tm_year % 10; break; #ifndef HAVE_STRFTIME case 'a': strucpy(&buf, astr[tm->tm_wday]); break; case 'b': strucpy(&buf, estr[tm->tm_mon]); break; case 'p': *buf++ = (tm->tm_hour > 11) ? 'p' : 'a'; *buf++ = 'm'; break; default: *buf++ = '%'; if (fmt[-1] != '%') *buf++ = fmt[-1]; #else default: *buf = '\0'; tmp[1] = fmt[-1]; strftime(buf, bufsize - strlen(origbuf), tmp, tm); buf += strlen(buf); #endif break; } } else *buf++ = *fmt++; *buf = '\0'; return 0; } /**/ char * zjoin(char **arr, int delim) { int len = 0; char **s, *ret, *ptr; for (s = arr; *s; s++) len += strlen(*s) + 1; if (!len) return ""; ptr = ret = (char *) ncalloc(len); for (s = arr; *s; s++) { strucpy(&ptr, *s); if (delim) *ptr++ = delim; } ptr[-1] = '\0'; return ret; } /* Split a string containing a colon separated list * * of items into an array of strings. */ /**/ char ** colonsplit(char *s, int uniq) { int ct; char *t, **ret, **ptr, **p; for (t = s, ct = 0; *t; t++) /* count number of colons */ if (*t == ':') ct++; ptr = ret = (char **) zalloc(sizeof(char **) * (ct + 2)); t = s; do { s = t; /* move t to point at next colon */ for (; *t && *t != ':'; t++); if (uniq) for (p = ret; p < ptr; p++) if (strlen(*p) == t - s && ! strncmp(*p, s, t - s)) goto cont; *ptr = (char *) zalloc((t - s) + 1); ztrncpy(*ptr++, s, t - s); cont: ; } while (*t++); *ptr = NULL; return ret; } /**/ int skipwsep(char **s) { char *t = *s; int i = 0; while (*t && iwsep(*t == Meta ? t[1] ^ 32 : *t)) { if (*t == Meta) t++; t++; i++; } *s = t; return i; } /**/ char ** spacesplit(char *s, int allownull) { char *t, **ret, **ptr; ptr = ret = (char **) ncalloc(sizeof(*ret) * (wordcount(s, NULL, -!allownull) + 1)); t = s; skipwsep(&s); if (*s && isep(*s == Meta ? s[1] ^ 32 : *s)) *ptr++ = dupstring(allownull ? "" : nulstring); else if (!allownull && t != s) *ptr++ = dupstring(""); while (*s) { if (isep(*s == Meta ? s[1] ^ 32 : *s)) { if (*s == Meta) s++; s++; skipwsep(&s); } t = s; findsep(&s, NULL); if (s > t || allownull) { *ptr = (char *) ncalloc((s - t) + 1); ztrncpy(*ptr++, t, s - t); } else *ptr++ = dupstring(nulstring); t = s; skipwsep(&s); } if (!allownull && t != s) *ptr++ = dupstring(""); *ptr = NULL; return ret; } /**/ int findsep(char **s, char *sep) { int i; char *t, *tt; if (!sep) { for (t = *s; *t; t++) { if (*t == Meta) { if (isep(t[1] ^ 32)) break; t++; } else if (isep(*t)) break; } i = t - *s; *s = t; return i; } if (!sep[0]) { return **s ? ++*s, 1 : -1; } for (i = 0; **s; i++) { for (t = sep, tt = *s; *t && *tt && *t == *tt; t++, tt++); if (!*t) return i; if (*(*s)++ == Meta) { (*s)++; #ifdef DEBUG if (! **s) fprintf(stderr, "BUG: unexpected end of string in findsep()\n"); #endif } } return -1; } /**/ char * findword(char **s, char *sep) { char *r, *t; int sl; if (!**s) return NULL; if (sep) { sl = strlen(sep); r = *s; while (! findsep(s, sep)) { r = *s += sl; } return r; } for (t = *s; *t; t++) { if (*t == Meta) { if (! isep(t[1] ^ 32)) break; t++; } else if (! isep(*t)) break; } *s = t; findsep(s, sep); return t; } /**/ int wordcount(char *s, char *sep, int mul) { int r, sl, c; if (sep) { r = 1; sl = strlen(sep); for (; (c = findsep(&s, sep)) >= 0; s += sl) if ((c && *(s + sl)) || mul) r++; } else { char *t = s; r = 0; if (mul <= 0) skipwsep(&s); if ((*s && isep(*s == Meta ? s[1] ^ 32 : *s)) || (mul < 0 && t != s)) r++; for (; *s; r++) { if (isep(*s == Meta ? s[1] ^ 32 : *s)) { if (*s == Meta) s++; s++; if (mul <= 0) skipwsep(&s); } findsep(&s, NULL); t = s; if (mul <= 0) skipwsep(&s); } if (mul < 0 && t != s) r++; } return r; } /**/ char * sepjoin(char **s, char *sep) { char *r, *p, **t; int l, sl, elide = 0; char sepbuf[3]; if (!*s) return ""; if (!sep) { elide = 1; sep = sepbuf; sepbuf[0] = *ifs; sepbuf[1] = *ifs == Meta ? ifs[1] ^ 32 : '\0'; sepbuf[2] = '\0'; } sl = strlen(sep); for (t = s, l = 1 - sl; *t; l += strlen(*t) + sl, t++); r = p = (char *) ncalloc(l); t = s; while (*t) { strucpy(&p, *t); if (*++t) strucpy(&p, sep); } *p = '\0'; return r; } /**/ char ** sepsplit(char *s, char *sep, int allownull) { int n, sl; char *t, *tt, **r, **p; if (!sep) return spacesplit(s, allownull); sl = strlen(sep); n = wordcount(s, sep, 1); r = p = (char **) ncalloc((n + 1) * sizeof(char *)); for (t = s; n--;) { tt = t; findsep(&t, sep); *p = (char *) ncalloc(t - tt + 1); strncpy(*p, tt, t - tt); (*p)[t - tt] = '\0'; p++; t += sl; } *p = NULL; return r; } /* Get the definition of a shell function */ /**/ List getshfunc(char *nam) { Shfunc shf; List l; if ((shf = (Shfunc) shfunctab->getnode(shfunctab, nam))) { /* if autoloaded and currently undefined */ if (shf->flags & PM_UNDEFINED) { if (!(l = getfpfunc(nam))) { zerr("function not found: %s", nam, 0); return NULL; } shf->flags &= ~PM_UNDEFINED; PERMALLOC { shf->funcdef = (List) dupstruct(l); } LASTALLOC; } return shf->funcdef; } else { return NULL; } } /* allocate a tree element */ static int sizetab[N_COUNT] = { sizeof(struct list), sizeof(struct sublist), sizeof(struct pline), sizeof(struct cmd), sizeof(struct redir), sizeof(struct cond), sizeof(struct forcmd), sizeof(struct casecmd), sizeof(struct ifcmd), sizeof(struct whilecmd), sizeof(struct varasg)}; static int flagtab[N_COUNT] = { NT_SET(N_LIST, 1, NT_NODE, NT_NODE, 0, 0), NT_SET(N_SUBLIST, 2, NT_NODE, NT_NODE, 0, 0), NT_SET(N_PLINE, 1, NT_NODE, NT_NODE, 0, 0), NT_SET(N_CMD, 2, NT_STR | NT_LIST, NT_NODE, NT_NODE | NT_LIST, NT_NODE | NT_LIST), NT_SET(N_REDIR, 3, NT_STR, 0, 0, 0), NT_SET(N_COND, 1, NT_NODE, NT_NODE, 0, 0), NT_SET(N_FOR, 1, NT_STR, NT_NODE, 0, 0), NT_SET(N_CASE, 0, NT_STR | NT_ARR, NT_NODE | NT_ARR, 0, 0), NT_SET(N_IF, 0, NT_NODE | NT_ARR, NT_NODE | NT_ARR, 0, 0), NT_SET(N_WHILE, 1, NT_NODE, NT_NODE, 0, 0), NT_SET(N_VARASG, 1, NT_STR, NT_STR, NT_STR | NT_LIST, 0)}; /**/ void * allocnode(int type) { struct node *n; n = (struct node *) alloc(sizetab[type]); memset((void *) n, 0, sizetab[type]); n->ntype = flagtab[type]; if (useheap) n->ntype |= NT_HEAP; return (void *) n; } /**/ void * dupstruct(void *a) { struct node *n, *r; n = (struct node *) a; if (!a || ((List) a) == &dummy_list) return (void *) a; if ((n->ntype & NT_HEAP) && !useheap) { HEAPALLOC { n = (struct node *) dupstruct2((void *) n); } LASTALLOC; n = simplifystruct(n); } r = (struct node *)dupstruct2((void *) n); if (!(n->ntype & NT_HEAP) && useheap) r = expandstruct(r, N_LIST); return (void *) r; } /**/ struct node * simplifystruct(struct node *n) { if (!n || ((List) n) == &dummy_list) return n; switch (NT_TYPE(n->ntype)) { case N_LIST: { List l = (List) n; l->left = (Sublist) simplifystruct((struct node *)l->left); if ((l->type & Z_SYNC) && !l->right) return (struct node *)l->left; } break; case N_SUBLIST: { Sublist sl = (Sublist) n; sl->left = (Pline) simplifystruct((struct node *)sl->left); if (sl->type == END && !sl->flags && !sl->right) return (struct node *)sl->left; } break; case N_PLINE: { Pline pl = (Pline) n; pl->left = (Cmd) simplifystruct((struct node *)pl->left); if (pl->type == END && !pl->right) return (struct node *)pl->left; } break; case N_CMD: { Cmd c = (Cmd) n; int i = 0; if (empty(c->args)) c->args = NULL, i++; if (empty(c->redir)) c->redir = NULL, i++; if (empty(c->vars)) c->vars = NULL, i++; c->u.list = (List) simplifystruct((struct node *)c->u.list); if (i == 3 && !c->flags && (c->type == CWHILE || c->type == CIF || c->type == COND)) return (struct node *)c->u.list; } break; case N_FOR: { Forcmd f = (Forcmd) n; f->list = (List) simplifystruct((struct node *)f->list); } break; case N_CASE: { struct casecmd *c = (struct casecmd *)n; List *l; for (l = c->lists; *l; l++) *l = (List) simplifystruct((struct node *)*l); } break; case N_IF: { struct ifcmd *i = (struct ifcmd *)n; List *l; for (l = i->ifls; *l; l++) *l = (List) simplifystruct((struct node *)*l); for (l = i->thenls; *l; l++) *l = (List) simplifystruct((struct node *)*l); } break; case N_WHILE: { struct whilecmd *w = (struct whilecmd *)n; w->cont = (List) simplifystruct((struct node *)w->cont); w->loop = (List) simplifystruct((struct node *)w->loop); } } return n; } /**/ struct node * expandstruct(struct node *n, int exp) { struct node *m; if (!n || ((List) n) == &dummy_list) return n; if (exp != N_COUNT && exp != NT_TYPE(n->ntype)) { switch (exp) { case N_LIST: { List l; m = (struct node *) allocnode(N_LIST); l = (List) m; l->type = Z_SYNC; l->left = (Sublist) expandstruct(n, N_SUBLIST); return (struct node *)l; } case N_SUBLIST: { Sublist sl; m = (struct node *) allocnode(N_SUBLIST); sl = (Sublist) m; sl->type = END; sl->left = (Pline) expandstruct(n, N_PLINE); return (struct node *)sl; } case N_PLINE: { Pline pl; m = (struct node *) allocnode(N_PLINE); pl = (Pline) m; pl->type = END; pl->left = (Cmd) expandstruct(n, N_CMD); return (struct node *)pl; } case N_CMD: { Cmd c; m = (struct node *) allocnode(N_CMD); c = (Cmd) m; switch (NT_TYPE(n->ntype)) { case N_WHILE: c->type = CWHILE; break; case N_IF: c->type = CIF; break; case N_COND: c->type = COND; } c->u.list = (List) expandstruct(n, NT_TYPE(n->ntype)); c->args = newlinklist(); c->vars = newlinklist(); c->redir = newlinklist(); return (struct node *)c; } } } else switch (NT_TYPE(n->ntype)) { case N_LIST: { List l = (List) n; l->left = (Sublist) expandstruct((struct node *)l->left, N_SUBLIST); l->right = (List) expandstruct((struct node *)l->right, N_LIST); } break; case N_SUBLIST: { Sublist sl = (Sublist) n; sl->left = (Pline) expandstruct((struct node *)sl->left, N_PLINE); sl->right = (Sublist) expandstruct((struct node *)sl->right, N_SUBLIST); } break; case N_PLINE: { Pline pl = (Pline) n; pl->left = (Cmd) expandstruct((struct node *)pl->left, N_CMD); pl->right = (Pline) expandstruct((struct node *)pl->right, N_PLINE); } break; case N_CMD: { Cmd c = (Cmd) n; if (!c->args) c->args = newlinklist(); if (!c->vars) c->vars = newlinklist(); if (!c->redir) c->redir = newlinklist(); switch (c->type) { case CFOR: case CSELECT: c->u.list = (List) expandstruct((struct node *)c->u.list, N_FOR); break; case CWHILE: c->u.list = (List) expandstruct((struct node *)c->u.list, N_WHILE); break; case CIF: c->u.list = (List) expandstruct((struct node *)c->u.list, N_IF); break; case CCASE: c->u.list = (List) expandstruct((struct node *)c->u.list, N_CASE); break; case COND: c->u.list = (List) expandstruct((struct node *)c->u.list, N_COND); break; case ZCTIME: c->u.list = (List) expandstruct((struct node *)c->u.list, N_SUBLIST); break; default: c->u.list = (List) expandstruct((struct node *)c->u.list, N_LIST); } } break; case N_FOR: { Forcmd f = (Forcmd) n; f->list = (List) expandstruct((struct node *)f->list, N_LIST); } break; case N_CASE: { struct casecmd *c = (struct casecmd *)n; List *l; for (l = c->lists; *l; l++) *l = (List) expandstruct((struct node *)*l, N_LIST); } break; case N_IF: { struct ifcmd *i = (struct ifcmd *)n; List *l; for (l = i->ifls; *l; l++) *l = (List) expandstruct((struct node *)*l, N_LIST); for (l = i->thenls; *l; l++) *l = (List) expandstruct((struct node *)*l, N_LIST); } break; case N_WHILE: { struct whilecmd *w = (struct whilecmd *)n; w->cont = (List) expandstruct((struct node *)w->cont, N_LIST); w->loop = (List) expandstruct((struct node *)w->loop, N_LIST); } } return n; } /* duplicate a syntax tree node of given type, argument number */ /**/ void * dupnode(int type, void *a, int argnum) { if (!a) return NULL; switch (NT_N(type, argnum)) { case NT_NODE: return (void *) dupstruct2(a); case NT_STR: return (useheap) ? ((void *) dupstring(a)) : ((void *) ztrdup(a)); case NT_LIST | NT_NODE: if (type & NT_HEAP) if (useheap) return (void *) duplist(a, (VFunc) dupstruct2); else return (void *) list2arr(a, (VFunc) dupstruct2); else if (useheap) return (void *) arr2list(a, (VFunc) dupstruct2); else return (void *) duparray(a, (VFunc) dupstruct2); case NT_LIST | NT_STR: if (type & NT_HEAP) if (useheap) return (void *) duplist(a, (VFunc) dupstring); else return (void *) list2arr(a, (VFunc) ztrdup); else if (useheap) return (void *) arr2list(a, (VFunc) dupstring); else return (void *) duparray(a, (VFunc) ztrdup); case NT_NODE | NT_ARR: return (void *) duparray(a, (VFunc) dupstruct2); case NT_STR | NT_ARR: return (void *) duparray(a, (VFunc) (useheap ? dupstring : ztrdup)); default: abort(); } } /* Free a syntax tree node of given type, argument number */ /**/ void freetreenode(int type, void *a, int argnum) { if (!a) return; switch (NT_N(type, argnum)) { case NT_NODE: freestruct(a); break; case NT_STR: zsfree(a); break; case NT_LIST | NT_NODE: case NT_NODE | NT_ARR: { char **p = (char **)a; while (*p) freestruct(*p++); free(a); } break; case NT_LIST | NT_STR: case NT_STR | NT_ARR: freearray(a); break; default: abort(); } } /* duplicate a syntax tree */ /**/ void ** dupstruct2(void *a) { struct node *n = (struct node *)a, *m; int type; if (!n || ((List) n) == &dummy_list) return a; type = n->ntype; m = (struct node *) alloc(sizetab[NT_TYPE(type)]); m->ntype = (type & ~NT_HEAP); if (useheap) m->ntype |= NT_HEAP; switch (NT_TYPE(type)) { case N_LIST: { List nl = (List) n; List ml = (List) m; ml->type = nl->type; ml->left = (Sublist) dupnode(type, nl->left, 0); ml->right = (List) dupnode(type, nl->right, 1); } break; case N_SUBLIST: { Sublist nsl = (Sublist) n; Sublist msl = (Sublist) m; msl->type = nsl->type; msl->flags = nsl->flags; msl->left = (Pline) dupnode(type, nsl->left, 0); msl->right = (Sublist) dupnode(type, nsl->right, 1); } break; case N_PLINE: { Pline npl = (Pline) n; Pline mpl = (Pline) m; mpl->type = npl->type; mpl->left = (Cmd) dupnode(type, npl->left, 0); mpl->right = (Pline) dupnode(type, npl->right, 1); } break; case N_CMD: { Cmd nc = (Cmd) n; Cmd mc = (Cmd) m; mc->type = nc->type; mc->flags = nc->flags; mc->lineno = nc->lineno; mc->args = (LinkList) dupnode(type, nc->args, 0); mc->u.generic = (void *) dupnode(type, nc->u.generic, 1); mc->redir = (LinkList) dupnode(type, nc->redir, 2); mc->vars = (LinkList) dupnode(type, nc->vars, 3); } break; case N_REDIR: { Redir nr = (Redir) n; Redir mr = (Redir) m; mr->type = nr->type; mr->fd1 = nr->fd1; mr->fd2 = nr->fd2; mr->name = (char *)dupnode(type, nr->name, 0); } break; case N_COND: { Cond nco = (Cond) n; Cond mco = (Cond) m; mco->type = nco->type; mco->left = (void *) dupnode(type, nco->left, 0); mco->right = (void *) dupnode(type, nco->right, 1); } break; case N_FOR: { Forcmd nf = (Forcmd) n; Forcmd mf = (Forcmd) m; mf->inflag = nf->inflag; mf->name = (char *)dupnode(type, nf->name, 0); mf->list = (List) dupnode(type, nf->list, 1); } break; case N_CASE: { struct casecmd *ncc = (struct casecmd *)n; struct casecmd *mcc = (struct casecmd *)m; mcc->pats = (char **)dupnode(type, ncc->pats, 0); mcc->lists = (List *) dupnode(type, ncc->lists, 1); } break; case N_IF: { struct ifcmd *nic = (struct ifcmd *)n; struct ifcmd *mic = (struct ifcmd *)m; mic->ifls = (List *) dupnode(type, nic->ifls, 0); mic->thenls = (List *) dupnode(type, nic->thenls, 1); } break; case N_WHILE: { struct whilecmd *nwc = (struct whilecmd *)n; struct whilecmd *mwc = (struct whilecmd *)m; mwc->cond = nwc->cond; mwc->cont = (List) dupnode(type, nwc->cont, 0); mwc->loop = (List) dupnode(type, nwc->loop, 1); } break; case N_VARASG: { Varasg nva = (Varasg) n; Varasg mva = (Varasg) m; mva->type = nva->type; mva->name = (char *)dupnode(type, nva->name, 0); mva->str = (char *)dupnode(type, nva->str, 1); mva->arr = (LinkList) dupnode(type, nva->arr, 2); } break; } return (void **) m; } /* free a syntax tree */ /**/ void freestruct(void *a) { struct node *n = (struct node *)a; int type; if (!n || ((List) n) == &dummy_list) return; type = n->ntype; switch (NT_TYPE(type)) { case N_LIST: { List nl = (List) n; freetreenode(type, nl->left, 0); freetreenode(type, nl->right, 1); } break; case N_SUBLIST: { Sublist nsl = (Sublist) n; freetreenode(type, nsl->left, 0); freetreenode(type, nsl->right, 1); } break; case N_PLINE: { Pline npl = (Pline) n; freetreenode(type, npl->left, 0); freetreenode(type, npl->right, 1); } break; case N_CMD: { Cmd nc = (Cmd) n; freetreenode(type, nc->args, 0); freetreenode(type, nc->u.generic, 1); freetreenode(type, nc->redir, 2); freetreenode(type, nc->vars, 3); } break; case N_REDIR: { Redir nr = (Redir) n; freetreenode(type, nr->name, 0); } break; case N_COND: { Cond nco = (Cond) n; freetreenode(type, nco->left, 0); freetreenode(type, nco->right, 1); } break; case N_FOR: { Forcmd nf = (Forcmd) n; freetreenode(type, nf->name, 0); freetreenode(type, nf->list, 1); } break; case N_CASE: { struct casecmd *ncc = (struct casecmd *)n; freetreenode(type, ncc->pats, 0); freetreenode(type, ncc->lists, 1); } break; case N_IF: { struct ifcmd *nic = (struct ifcmd *)n; freetreenode(type, nic->ifls, 0); freetreenode(type, nic->thenls, 1); } break; case N_WHILE: { struct whilecmd *nwc = (struct whilecmd *)n; freetreenode(type, nwc->cont, 0); freetreenode(type, nwc->loop, 1); } break; case N_VARASG: { Varasg nva = (Varasg) n; freetreenode(type, nva->name, 0); freetreenode(type, nva->str, 1); freetreenode(type, nva->arr, 2); } break; } zfree(n, sizetab[NT_TYPE(type)]); } /**/ LinkList duplist(LinkList l, VFunc func) { LinkList ret; LinkNode node; ret = newlinklist(); for (node = firstnode(l); node; incnode(node)) addlinknode(ret, func(getdata(node))); return ret; } /**/ char ** duparray(char **arr, VFunc func) { char **ret, **rr; ret = (char **) alloc((arrlen(arr) + 1) * sizeof(char *)); for (rr = ret; *arr;) *rr++ = (char *)func(*arr++); *rr = NULL; return ret; } /**/ char ** list2arr(LinkList l, VFunc func) { char **arr, **r; LinkNode n; arr = r = (char **) alloc((countlinknodes(l) + 1) * sizeof(char *)); for (n = firstnode(l); n; incnode(n)) *r++ = (char *)func(getdata(n)); *r = NULL; return arr; } /**/ LinkList arr2list(char **arr, VFunc func) { LinkList l = newlinklist(); while (*arr) addlinknode(l, func(*arr++)); return l; } /**/ char ** mkarray(char *s) { char **t = (char **) zalloc((s) ? (2 * sizeof s) : (sizeof s)); if ((*t = s)) t[1] = NULL; return t; } /**/ void feep(void) { if (isset(BEEP)) write(2, "\07", 1); } /**/ void freearray(char **s) { char **t = s; while (*s) zsfree(*s++); free(t); } /**/ int equalsplit(char *s, char **t) { for (; *s && *s != '='; s++); if (*s == '=') { *s++ = '\0'; *t = s; return 1; } return 0; } /* see if the right side of a list is trivial */ /**/ void simplifyright(List l) { Cmd c; if (l == &dummy_list || !l->right) return; if (l->right->right || l->right->left->right || l->right->left->flags || l->right->left->left->right || l->left->flags) return; c = l->left->left->left; if (c->type != SIMPLE || nonempty(c->args) || nonempty(c->redir) || nonempty(c->vars)) return; l->right = NULL; return; } /* initialize the ztypes table */ /**/ void inittyptab(void) { int t0; char *s; for (t0 = 0; t0 != 256; t0++) typtab[t0] = 0; for (t0 = 0; t0 != 32; t0++) typtab[t0] = typtab[t0 + 128] = ICNTRL; typtab[127] = ICNTRL; for (t0 = '0'; t0 <= '9'; t0++) typtab[t0] = IDIGIT | IALNUM | IWORD | IIDENT | IUSER; for (t0 = 'a'; t0 <= 'z'; t0++) typtab[t0] = typtab[t0 - 'a' + 'A'] = IALPHA | IALNUM | IIDENT | IUSER | IWORD; for (t0 = 0240; t0 != 0400; t0++) typtab[t0] = IALPHA | IALNUM | IIDENT | IUSER | IWORD; typtab['_'] = IIDENT | IUSER; typtab['-'] = IUSER; typtab[' '] |= IBLANK | INBLANK; typtab['\t'] |= IBLANK | INBLANK; typtab['\n'] |= INBLANK; typtab['\0'] |= IMETA; typtab[STOUC(Meta) ] |= IMETA; typtab[STOUC(Marker)] |= IMETA; for (t0 = (int)STOUC(Pound); t0 <= (int)STOUC(Nularg); t0++) typtab[t0] |= ITOK | IMETA; for (s = ifs ? ifs : DEFAULT_IFS; *s; s++) { if (inblank(*s)) if (s[1] == *s) s++; else typtab[STOUC(*s)] |= IWSEP; typtab[STOUC(*s == Meta ? *++s ^ 32 : *s)] |= ISEP; } for (s = wordchars ? wordchars : DEFAULT_WORDCHARS; *s; s++) typtab[STOUC(*s == Meta ? *++s ^ 32 : *s)] |= IWORD; for (s = SPECCHARS; *s; s++) typtab[STOUC(*s)] |= ISPECIAL; if (isset(BANGHIST) && bangchar && interact && isset(SHINSTDIN)) typtab[bangchar] |= ISPECIAL; } /**/ char ** arrdup(char **s) { char **x, **y; y = x = (char **) ncalloc(sizeof(char *) * (arrlen(s) + 1)); while ((*x++ = dupstring(*s++))); return y; } /**/ char * spname(char *oldname) { char *p, spnameguess[PATH_MAX + 1], spnamebest[PATH_MAX + 1]; static char newname[PATH_MAX + 1]; char *new = newname, *old; int bestdist = 200, thisdist; old = oldname; for (;;) { while (*old == '/') *new++ = *old++; *new = '\0'; if (*old == '\0') return newname; p = spnameguess; for (; *old != '/' && *old != '\0'; old++) if (p < spnameguess + PATH_MAX) *p++ = *old; *p = '\0'; if ((thisdist = mindist(newname, spnameguess, spnamebest)) >= 3) { if (bestdist < 3) { strcpy(new, spnameguess); strcat(new, old); return newname; } else return NULL; } else bestdist = thisdist; for (p = spnamebest; (*new = *p++);) new++; } } /**/ int mindist(char *dir, char *mindistguess, char *mindistbest) { int mindistd, nd; DIR *dd; char *fn; char buf[PATH_MAX]; if (dir[0] == '\0') dir = "."; mindistd = 100; sprintf(buf, "%s/%s", dir, mindistguess); if (access(unmeta(buf), F_OK) == 0) { strcpy(mindistbest, mindistguess); return 0; } if (!(dd = opendir(unmeta(dir)))) return mindistd; while ((fn = zreaddir(dd))) { nd = spdist(fn, mindistguess, (int)strlen(mindistguess) / 4 + 1); if (nd <= mindistd) { strcpy(mindistbest, fn); mindistd = nd; if (mindistd == 0) break; } } closedir(dd); return mindistd; } /**/ int spdist(char *s, char *t, int thresh) { char *p, *q; char *keymap = "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\ \t1234567890-=\t\ \tqwertyuiop[]\t\ \tasdfghjkl;'\n\t\ \tzxcvbnm,./\t\t\t\ \n\n\n\n\n\n\n\n\n\n\n\n\n\n\ \t!@#$%^&*()_+\t\ \tQWERTYUIOP{}\t\ \tASDFGHJKL:\"\n\t\ \tZXCVBNM<>?\n\n\t\ \n\n\n\n\n\n\n\n\n\n\n\n\n\n"; if (!strcmp(s, t)) return 0; /* any number of upper/lower mistakes allowed (dist = 1) */ for (p = s, q = t; *p && tulower(*p) == tulower(*q); p++, q++); if (!*p && !*q) return 1; if (!thresh) return 200; for (p = s, q = t; *p && *q; p++, q++) if (*p == *q) continue; /* don't consider "aa" transposed, ash */ else if (p[1] == q[0] && q[1] == p[0]) /* transpositions */ return spdist(p + 2, q + 2, thresh - 1) + 1; else if (p[1] == q[0]) /* missing letter */ return spdist(p + 1, q + 0, thresh - 1) + 2; else if (p[0] == q[1]) /* missing letter */ return spdist(p + 0, q + 1, thresh - 1) + 2; else if (*p != *q) break; if ((!*p && strlen(q) == 1) || (!*q && strlen(p) == 1)) return 2; for (p = s, q = t; *p && *q; p++, q++) if (p[0] != q[0] && p[1] == q[1]) { int t0; char *z; /* mistyped letter */ if (!(z = strchr(keymap, p[0])) || *z == '\n' || *z == '\t') return spdist(p + 1, q + 1, thresh - 1) + 1; t0 = z - keymap; if (*q == keymap[t0 - 15] || *q == keymap[t0 - 14] || *q == keymap[t0 - 13] || *q == keymap[t0 - 1] || *q == keymap[t0 + 1] || *q == keymap[t0 + 13] || *q == keymap[t0 + 14] || *q == keymap[t0 + 15]) return spdist(p + 1, q + 1, thresh - 1) + 2; return 200; } else if (*p != *q) break; return 200; } /* set cbreak mode, or the equivalent */ /**/ void setcbreak(void) { struct ttyinfo ti; ti = shttyinfo; #ifdef HAS_TIO ti.tio.c_lflag &= ~ICANON; ti.tio.c_cc[VMIN] = 1; ti.tio.c_cc[VTIME] = 0; #else ti.sgttyb.sg_flags |= CBREAK; #endif settyinfo(&ti); } /* give the tty to some process */ /**/ void attachtty(pid_t pgrp) { static int ep = 0; if (jobbing) { #ifdef HAVE_TCSETPGRP if (SHTTY != -1 && tcsetpgrp(SHTTY, pgrp) == -1 && !ep) #else # if ardent if (SHTTY != -1 && setpgrp() == -1 && !ep) # else int arg = pgrp; if (SHTTY != -1 && ioctl(SHTTY, TIOCSPGRP, &arg) == -1 && !ep) # endif #endif { if (pgrp != mypgrp && kill(pgrp, 0) == -1) attachtty(mypgrp); else { if (errno != ENOTTY) { zerr("can't set tty pgrp: %e", NULL, errno); fflush(stderr); } opts[MONITOR] = 0; ep = 1; errflag = 0; } } } } /* get the process group associated with the tty */ /**/ pid_t gettygrp(void) { pid_t arg; if (SHTTY == -1) return -1; #ifdef HAVE_TCSETPGRP arg = tcgetpgrp(SHTTY); #else ioctl(SHTTY, TIOCGPGRP, &arg); #endif return arg; } /* Return the output baudrate */ #ifdef HAVE_SELECT /**/ long getbaudrate(struct ttyinfo *shttyinfo) { long speedcode; #ifdef HAS_TIO # if defined(HAVE_TCGETATTR) && defined(HAVE_TERMIOS_H) speedcode = cfgetospeed(&shttyinfo->tio); # else speedcode = shttyinfo->tio.c_cflag & CBAUD; # endif #else speedcode = shttyinfo->sgttyb.sg_ospeed; #endif switch (speedcode) { case B0: return (0L); case B50: return (50L); case B75: return (75L); case B110: return (110L); case B134: return (134L); case B150: return (150L); case B200: return (200L); case B300: return (300L); case B600: return (600L); #ifdef _B900 case _B900: return (900L); #endif case B1200: return (1200L); case B1800: return (1800L); case B2400: return (2400L); #ifdef _B3600 case _B3600: return (3600L); #endif case B4800: return (4800L); #ifdef _B7200 case _B7200: return (7200L); #endif case B9600: return (9600L); #ifdef B19200 case B19200: return (19200L); #else # ifdef EXTA case EXTA: return (19200L); # endif #endif #ifdef B38400 case B38400: return (38400L); #else # ifdef EXTB case EXTB: return (38400L); # endif #endif #ifdef B57600 case B57600: return (57600L); #endif #ifdef B115200 case B115200: return (115200L); #endif #ifdef B230400 case B230400: return (230400L); #endif #ifdef B460800 case B460800: return (460800L); #endif default: if (speedcode >= 100) return speedcode; break; } return (0L); } #endif /* Escape tokens and null characters. Buf is the string which should be * * escaped. len is the length of the string. If len is -1, buf should * * be null terminated. If len is non-zero and the third paramerer is not * * META_DUP buf should point to an at least len+1 long memory area. The * * return value points to the quoted string. If the given string does not * * contain any special character which should be quoted and the third * * parameter is not META_DUP, buf is returned unchanged (a terminating null * * character is appended to buf if necessary). Otherwise the third `heap' * * argument determines the method used to allocate space for the result. * * It can have the following values: * * META_REALLOC: use zrealloc on buf * * META_USEHEAP: get memory from the heap * * META_NOALLOC: buf points to a memory area which is long enough to hold * * the quoted form, just quote it and return buf. * * META_STATIC: store the quoted string in a static area. The original * * sting should be at most PATH_MAX long. * * META_ALLOC: allocate memory for the new string with zalloc(). * * META_DUP: leave buf unchanged and allocate space for the return * * value even if buf does not contains special characters * * META_HEAPDUP: same as META_DUP, but uses the heap */ /**/ char * metafy(char *buf, int len, int heap) { int meta = 0; char *t, *p, *e; static char mbuf[PATH_MAX*2+1]; if (len == -1) { for (e = buf, len = 0; *e; len++) if (imeta(*e++)) meta++; } else for (e = buf; e < buf + len;) if (imeta(*e++)) meta++; if (meta || heap == META_DUP || heap == META_HEAPDUP) { switch (heap) { case META_REALLOC: buf = zrealloc(buf, len + meta + 1); break; case META_USEHEAP: buf = hrealloc(buf, len, len + meta + 1); break; case META_ALLOC: case META_DUP: buf = memcpy(zalloc(len + meta + 1), buf, len); break; case META_HEAPDUP: buf = memcpy(halloc(len + meta + 1), buf, len); break; case META_STATIC: #ifdef DEBUG if (len > PATH_MAX) { fprintf(stderr, "BUG: len = %d > PATH_MAX in metafy\n", len); fflush(stderr); } #endif buf = memcpy(mbuf, buf, len); break; #ifdef DEBUG case META_NOALLOC: break; default: fprintf(stderr, "BUG: metafy called with invaild heap value\n"); fflush(stderr); break; #endif } p = buf + len; e = t = buf + len + meta; while (meta) { if (imeta(*--t = *--p)) { *t-- ^= 32; *t = Meta; meta--; } } } *e = '\0'; return buf; } /**/ char * unmetafy(char *s, int *len) { char *p, *t; for (p = s; *p && *p != Meta; p++); for (t = p; (*t = *p++);) if (*t++ == Meta) t[-1] = *p++ ^ 32; if (len) *len = t - s; return s; } /* Return the character length of a metafied substring, given the * * unmetafied substring length. */ /**/ int metalen(char *s, int len) { int mlen = len; while (len--) { if (*s++ == Meta) { mlen++; s++; } } return mlen; } /* This function converts a zsh internal string to a form which can be * * passed to a system call as a filename. The result is stored in a * * single static area. NULL returned if the result is longer than * * PATH_MAX. */ /**/ char * unmeta(char *file_name) { static char fn[PATH_MAX]; char *p, *t; for (t = file_name, p = fn; *t && p < fn + PATH_MAX - 1; p++) if ((*p = *t++) == Meta) *p = *t++ ^ 32; if (*t) return NULL; if (p - fn == t - file_name) return file_name; *p = '\0'; return fn; } /* Unmetafy and compare two strings, with unsigned characters. * * "a\0" sorts after "a". */ /**/ int ztrcmp(unsigned char const *s1, unsigned char const *s2) { int c1, c2; while(*s1 && *s1 == *s2) { s1++; s2++; } if(!(c1 = *s1)) c1 = -1; else if(c1 == STOUC(Meta)) c1 = *++s1 ^ 32; if(!(c2 = *s2)) c2 = -1; else if(c2 == STOUC(Meta)) c2 = *++s2 ^ 32; if(c1 == c2) return 0; else if(c1 < c2) return -1; else return 1; } /* Return zero if the metafied string s and the non-metafied, * * len-long string r are the same. Return -1 if r is a prefix * * of s. Return 1 if r is the lowercase version of s. Return * * 2 is r is the lowercase prefix of s and return 3 otherwise. */ /**/ int metadiffer(char const *s, char const *r, int len) { int l = len; while (l-- && *s && *r++ == (*s == Meta ? *++s ^ 32 : *s)) s++; if (*s && l < 0) return -1; if (l < 0) return 0; if (!*s) return 3; s -= len - l - 1; r -= len - l; while (len-- && *s && *r++ == tulower(*s == Meta ? *++s ^ 32 : *s)) s++; if (*s && len < 0) return 2; if (len < 0) return 1; return 3; } /* Return the unmetafied length of a metafied string. */ /**/ int ztrlen(char const *s) { int l; for (l = 0; *s; l++) if (*s++ == Meta) { #ifdef DEBUG if (! *s) fprintf(stderr, "BUG: unexpected end of string in ztrlen()\n"); else #endif s++; } return l; } /* Subtract two pointers in a metafied string. */ /**/ int ztrsub(char const *t, char const *s) { int l = t - s; while (s != t) if (*s++ == Meta) { #ifdef DEBUG if (! *s || s == t) fprintf(stderr, "BUG: substring ends in the middle of a metachar in ztrsub()\n"); else #endif s++; l--; } return l; } /**/ char * zreaddir(DIR *dir) { struct dirent *de = readdir(dir); return de ? metafy(de->d_name, -1, META_STATIC) : NULL; } /* Unmetafy and output a string. */ /**/ int zputs(char const *s, FILE *stream) { int c; while (*s) { if (*s == Meta) c = *++s ^ 32; else c = *s; s++; if (fputc(c, stream) < 0) return EOF; } return 0; } /* Unmetafy and output a string, displaying special characters readably. */ /**/ int nicezputs(char const *s, FILE *stream) { int c; while ((c = *s++)) { if (itok(c)) if (c <= Comma) c = ztokens[c - Pound]; else continue; if (c == Meta) c = *s++ ^ 32; if(fputs(nicechar(c), stream) < 0) return EOF; } return 0; } /* Return the length of the visible representation of a metafied string. */ /**/ size_t niceztrlen(char const *s) { size_t l = 0; int c; while ((c = *s++)) { if (itok(c)) if (c <= Comma) c = ztokens[c - Pound]; else continue; if (c == Meta) c = *s++ ^ 32; l += strlen(nicechar(STOUC(c))); } return l; } /* check for special characters in the string */ /**/ int hasspecial(char const *s) { for (; *s; s++) if (ispecial(*s == Meta ? *++s ^ 32 : *s)) return 1; return 0; } /* Unmetafy and output a string, quoted if it contains special characters. */ /**/ int quotedzputs(char const *s, FILE *stream) { int inquote = 0, c; /* check for empty string */ if(!*s) return fputs("''", stream); if (!hasspecial(s)) return zputs(s, stream); if (isset(RCQUOTES)) { /* use rc-style quotes-within-quotes for the whole string */ if(fputc('\'', stream) < 0) return EOF; while(*s) { if (*s == Meta) c = *++s ^ 32; else c = *s; s++; if (c == '\'') { if(fputc('\'', stream) < 0) return EOF; } else if(c == '\n' && isset(CSHJUNKIEQUOTES)) { if(fputc('\\', stream) < 0) return EOF; } if(fputc(c, stream) < 0) return EOF; } if(fputc('\'', stream) < 0) return EOF; } else { /* use Bourne-style quoting, avoiding empty quoted strings */ while(*s) { if (*s == Meta) c = *++s ^ 32; else c = *s; s++; if (c == '\'') { if(inquote) { if(fputc('\'', stream) < 0) return EOF; inquote=0; } if(fputs("\\'", stream) < 0) return EOF; } else { if (!inquote) { if(fputc('\'', stream) < 0) return EOF; inquote=1; } if(c == '\n' && isset(CSHJUNKIEQUOTES)) { if(fputc('\\', stream) < 0) return EOF; } if(fputc(c, stream) < 0) return EOF; } } if (inquote) { if(fputc('\'', stream) < 0) return EOF; } } return 0; } /* Identify an option name */ /**/ int optlookup(char *s) { char *t; int optno, starts_no; t = s = dupstring(s); /* exorcise underscores, and change to lowercase */ while (*t) if (*t == '_') chuck(t); else { *t = tulower(*t); t++; } starts_no = (s[0] == 'n' && s[1] == 'o'); /* search for name in table */ for (optno = OPT_SIZE; --optno; ) { if (!strcmp(optns[optno].name, s)) return optno; if (starts_no && !strcmp(optns[optno].name, s+2)) return -optno; } return 0; } /* Identify an option letter */ /**/ int optlookupc(char c) { int optno; if(!c || (c & OPT_REV)) return 0; /* search for letter in the table */ for (optno = OPT_SIZE; --optno; ) { char id = optid(optns[optno]); if (id == c) return optno; if (id == (char)(c | OPT_REV)) return -optno; } return 0; } /* Set or unset an option. The option number may be negative, indicating * * that the sense is reversed from the usual meaning of the option. */ /**/ int dosetopt(int optno, int value, int force) { if(!optno) return -1; if(optno < 0) { optno = -optno; value = !value; } if(!force && (optno == INTERACTIVE || optno == SHINSTDIN || optno == SINGLECOMMAND)) { /* it is not permitted to change the value of these options */ return -1; } else if(!force && optno == USEZLE && value) { /* we require a terminal in order to use ZLE */ if(!interact || SHTTY == -1 || !shout) return -1; } else if(optno == PRIVILEGED && !value) { /* unsetting PRIVILEGED causes the shell to make itself unprivileged */ #ifdef HAVE_SETUID setuid(getuid()); setgid(getgid()); #endif /* HAVE_SETUID */ } opts[optno] = value; if (optno == BANGHIST || optno == SHINSTDIN) inittyptab(); return 0; } /**/ char * dupstrpfx(const char *s, int len) { char *r = ncalloc(len + 1); memcpy(r, s, len); r[len] = '\0'; return r; } /**/ char * ztrduppfx(const char *s, int len) { char *r = zalloc(len + 1); memcpy(r, s, len); r[len] = '\0'; return r; } #ifdef DEBUG /**/ void dputs(char *message) { fprintf(stderr, "%s\n", message); fflush(stderr); } #endif
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.