static Namval_t *make_time(Namval_t* np) { int offset = stktell(stkstd); char *name = nv_name(np); struct dctime *dp = newof(NULL,struct dctime,1,0); if(!dp) return((Namval_t*)0); sfprintf(stkstd,"%s.format\0",name); sfputc(stkstd,0); dp->format = nv_search(stkptr(stkstd,offset),sh.var_tree,NV_ADD); dp->fun.disc = &timedisc; nv_stack(np,&dp->fun); return(np); }
static Namval_t *sh_newnode(register Shfield_t *fp, Namval_t *np) { char *val = np->nvalue + fp->offset; char *name = nv_name(np); register Namval_t *nq; int offset = stktell(stkstd); sfprintf(stkstd,"%s.%s\0",name,fp->name); sfputc(stkstd,0); nq = nv_search(stkptr(stkstd,offset),sh.var_tree,NV_ADD); if(fp->size<0) val = *(char**)val; nv_putval(nq,val,fp->flags|NV_NOFREE); if(fp->make) (*fp->make)(nq); return(nq); }
static char *fmtx(Shell_t *shp, const char *string) { const char *cp = string; int n, c; const unsigned char *norm_state = (const unsigned char *)sh_lexstates[ST_NORM]; int offset = stktell(shp->stk); if (*cp == '#' || *cp == '~') sfputc(shp->stk, '\\'); while ((c = mb1char((char **)&cp)), (c > UCHAR_MAX) || (n = norm_state[c]) == 0 || n == S_EPAT) { ; // empty loop } if (n == S_EOF && *string != '#') return (char *)string; sfwrite(shp->stk, string, --cp - string); for (string = cp; (c = mb1char((char **)&cp)); string = cp) { if ((n = cp - string) == 1) { n = norm_state[c]; if (n && n != S_EPAT) sfputc(shp->stk, '\\'); sfputc(shp->stk, c); } else { sfwrite(shp->stk, string, n); } } sfputc(shp->stk, 0); return stkptr(shp->stk, offset); }
// // Open the history file. If HISTNAME is not given and userid==0 then no history file. If login_sh // and HISTFILE is longer than HIST_MAX bytes then it is cleaned up. // // hist_open() returns 1, if history file is opened. // int sh_histinit(void *sh_context) { Shell_t *shp = sh_context; int fd; History_t *hp; char *histname; char *fname = NULL; int histmask, maxlines, hist_start = 0; char *cp; off_t hsize = 0; shgd->hist_ptr = hist_ptr; if (shgd->hist_ptr) return 1; if (!(histname = nv_getval(HISTFILE))) { int offset = stktell(shp->stk); cp = nv_getval(HOME); if (cp) sfputr(shp->stk, cp, -1); sfputr(shp->stk, hist_fname, 0); stkseek(shp->stk, offset); histname = stkptr(shp->stk, offset); } #if 0 // TODO: Figure out if this should be enabled. Originally excluded via `#ifdef future`. if (hp = wasopen) { // Reuse history file if same name. wasopen = 0; shgd->hist_ptr = hist_ptr = hp; if (strcmp(histname, hp->histname) == 0) { return 1; } else { hist_free(); } } #endif // future retry: cp = path_relative(shp, histname); if (!histinit) histmode = S_IRUSR | S_IWUSR; if ((fd = open(cp, O_BINARY | O_APPEND | O_RDWR | O_CREAT | O_CLOEXEC, histmode)) >= 0) { hsize = lseek(fd, (off_t)0, SEEK_END); } if ((unsigned)fd < 10) { int n; if ((n = sh_fcntl(fd, F_DUPFD_CLOEXEC, 10)) >= 0) { sh_close(fd); fd = n; } } // Make sure that file has history file format. if (hsize && hist_check(fd)) { sh_close(fd); hsize = 0; if (unlink(cp) >= 0) goto retry; fd = -1; } // Don't allow root a history_file in /tmp. if (fd < 0 && shgd->userid) { fname = ast_temp_file(NULL, NULL, &fd, O_APPEND | O_CLOEXEC); if (!fname) return 0; } if (fd < 0) return 0; // Set the file to close-on-exec. (void)fcntl(fd, F_SETFD, FD_CLOEXEC); cp = nv_getval(HISTSIZE); if (cp) { maxlines = (unsigned)strtol(cp, NULL, 10); } else { maxlines = HIST_DFLT; } for (histmask = 16; histmask <= maxlines; histmask <<= 1) { ; // empty loop } histmask -= 1; hp = calloc(1, sizeof(History_t) + histmask * sizeof(off_t)); if (!hp) { sh_close(fd); return 0; } shgd->hist_ptr = hist_ptr = hp; hp->histshell = shp; hp->histsize = maxlines; hp->histmask = histmask; hp->histfp = sfnew(NULL, NULL, HIST_BSIZE, fd, SF_READ | SF_WRITE | SF_APPENDWR | SF_SHARE); hp->histind = 1; hp->histcmds[1] = 2; hp->histcnt = 2; hp->histname = strdup(histname); hp->histdisc = hist_disc; if (hsize == 0) { // Put special characters at front of file. sfwrite(hp->histfp, (char *)hist_stamp, 2); sfsync(hp->histfp); } else { // Initialize history list. int first, last; off_t mark, size = (HIST_MAX / 4) + maxlines * HIST_LINE; hp->histind = first = hist_nearend(hp, hp->histfp, hsize - size); histinit = 1; hist_eof(hp); // this sets histind to last command if ((hist_start = (last = (int)hp->histind) - maxlines) <= 0) hist_start = 1; mark = hp->histmarker; while (first > hist_start) { size += size; first = hist_nearend(hp, hp->histfp, hsize - size); hp->histind = first; } histinit = hist_start; hist_eof(hp); if (!histinit) { sfseek(hp->histfp, hp->histcnt = hsize, SEEK_SET); hp->histind = last; hp->histmarker = mark; } histinit = 0; } if (fname) { unlink(fname); free(fname); } if (hist_clean(fd) && hist_start > 1 && hsize > HIST_MAX) { #ifdef DEBUG sfprintf(sfstderr, "%d: hist_trim hsize=%d\n", getpid(), hsize); sfsync(sfstderr); #endif // DEBUG hp = hist_trim(hp, (int)hp->histind - maxlines); } sfdisc(hp->histfp, &hp->histdisc); STORE_VT((HISTCUR)->nvalue, i32p, &hp->histind); sh_timeradd(1000L * (HIST_RECENT - 30), 1, hist_touch, hp->histname); hp->auditfp = NULL; char buff[SF_BUFSIZE]; if (!sh_isstate(shp, SH_INTERACTIVE)) return 1; hp->auditmask = sh_checkaudit(hp, AUDIT_FILE, buff, sizeof(buff)); if (!hp->auditmask) return 1; if ((fd = sh_open(buff, O_BINARY | O_WRONLY | O_APPEND | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR)) >= 0 && fd < 10) { int n; if ((n = sh_fcntl(fd, F_DUPFD_CLOEXEC, 10)) >= 0) { sh_close(fd); fd = n; } } if (fd >= 0) { (void)fcntl(fd, F_SETFD, FD_CLOEXEC); hp->tty = strdup(isatty(2) ? ttyname(2) : "notty"); hp->auditfp = sfnew(NULL, NULL, -1, fd, SF_WRITE); } return 1; }
void errorv(const char* id, int level, va_list ap) { register int n; int fd; int flags; char* s; char* t; char* format; char* library; const char* catalog; int line; char* file; #if !_PACKAGE_astsa unsigned long d; struct tms us; #endif if (!error_info.init) { error_info.init = 1; stropt(getenv("ERROR_OPTIONS"), options, sizeof(*options), setopt, NiL); } if (level > 0) { flags = level & ~ERROR_LEVEL; level &= ERROR_LEVEL; } else flags = 0; if ((flags & (ERROR_USAGE|ERROR_NOID)) == ERROR_NOID) { format = (char*)id; id = 0; } else format = 0; if (id) { catalog = (char*)id; if (!*catalog || *catalog == ':') { catalog = 0; library = 0; } else if ((library = strchr(catalog, ':')) && !*++library) library = 0; } else { catalog = 0; library = 0; } if (catalog) id = 0; else { id = (const char*)error_info.id; catalog = error_info.catalog; } if (level < error_info.trace || (flags & ERROR_LIBRARY) && !(((error_info.set | error_info.flags) ^ error_info.clear) & ERROR_LIBRARY) || level < 0 && error_info.mask && !(error_info.mask & (1<<(-level - 1)))) { if (level >= ERROR_FATAL) (*error_info.exit)(level - 1); return; } if (error_info.trace < 0) flags |= ERROR_LIBRARY|ERROR_SYSTEM; flags |= error_info.set | error_info.flags; flags &= ~error_info.clear; if (!library) flags &= ~ERROR_LIBRARY; fd = (flags & ERROR_OUTPUT) ? va_arg(ap, int) : error_info.fd; if (error_info.write) { long off; char* bas; bas = stkptr(stkstd, 0); if (off = stktell(stkstd)) stkfreeze(stkstd, 0); file = error_info.id; if (error_state.prefix) sfprintf(stkstd, "%s: ", error_state.prefix); if (flags & ERROR_USAGE) { if (flags & ERROR_NOID) sfprintf(stkstd, " "); else sfprintf(stkstd, "%s: ", ERROR_translate(NiL, NiL, ast.id, "Usage")); if (file || opt_info.argv && (file = opt_info.argv[0])) print(stkstd, file, " "); } else { if (level && !(flags & ERROR_NOID)) { if (error_info.context && level > 0) context(stkstd, CONTEXT(error_info.flags, error_info.context)); if (file) print(stkstd, file, (flags & ERROR_LIBRARY) ? " " : ": "); if (flags & (ERROR_CATALOG|ERROR_LIBRARY)) { sfprintf(stkstd, "["); if (flags & ERROR_CATALOG) sfprintf(stkstd, "%s %s%s", catalog ? catalog : ERROR_translate(NiL, NiL, ast.id, "DEFAULT"), ERROR_translate(NiL, NiL, ast.id, "catalog"), (flags & ERROR_LIBRARY) ? ", " : ""); if (flags & ERROR_LIBRARY) sfprintf(stkstd, "%s %s", library, ERROR_translate(NiL, NiL, ast.id, "library")); sfprintf(stkstd, "]: "); } } if (level > 0 && error_info.line > ((flags & ERROR_INTERACTIVE) != 0)) { if (error_info.file && *error_info.file) sfprintf(stkstd, "\"%s\", ", error_info.file); sfprintf(stkstd, "%s %d: ", ERROR_translate(NiL, NiL, ast.id, "line"), error_info.line); } } #if !_PACKAGE_astsa if (error_info.time) { if ((d = times(&us)) < error_info.time || error_info.time == 1) error_info.time = d; sfprintf(stkstd, " %05lu.%05lu.%05lu ", d - error_info.time, (unsigned long)us.tms_utime, (unsigned long)us.tms_stime); } #endif switch (level) { case 0: flags &= ~ERROR_SYSTEM; break; case ERROR_WARNING: sfprintf(stkstd, "%s: ", ERROR_translate(NiL, NiL, ast.id, "warning")); break; case ERROR_PANIC: sfprintf(stkstd, "%s: ", ERROR_translate(NiL, NiL, ast.id, "panic")); break; default: if (level < 0) { s = ERROR_translate(NiL, NiL, ast.id, "debug"); if (error_info.trace < -1) sfprintf(stkstd, "%s%d:%s", s, level, level > -10 ? " " : ""); else sfprintf(stkstd, "%s: ", s); for (n = 0; n < error_info.indent; n++) { sfputc(stkstd, ' '); sfputc(stkstd, ' '); } } break; } if (flags & ERROR_SOURCE) { /* * source ([version], file, line) message */ file = va_arg(ap, char*); line = va_arg(ap, int); s = ERROR_translate(NiL, NiL, ast.id, "line"); if (error_info.version) sfprintf(stkstd, "(%s: \"%s\", %s %d) ", error_info.version, file, s, line); else sfprintf(stkstd, "(\"%s\", %s %d) ", file, s, line); }
// // File name generation for edit modes. // Non-zero exit for error, <0 ring bell. // Don't search back past beginning of the buffer. // Mode is '*' for inline expansion. // Mode is '\' for filename completion. // Mode is '=' cause files to be listed in select format. // int ed_expand(Edit_t *ep, char outbuff[], int *cur, int *eol, int mode, int count) { struct comnod *comptr; struct argnod *ap; char *out; char *av[2], *begin; char *dir = NULL; int addstar = 0, rval = 0, var = 0, strip = 1, narg = 0; int nomarkdirs = !sh_isoption(ep->sh, SH_MARKDIRS); Shell_t *shp = ep->sh; char **com = NULL; sh_onstate(shp, SH_FCOMPLETE); if (ep->e_nlist) { if (mode == '=' && count > 0) { if (count > ep->e_nlist) return -1; mode = '?'; av[0] = ep->e_clist[count - 1]; av[1] = 0; } else { stkset(shp->stk, ep->e_stkptr, ep->e_stkoff); ep->e_nlist = 0; } } comptr = stkalloc(shp->stk, sizeof(struct comnod)); ap = (struct argnod *)stkseek(shp->stk, ARGVAL); { // Adjust cur. int c; genchar *cp; cp = (genchar *)outbuff + *cur; c = *cp; *cp = 0; *cur = ed_external((genchar *)outbuff, (char *)stkptr(shp->stk, 0)); *cp = c; *eol = ed_external((genchar *)outbuff, outbuff); } out = outbuff + *cur + (sh_isoption(shp, SH_VI) != 0); #if 0 if(out[-1]=='"' || out[-1]=='\'') { rval = -(sh_isoption(shp,SH_VI)!=0); goto done; } #endif comptr->comtyp = COMSCAN; comptr->comarg = ap; ap->argflag = (ARG_MAC | ARG_EXP); ap->argnxt.ap = NULL; ap->argchn.cp = NULL; { char *last = out; Namval_t *np = nv_search("COMP_KEY", shp->var_tree, 0); if (np) STORE_VT(np->nvalue, i16, '\t'); np = nv_search("COMP_TYPE", shp->var_tree, 0); if (np) STORE_VT(np->nvalue, i16, mode == '\\' ? '\t' : '?'); var = mode; begin = out = find_begin(outbuff, last, 0, &var); if (ep->compdict && mode != '?' && (com = prog_complete(ep->compdict, outbuff, out, *cur))) { char **av; for (av = com; *av; av++) { ; // empty loop } narg = av - com; } // Addstar set to zero if * should not be added. if (var == '$') { sfwrite(shp->stk, "${!", 3); sfwrite(shp->stk, out, last - out); sfwrite(shp->stk, "$@}", 2); out = last; } else { addstar = '*'; while (out < last) { char c = *out; if (c == 0) break; if (isexp(c)) addstar = 0; if (c == '/') { if (addstar == 0) strip = 0; dir = out + 1; } sfputc(shp->stk, c); out++; } } if (mode == '?') mode = '*'; if (var != '$' && mode == '\\' && out[-1] != '*') addstar = '*'; if (*begin == '~' && !strchr(begin, '/')) addstar = 0; sfputc(shp->stk, addstar); ap = (struct argnod *)stkfreeze(shp->stk, 1); } if (mode != '*') sh_onoption(shp, SH_MARKDIRS); { char *cp = begin, *left = NULL; int cmd_completion = 0; int size = 'x'; while (cp > outbuff && ((size = cp[-1]) == ' ' || size == '\t')) cp--; if (!var && !strchr(ap->argval, '/') && ((cp == outbuff && shp->nextprompt == 1) || (strchr(";&|(", size) && (cp == outbuff + 1 || size == '(' || cp[-2] != '>') && *begin != '~'))) { cmd_completion = 1; sh_onstate(shp, SH_COMPLETE); } if (ep->e_nlist) { narg = 1; com = av; if (dir) begin += (dir - begin); } else { if (!com) com = sh_argbuild(shp, &narg, comptr, 0); // Special handling for leading quotes. if (begin > outbuff && (begin[-1] == '"' || begin[-1] == '\'')) begin--; } sh_offstate(shp, SH_COMPLETE); // Allow a search to be aborted. if (shp->trapnote & SH_SIGSET) { rval = -1; goto done; } // Match? if (*com == 0 || ((narg <= 1 && (strcmp(ap->argval, *com) == 0)) || (addstar && com[0][strlen(*com) - 1] == '*'))) { rval = -1; goto done; } if (mode == '\\' && out[-1] == '/' && narg > 1) mode = '='; if (mode == '=') { if (strip && !cmd_completion) { char **ptrcom; for (ptrcom = com; *ptrcom; ptrcom++) { // trim directory prefix *ptrcom = path_basename(*ptrcom); } } sfputc(sfstderr, '\n'); sh_menu(shp, sfstderr, narg, com); sfsync(sfstderr); ep->e_nlist = narg; ep->e_clist = com; goto done; } // See if there is enough room. size = *eol - (out - begin); if (mode == '\\') { int c; if (dir) { c = *dir; *dir = 0; } if (dir) *dir = c; // Just expand until name is unique. size += strlen(*com); } else { char **tmpcom = com; size += narg; while (*tmpcom) { cp = fmtx(shp, *tmpcom++); size += strlen(cp); } } // See if room for expansion. if (outbuff + size >= &outbuff[MAXLINE]) { com[0] = ap->argval; com[1] = 0; } // Save remainder of the buffer. if (*out) left = stkcopy(shp->stk, out); if (cmd_completion && mode == '\\') { cp = *com++; out = stpcpy(begin, path_basename(cp)); } else if (mode == '*') { if (ep->e_nlist && dir && var) { if (*cp == var) { cp++; } else { *begin++ = var; } out = stpcpy(begin, cp); var = 0; } else { out = stpcpy(begin, fmtx(shp, *com)); } com++; } else { out = stpcpy(begin, *com++); } if (mode == '\\') { char *saveout = ++out; while (*com && *begin) { if (cmd_completion) { out = overlaid(begin, path_basename(*com++), false); } else { out = overlaid(begin, *com++, false); } } mode = (out == saveout); if (out[-1] == 0) out--; if (mode && out[-1] != '/') { if (cmd_completion) { Namval_t *np; // Add as tracked alias. Pathcomp_t *pp; if (*cp == '/' && (pp = path_dirfind(shp->pathlist, cp, '/')) && (np = nv_search(begin, shp->track_tree, NV_ADD))) { path_alias(np, pp); } out = stpcpy(begin, cp); } // Add quotes if necessary. if ((cp = fmtx(shp, begin)) != begin) out = stpcpy(begin, cp); if (var == '$' && begin[-1] == '{') { *out = '}'; } else { *out = ' '; } *++out = 0; } else if ((cp = fmtx(shp, begin)) != begin) { out = stpcpy(begin, cp); if (out[-1] == '"' || out[-1] == '\'') *--out = 0; } if (*begin == 0 && begin[-1] != ' ') ed_ringbell(); } else { while (*com) { *out++ = ' '; out = stpcpy(out, fmtx(shp, *com++)); } } if (ep->e_nlist) { cp = com[-1]; if (cp[strlen(cp) - 1] != '/') { if (var == '$' && begin[-1] == '{') { *out = '}'; } else { *out = ' '; } out++; } else if (out[-1] == '"' || out[-1] == '\'') { out--; } *out = 0; } *cur = (out - outbuff); // Restore rest of buffer. if (left) out = stpcpy(out, left); *eol = (out - outbuff); } done: sh_offstate(shp, SH_FCOMPLETE); if (!ep->e_nlist) stkset(shp->stk, ep->e_stkptr, ep->e_stkoff); if (nomarkdirs) sh_offoption(shp, SH_MARKDIRS); { // First re-adjust cur. int c, n = 0; c = outbuff[*cur]; outbuff[*cur] = 0; for (out = outbuff; *out; n++) mb1char(&out); outbuff[*cur] = c; *cur = n; outbuff[*eol + 1] = 0; *eol = ed_internal(outbuff, (genchar *)outbuff); } return rval; }
int b_enum(int argc, char **argv, Shbltin_t *context) { bool pflag = false, iflag = false; int i, n; ssize_t sz = -1; Namval_t *np, *tp, *mp; Namarr_t *ap; char *cp; const char *sp; struct Enum *ep; Shell_t *shp = context->shp; struct { Optdisc_t opt; Namval_t *np; } optdisc; if (cmdinit(argc, argv, context, ERROR_NOTIFY)) return -1; while ((n = optget(argv, enum_usage))) { switch (n) { case 'p': { pflag = true; break; } case 'i': { iflag = true; break; } case ':': { errormsg(SH_DICT, 2, "%s", opt_info.arg); break; } case '?': { errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg); __builtin_unreachable(); } default: { break; } } } argv += opt_info.index; argc -= opt_info.index; if (error_info.errors || argc != 1) { error(ERROR_USAGE | 2, "%s", optusage(NULL)); return 1; } while ((cp = *argv++)) { np = nv_open(cp, shp->var_tree, NV_VARNAME | NV_NOADD); if (!np || !(ap = nv_arrayptr(np)) || ap->fun || ap->nelem < 2) { error(ERROR_exit(1), "%s must name an array containing at least two elements", cp); } n = stktell(shp->stk); sfprintf(shp->stk, "%s.%s%c", NV_CLASS, np->nvname, 0); tp = nv_open(stkptr(shp->stk, n), shp->var_tree, NV_VARNAME); if (pflag) { sh_outenum(shp, sfstdout, tp); continue; } stkseek(shp->stk, n); n = ap->nelem; i = 0; nv_onattr(tp, NV_UINT16); nv_putval(tp, (char *)&i, NV_INTEGER); nv_putsub(np, NULL, 0L, ARRAY_SCAN); do { sz += strlen(nv_getval(np)); } while (nv_nextsub(np)); ep = calloc(1, sizeof(struct Enum)); if (!ep) { error(ERROR_system(1), "out of space"); __builtin_unreachable(); } ep->nelem = n; mp = nv_namptr(ep->node, 0); mp->nvshell = shp; nv_setsize(mp, 10); nv_onattr(mp, NV_UINT16); ep->iflag = iflag; ep->values = malloc(n * sizeof(*ep->values)); nv_putsub(np, NULL, 0L, ARRAY_SCAN); i = 0; do { sp = nv_getval(np); ep->values[i++] = strdup(sp); } while (nv_nextsub(np)); assert(n == i); ep->namfun.dsize = sizeof(struct Enum); ep->namfun.disc = &ENUM_disc; ep->namfun.type = tp; nv_onattr(tp, NV_RDONLY); nv_disc(tp, &ep->namfun, DISC_OP_FIRST); memset(&optdisc, 0, sizeof(optdisc)); optdisc.opt.infof = enuminfo; optdisc.np = tp; nv_addtype(tp, enum_type, &optdisc, sizeof(optdisc)); nv_onattr(np, NV_LTOU | NV_UTOL); } nv_open(0, shp->var_tree, 0); return error_info.errors != 0; }
int b_enum(int argc, char** argv, Shbltin_t *context) #endif { bool pflag=false, iflag=false; int i,n; ssize_t sz = -1; Namval_t *np, *tp, *mp; Namarr_t *ap; char *cp,*sp; struct Enum *ep; Shell_t *shp = context->shp; struct { Optdisc_t opt; Namval_t *np; } optdisc; cmdinit(argc, argv, context, ERROR_CATALOG, ERROR_NOTIFY); for (;;) { switch (optget(argv, enum_usage)) { case 'p': pflag = true; continue; case 'i': iflag = true; continue; case '?': error(ERROR_USAGE|4, "%s", opt_info.arg); break; case ':': error(2, "%s", opt_info.arg); break; } break; } argv += opt_info.index; if (error_info.errors) { error(ERROR_USAGE|2, "%s", optusage(NiL)); return 1; } if(!*argv) sh_outenum(shp,sfstdout,(Namval_t*)0); while(cp = *argv++) { if(!(np = nv_open(cp, shp->var_tree, NV_VARNAME|NV_NOADD)) || !(ap=nv_arrayptr(np)) || ap->fun || (sz=ap->nelem) < 2) error(ERROR_exit(1), "%s must name an array containing at least two elements",cp); n = stktell(shp->stk); sfprintf(shp->stk,"%s.%s%c",NV_CLASS,np->nvname,0); tp = nv_open(stkptr(shp->stk,n), shp->var_tree, NV_VARNAME); if(pflag) { sh_outenum(shp,sfstdout,tp); continue; } stkseek(shp->stk,n); n = sz; i = 0; nv_onattr(tp, NV_UINT16); nv_putval(tp, (char*)&i, NV_INTEGER); nv_putsub(np, (char*)0, 0L, ARRAY_SCAN); do { sz += strlen(nv_getval(np)); } while(nv_nextsub(np)); sz += n*sizeof(char*); if(!(ep = newof(0,struct Enum,1,sz))) error(ERROR_system(1), "out of space"); mp = nv_namptr(ep->node,0); mp->nvshell = shp; nv_setsize(mp,10); nv_onattr(mp, NV_UINT16); ep->iflag = iflag; ep->nelem = n; cp = (char*)&ep->values[n+1]; nv_putsub(np, (char*)0, 0L, ARRAY_SCAN); ep->values[n] = 0; i = 0; do { ep->values[i++] = cp; sp = nv_getval(np); n = strlen(sp); memcpy(cp,sp,n+1); cp += n+1; } while(nv_nextsub(np)); ep->hdr.dsize = sizeof(struct Enum)+sz; ep->hdr.disc = &ENUM_disc; ep->hdr.type = tp; nv_onattr(tp, NV_RDONLY); nv_disc(tp, &ep->hdr,NV_FIRST); memset(&optdisc,0,sizeof(optdisc)); optdisc.opt.infof = enuminfo; optdisc.np = tp; nv_addtype(tp, enum_type, &optdisc.opt, sizeof(optdisc)); nv_onattr(np,NV_LTOU|NV_UTOL); } nv_open(0,shp->var_tree,0); return error_info.errors != 0; }
int b_dot_cmd(int n, char *argv[], Shbltin_t *context) { char *script; Namval_t *np; int jmpval; Shell_t *shp = context->shp; struct sh_scoped savst, *prevscope = shp->st.self; int fd; char *filename = NULL; char *buffer = NULL; struct dolnod *saveargfor = NULL; volatile struct dolnod *argsave = NULL; checkpt_t buff; Sfio_t *iop = NULL; short level; Optdisc_t disc; memset(&disc, 0, sizeof(disc)); disc.version = OPT_VERSION; opt_info.disc = &disc; while ((n = optget(argv, sh_optdot))) { switch (n) { case ':': { errormsg(SH_DICT, 2, "%s", opt_info.arg); break; } case '?': { errormsg(SH_DICT, ERROR_usage(0), "%s", opt_info.arg); return 2; } default: { break; } } } argv += opt_info.index; script = *argv; if (error_info.errors || !script) { errormsg(SH_DICT, ERROR_usage(2), "%s", optusage(NULL)); __builtin_unreachable(); } if (shp->dot_depth + 1 > DOTMAX) { errormsg(SH_DICT, ERROR_exit(1), e_toodeep, script); __builtin_unreachable(); } np = shp->posix_fun; if (!np) { // Check for KornShell style function first. np = nv_search(script, shp->fun_tree, 0); if (np && is_afunction(np) && !nv_isattr(np, NV_FPOSIX)) { if (!FETCH_VT(np->nvalue, ip)) { // TODO: Replace this with a comment explaining why the return value of this // path_search() call is ignored. At the time I wrote this (2019-03-16) no unit test // exercises this statement. I added the void cast to silence Coverity Scan 253792. (void)path_search(shp, script, NULL, 0); if (FETCH_VT(np->nvalue, ip)) { if (nv_isattr(np, NV_FPOSIX)) np = NULL; } else { errormsg(SH_DICT, ERROR_exit(1), e_found, script); __builtin_unreachable(); } } } else { np = NULL; } if (!np) { fd = path_open(shp, script, path_get(shp, script)); if (fd < 0) { errormsg(SH_DICT, ERROR_system(1), e_open, script); __builtin_unreachable(); } filename = path_fullname(shp, stkptr(shp->stk, PATH_OFFSET)); } } *prevscope = shp->st; shp->st.lineno = np ? ((struct functnod *)nv_funtree(np))->functline : 1; shp->st.var_local = shp->st.save_tree = shp->var_tree; if (filename) { shp->st.filename = filename; shp->st.lineno = 1; } level = shp->fn_depth + shp->dot_depth + 1; nv_putval(SH_LEVELNOD, (char *)&level, NV_INT16); shp->st.prevst = prevscope; shp->st.self = &savst; shp->topscope = (Shscope_t *)shp->st.self; prevscope->save_tree = shp->var_tree; if (np) { struct Ufunction *rp = FETCH_VT(np->nvalue, rp); shp->st.filename = strdup(rp->fname ? rp->fname : ""); } nv_putval(SH_PATHNAMENOD, shp->st.filename, NV_NOFREE); shp->posix_fun = NULL; if (np || argv[1]) argsave = sh_argnew(shp, argv, &saveargfor); sh_pushcontext(shp, &buff, SH_JMPDOT); jmpval = sigsetjmp(buff.buff, 0); if (jmpval == 0) { shp->dot_depth++; if (np) { sh_exec(shp, (Shnode_t *)(nv_funtree(np)), sh_isstate(shp, SH_ERREXIT)); } else { buffer = malloc(IOBSIZE + 1); iop = sfnew(NULL, buffer, IOBSIZE, fd, SF_READ); sh_offstate(shp, SH_NOFORK); sh_eval(shp, iop, sh_isstate(shp, SH_PROFILE) ? SH_FUNEVAL : 0); } } sh_popcontext(shp, &buff); if (buffer) free(buffer); if (!np) { free(shp->st.filename); shp->st.filename = NULL; } shp->dot_depth--; if ((np || argv[1]) && jmpval != SH_JMPSCRIPT) { sh_argreset(shp, (struct dolnod *)argsave, saveargfor); } else { prevscope->dolc = shp->st.dolc; prevscope->dolv = shp->st.dolv; } if (shp->st.self != &savst) *shp->st.self = shp->st; // Only restore the top Shscope_t portion for posix functions. memcpy(&shp->st, prevscope, sizeof(Shscope_t)); shp->topscope = (Shscope_t *)prevscope; nv_putval(SH_PATHNAMENOD, shp->st.filename, NV_NOFREE); if (jmpval && jmpval != SH_JMPFUN) siglongjmp(shp->jmplist->buff, jmpval); return shp->exitval; }
int path_expand(Shell_t *shp, const char *pattern, struct argnod **arghead) { glob_t gdata; struct argnod *ap; glob_t *gp = &gdata; int flags, extra = 0; #if SHOPT_BASH int off; char *sp, *cp, *cp2; #endif sh_stats(STAT_GLOBS); memset(gp, 0, sizeof(gdata)); flags = GLOB_GROUP | GLOB_AUGMENTED | GLOB_NOCHECK | GLOB_NOSORT | GLOB_STACK | GLOB_LIST | GLOB_DISC; if (sh_isoption(shp, SH_MARKDIRS)) flags |= GLOB_MARK; if (sh_isoption(shp, SH_GLOBSTARS)) flags |= GLOB_STARSTAR; #if SHOPT_BASH #if 0 if(sh_isoption(shp,SH_BASH) && !sh_isoption(shp,SH_EXTGLOB)) flags &= ~GLOB_AUGMENTED; #endif if (sh_isoption(shp, SH_NULLGLOB)) flags &= ~GLOB_NOCHECK; if (sh_isoption(shp, SH_NOCASEGLOB)) flags |= GLOB_ICASE; #endif if (sh_isstate(shp, SH_COMPLETE)) { extra += scantree(shp, shp->alias_tree, pattern, arghead); extra += scantree(shp, shp->fun_tree, pattern, arghead); gp->gl_nextdir = nextdir; flags |= GLOB_COMPLETE; flags &= ~GLOB_NOCHECK; } #if SHOPT_BASH off = stktell(shp->stk); if (off) sp = stkfreeze(shp->stk, 0); if (sh_isoption(shp, SH_BASH)) { // For bash, FIGNORE is a colon separated list of suffixes to ignore // when doing filename/command completion. GLOBIGNORE is similar to ksh // FIGNORE, but colon separated instead of being an augmented shell // pattern. Generate shell patterns out of those here. if (sh_isstate(shp, SH_FCOMPLETE)) { cp = nv_getval(sh_scoped(shp, FIGNORENOD)); } else { static Namval_t *GLOBIGNORENOD; if (!GLOBIGNORENOD) GLOBIGNORENOD = nv_open("GLOBIGNORE", shp->var_tree, 0); cp = nv_getval(sh_scoped(shp, GLOBIGNORENOD)); } if (cp) { flags |= GLOB_AUGMENTED; sfputr(shp->stk, "@(", -1); if (!sh_isstate(shp, SH_FCOMPLETE)) { sfputr(shp->stk, cp, -1); for (cp = stkptr(shp->stk, off); *cp; cp++) { if (*cp == ':') *cp = '|'; } } else { cp2 = strtok(cp, ":"); if (!cp2) cp2 = cp; do { sfputc(shp->stk, '*'); sfputr(shp->stk, cp2, -1); cp2 = strtok(NULL, ":"); if (cp2) { *(cp2 - 1) = ':'; sfputc(shp->stk, '|'); } } while (cp2); } sfputc(shp->stk, ')'); gp->gl_fignore = stkfreeze(shp->stk, 1); } else if (!sh_isstate(shp, SH_FCOMPLETE) && sh_isoption(shp, SH_DOTGLOB)) { gp->gl_fignore = ""; } } else #endif gp->gl_fignore = nv_getval(sh_scoped(shp, FIGNORENOD)); if (suflen) gp->gl_suffix = sufstr; gp->gl_intr = &shp->trapnote; suflen = 0; if (strncmp(pattern, "~(N", 3) == 0) flags &= ~GLOB_NOCHECK; ast_glob(pattern, flags, 0, gp); #if SHOPT_BASH if (off) { stkset(shp->stk, sp, off); } else { stkseek(shp->stk, 0); } #endif sh_sigcheck(shp); for (ap = (struct argnod *)gp->gl_list; ap; ap = ap->argnxt.ap) { ap->argchn.ap = ap->argnxt.ap; if (!ap->argnxt.ap) ap->argchn.ap = *arghead; } if (gp->gl_list) *arghead = (struct argnod *)gp->gl_list; return gp->gl_pathc + extra; }