static_fn Namval_t *create_enum(Namval_t *np, const void *vp, nvflag_t flags, Namfun_t *fp) { UNUSED(flags); const char *name = vp; struct Enum *ep = (struct Enum *)fp; Namval_t *mp; const char *v; int i, n; mp = nv_namptr(ep->node, 0); mp->nvenv = np; for (i = 0; i < ep->nelem; i++) { v = ep->values[i]; if (ep->iflag) { n = strcasecmp(v, name); } else { n = strcmp(v, name); } if (n == 0) { STORE_VT(mp->nvalue, i16, i); mp->nvname = (char *)v; fp->last = (char *)(name + strlen(name)); return mp; } } error(ERROR_exit(1), "%s: invalid enum constant for %s", name, nv_name(np)); return mp; }
static_fn void put_enum(Namval_t *np, const void *val, nvflag_t flags, Namfun_t *fp) { struct Enum *ep = (struct Enum *)fp; const char *v; int n; if (!val && !(flags & NV_INTEGER)) { nv_putv(np, val, flags, fp); nv_disc(np, &ep->namfun, DISC_OP_POP); if (!ep->namfun.nofree) free_enum(ep); return; } if (flags & NV_INTEGER) { nv_putv(np, val, flags, fp); return; } for (int i = 0; i < ep->nelem; i++) { v = ep->values[i]; if (ep->iflag) { n = strcasecmp(v, val); } else { n = strcmp(v, val); } if (n == 0) { // TODO: Figure out if a static var is correct. The code used to store a pointer to the // stack local var `i` which is obviously wrong and only works by accident if the // pointer is used before the stack location is overwritten. static uint16_t x; x = i; nv_putv(np, (char *)&x, NV_UINT16, fp); return; } } if (nv_isattr(np, NV_NOFREE)) error(ERROR_exit(1), "%s: invalid value %s", nv_name(np), val); }
static void put_enum(Namval_t* np,const char *val,int flags,Namfun_t *fp) { struct Enum *ep = (struct Enum*)fp; register const char *v; unsigned short i=0, n; if(!val && !(flags&NV_INTEGER)) { nv_putv(np, val, flags,fp); nv_disc(np,&ep->hdr,NV_POP); if(!ep->hdr.nofree) free((void*)ep); return; } if(flags&NV_INTEGER) { nv_putv(np,val,flags,fp); return; } while(v=ep->values[i]) { if(ep->iflag) n = strcasecmp(v,val); else n = strcmp(v,val); if(n==0) { nv_putv(np, (char*)&i, NV_UINT16, fp); return; } i++; } if(nv_isattr(np,NV_NOFREE)) error(ERROR_exit(1), "%s: invalid value %s",nv_name(np),val); }
static Namval_t *make_mode(Namval_t* np) { char *name = nv_name(np); Namfun_t *nfp = newof(NULL,Namfun_t,1,0); if(!nfp) return((Namval_t*)0); nfp->disc = &modedisc; nv_stack(np,nfp); return(np); }
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 int read_tree(Namval_t* np, Sfio_t *iop, int n, Namfun_t *dp) { Sfio_t *sp; char *cp; int c; if(n>=0) return(-1); while((c = sfgetc(iop)) && isblank(c)); sfungetc(iop,c); sfprintf(sh.strbuf,"%s=%c",nv_name(np),0); cp = sfstruse(sh.strbuf); sp = sfopen((Sfio_t*)0,cp,"s"); sfstack(iop,sp); c=sh_eval(iop,SH_READEVAL); return(c); }
// // 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 Namval_t* create_enum(Namval_t *np, const char *name, int flags, Namfun_t *fp) { struct Enum *ep = (struct Enum*)fp; Namval_t *mp; const char *v; int i,n; mp = nv_namptr(ep->node,0); mp->nvenv = (char*)np; for(i=0;v=ep->values[i];i++) { if(ep->iflag) n = strcasecmp(v,name); else n = strcmp(v,name); if(n==0) { mp->nvalue.s = i; mp->nvname = (char*)v; fp->last = (char*)(name+strlen(name)); return(mp); } } if(strcmp(name,"MAX")==0 || strcmp(name,"MIN")==0 || strcmp(name,"DIG")==0) { if(name[2]=='X') i--; else if(name[2]=='G') i = i<100?(i<10?1:2):(i<1000?3:4); else i = 0; mp->nvalue.s = i; mp->nvname = (char*)name; fp->last = (char*)(name+strlen(name)); return(mp); } error(ERROR_exit(1), "%s: invalid enum constant for %s",name,nv_name(np)); return(mp); }
// This routine turns options on and off. // The options "PDicr" are illegal from set command. // The -o option is used to set option by name. // This routine returns the number of non-option arguments. int sh_argopts(int argc, char *argv[], void *context) { Shell_t *shp = context; int n, o; Arg_t *ap = shp->arg_context; Lex_t *lp = shp->lex_context; Shopt_t newflags; int setflag = 0, action = 0, trace = (int)sh_isoption(shp, SH_XTRACE); Namval_t *np = NULL; const char *sp; char *keylist = NULL; int verbose, f, unsetnp = 0; Optdisc_t disc; newflags = shp->options; memset(&disc, 0, sizeof(disc)); disc.version = OPT_VERSION; disc.infof = infof; opt_info.disc = &disc; if (argc > 0) { setflag = 4; } else { argc = -argc; } while ((n = optget(argv, setflag ? sh_optset : sh_optksh))) { o = 0; f = *opt_info.option == '-' && (opt_info.num || opt_info.arg); switch (n) { case 'A': { np = nv_open(opt_info.arg, shp->var_tree, NV_ARRAY | NV_VARNAME); if (f) unsetnp = 1; continue; } case 'K': { keylist = opt_info.arg; continue; } #if SHOPT_BASH case 'O': { // shopt options, only in bash mode if (!sh_isoption(shp, SH_BASH)) { errormsg(SH_DICT, ERROR_exit(1), e_option, opt_info.name); __builtin_unreachable(); } } #endif // FALLTHRU case 'o': { // set options byname: if (!opt_info.arg || !*opt_info.arg || *opt_info.arg == '-') { action = PRINT; // print style: -O => shopt options. // bash => print unset options also, no heading. verbose = (f ? PRINT_VERBOSE : PRINT_NO_HEADER) | (n == 'O' ? PRINT_SHOPT : 0) | (sh_isoption(shp, SH_BASH) ? PRINT_ALL | PRINT_NO_HEADER : 0) | ((opt_info.arg && (!*opt_info.arg || *opt_info.arg == '-')) ? (PRINT_TABLE | PRINT_NO_HEADER) : 0); continue; } o = sh_lookopt(opt_info.arg, &f); if (o <= 0 || (!sh_isoption(shp, SH_BASH) && (o & SH_BASHEXTRA)) || ((!sh_isoption(shp, SH_BASH) || n == 'o') && (o & SH_BASHOPT)) || (setflag && (o & SH_COMMANDLINE))) { errormsg(SH_DICT, 2, e_option, opt_info.arg); error_info.errors++; } o &= 0xff; if (sh_isoption(shp, SH_RESTRICTED) && !f && o == SH_RESTRICTED) { errormsg(SH_DICT, ERROR_exit(1), e_restricted, opt_info.arg); __builtin_unreachable(); } break; } #if SHOPT_BASH case -1: { // --rcfile shp->gd->rcfile = opt_info.arg; continue; } case -2: { // --noediting if (!f) { off_option(&newflags, SH_VI); off_option(&newflags, SH_EMACS); off_option(&newflags, SH_GMACS); } continue; } case -3: { // --profile n = 'l'; sp = strchr(optksh, n); if (sp) o = flagval[sp - optksh]; break; } case -4: { // --posix // Mask lower 8 bits to find char in optksh string. n &= 0xff; sp = strchr(optksh, n); if (sp) o = flagval[sp - optksh]; break; } case -5: { // --version sfputr(sfstdout, "ksh bash emulation, version ", -1); np = nv_open("BASH_VERSION", shp->var_tree, 0); sfputr(sfstdout, nv_getval(np), -1); np = nv_open("MACHTYPE", shp->var_tree, 0); sfprintf(sfstdout, " (%s)\n", nv_getval(np)); sh_exit(shp, 0); } #endif case -6: { // --default const Shtable_t *tp; for (tp = shtab_options; (o = tp->sh_number); tp++) { if (!(o & SH_COMMANDLINE) && is_option(&newflags, o & 0xff)) { off_option(&newflags, o & 0xff); } } continue; } case -7: { f = 0; goto byname; } case 'D': { on_option(&newflags, SH_NOEXEC); // Cppcheck doesn't recognize the "goto" in the preceding case and thus thinks we // might fall through and call strchr() with n == -7. Even though this it // technically a bug in cppcheck it is one reason why `goto` shouldn't be used; at // least inside `switch` blocks. // cppcheck-suppress invalidFunctionArg sp = strchr(optksh, n); if (sp) o = flagval[sp - optksh]; break; } case 'T': { if (opt_info.num) { shp->test |= opt_info.num; } else { shp->test = 0; } continue; } case 's': { if (setflag) { action = SORT; continue; } sp = strchr(optksh, n); if (sp) o = flagval[sp - optksh]; break; } case 'R': { if (setflag) { n = ':'; } else { ap->kiafile = opt_info.arg; n = 'n'; } sp = strchr(optksh, n); if (sp) o = flagval[sp - optksh]; break; } case ':': { if (opt_info.name[0] == '-' && opt_info.name[1] == '-') { opt_info.arg = argv[opt_info.index - 1] + 2; f = 1; goto byname; } errormsg(SH_DICT, 2, "%s", opt_info.arg); continue; } case '?': { errormsg(SH_DICT, ERROR_usage(0), "%s", opt_info.arg); return -1; } default: { sp = strchr(optksh, n); if (sp) o = flagval[sp - optksh]; break; } } if (f) { if (o == SH_VI || o == SH_EMACS || o == SH_GMACS) { off_option(&newflags, SH_VI); off_option(&newflags, SH_EMACS); off_option(&newflags, SH_GMACS); } on_option(&newflags, o); off_option(&shp->offoptions, o); } else { if (o == SH_RESTRICTED && sh_isoption(shp, SH_RESTRICTED)) { errormsg(SH_DICT, ERROR_exit(1), e_restricted, "r"); __builtin_unreachable(); } if (o == SH_XTRACE) trace = 0; off_option(&newflags, o); if (setflag == 0) on_option(&shp->offoptions, o); } } if (error_info.errors) { errormsg(SH_DICT, ERROR_usage(2), "%s", optusage(NULL)); __builtin_unreachable(); } // Check for '-' or '+' argument. sp = argv[opt_info.index]; if (sp && sp[1] == 0 && (*sp == '+' || *sp == '-') && strcmp(argv[opt_info.index - 1], "--")) { opt_info.index++; off_option(&newflags, SH_XTRACE); off_option(&newflags, SH_VERBOSE); trace = 0; } if (trace) sh_trace(shp, argv, 1); argc -= opt_info.index; argv += opt_info.index; if (action == PRINT) sh_printopts(shp, newflags, verbose, 0); if (setflag) { if (action == SORT) { int (*sortfn)(const char *, const char *) = strcoll; Namarr_t *arp; struct Value *args; unsigned char *bits; if (argc > 0) { strsort(argv, argc, sortfn); } else if (np && (arp = nv_arrayptr(np)) && (args = nv_aivec(np, &bits))) { char *cp; int i, c, keys = 0; if (keylist) { for (cp = keylist; (c = *cp); cp++) { if (c == ',') keys++; } keys++; } else { keylist = ""; } arp->nelem = nv_aipack(arp); cp = nv_name(np); c = strlen(cp); // This used to multiply by `(keys - 1)` but `keys` can be zero which means the // nodesize can be less than `sizeof(struct Node)` which is obviously wrong. // Whether multiplying by `keys` is correct is unclear. // See issue #824. size_t nodesize = sizeof(struct Node) + keys * sizeof(Namval_t *); struct Sort *sp = malloc(sizeof(struct Sort) + strlen(keylist) + (sizeof(char *) + 1) * keys + (arp->nelem + 1) * (nodesize + sizeof(void *)) + c + 3); sp->shp = shp; sp->np = np; if (!(sp->root = shp->last_root)) sp->root = shp->var_tree; sp->vp = args; sp->cur = 0; sp->nodes = (struct Node *)&sp->keys[keys + 2]; memset(sp->nodes, 0, arp->nelem * nodesize); sp->nptrs = (struct Node **)((char *)sp->nodes + arp->nelem * nodesize); sp->flags = (char *)&sp->nptrs[arp->nelem + 1]; memset(sp->flags, 0, keys + 1); sp->name = sp->flags + keys + 1; memcpy(sp->name, cp, c + 1); sp->keys[0] = sp->name + c + 1; strcpy(sp->keys[0], keylist); cp = (char *)sp->nodes; for (c = 0; c < arp->nelem; c++) { if (*keylist && *keylist != ':') { struct Namval *np = FETCH_VT(args[c], np); ((struct Node *)cp)->index = strtol(np->nvname, NULL, 10); ((struct Node *)cp)->bits = bits[c]; } else { ((struct Node *)cp)->index = c; } ((struct Node *)cp)->vp = args[c]; sp->nptrs[c] = (struct Node *)cp; cp += nodesize; } if (!(cp = sp->keys[0])) cp = keylist; for (keys = 0; (c = *cp); cp++) { if (c == ',') { *cp++ = 0; sp->keys[++keys] = cp; sp->flags[keys] = 0; } else if (c == ':') { again: *cp++ = 0; c = *cp; if (c == 'r') { sp->flags[keys] |= SORT_reverse; c = cp[1]; } else if (c == 'n') { sp->flags[keys] |= SORT_numeric; c = cp[1]; } if (c == 'n' || c == 'r') goto again; } } sp->keys[++keys] = 0; Sp = sp; if (sp->keys[0] && *sp->keys[0]) { sortfn = arraysort; } else if (sp->flags[0] & SORT_numeric) { sortfn = numsort; } else { sortfn = alphasort; } strsort((char **)sp->nptrs, arp->nelem, sortfn); cp = (char *)sp->nodes; for (c = 0; c < arp->nelem; c++) { i = (char *)sp->nptrs[c] - (char *)&sp->nodes[0]; if (i / nodesize != c) { args[c] = ((struct Node *)(cp + i))->vp; bits[c] = ((struct Node *)(cp + i))->bits; } } free(sp); nv_close(np); np = NULL; } else { strsort(shp->st.dolv + 1, shp->st.dolc, sortfn); } } if (np) { if (unsetnp) nv_unset(np); nv_setvec(np, 0, argc, argv); nv_close(np); } else if (argc > 0 || ((sp = argv[-1]) && strcmp(sp, "--") == 0)) { sh_argset(ap, argv - 1); } } else if (is_option(&newflags, SH_CFLAG)) { if (!(shp->comdiv = *argv++)) { errormsg(SH_DICT, 2, e_cneedsarg); errormsg(SH_DICT, ERROR_usage(2), optusage(NULL)); __builtin_unreachable(); } argc--; } // Handling SH_INTERACTIVE and SH_PRIVILEGED has been moved to // sh_applyopts(), so that the code can be reused from b_shopt(), too. sh_applyopts(shp, newflags); if (!ap->kiafile) return argc; if (!argv[0]) { errormsg(SH_DICT, ERROR_usage(2), "-R requires scriptname"); __builtin_unreachable(); } if (!(lp->kiafile = sfopen(NULL, ap->kiafile, "w+"))) { errormsg(SH_DICT, ERROR_system(3), e_create, ap->kiafile); __builtin_unreachable(); } if (!(lp->kiatmp = sftmp(2 * SF_BUFSIZE))) { errormsg(SH_DICT, ERROR_system(3), e_tmpcreate); __builtin_unreachable(); } sfputr(lp->kiafile, ";vdb;CIAO/ksh", '\n'); lp->kiabegin = sftell(lp->kiafile); lp->entity_tree = dtopen(&_Nvdisc, Dtbag); lp->scriptname = strdup(sh_fmtq(argv[0])); lp->script = kiaentity(lp, lp->scriptname, -1, 'p', -1, 0, 0, 's', 0, ""); lp->fscript = kiaentity(lp, lp->scriptname, -1, 'f', -1, 0, 0, 's', 0, ""); lp->unknown = kiaentity(lp, "<unknown>", -1, 'p', -1, 0, 0, '0', 0, ""); kiaentity(lp, "<unknown>", -1, 'p', 0, 0, lp->unknown, '0', 0, ""); lp->current = lp->script; ap->kiafile = NULL; return argc; }
int main(int argc, char *argv[]) { Sfio_t *in, *out; Shell_t *shp; Namval_t *np; Shnode_t *t; char *cp; int n, nflag=0, vflag=0, dflag=0; error_info.id = argv[0]; while(n = optget(argv, usage )) switch(n) { case 'D': dflag=1; break; case 'v': vflag=1; break; case 'n': nflag=1; break; case ':': errormsg(SH_DICT,2,"%s",opt_info.arg); break; case '?': errormsg(SH_DICT,ERROR_usage(2),"%s",opt_info.arg); break; } shp = sh_init(argc,argv,(Shinit_f)0); shp->shcomp = 1; argv += opt_info.index; argc -= opt_info.index; if(error_info.errors || argc>2) errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0)); if(cp= *argv) { argv++; in = sh_pathopen(cp); } else in = sfstdin; if(cp= *argv) { struct stat statb; if(!(out = sfopen((Sfio_t*)0,cp,"w"))) errormsg(SH_DICT,ERROR_system(1),"%s: cannot create",cp); if(fstat(sffileno(out),&statb) >=0) chmod(cp,(statb.st_mode&~S_IFMT)|S_IXUSR|S_IXGRP|S_IXOTH); } else out = sfstdout; if(dflag) { sh_onoption(SH_DICTIONARY); sh_onoption(SH_NOEXEC); } if(nflag) sh_onoption(SH_NOEXEC); if(vflag) sh_onoption(SH_VERBOSE); if(!dflag) sfwrite(out,header,sizeof(header)); shp->inlineno = 1; #if SHOPT_BRACEPAT sh_onoption(SH_BRACEEXPAND); #endif while(1) { stakset((char*)0,0); if(t = (Shnode_t*)sh_parse(shp,in,0)) { if((t->tre.tretyp&(COMMSK|COMSCAN))==0 && t->com.comnamp && strcmp(nv_name((Namval_t*)t->com.comnamp),"alias")==0) sh_exec(t,0); if(!dflag && sh_tdump(out,t) < 0) errormsg(SH_DICT,ERROR_exit(1),"dump failed"); } else if(sfeof(in)) break; if(sferror(in)) errormsg(SH_DICT,ERROR_system(1),"I/O error"); if(t && ((t->tre.tretyp&COMMSK)==TCOM) && (np=t->com.comnamp) && (cp=nv_name(np))) { if(strcmp(cp,"exit")==0) break; /* check for exec of a command */ if(strcmp(cp,"exec")==0) { if(t->com.comtyp&COMSCAN) { if(t->com.comarg->argnxt.ap) break; } else { struct dolnod *ap = (struct dolnod*)t->com.comarg; if(ap->dolnum>1) break; } } } } /* copy any remaining input */ sfmove(in,out,SF_UNBOUND,-1); if(in!=sfstdin) sfclose(in); if(out!=sfstdout) sfclose(out); return(0); }
void *nv_diropen(Namval_t *np,const char *name) { char *next,*last; int c,len=strlen(name); struct nvdir *save, *dp = new_of(struct nvdir,len+1); Namval_t *nq=0,fake; Namfun_t *nfp=0; if(!dp) return(0); memset((void*)dp, 0, sizeof(*dp)); dp->data = (char*)(dp+1); if(name[len-1]=='*' || name[len-1]=='@') len -= 1; name = memcpy(dp->data,name,len); dp->data[len] = 0; dp->len = len; dp->root = sh.last_root?sh.last_root:sh.var_tree; #if 1 while(1) { dp->table = sh.last_table; sh.last_table = 0; if(*(last=(char*)name)==0) break; if(!(next=nextdot(last))) break; *next = 0; np = nv_open(name, dp->root, NV_NOFAIL); *next = '.'; if(!np || !nv_istable(np)) break; dp->root = nv_dict(np); name = next+1; } #else dp->table = sh.last_table; sh.last_table = 0; last = dp->data; #endif if(*name) { fake.nvname = (char*)name; if(dp->hp = (Namval_t*)dtprev(dp->root,&fake)) { char *cp = nv_name(dp->hp); c = strlen(cp); if(memcmp(name,cp,c) || name[c]!='[') dp->hp = (Namval_t*)dtnext(dp->root,dp->hp); else { np = dp->hp; last = 0; } } else dp->hp = (Namval_t*)dtfirst(dp->root); } else dp->hp = (Namval_t*)dtfirst(dp->root); while(1) { if(!last) next = 0; else if(next= nextdot(last)) { c = *next; *next = 0; } if(!np) { if(nfp && nfp->disc && nfp->disc->createf) { np = (*nfp->disc->createf)(nq,last,0,nfp); if(*nfp->last == '[') { nv_endsubscript(np,nfp->last,NV_NOADD); if(nq = nv_opensub(np)) np = nq; } } else np = nv_search(last,dp->root,0); } if(next) *next = c; if(np==dp->hp && !next) dp->hp = (Namval_t*)dtnext(dp->root,dp->hp); if(np && ((nfp=nextdisc(np)) || nv_istable(np))) { if(!(save = new_of(struct nvdir,0))) return(0); *save = *dp; dp->prev = save; if(nv_istable(np)) dp->root = nv_dict(np); else dp->root = (Dt_t*)np; if(nfp) { dp->nextnode = nfp->disc->nextf; dp->table = np; dp->otable = sh.last_table; dp->fun = nfp; dp->hp = (*dp->nextnode)(np,(Dt_t*)0,nfp); } else dp->nextnode = 0; } else break; if(!next || next[1]==0) break; last = next+1; nq = np; np = 0; }
/* * This routine turns options on and off * The options "PDicr" are illegal from set command. * The -o option is used to set option by name * This routine returns the number of non-option arguments */ int sh_argopts(int argc,register char *argv[], void *context) { Shell_t *shp = (Shell_t*)context; register int n,o; register Arg_t *ap = (Arg_t*)(shp->arg_context); Lex_t *lp = (Lex_t*)(shp->lex_context); Shopt_t newflags; int setflag=0, action=0, trace=(int)sh_isoption(shp,SH_XTRACE); Namval_t *np = NIL(Namval_t*); const char *sp; char *keylist=0; int verbose,f,unsetnp=0; Optdisc_t disc; newflags=shp->options; memset(&disc, 0, sizeof(disc)); disc.version = OPT_VERSION; disc.infof = infof; opt_info.disc = &disc; if(argc>0) setflag = 4; else argc = -argc; while((n = optget(argv,setflag?sh_optset:sh_optksh))) { o=0; f=*opt_info.option=='-' && (opt_info.num || opt_info.arg); switch(n) { case 'A': np = nv_open(opt_info.arg,shp->var_tree,NV_NOASSIGN|NV_ARRAY|NV_VARNAME); if(f) unsetnp=1; continue; case 'K': keylist = opt_info.arg; continue; #if SHOPT_BASH case 'O': /* shopt options, only in bash mode */ if(!sh_isoption(shp,SH_BASH)) errormsg(SH_DICT,ERROR_exit(1), e_option, opt_info.name); #endif case 'o': /* set options */ byname: if(!opt_info.arg||!*opt_info.arg||*opt_info.arg=='-') { action = PRINT; /* print style: -O => shopt options * bash => print unset options also, no heading */ verbose = (f?PRINT_VERBOSE:PRINT_NO_HEADER)| (n=='O'?PRINT_SHOPT:0)| (sh_isoption(shp,SH_BASH)?PRINT_ALL|PRINT_NO_HEADER:0)| ((opt_info.arg&&(!*opt_info.arg||*opt_info.arg=='-'))?(PRINT_TABLE|PRINT_NO_HEADER):0); continue; } o = sh_lookopt(opt_info.arg,&f); if(o<=0 || (!sh_isoption(shp,SH_BASH) && (o&SH_BASHEXTRA)) || ((!sh_isoption(shp,SH_BASH) || n=='o') && (o&SH_BASHOPT)) || (setflag && (o&SH_COMMANDLINE))) { errormsg(SH_DICT,2, e_option, opt_info.arg); error_info.errors++; } o &= 0xff; if(sh_isoption(shp,SH_RESTRICTED) && !f && o==SH_RESTRICTED) errormsg(SH_DICT,ERROR_exit(1), e_restricted, opt_info.arg); break; #if SHOPT_BASH case -1: /* --rcfile */ shp->gd->rcfile = opt_info.arg; continue; case -2: /* --noediting */ if (!f) { off_option(&newflags,SH_VI); off_option(&newflags,SH_EMACS); off_option(&newflags,SH_GMACS); } continue; case -3: /* --profile */ n = 'l'; goto skip; case -4: /* --posix */ /* mask lower 8 bits to find char in optksh string */ n&=0xff; goto skip; case -5: /* --version */ sfputr(sfstdout, "ksh bash emulation, version ",-1); np = nv_open("BASH_VERSION",shp->var_tree,0); sfputr(sfstdout, nv_getval(np),-1); np = nv_open("MACHTYPE",shp->var_tree,0); sfprintf(sfstdout, " (%s)\n", nv_getval(np)); sh_exit(shp,0); #endif case -6: /* --default */ { register const Shtable_t *tp; for(tp=shtab_options; o = tp->sh_number; tp++) if(!(o&SH_COMMANDLINE) && is_option(&newflags,o&0xff)) off_option(&newflags,o&0xff); } continue; case -7: f = 0; goto byname; case 'D': on_option(&newflags,SH_NOEXEC); goto skip; case 'T': if (opt_info.num) shp->test |= opt_info.num; else shp->test = 0; continue; case 's': if(setflag) { action = SORT; continue; } #if SHOPT_KIA goto skip; case 'R': if(setflag) n = ':'; else { ap->kiafile = opt_info.arg; n = 'n'; } /*FALLTHROUGH*/ #endif /* SHOPT_KIA */ #if SHOPT_REGRESS goto skip; case 'I': continue; #endif /* SHOPT_REGRESS */ skip: default: if(sp=strchr(optksh,n)) o = flagval[sp-optksh]; break; case ':': if(opt_info.name[0]=='-'&&opt_info.name[1]=='-') { opt_info.arg = argv[opt_info.index-1] + 2; f = 1; goto byname; } errormsg(SH_DICT,2, "%s", opt_info.arg); continue; case '?': errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg); return(-1); } if(f) { if(o==SH_VI || o==SH_EMACS || o==SH_GMACS) { off_option(&newflags,SH_VI); off_option(&newflags,SH_EMACS); off_option(&newflags,SH_GMACS); } on_option(&newflags,o); off_option(&shp->offoptions,o); } else { if(o==SH_XTRACE) trace = 0; off_option(&newflags,o); if(setflag==0) on_option(&shp->offoptions,o); } } if(error_info.errors) errormsg(SH_DICT,ERROR_usage(2),"%s",optusage(NIL(char*))); /* check for '-' or '+' argument */ if((sp=argv[opt_info.index]) && sp[1]==0 && (*sp=='+' || *sp=='-') && strcmp(argv[opt_info.index-1],"--")) { opt_info.index++; off_option(&newflags,SH_XTRACE); off_option(&newflags,SH_VERBOSE); trace = 0; } if(trace) sh_trace(shp,argv,1); argc -= opt_info.index; argv += opt_info.index; if(action==PRINT) sh_printopts(shp,newflags,verbose,0); if(setflag) { if(action==SORT) { int (*sortfn)(const char*,const char*) = strcoll; Namarr_t *arp; union Value *args; unsigned char *bits; if(argc>0) strsort(argv,argc,sortfn); else if(np && (arp=nv_arrayptr(np)) && (args = nv_aivec(np,&bits))) { struct Sort *sp; char *cp; int i, c, keys=0; size_t nodesize; if(keylist) { for(cp=keylist;c= *cp; cp++) { if(c==',') keys++; } keys++; } else keylist = Empty; arp->nelem = nv_aipack(arp);; cp = nv_name(np); c = strlen(cp); nodesize = sizeof(struct Node)+(keys-1)*sizeof(Namval_t*); sp = (struct Sort*)malloc(sizeof(struct Sort)+strlen(keylist)+(sizeof(char*)+1)*keys+(arp->nelem+1)*(nodesize+sizeof(void*))+c+3); sp->shp = shp; sp->np = np; if(!(sp->root = shp->last_root)) sp->root = shp->var_tree; sp->vp = args; sp->cur = 0; sp->nodes = (struct Node*)&sp->keys[keys+2]; memset(sp->nodes, 0, arp->nelem*nodesize); sp->nptrs = (struct Node**)((char*)sp->nodes+arp->nelem*nodesize); sp->flags = (char*)&sp->nptrs[arp->nelem+1]; memset(sp->flags,0,keys+1); sp->name = sp->flags + keys+1; memcpy(sp->name,cp,c+1); sp->keys[0] = sp->name+c+1; strcpy(sp->keys[0],keylist); cp = (char*)sp->nodes; for(c=0; c < arp->nelem; c++) { if(keylist!=Empty && *keylist!=':') { ((struct Node*)cp)->index = strtol(args[c].np->nvname,NULL,10); ((struct Node*)cp)->bits = bits[c]; } else ((struct Node*)cp)->index = c; ((struct Node*)cp)->vp = args[c]; sp->nptrs[c] = (struct Node*)cp; cp += nodesize; } if(!(cp = sp->keys[0])) cp = keylist; for(keys=0;c= *cp; cp++) { if(c==',') { *cp++ = 0; sp->keys[++keys] = cp; sp->flags[keys] = 0; } else if(c==':') { again: *cp++ = 0; if((c= *cp) == 'r') { sp->flags[keys] |= SORT_reverse; c = cp[1]; } else if(c=='n') { sp->flags[keys] |= SORT_numeric; c = cp[1]; } if(c=='n' || c=='r') goto again; } } sp->keys[++keys] = 0; Sp = sp; if(sp->keys[0] && *sp->keys[0]) sortfn = arraysort; else if(sp->flags[0]&SORT_numeric) sortfn = numsort; else sortfn = alphasort; strsort((char**)sp->nptrs,arp->nelem,sortfn); cp = (char*)sp->nodes; for(c=0; c < arp->nelem; c++) { i = (char*)sp->nptrs[c]-(char*)&sp->nodes[0]; if(i/nodesize !=c) { args[c] = ((struct Node*)(cp+i))->vp; bits[c] = ((struct Node*)(cp+i))->bits; } } free(sp); nv_close(np); np = 0; } else strsort(shp->st.dolv+1,shp->st.dolc,sortfn); } if(np) { if(unsetnp) nv_unset(np); nv_setvec(np,0,argc,argv); nv_close(np); } else if(argc>0 || ((sp=argv[-1]) && strcmp(sp,"--")==0)) sh_argset(ap,argv-1); } else if(is_option(&newflags,SH_CFLAG)) { if(!(shp->comdiv = *argv++)) { errormsg(SH_DICT,2,e_cneedsarg); errormsg(SH_DICT,ERROR_usage(2),optusage(NIL(char*))); } argc--; }