static struct argnod *r_arg(Shell_t *shp) { register struct argnod *ap=0, *apold, *aptop=0; register long l; Stk_t *stkp=shp->stk; while((l=sfgetu(infile))>0) { ap = (struct argnod*)stkseek(stkp,(unsigned)l+ARGVAL); if(!aptop) aptop = ap; else apold->argnxt.ap = ap; if(--l > 0) { sfread(infile,ap->argval,(size_t)l); ccmaps(ap->argval, l, CC_ASCII, CC_NATIVE); } ap->argval[l] = 0; ap->argchn.cp = 0; ap->argflag = sfgetc(infile); #if 0 if((ap->argflag&ARG_MESSAGE) && *ap->argval) { /* replace international messages */ sh_endword(shp,1); ap->argflag &= ~ARG_MESSAGE; if(!(ap->argflag&(ARG_MAC|ARG_EXP))) ap = sh_endword(shp,0); else { ap = (struct argnod*)stkfreeze(stkp,0); if(ap->argflag==0) ap->argflag = ARG_RAW; } } else #endif ap = (struct argnod*)stkfreeze(stkp,0); if(*ap->argval==0 && (ap->argflag&ARG_EXP)) ap->argchn.ap = (struct argnod*)r_tree(shp); else if(*ap->argval==0 && (ap->argflag&~(ARG_APPEND|ARG_MESSAGE|ARG_QUOTED|ARG_ARRAY))==0) { struct fornod *fp = (struct fornod*)getnode(shp->stk,fornod); fp->fortyp = sfgetu(infile); fp->fortre = r_tree(shp); fp->fornam = ap->argval+1; ap->argchn.ap = (struct argnod*)fp; } apold = ap; } if(ap) ap->argnxt.ap = 0; return(aptop); }
static void* vecseek(Vector_t** p, int index) { Vector_t* v = *p; if (index >= v->max) { while ((v->max += v->inc) <= index); if (!(v = (Vector_t*)stkseek(v->stk, sizeof(Vector_t) + v->max * v->siz))) return 0; *p = v; v->vec = (char*)v + sizeof(Vector_t); } return v->vec + index * v->siz; }
// // Scan tree and add each name that matches the given pattern. // static_fn int scantree(Shell_t *shp, Dt_t *tree, const char *pattern, struct argnod **arghead) { Namval_t *np; struct argnod *ap; int nmatch = 0; char *cp; np = (Namval_t *)dtfirst(tree); for (; np && !nv_isnull(np); (np = (Namval_t *)dtnext(tree, np))) { cp = nv_name(np); if (strmatch(cp, pattern)) { (void)stkseek(shp->stk, ARGVAL); sfputr(shp->stk, cp, -1); ap = (struct argnod *)stkfreeze(shp->stk, 1); ap->argbegin = NULL; ap->argchn.ap = *arghead; ap->argflag = ARG_RAW | ARG_MAKE; *arghead = ap; nmatch++; } } return nmatch; }
static Vector_t* vecopen(int inc, int siz) { Vector_t* v; Stk_t* sp; if (inc <= 0) inc = 16; if (!(sp = stkopen(STK_SMALL|STK_NULL))) return 0; if (!(v = (Vector_t*)stkseek(sp, sizeof(Vector_t) + inc * siz))) { stkclose(sp); return 0; } v->stk = sp; v->vec = (char*)v + sizeof(Vector_t); v->max = v->inc = inc; v->siz = siz; v->cur = 0; return v; }
// // 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; }
struct argnod *sh_argprocsub(Shell_t *shp, struct argnod *argp) { // Argument of the form <(cmd) or >(cmd). struct argnod *ap; int nn, monitor, fd, pv[3]; int subshell = shp->subshell; pid_t pid0; ap = (struct argnod *)stkseek(shp->stk, ARGVAL); ap->argflag |= ARG_MAKE; ap->argflag &= ~ARG_RAW; fd = argp->argflag & ARG_RAW; if (fd == 0 && shp->subshell) sh_subtmpfile(shp); #if has_dev_fd sfwrite(shp->stk, e_devfdNN, 8); pv[2] = 0; sh_pipe(pv); sfputr(shp->stk, fmtbase((long)pv[fd], 10, 0), 0); #else // has_dev_fd pv[0] = -1; shp->fifo = ast_temp_path("ksh.fifo"); if (mkfifo(shp->fifo, S_IRUSR | S_IWUSR)) abort(); sfputr(shp->stk, shp->fifo, 0); #endif // has_dev_fd ap = (struct argnod *)stkfreeze(shp->stk, 0); shp->inpipe = shp->outpipe = NULL; monitor = (sh_isstate(shp, SH_MONITOR) != 0); if (monitor) sh_offstate(shp, SH_MONITOR); shp->subshell = 0; #if has_dev_fd #if USE_SPAWN if (shp->vex || (shp->vex = spawnvex_open(0))) { spawnvex_add(shp->vex, pv[fd], pv[fd], 0, 0); } else #endif // USE_SPAWN fcntl(pv[fd], F_SETFD, 0); shp->fdstatus[pv[fd]] &= ~IOCLEX; #endif // has_dev_fd pid0 = shp->procsub ? *shp->procsub : 0; if (fd) { if (!shp->procsub) { shp->nprocsub = 4; shp->procsub = procsub = calloc(1, shp->nprocsub * sizeof(pid_t)); } else { nn = procsub - shp->procsub; if (nn >= shp->nprocsub) { shp->nprocsub += 3; shp->procsub = realloc(shp->procsub, shp->nprocsub * sizeof(pid_t)); procsub = shp->procsub + nn; } } if (pid0) *shp->procsub = 0; shp->inpipe = pv; sh_exec(shp, (Shnode_t *)argp->argchn.ap, (int)sh_isstate(shp, SH_ERREXIT)); if (pid0) *shp->procsub = pid0; *procsub++ = job.lastpost; } else { shp->outpipe = pv; sh_exec(shp, (Shnode_t *)argp->argchn.ap, (int)sh_isstate(shp, SH_ERREXIT)); } shp->subshell = subshell; if (monitor) sh_onstate(shp, SH_MONITOR); #if has_dev_fd sh_close(pv[1 - fd]); sh_iosave(shp, -pv[fd], shp->topfd, NULL); #else free(shp->fifo); shp->fifo = NULL; #endif // has_dev_fd return ap; }
// // 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 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; }
int path_generate(Shell_t *shp, struct argnod *todo, struct argnod **arghead) { char *cp; int brace; struct argnod *ap; struct argnod *top = NULL; struct argnod *apin; char *pat, *rescan; char *format = NULL; char comma, range = 0; int first, last, incr, count = 0; char end_char; char tmp[32]; if (!sh_isoption(shp, SH_BRACEEXPAND)) return path_expand(shp, todo->argval, arghead); todo->argchn.ap = NULL; again: apin = ap = todo; todo = ap->argchn.ap; cp = ap->argval; range = comma = brace = 0; // First search for {...,...}. while (1) { switch (*cp++) { case '{': { if (brace++ == 0) pat = cp; break; } case '}': { if (--brace > 0) break; if (brace == 0 && comma && *cp != '(') goto endloop1; comma = brace = 0; break; } case '.': { if (brace != 1) break; if (*cp != '.') break; char *endc; incr = 1; if (isdigit(*pat) || *pat == '+' || *pat == '-') { first = strtol(pat, &endc, 0); if (endc == (cp - 1)) { last = strtol(cp + 1, &endc, 0); if (*endc == '.' && endc[1] == '.') { incr = strtol(endc + 2, &endc, 0); } else if (last < first) { incr = -1; } if (incr) { if (*endc == '%') { Sffmt_t fmt; memset(&fmt, 0, sizeof(fmt)); fmt.version = SFIO_VERSION; fmt.form = endc; fmt.extf = checkfmt; sfprintf(sfstdout, "%!", &fmt); if (!(fmt.flags & (SFFMT_LLONG | SFFMT_LDOUBLE))) { switch (fmt.fmt) { case 'c': case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': { format = endc; endc = fmt.form; break; } default: { break; } } } } else { format = "%d"; } if (*endc == '}') { cp = endc + 1; range = 2; goto endloop1; } } } } else if ((cp[2] == '}' || (cp[2] == '.' && cp[3] == '.')) && ((*pat >= 'a' && *pat <= 'z' && cp[1] >= 'a' && cp[1] <= 'z') || (*pat >= 'A' && *pat <= 'Z' && cp[1] >= 'A' && cp[1] <= 'Z'))) { first = *pat; last = cp[1]; cp += 2; if (*cp == '.') { incr = strtol(cp + 2, &endc, 0); cp = endc; } else if (first > last) { incr = -1; } if (incr && *cp == '}') { cp++; range = 1; goto endloop1; } } cp++; break; } case ',': { if (brace == 1) comma = 1; break; } case '\\': { cp++; break; } case 0: { // insert on stack ap->argchn.ap = top; top = ap; if (todo) goto again; for (; ap; ap = apin) { apin = ap->argchn.ap; if (!sh_isoption(shp, SH_NOGLOB)) { brace = path_expand(shp, ap->argval, arghead); } else { ap->argchn.ap = *arghead; *arghead = ap; brace = 1; } if (brace) { count += brace; (*arghead)->argflag |= ARG_MAKE; } } return count; } default: { break; } } } endloop1: rescan = cp; cp = pat - 1; *cp = 0; while (1) { brace = 0; if (range) { if (range == 1) { pat[0] = first; cp = &pat[1]; } else { *(rescan - 1) = 0; pat = tmp; assert(format); sfsprintf(pat, sizeof(tmp), format, first); *(rescan - 1) = '}'; cp = &end_char; *cp = 0; } if (incr * (first + incr) > last * incr) { *cp = '}'; } else { first += incr; } } else { // generate each pattern and put on the todo list while (1) { switch (*++cp) { case '\\': { cp++; break; } case '{': { brace++; break; } case ',': { if (brace == 0) goto endloop2; break; } case '}': { if (--brace < 0) goto endloop2; } default: { break; } } } } endloop2: brace = *cp; *cp = 0; sh_sigcheck(shp); ap = (struct argnod *)stkseek(shp->stk, ARGVAL); ap->argflag = ARG_RAW; ap->argchn.ap = todo; sfputr(shp->stk, apin->argval, -1); sfputr(shp->stk, pat, -1); sfputr(shp->stk, rescan, -1); todo = ap = (struct argnod *)stkfreeze(shp->stk, 1); if (brace == '}') break; if (!range) pat = cp + 1; } goto again; }