extern void assign(List *s1, List *s2, bool stack) { List *val = s2; if (s1 == NULL) rc_error("null variable name"); if (s1->n != NULL) rc_error("multi-word variable name"); if (*s1->w == '\0') rc_error("zero-length variable name"); if (a2u(s1->w) != -1) rc_error("numeric variable name"); if (strchr(s1->w, '=') != NULL) rc_error("'=' in variable name"); if (*s1->w == '*' && s1->w[1] == '\0') val = append(varlookup("0"), s2); /* preserve $0 when * is assigned explicitly */ if (s2 != NULL || stack) { if (dashex) prettyprint_var(2, s1->w, val); varassign(s1->w, val, stack); alias(s1->w, varlookup(s1->w), stack); } else { if (dashex) prettyprint_var(2, s1->w, NULL); varrm(s1->w, stack); } }
static void b_shift(char **av) { int shift = (av[1] == NULL ? 1 : a2u(av[1])); List *s, *dollarzero; if (av[1] != NULL && av[2] != NULL) { arg_count("shift"); return; } if (shift < 0) { badnum(av[1]); return; } s = varlookup("*")->n; dollarzero = varlookup("0"); while (s != NULL && shift != 0) { s = s->n; --shift; } if (s == NULL && shift != 0) { fprint(2, "cannot shift\n"); set(FALSE); } else { varassign("*", append(dollarzero, s), FALSE); set(TRUE); } }
static void b_cd(char **av) { if (*++av == NULL) { List *s2 = varlookup("home"); *av = (s2 == NULL) ? "/" : s2->w; } else if (av[1] != NULL) { arg_count("cd"); return; } if (isabsolute(*av) || streq(*av, ".") || streq(*av, "..")) { /* absolute pathname? */ if (chdir(*av) < 0) { set(FALSE); uerror(*av); } else { update_cwd_var(); set(TRUE); } } else { char *path = NULL; size_t pathlen = 0; List nil; List *s = varlookup("cdpath"); if (s == NULL) { s = &nil; nil.w = ""; nil.n = NULL; } do { if (s != &nil && *s->w != '\0') { const size_t t = strlen(*av) + strlen(s->w) + 2; if (t > pathlen) path = nnew_arr(char, pathlen = t); strcpy(path, s->w); if (!streq(s->w, "/")) /* "//" is special to POSIX */ strcat(path, "/"); strcat(path, *av); } else { pathlen = 0; path = *av; } if (chdir(path) >= 0) { update_cwd_var(); set(TRUE); if (interactive && *s->w != '\0' && !streq(s->w, ".")) fprint(1, "%s\n", path); return; } s = s->n; } while (s != NULL); fprint(2, "couldn't cd to %s\n", *av); set(FALSE); }
/* pathsearch -- evaluate fn %pathsearch + some argument */ extern List *pathsearch(Term *term) { List *search, *list; search = varlookup("fn-%pathsearch", NULL); if (search == NULL) fail("es:pathsearch", "%E: fn %%pathsearch undefined", term); list = mklist(term, NULL); return eval(append(search, list), NULL, 0); }
EPNODE * dlookup( /* look up a definition */ char *name ) { VARDEF *vp; if ((vp = varlookup(name)) == NULL) return(NULL); return(vp->def); }
extern char *which(char *name, bool verbose) { static char *test = NULL; static size_t testlen = 0; List *path; int len; if (name == NULL) /* no filename? can happen with "> foo" as a command */ return NULL; if (!initialized) { initialized = TRUE; uid = geteuid(); gid = getegid(); #if HAVE_GETGROUPS #if HAVE_POSIX_GETGROUPS ngroups = getgroups(0, (GETGROUPS_T *)0); if (ngroups < 0) { uerror("getgroups"); rc_exit(1); } #else ngroups = NGROUPS; #endif if (ngroups) { gidset = ealloc(ngroups * sizeof(GETGROUPS_T)); getgroups(ngroups, gidset); } #endif } if (isabsolute(name)) /* absolute pathname? */ return rc_access(name, verbose) ? name : NULL; len = strlen(name); for (path = varlookup("path"); path != NULL; path = path->n) { size_t need = strlen(path->w) + len + 2; /* one for null terminator, one for the '/' */ if (testlen < need) { efree(test); test = ealloc(testlen = need); } if (*path->w == '\0') { strcpy(test, name); } else { strcpy(test, path->w); if (!streq(test, "/")) /* "//" is special to POSIX */ strcat(test, "/"); strcat(test, name); } if (rc_access(test, FALSE)) return test; } if (verbose) { char *n = protect(name); fprint(2, RC "cannot find `%s'\n", n); efree(n); } return NULL; }
extern void applylocale() { char *lvar[3] = { "LC_ALL", "LC_CTYPE", "LANG" }; size_t i; for (i = 0; i < arraysize(lvar); i++) { List *loc = varlookup(lvar[i]); if (loc) { setlocale(LC_CTYPE, loc->w); break; } } }
static List *expandtilde(List *s) { List *top, *r, *var; char *home; size_t i, j, hsize, psize; bool tilde; for (r = s, tilde = FALSE; r != NULL; r = r->n) if (r->m != NULL && r->m[0] && r->w[0] == '~') tilde = TRUE; if (!tilde) return s; for (top = NULL; s != NULL; s = s->n) { if (top == NULL) top = r = nnew(List); else r = r->n = nnew(List); r->w = s->w; r->m = s->m; if (s->m == NULL || !s->m[0] || s->w[0] != '~') continue; for (i = 1; s->w[i] != '/' && s->w[i] != '\0'; i++); home = NULL; if (i == 1) { if ((var = varlookup("HOME")) != NULL) home = var->w; } else { char c = s->w[i]; struct passwd *pw; s->w[i] = '\0'; if ((pw = getpwnam(s->w + 1)) != NULL) home = pw->pw_dir; s->w[i] = c; } if (home == NULL || (hsize = strlen(home)) == 0) continue; psize = strlen(s->w + i) + 1; r->w = nalloc(psize + hsize); memcpy(r->w, home, hsize); memcpy(r->w + hsize, s->w + i, psize); for (j = i; s->w[j] != '\0'; j++) if (s->m[j]) break; if (s->w[j] != '\0') { r->m = nalloc(psize + hsize); memset(r->m, 0, hsize); memcpy(r->m + hsize, s->m + i, psize); } else r->m = NULL; } r->n = NULL; return top; }
EPNODE * dpop( /* pop a definition */ char *name ) { VARDEF *vp; EPNODE *dp; if ((vp = varlookup(name)) == NULL || vp->def == NULL) return(NULL); dp = vp->def; vp->def = dp->sibling; varfree(vp); return(dp); }
static noreturn failexec(char *file, List *args) { List *fn; assert(gcisblocked()); fn = varlookup("fn-%exec-failure", NULL); if (fn != NULL) { int olderror = errno; Ref(List *, list, append(fn, mklist(mkstr(file), args))); RefAdd(file); gcenable(); RefRemove(file); eval(list, NULL, 0); RefEnd(list); errno = olderror; } eprint("%s: %s\n", file, esstrerror(errno)); exit(1); }
void getstatement(void) /* get next statement */ { EPNODE *ep; char *qname; VARDEF *vdef; if (nextc == ';') { /* empty statement */ scan(); return; } if (esupport&E_OUTCHAN && nextc == '$') { /* channel assignment */ ep = getchan(); addchan(ep); } else { /* ordinary definition */ ep = getdefn(); qname = qualname(dname(ep), 0); if (esupport&E_REDEFW && (vdef = varlookup(qname)) != NULL) { if (vdef->def != NULL && epcmp(ep, vdef->def)) { wputs(qname); if (vdef->def->type == ':') wputs(": redefined constant expression\n"); else wputs(": redefined\n"); } else if (ep->v.kid->type == FUNC && vdef->lib != NULL) { wputs(qname); wputs(": definition hides library function\n"); } } if (ep->type == ':') dremove(qname); else dclear(qname); dpush(qname, ep); } if (nextc != EOF) { if (nextc != ';') syntax("';' expected"); scan(); } }
/* varlookup -- lookup a variable in the current context */ extern List *varlookup(const char *name, Binding *bp) { Var *var; if (iscounting(name)) { Term *term = nth(varlookup("*", bp), strtol(name, NULL, 10)); if (term == NULL) return NULL; return mklist(term, NULL); } validatevar(name); for (; bp != NULL; bp = bp->next) if (streq(name, bp->name)) return bp->defn; var = dictget(vars, name); if (var == NULL) return NULL; return var->defn; }
VARDEF * varinsert( /* get a link to a variable */ char *name ) { VARDEF *vp; int hv; if ((vp = varlookup(name)) != NULL) { vp->nlinks++; return(vp); } vp = (VARDEF *)emalloc(sizeof(VARDEF)); vp->lib = liblookup(name); if (vp->lib == NULL) /* if name not in library */ name = qualname(name, 0); /* use fully qualified version */ hv = hash(name); vp->name = savestr(name); vp->nlinks = 1; vp->def = NULL; vp->next = hashtbl[hv]; hashtbl[hv] = vp; return(vp); }
/* expandhome -- do tilde expansion by calling fn %home */ static char *expandhome(char *s, StrList *qp) { int c; size_t slash; List *fn = varlookup("fn-%home", NULL); assert(*s == '~'); assert(qp->str == UNQUOTED || *qp->str == 'r'); if (fn == NULL) return s; for (slash = 1; (c = s[slash]) != '/' && c != '\0'; slash++) ; Ref(char *, string, s); Ref(StrList *, quote, qp); Ref(List *, list, NULL); RefAdd(fn); if (slash > 1) list = mklist(mkstr(gcndup(s + 1, slash - 1)), NULL); RefRemove(fn); list = eval(append(fn, list), NULL, 0); if (list != NULL) { if (list->next != NULL) fail("es:expandhome", "%%home returned more than one value"); Ref(char *, home, getstr(list->term)); if (c == '\0') { string = home; quote->str = QUOTED; } else { char *q; size_t pathlen = strlen(string); size_t homelen = strlen(home); size_t len = pathlen - slash + homelen; s = gcalloc(len + 1, &StringTag); memcpy(s, home, homelen); memcpy(&s[homelen], &string[slash], pathlen - slash); s[len] = '\0'; string = s; q = quote->str; if (q == UNQUOTED) { q = gcalloc(len + 1, &StringTag); memset(q, 'q', homelen); memset(&q[homelen], 'r', pathlen - slash); q[len] = '\0'; } else if (strchr(q, 'r') == NULL) q = QUOTED; else { q = gcalloc(len + 1, &StringTag); memset(q, 'q', homelen); memcpy(&q[homelen], "e->str[slash], pathlen - slash); q[len] = '\0'; } quote->str = q; } RefEnd(home); } RefEnd2(list, quote); RefReturn(string); }
extern int main(int argc, char *argv[], char *envp[]) { char *dashsee[2], *dollarzero, *null[1]; int c; initprint(); dashsee[0] = dashsee[1] = NULL; dollarzero = argv[0]; rc_pid = getpid(); dashell = (*argv[0] == '-'); /* Unix tradition */ while ((c = rc_getopt(argc, argv, "c:deiIlnopsvx")) != -1) switch (c) { case 'c': dashsee[0] = rc_optarg; goto quitopts; case 'd': dashdee = TRUE; break; case 'e': dashee = TRUE; break; case 'I': dashEYE = TRUE; interactive = FALSE; break; case 'i': dasheye = interactive = TRUE; break; case 'l': dashell = TRUE; break; case 'n': dashen = TRUE; break; case 'o': dashoh = TRUE; break; case 'p': dashpee = TRUE; break; case 's': dashess = TRUE; break; case 'v': dashvee = TRUE; break; case 'x': dashex = TRUE; break; case '?': exit(1); } quitopts: argv += rc_optind; /* use isatty() iff neither -i nor -I is set, and iff the input is not from a script or -c flags */ if (!dasheye && !dashEYE && dashsee[0] == NULL && (dashess || *argv == NULL)) interactive = isatty(0); if (!dashoh) { checkfd(0, rFrom); checkfd(1, rCreate); checkfd(2, rCreate); } initsignal(); inithash(); initparse(); assigndefault("ifs", " ", "\t", "\n", (void *)0); #ifdef DEFAULTPATH assigndefault("path", DEFAULTPATH, (void *)0); #endif assigndefault("pid", nprint("%d", rc_pid), (void *)0); assigndefault("prompt", "; ", "", (void *)0); assigndefault("version", VERSION, "$Release: @(#)" PACKAGE " " VERSION " " RELDATE " $", (void *)0); initenv(envp); initinput(); null[0] = NULL; starassign(dollarzero, null, FALSE); /* assign $0 to $* */ inithandler(); if (dashell) { char *rcrc; int fd; rcrc = concat(varlookup("home"), word("/.rcrc", NULL))->w; fd = rc_open(rcrc, rFrom); if (fd == -1) { if (errno != ENOENT) uerror(rcrc); } else { bool push_interactive; pushfd(fd); push_interactive = interactive; interactive = FALSE; doit(TRUE); interactive = push_interactive; close(fd); } } if (dashsee[0] != NULL || dashess) { /* input from -c or -s? */ if (*argv != NULL) starassign(dollarzero, argv, FALSE); if (dashess) pushfd(0); else pushstring(dashsee, TRUE); } else if (*argv != NULL) { /* else from a file? */ b_dot(--argv); rc_exit(getstatus()); } else { /* else stdin */ pushfd(0); } dasheye = FALSE; doit(TRUE); rc_exit(getstatus()); return 0; /* Never really reached. */ }
static void b_whatis(char **av) { bool ess, eff, vee, pee, bee; bool f, found; int i, ac, c; List *s; Node *n; char *e; for (rc_optind = ac = 0; av[ac] != NULL; ac++) ; /* count the arguments for getopt */ ess = eff = vee = pee = bee = FALSE; while ((c = rc_getopt(ac, av, "sfvpb")) != -1) switch (c) { default: set(FALSE); return; case 's': ess = TRUE; break; case 'f': eff = TRUE; break; case 'v': vee = TRUE; break; case 'p': pee = TRUE; break; case 'b': bee = TRUE; break; } av += rc_optind; if (*av == NULL) { if (vee|eff) whatare_all_vars(eff, vee); if (ess) whatare_all_signals(); if (bee) for (i = 0; i < arraysize(builtins); i++) fprint(1, "builtin %s\n", builtins[i].name); if (pee) fprint(2, "whatis -p: must specify argument\n"); if (show(FALSE)) /* no options? */ whatare_all_vars(TRUE, TRUE); set(TRUE); return; } found = TRUE; for (i = 0; av[i] != NULL; i++) { f = FALSE; errno = ENOENT; if (show(vee) && (s = varlookup(av[i])) != NULL) { f = TRUE; prettyprint_var(1, av[i], s); } if (((show(ess)&&issig(av[i])) || show(eff)) && (n = fnlookup(av[i])) != NULL) { f = TRUE; prettyprint_fn(1, av[i], n); } else if (show(bee) && isbuiltin(av[i]) != NULL) { f = TRUE; fprint(1, "builtin %s\n", av[i]); } else if (show(pee) && (e = which(av[i], FALSE)) != NULL) { f = TRUE; fprint(1, "%S\n", e); } if (!f) { found = FALSE; if (errno != ENOENT) uerror(av[i]); else fprint(2, "%s not found\n", av[i]); } } set(found); }
extern List *glom(Node *n) { List *v, *head, *tail; Node *words; if (n == NULL) return NULL; switch (n->type) { case nArgs: case nLappend: words = n->u[0].p; tail = NULL; while (words != NULL && (words->type == nArgs || words->type == nLappend)) { if (words->u[1].p != NULL && words->u[1].p->type != nWord) break; head = glom(words->u[1].p); if (head != NULL) { head->n = tail; tail = head; } words = words->u[0].p; } v = append(glom(words), tail); /* force left to right evaluation */ return append(v, glom(n->u[1].p)); case nBackq: return backq(n->u[0].p, n->u[1].p); case nConcat: head = glom(n->u[0].p); /* force left-to-right evaluation */ return concat(head, glom(n->u[1].p)); case nDup: case nRedir: qredir(n); return NULL; case nWord: return word(n->u[0].s, n->u[1].s); case nNmpipe: return mkcmdarg(n); default: /* The next four operations depend on the left-child of glom to be a variable name. Therefore the variable is looked up here. */ if ((v = glom(n->u[0].p)) == NULL) rc_error("null variable name"); if (v->n != NULL) rc_error("multi-word variable name"); if (*v->w == '\0') rc_error("zero-length variable name"); v = (*v->w == '*' && v->w[1] == '\0') ? varlookup(v->w)->n : varlookup(v->w); switch (n->type) { default: panic("unexpected node in glom"); exit(1); /* NOTREACHED */ case nCount: return count(v); case nFlat: return flatten(v); case nVar: return v; case nVarsub: return varsub(v, glom(n->u[1].p)); } } }