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); }
void bash_init(int mode) { Shell_t *shp = &sh; Sfio_t *iop; Namval_t *np; int n=0,xtrace,verbose; if(mode>0) goto reinit; if(mode < 0) { /* termination code */ if(sh_isoption(SH_LOGIN_SHELL) && !sh_isoption(SH_POSIX)) sh_source(shp, NiL, sh_mactry(shp,(char*)e_bash_logout)); return; } if(sh_isstate(SH_PREINIT)) { /* pre-init stage */ if(sh_isoption(SH_RESTRICTED)) sh_onoption(SH_RESTRICTED2); sh_onoption(SH_HISTORY2); sh_onoption(SH_INTERACTIVE_COMM); sh_onoption(SH_SOURCEPATH); sh_onoption(SH_HISTAPPEND); sh_onoption(SH_CMDHIST); sh_onoption(SH_LITHIST); sh_onoption(SH_NOEMPTYCMDCOMPL); if(shp->login_sh==2) sh_onoption(SH_LOGIN_SHELL); if(strcmp(astconf("CONFORMANCE",0,0),"standard")==0) sh_onoption(SH_POSIX); if(strcmp(astconf("UNIVERSE",0,0),"att")==0) sh_onoption(SH_XPG_ECHO); else sh_offoption(SH_XPG_ECHO); if(strcmp(astconf("PATH_RESOLVE",0,0),"physical")==0) sh_onoption(SH_PHYSICAL); else sh_offoption(SH_PHYSICAL); /* add builtins */ sh_addbuiltin("shopt", b_shopt, &sh); /* set up some variables needed for --version * needs to go here because --version option is parsed before the init script. */ if(np=nv_open("HOSTTYPE",shp->var_tree,0)) nv_putval(np, BASH_HOSTTYPE, NV_NOFREE); if(np=nv_open("MACHTYPE",shp->var_tree,0)) nv_putval(np, BASH_MACHTYPE, NV_NOFREE); if(np=nv_open("BASH_VERSION",shp->var_tree,0)) nv_putval(np, BASH_VERSION, NV_NOFREE); if(np=nv_open("BASH_VERSINFO",shp->var_tree,0)) { char *argv[7]; argv[0] = BASH_MAJOR; argv[1] = BASH_MINOR; argv[2] = BASH_PATCH; argv[3] = BASH_BUILD; argv[4] = BASH_RELEASE; argv[5] = BASH_MACHTYPE; argv[6] = 0; nv_setvec(np, 0, 6, argv); nv_onattr(np,NV_RDONLY); } return; } /* rest of init stage */ /* restrict BASH_ENV */ if(np=nv_open("BASH_ENV",shp->var_tree,0)) { const Namdisc_t *dp = nv_discfun(NV_DCRESTRICT); Namfun_t *fp = calloc(dp->dsize,1); fp->disc = dp; nv_disc(np, fp, 0); } /* open GLOBIGNORE node */ if(np=nv_open("GLOBIGNORE",shp->var_tree,0)) { const Namdisc_t *dp = &SH_GLOBIGNORE_disc; Namfun_t *fp = calloc(dp->dsize,1); fp->disc = dp; nv_disc(np, fp, 0); } /* set startup files */ n=0; if(sh_isoption(SH_LOGIN_SHELL)) { if(!sh_isoption(SH_POSIX)) { login_files[n++] = (char*)e_bash_profile; login_files[n++] = (char*)e_bash_login; } login_files[n++] = (char*)e_profile; } shp->login_files = login_files; reinit: xtrace = sh_isoption(SH_XTRACE); sh_offoption(SH_XTRACE); verbose = sh_isoption(SH_VERBOSE); sh_offoption(SH_VERBOSE); if(np = nv_open("SHELLOPTS", shp->var_tree, NV_NOADD)) nv_offattr(np,NV_RDONLY); iop = sfopen(NULL, bash_pre_rc, "s"); sh_eval(iop,0); if(xtrace) sh_offoption(SH_XTRACE); if(verbose) sh_offoption(SH_VERBOSE); }
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; }
// // mode = 0: init, called two times // before parsing shell args with SH_PREINIT state turned on // second time after sh_init() is through and with SH_PREINIT state turned off // mode > 1: re-init // mode < 0: shutdown // void bash_init(Shell_t *shp, int mode) { Sfio_t *iop; Namval_t *np; int n = 0, xtrace, verbose; if (mode > 0) goto reinit; if (mode < 0) { // termination code if (sh_isoption(shp, SH_LOGIN_SHELL) && !sh_isoption(shp, SH_POSIX)) { sh_source(shp, NULL, sh_mactry(shp, (char *)e_bash_logout)); } return; } if (sh_isstate(shp, SH_PREINIT)) { // pre-init stage if (sh_isoption(shp, SH_RESTRICTED)) sh_onoption(shp, SH_RESTRICTED2); sh_onoption(shp, SH_HISTORY2); sh_onoption(shp, SH_INTERACTIVE_COMM); sh_onoption(shp, SH_SOURCEPATH); sh_onoption(shp, SH_HISTAPPEND); sh_onoption(shp, SH_CMDHIST); sh_onoption(shp, SH_LITHIST); sh_onoption(shp, SH_NOEMPTYCMDCOMPL); sh_onoption(shp, SH_POSIX); if (shp->login_sh == 2) sh_onoption(shp, SH_LOGIN_SHELL); if (strcmp(astconf("UNIVERSE", 0, 0), "att") == 0) { sh_onoption(shp, SH_XPG_ECHO); } else { sh_offoption(shp, SH_XPG_ECHO); } sh_offoption(shp, SH_PHYSICAL); // Add builtins. sh_addbuiltin(shp, "shopt", b_shopt, &sh); sh_addbuiltin(shp, "enable", b_builtin, &sh); // Set up some variables needed for --version. // Needs to go here because --version option is parsed before the init script. #if 0 /* This was causing a core dump when running set to display all variables */ if(np=nv_open("HOSTTYPE",shp->var_tree,0)) nv_putval(np, BASH_HOSTTYPE, NV_NOFREE); #endif np = nv_open("MACHTYPE", shp->var_tree, 0); if (np) nv_putval(np, BASH_MACHTYPE, NV_NOFREE); np = nv_open("BASH_VERSION", shp->var_tree, 0); if (np) nv_putval(np, BASH_VERSION, NV_NOFREE); np = nv_open("BASH_VERSINFO", shp->var_tree, 0); if (np) { char *argv[7]; argv[0] = BASH_MAJOR; argv[1] = BASH_MINOR; argv[2] = BASH_PATCH; argv[3] = BASH_BUILD; argv[4] = BASH_RELEASE; argv[5] = BASH_MACHTYPE; argv[6] = 0; nv_setvec(np, 0, 6, argv); nv_onattr(np, NV_RDONLY); } return; } // Rest of init stage. // Restrict BASH_ENV. np = nv_open("BASH_ENV", shp->var_tree, 0); if (np) { const Namdisc_t *dp = nv_discfun(DISCFUN_RESTRICT); Namfun_t *fp = calloc(dp->dsize, 1); fp->disc = dp; nv_disc(np, fp, DISC_NOOP); } // Open GLOBIGNORE node. np = nv_open("GLOBIGNORE", shp->var_tree, 0); if (np) { const Namdisc_t *dp = &SH_GLOBIGNORE_disc; Namfun_t *fp = calloc(dp->dsize, 1); fp->disc = dp; nv_disc(np, fp, DISC_NOOP); } np = nv_open("BASH_EXECUTION_STRING", shp->var_tree, 0); if (np) { np->nvalue.cp = shp->comdiv; nv_onattr(np, NV_NOFREE); } // Set startup files. n = 0; if (sh_isoption(shp, SH_LOGIN_SHELL)) { if (!sh_isoption(shp, SH_POSIX)) { shp->gd->login_files[n++] = (char *)e_bash_profile; shp->gd->login_files[n++] = (char *)e_bash_login; } shp->gd->login_files[n++] = (char *)e_profile; } shp->gd->login_files = login_files; reinit: xtrace = sh_isoption(shp, SH_XTRACE); sh_offoption(shp, SH_XTRACE); verbose = sh_isoption(shp, SH_VERBOSE); sh_offoption(shp, SH_VERBOSE); np = nv_open("SHELLOPTS", shp->var_tree, NV_NOADD); if (np) nv_offattr(np, NV_RDONLY); iop = sfopen(NULL, bash_pre_rc, "s"); sh_eval(shp, iop, 0); if (xtrace) sh_offoption(shp, SH_XTRACE); if (verbose) sh_offoption(shp, SH_VERBOSE); }