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 char *walk_class(register Namval_t *np, int dlete, struct dcclass *dcp) { static Sfio_t *out; Sfio_t *outfile; int savtop = stktell(stkstd); char *savptr = stkfreeze(stkstd,0); if(dlete) outfile = 0; else if(!(outfile=out)) outfile = out = sfnew((Sfio_t*)0,(char*)0,-1,-1,SF_WRITE|SF_STRING); else sfseek(outfile,0L,SEEK_SET); genvalue(outfile,&dcp->sclass,0,np); stkset(stkstd,savptr,savtop); if(!outfile) return((char*)0); sfputc(out,0); return((char*)out->_data); }
// // 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; }
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; }
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 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; }