/*********************************************************************** * * * This software is part of the ast package * * Copyright (c) 1982-2012 AT&T Intellectual Property * * and is licensed under the * * Eclipse Public License, Version 1.0 * * by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.eclipse.org/org/documents/epl-v10.html * * (with md5 checksum b35adb5213ca9657e911e9befb180842) * * * * Information and Software Systems Research * * AT&T Research * * Florham Park NJ * * * * David Korn * * * ***********************************************************************/ #pragma prototyped /* * export [-p] [arg...] * readonly [-p] [arg...] * typeset [options] [arg...] * alias [-ptx] [arg...] * unalias [arg...] * builtin [-sd] [-f file] [name...] * set [options] [name...] * unset [-fnv] [name...] * * David Korn * AT&T Labs * */ #include "defs.h" #include #include "path.h" #include "name.h" #include "history.h" #include "builtins.h" #include "variables.h" #include "FEATURE/dynamic" struct tdata { Shell_t *sh; Namval_t *tp; const char *wctname; Sfio_t *outfile; char *prefix; char *tname; char *help; short aflag; short pflag; int argnum; int scanmask; Dt_t *scanroot; char **argnam; int indent; int noref; }; static int print_namval(Sfio_t*, Namval_t*, int, struct tdata*); static void print_attribute(Namval_t*,void*); static void print_all(Sfio_t*, Dt_t*, struct tdata*); static void print_scan(Sfio_t*, int, Dt_t*, int, struct tdata*); static int unall(int, char**, Dt_t*, Shell_t*); static int setall(char**, int, Dt_t*, struct tdata*); static void pushname(Namval_t*,void*); static void(*nullscan)(Namval_t*,void*); static Namval_t *load_class(const char *name) { errormsg(SH_DICT,ERROR_exit(1),"%s: type not loadable",name); return(0); } /* * Note export and readonly are the same */ #if 0 /* for the dictionary generator */ int b_export(int argc,char *argv[],Shbltin_t *context){} #endif int b_readonly(int argc,char *argv[],Shbltin_t *context) { register int flag; char *command = argv[0]; struct tdata tdata; NOT_USED(argc); memset((void*)&tdata,0,sizeof(tdata)); tdata.sh = context->shp; tdata.aflag = '-'; while((flag = optget(argv,*command=='e'?sh_optexport:sh_optreadonly))) switch(flag) { case 'p': tdata.prefix = command; break; case ':': errormsg(SH_DICT,2, "%s", opt_info.arg); break; case '?': errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg); return(2); } if(error_info.errors) errormsg(SH_DICT,ERROR_usage(2),optusage(NIL(char*))); argv += (opt_info.index-1); if(*command=='r') flag = (NV_ASSIGN|NV_RDONLY|NV_VARNAME); #ifdef _ENV_H else if(!argv[1]) { char *cp,**env=env_get(tdata.sh->env); while(cp = *env++) { if(tdata.prefix) sfputr(sfstdout,tdata.prefix,' '); sfprintf(sfstdout,"%s\n",sh_fmtq(cp)); } return(0); } #endif else { flag = (NV_ASSIGN|NV_EXPORT|NV_IDENT); if(!tdata.sh->prefix) tdata.sh->prefix = ""; } return(setall(argv,flag,tdata.sh->var_tree, &tdata)); } int b_alias(int argc,register char *argv[],Shbltin_t *context) { register unsigned flag = NV_NOARRAY|NV_NOSCOPE|NV_ASSIGN; register Dt_t *troot; register int n; struct tdata tdata; NOT_USED(argc); memset((void*)&tdata,0,sizeof(tdata)); tdata.sh = context->shp; troot = tdata.sh->alias_tree; if(*argv[0]=='h') flag = NV_TAGGED; if(argv[1]) { opt_info.offset = 0; opt_info.index = 1; *opt_info.option = 0; tdata.argnum = 0; tdata.aflag = *argv[1]; while((n = optget(argv,sh_optalias))) switch(n) { case 'p': tdata.prefix = argv[0]; break; case 't': flag |= NV_TAGGED; break; case 'x': flag |= NV_EXPORT; break; case ':': errormsg(SH_DICT,2, "%s", opt_info.arg); break; case '?': errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg); return(2); } if(error_info.errors) errormsg(SH_DICT,ERROR_usage(2),"%s",optusage(NIL(char*))); argv += (opt_info.index-1); if(flag&NV_TAGGED) { /* hacks to handle hash -r | -- */ if(argv[1] && argv[1][0]=='-') { if(argv[1][1]=='r' && argv[1][2]==0) { Namval_t *np = nv_search((char*)PATHNOD,tdata.sh->var_tree,HASH_BUCKET); nv_putval(np,nv_getval(np),NV_RDONLY); argv++; if(!argv[1]) return(0); } if(argv[1][0]=='-') { if(argv[1][1]=='-' && argv[1][2]==0) argv++; else errormsg(SH_DICT, ERROR_exit(1), e_option, argv[1]); } } troot = tdata.sh->track_tree; } } return(setall(argv,flag,troot,&tdata)); } #if 0 /* for the dictionary generator */ int b_local(int argc,char *argv[],Shbltin_t *context){} #endif int b_typeset(int argc,register char *argv[],Shbltin_t *context) { register int n, flag = NV_VARNAME|NV_ASSIGN; struct tdata tdata; const char *optstring = sh_opttypeset; Namdecl_t *ntp = (Namdecl_t*)context->ptr; Dt_t *troot; int isfloat=0, shortint=0, sflag=0; NOT_USED(argc); memset((void*)&tdata,0,sizeof(tdata)); tdata.sh = context->shp; if(ntp) { tdata.tp = ntp->tp; opt_info.disc = (Optdisc_t*)ntp->optinfof; optstring = ntp->optstring; } troot = tdata.sh->var_tree; while((n = optget(argv,optstring))) { if(tdata.aflag==0) tdata.aflag = *opt_info.option; switch(n) { case 'a': flag |= NV_IARRAY; if(opt_info.arg && *opt_info.arg!='[') { opt_info.index--; goto endargs; } tdata.tname = opt_info.arg; break; case 'A': flag |= NV_ARRAY; break; case 'C': flag |= NV_COMVAR; break; case 'E': /* The following is for ksh88 compatibility */ if(opt_info.offset && !strchr(argv[opt_info.index],'E')) { tdata.argnum = (int)opt_info.num; break; } /* FALLTHROUGH */ case 'F': case 'X': if(!opt_info.arg || (tdata.argnum = opt_info.num) <0) tdata.argnum = (n=='X'?2*sizeof(Sfdouble_t):10); isfloat = 1; if(n=='E') { flag &= ~NV_HEXFLOAT; flag |= NV_EXPNOTE; } else if(n=='X') { flag &= ~NV_EXPNOTE; flag |= NV_HEXFLOAT; } break; case 'b': flag |= NV_BINARY; break; case 'm': flag |= NV_MOVE; break; case 'n': flag &= ~NV_VARNAME; flag |= (NV_REF|NV_IDENT); break; case 'H': flag |= NV_HOST; break; case 'T': flag |= NV_TYPE; tdata.prefix = opt_info.arg; break; case 'L': case 'Z': case 'R': if(tdata.argnum==0) tdata.argnum = (int)opt_info.num; if(tdata.argnum < 0) errormsg(SH_DICT,ERROR_exit(1), e_badfield, tdata.argnum); if(n=='Z') flag |= NV_ZFILL; else { flag &= ~(NV_LJUST|NV_RJUST); flag |= (n=='L'?NV_LJUST:NV_RJUST); } break; case 'M': if((tdata.wctname = opt_info.arg) && !nv_mapchar((Namval_t*)0,tdata.wctname)) errormsg(SH_DICT, ERROR_exit(1),e_unknownmap, tdata.wctname); if(tdata.wctname && strcmp(tdata.wctname,e_tolower)==0) flag |= NV_UTOL; else flag |= NV_LTOU; if(!tdata.wctname) flag |= NV_UTOL; break; case 'f': flag &= ~(NV_VARNAME|NV_ASSIGN); troot = tdata.sh->fun_tree; break; case 'i': if(!opt_info.arg || (tdata.argnum = opt_info.num) <0) tdata.argnum = 10; flag |= NV_INTEGER; break; case 'l': tdata.wctname = e_tolower; flag |= NV_UTOL; break; case 'p': tdata.prefix = argv[0]; tdata.pflag = 1; flag &= ~NV_ASSIGN; break; case 'r': flag |= NV_RDONLY; break; #ifdef SHOPT_TYPEDEF case 'S': sflag=1; break; case 'h': tdata.help = opt_info.arg; break; #endif /*SHOPT_TYPEDEF*/ case 's': shortint=1; break; case 't': flag |= NV_TAGGED; break; case 'u': tdata.wctname = e_toupper; flag |= NV_LTOU; break; case 'x': flag &= ~NV_VARNAME; flag |= (NV_EXPORT|NV_IDENT); break; case ':': errormsg(SH_DICT,2, "%s", opt_info.arg); break; case '?': errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg); opt_info.disc = 0; return(2); } } endargs: argv += opt_info.index; opt_info.disc = 0; /* handle argument of + and - specially */ if(*argv && argv[0][1]==0 && (*argv[0]=='+' || *argv[0]=='-')) tdata.aflag = *argv[0]; else argv--; if((flag&NV_ZFILL) && !(flag&NV_LJUST)) flag |= NV_RJUST; if((flag&NV_INTEGER) && (flag&(NV_LJUST|NV_RJUST|NV_ZFILL))) error_info.errors++; if((flag&NV_BINARY) && (flag&(NV_LJUST|NV_UTOL|NV_LTOU))) error_info.errors++; if((flag&NV_MOVE) && (flag&~(NV_MOVE|NV_VARNAME|NV_ASSIGN))) error_info.errors++; if((flag&NV_REF) && (flag&~(NV_REF|NV_IDENT|NV_ASSIGN))) error_info.errors++; if((flag&NV_TYPE) && (flag&~(NV_TYPE|NV_VARNAME|NV_ASSIGN))) error_info.errors++; if(troot==tdata.sh->fun_tree && ((isfloat || flag&~(NV_FUNCT|NV_TAGGED|NV_EXPORT|NV_LTOU)))) error_info.errors++; if(sflag && troot==tdata.sh->fun_tree) { /* static function */ sflag = 0; flag |= NV_STATICF; } if(error_info.errors) errormsg(SH_DICT,ERROR_usage(2),"%s", optusage(NIL(char*))); if(sizeof(char*)<8 && tdata.argnum > SHRT_MAX) errormsg(SH_DICT,ERROR_exit(2),"option argument cannot be greater than %d",SHRT_MAX); if(isfloat) flag |= NV_DOUBLE; if(shortint) { flag &= ~NV_LONG; flag |= NV_SHORT|NV_INTEGER; } if(sflag) { if(tdata.sh->mktype) flag |= NV_REF|NV_TAGGED; else if(!tdata.sh->typeinit) flag |= NV_STATIC|NV_IDENT; } if(tdata.sh->fn_depth && !tdata.pflag) flag |= NV_NOSCOPE; if(tdata.help) tdata.help = strdup(tdata.help); if(flag&NV_TYPE) { Stk_t *stkp = tdata.sh->stk; int off=0,offset = stktell(stkp); if(!tdata.prefix) return(sh_outtype(tdata.sh,sfstdout)); sfputr(stkp,NV_CLASS,-1); #if SHOPT_NAMESPACE if(tdata.sh->namespace) { off = stktell(stkp)+1; sfputr(stkp,nv_name(tdata.sh->namespace),'.'); } else #endif /* SHOPT_NAMESPACE */ if(NV_CLASS[sizeof(NV_CLASS)-2]!='.') sfputc(stkp,'.'); sfputr(stkp,tdata.prefix,0); tdata.tp = nv_open(stkptr(stkp,offset),tdata.sh->var_tree,NV_VARNAME|NV_NOARRAY|NV_NOASSIGN); #if SHOPT_NAMESPACE if(!tdata.tp && off) { *stkptr(stkp,off)=0; tdata.tp = nv_open(stkptr(stkp,offset),tdata.sh->var_tree,NV_VARNAME|NV_NOARRAY|NV_NOASSIGN); } #endif /* SHOPT_NAMESPACE */ stkseek(stkp,offset); if(!tdata.tp) errormsg(SH_DICT,ERROR_exit(1),"%s: unknown type",tdata.prefix); else if(nv_isnull(tdata.tp)) nv_newtype(tdata.tp); tdata.tp->nvenv = tdata.help; flag &= ~NV_TYPE; if(nv_isattr(tdata.tp,NV_TAGGED)) { nv_offattr(tdata.tp,NV_TAGGED); return(0); } } else if(tdata.aflag==0 && ntp && ntp->tp) tdata.aflag = '-'; if(!tdata.sh->mktype) tdata.help = 0; if(tdata.aflag=='+' && (flag&(NV_ARRAY|NV_IARRAY|NV_COMVAR)) && argv[1]) errormsg(SH_DICT,ERROR_exit(1),e_nounattr); return(setall(argv,flag,troot,&tdata)); } static void print_value(Sfio_t *iop, Namval_t *np, struct tdata *tp) { char *name; int aflag=tp->aflag; if(nv_isnull(np)) { if(!np->nvflag) return; aflag = '+'; } else if(nv_istable(np)) { Dt_t *root = tp->sh->last_root; Namval_t *nsp = tp->sh->namespace; char *cp; if(!tp->pflag) return; cp = name = nv_name(np); if(*name=='.') name++; if(tp->indent) sfnputc(iop,'\t',tp->indent); sfprintf(iop,"namespace %s\n", name); if(tp->indent) sfnputc(iop,'\t',tp->indent); sfprintf(iop,"{\n", name); tp->indent++; /* output types from namespace */ tp->sh->namespace = 0; tp->sh->prefix = nv_name(np)+1; sh_outtype(tp->sh,iop); tp->sh->prefix = 0; tp->sh->namespace = np; tp->sh->last_root = root; /* output variables from namespace */ print_scan(iop,NV_NOSCOPE,nv_dict(np),aflag=='+',tp); tp->wctname = cp; tp->sh->namespace = 0; /* output functions from namespace */ print_scan(iop,NV_FUNCTION|NV_NOSCOPE,tp->sh->fun_tree,aflag=='+',tp); tp->wctname = 0; tp->sh->namespace = nsp; if(--tp->indent) sfnputc(iop,'\t',tp->indent); sfwrite(iop,"}\n",2); return; } sfputr(iop,nv_name(np),aflag=='+'?'\n':'='); if(aflag=='+') return; if(nv_isarray(np) && nv_arrayptr(np)) { nv_outnode(np,iop,-1,0); sfwrite(iop,")\n",2); } else { if(nv_isvtree(np)) nv_onattr(np,NV_EXPORT); if(!(name = nv_getval(np))) name = Empty; if(!nv_isvtree(np)) name = sh_fmtq(name); sfputr(iop,name,'\n'); } } static int setall(char **argv,register int flag,Dt_t *troot,struct tdata *tp) { register char *name; char *last = 0; int nvflags=(flag&(NV_ARRAY|NV_NOARRAY|NV_VARNAME|NV_IDENT|NV_ASSIGN|NV_STATIC|NV_MOVE)); int r=0, ref=0, comvar=(flag&NV_COMVAR),iarray=(flag&NV_IARRAY); Shell_t *shp =tp->sh; if(!shp->prefix) { if(!tp->pflag) nvflags |= NV_NOSCOPE; } else if(*shp->prefix==0) shp->prefix = 0; if(*argv[0]=='+') nvflags |= NV_NOADD; flag &= ~(NV_NOARRAY|NV_NOSCOPE|NV_VARNAME|NV_IDENT|NV_STATIC|NV_COMVAR|NV_IARRAY); if(argv[1]) { if(flag&NV_REF) { flag &= ~NV_REF; ref=1; if(tp->aflag!='-') nvflags |= NV_NOREF; } if(tp->pflag) nvflags |= (NV_NOREF|NV_NOADD|NV_NOFAIL); while(name = *++argv) { register unsigned newflag; register Namval_t *np; Namarr_t *ap; Namval_t *mp; unsigned curflag; if(troot == shp->fun_tree) { /* *functions can be exported or * traced but not set */ flag &= ~NV_ASSIGN; if(flag&NV_LTOU) { /* Function names cannot be special builtin */ if((np=nv_search(name,shp->bltin_tree,0)) && nv_isattr(np,BLT_SPC)) errormsg(SH_DICT,ERROR_exit(1),e_badfun,name); #if SHOPT_NAMESPACE if(shp->namespace) np = sh_fsearch(shp,name,NV_ADD|HASH_NOSCOPE); else #endif /* SHOPT_NAMESPACE */ np = nv_open(name,sh_subfuntree(1),NV_NOARRAY|NV_IDENT|NV_NOSCOPE); } else { if(shp->prefix) { sfprintf(shp->strbuf,"%s.%s%c",shp->prefix,name,0); name = sfstruse(shp->strbuf); } #if SHOPT_NAMESPACE np = 0; if(shp->namespace) np = sh_fsearch(shp,name,HASH_NOSCOPE); if(!np) #endif /* SHOPT_NAMESPACE */ if(np=nv_search(name,troot,0)) { if(!is_afunction(np)) np = 0; } else if(memcmp(name,".sh.math.",9)==0 && sh_mathstd(name+9)) continue; } if(np && ((flag&NV_LTOU) || !nv_isnull(np) || nv_isattr(np,NV_LTOU))) { if(flag==0 && !tp->help) { print_namval(sfstdout,np,tp->aflag=='+',tp); continue; } if(shp->subshell && !shp->subshare) sh_subfork(); if(tp->aflag=='-') nv_onattr(np,flag|NV_FUNCTION); else if(tp->aflag=='+') nv_offattr(np,flag); } else r++; if(tp->help) { int offset = stktell(shp->stk); if(!np) { sfputr(shp->stk,shp->prefix,'.'); sfputr(shp->stk,name,0); np = nv_search(stkptr(shp->stk,offset),troot,0); stkseek(shp->stk,offset); } if(np && np->nvalue.cp) np->nvalue.rp->help = tp->help; } continue; } /* tracked alias */ if(troot==shp->track_tree && tp->aflag=='-') { np = nv_search(name,troot,NV_ADD); path_alias(np,path_absolute(shp,nv_name(np),NIL(Pathcomp_t*))); continue; } np = nv_open(name,troot,nvflags|((nvflags&NV_ASSIGN)?0:NV_ARRAY)|((iarray|(nvflags&(NV_REF|NV_NOADD)==NV_REF))?NV_FARRAY:0)); if(!np) continue; if(nv_isnull(np) && !nv_isarray(np) && nv_isattr(np,NV_NOFREE)) nv_offattr(np,NV_NOFREE); else if(tp->tp && !nv_isattr(np,NV_MINIMAL|NV_EXPORT) && (mp=(Namval_t*)np->nvenv) && (ap=nv_arrayptr(mp)) && (ap->nelem&ARRAY_TREE)) errormsg(SH_DICT,ERROR_exit(1),e_typecompat,nv_name(np)); else if((ap=nv_arrayptr(np)) && nv_aindex(np)>0 && ap->nelem==1 && nv_getval(np)==Empty) { ap->nelem++; _nv_unset(np,0); ap->nelem--; } else if(iarray && ap && ap->fun) errormsg(SH_DICT,ERROR_exit(1),"cannot change associative array %s to index array",nv_name(np)); else if( (iarray||(flag&NV_ARRAY)) && nv_isvtree(np) && !nv_type(np)) _nv_unset(np,NV_EXPORT); if(tp->pflag) { if(!nv_istable(np)) nv_attribute(np,sfstdout,tp->prefix,1); print_value(sfstdout,np,tp); continue; } if(flag==NV_ASSIGN && !ref && tp->aflag!='-' && !strchr(name,'=')) { if(troot!=shp->var_tree && (nv_isnull(np) || !print_namval(sfstdout,np,0,tp))) { sfprintf(sfstderr,sh_translate(e_noalias),name); r++; } if(!comvar && !iarray) continue; } if(!nv_isarray(np) && !strchr(name,'=') && !(shp->envlist && nv_onlist(shp->envlist,name))) { if(comvar || (shp->last_root==shp->var_tree && (tp->tp || (!shp->st.real_fun && (nvflags&NV_STATIC)) || (!(flag&(NV_EXPORT|NV_RDONLY)) && nv_isattr(np,(NV_EXPORT|NV_IMPORT))==(NV_EXPORT|NV_IMPORT))))) { _nv_unset(np,0); } } if(troot==shp->var_tree) { if(iarray) { if(tp->tname) nv_atypeindex(np,tp->tname+1); else if(nv_isnull(np)) nv_onattr(np,NV_ARRAY|(comvar?NV_NOFREE:0)); else { if(ap && comvar) ap->nelem |= ARRAY_TREE; nv_putsub(np, (char*)0, 0); } } else if(nvflags&NV_ARRAY) { if(comvar) { Namarr_t *ap=nv_arrayptr(np); if(ap) ap->nelem |= ARRAY_TREE; else { _nv_unset(np,NV_RDONLY); nv_onattr(np,NV_NOFREE); } } nv_setarray(np,nv_associative); } else if(comvar && !nv_isvtree(np) && !nv_rename(np,flag|NV_COMVAR)) nv_setvtree(np); } if(flag&NV_MOVE) { nv_rename(np, flag); nv_close(np); continue; } if(tp->tp && nv_type(np)!=tp->tp) { nv_settype(np,tp->tp,tp->aflag=='-'?0:NV_APPEND); flag = (np->nvflag&NV_NOCHANGE); } flag &= ~NV_ASSIGN; if(last=strchr(name,'=')) *last = 0; if (shp->typeinit) continue; curflag = np->nvflag; if(!(flag&NV_INTEGER) && (flag&(NV_LTOU|NV_UTOL))) { Namfun_t *fp; char *cp; if(!tp->wctname) errormsg(SH_DICT,ERROR_exit(1),e_mapchararg,nv_name(np)); cp = (char*)nv_mapchar(np,0); if(fp=nv_mapchar(np,tp->wctname)) { if(tp->aflag=='+') { if(cp && strcmp(cp,tp->wctname)==0) { nv_disc(np,fp,NV_POP); if(!(fp->nofree&1)) free((void*)fp); nv_offattr(np,flag&(NV_LTOU|NV_UTOL)); } } else if(!cp || strcmp(cp,tp->wctname)) { nv_disc(np,fp,NV_LAST); nv_onattr(np,flag&(NV_LTOU|NV_UTOL)); } } } if (tp->aflag == '-') { if((flag&NV_EXPORT) && (strchr(name,'.') || nv_isvtree(np))) errormsg(SH_DICT,ERROR_exit(1),e_badexport,name); #if SHOPT_BSH if(flag&NV_EXPORT) nv_offattr(np,NV_IMPORT); #endif /* SHOPT_BSH */ newflag = curflag; if(flag&~NV_NOCHANGE) newflag &= NV_NOCHANGE; newflag |= flag; if (flag & (NV_LJUST|NV_RJUST)) { if(!(flag&NV_RJUST)) newflag &= ~NV_RJUST; else if(!(flag&NV_LJUST)) newflag &= ~NV_LJUST; } } else { if((flag&NV_RDONLY) && (curflag&NV_RDONLY)) errormsg(SH_DICT,ERROR_exit(1),e_readonly,nv_name(np)); newflag = curflag & ~flag; } if (tp->aflag && (tp->argnum>0 || (curflag!=newflag))) { if(shp->subshell) sh_assignok(np,1); if(troot!=shp->var_tree) nv_setattr(np,newflag&~NV_ASSIGN); else { char *oldname=0; int len=strlen(name); if(tp->argnum==1 && newflag==NV_INTEGER && nv_isattr(np,NV_INTEGER)) tp->argnum = 10; if(np->nvfun && !nv_isarray(np) && name[len-1]=='.') newflag |= NV_NODISC; nv_newattr (np, newflag&~NV_ASSIGN,tp->argnum); if(oldname) np->nvname = oldname; } } if(tp->help && !nv_isattr(np,NV_MINIMAL|NV_EXPORT)) { np->nvenv = tp->help; nv_onattr(np,NV_EXPORT); } if(last) *last = '='; /* set or unset references */ if(ref) { if(tp->aflag=='-') { Dt_t *hp=0; if(nv_isattr(np,NV_PARAM) && shp->st.prevst) { if(!(hp=(Dt_t*)shp->st.prevst->save_tree)) hp = dtvnext(shp->var_tree); } if(tp->sh->mktype) nv_onattr(np,NV_REF|NV_FUNCT); else nv_setref(np,hp,NV_VARNAME); } else nv_unref(np); } nv_close(np); } } else { if(shp->prefix) errormsg(SH_DICT,2, e_subcomvar,shp->prefix); if(tp->aflag) { if(troot==shp->fun_tree) { flag |= NV_FUNCTION; tp->prefix = 0; } else if(troot==shp->var_tree) { flag |= (nvflags&NV_ARRAY); if(iarray) flag |= NV_ARRAY|NV_IARRAY; if(comvar) flag |= NV_TABLE; if(!(flag&~NV_ASSIGN)) tp->noref = 1; } if((flag&(NV_UTOL|NV_LTOU)) ==(NV_UTOL|NV_LTOU)) { print_scan(sfstdout,flag&~NV_UTOL,troot,tp->aflag=='+',tp); flag &= ~NV_LTOU; } print_scan(sfstdout,flag,troot,tp->aflag=='+',tp); if(tp->noref) { tp->noref = 0; print_scan(sfstdout,flag|NV_REF,troot,tp->aflag=='+',tp); } } else if(troot==shp->alias_tree) print_scan(sfstdout,0,troot,0,tp); else print_all(sfstdout,troot,tp); sfsync(sfstdout); } return(r); } #if SHOPT_DYNAMIC typedef void (*Libinit_f)(int,void*); typedef struct Libcomp_s { void* dll; char* lib; dev_t dev; ino_t ino; unsigned int attr; } Libcomp_t; #define GROWLIB 4 static Libcomp_t *liblist; static int nlib; static int maxlib; /* * add library to loaded list * call (*lib_init)() on first load if defined * always move to head of search list * return: 0: already loaded 1: first load */ int sh_addlib(Shell_t* shp, void* dll, char* name, Pathcomp_t* pp) { register int n; register int r; Libinit_f initfn; Shbltin_t *sp = &shp->bltindata; sp->nosfio = 0; for (n = r = 0; n < nlib; n++) { if (r) liblist[n-1] = liblist[n]; else if (liblist[n].dll == dll) r++; } if (r) nlib--; else if ((initfn = (Libinit_f)dlllook(dll, "lib_init"))) (*initfn)(0,sp); if (nlib >= maxlib) { maxlib += GROWLIB; liblist = newof(liblist, Libcomp_t, maxlib+1, 0); } liblist[nlib].dll = dll; liblist[nlib].attr = (sp->nosfio?BLT_NOSFIO:0); if (name) liblist[nlib].lib = strdup(name); if (pp) { liblist[nlib].dev = pp->dev; liblist[nlib].ino = pp->ino; } nlib++; return !r; } Shbltin_f sh_getlib(Shell_t* shp, char* sym, Pathcomp_t* pp) { register int n; for (n = 0; n < nlib; n++) if (liblist[n].ino == pp->ino && liblist[n].dev == pp->dev) return (Shbltin_f)dlllook(liblist[n].dll, sym); return 0; } #else int sh_addlib(Shell_t* shp, void* library, char* name, Pathcomp_t* pp) { return 0; } Shbltin_f sh_getlib(Shell_t* shp, char* name, Pathcomp_t* pp) { return 0; } #endif /* SHOPT_DYNAMIC */ /* * add change or list built-ins * adding builtins requires dlopen() interface */ int b_builtin(int argc,char *argv[],Shbltin_t *context) { register char *arg=0, *name; register int n, r=0, flag=0; register Namval_t *np; long dlete=0; struct tdata tdata; Shbltin_f addr; Stk_t *stkp; void *library=0; char *errmsg; #ifdef SH_PLUGIN_VERSION unsigned long ver; int list = 0; char path[1024]; #endif NOT_USED(argc); memset(&tdata,0,sizeof(tdata)); tdata.sh = context->shp; stkp = tdata.sh->stk; if(!tdata.sh->pathlist) path_absolute(tdata.sh,argv[0],NIL(Pathcomp_t*)); while (n = optget(argv,sh_optbuiltin)) switch (n) { case 's': flag = BLT_SPC; break; case 'd': dlete=1; break; case 'f': #if SHOPT_DYNAMIC arg = opt_info.arg; #else errormsg(SH_DICT,2, "adding built-ins not supported"); error_info.errors++; #endif /* SHOPT_DYNAMIC */ break; case 'l': #ifdef SH_PLUGIN_VERSION list = 1; #endif break; case ':': errormsg(SH_DICT,2, "%s", opt_info.arg); break; case '?': errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg); break; } argv += opt_info.index; if(error_info.errors) errormsg(SH_DICT,ERROR_usage(2),"%s", optusage(NIL(char*))); if(arg || *argv) { if(sh_isoption(SH_RESTRICTED)) errormsg(SH_DICT,ERROR_exit(1),e_restricted,argv[-opt_info.index]); if(sh_isoption(SH_PFSH)) errormsg(SH_DICT,ERROR_exit(1),e_pfsh,argv[-opt_info.index]); if(tdata.sh->subshell && !tdata.sh->subshare) sh_subfork(); } #if SHOPT_DYNAMIC if(arg) { #ifdef SH_PLUGIN_VERSION if(!(library = dllplugin(SH_ID, arg, NiL, SH_PLUGIN_VERSION, &ver, RTLD_LAZY, path, sizeof(path)))) { errormsg(SH_DICT,ERROR_exit(0),"%s: %s",arg,dllerror(0)); return(1); } if(list) sfprintf(sfstdout, "%s %08lu %s\n", arg, ver, path); #else #if (_AST_VERSION>=20040404) if(!(library = dllplug(SH_ID,arg,NIL(char*),RTLD_LAZY,NIL(char*),0))) #else if(!(library = dllfind(arg,NIL(char*),RTLD_LAZY,NIL(char*),0))) #endif { errormsg(SH_DICT,ERROR_exit(0),"%s: %s",arg,dlerror()); return(1); } #endif sh_addlib(tdata.sh,library,arg,NiL); } else #endif /* SHOPT_DYNAMIC */ if(*argv==0 && !dlete) { print_scan(sfstdout, flag, tdata.sh->bltin_tree, 1, &tdata); return(0); } r = 0; flag = stktell(stkp); while(arg = *argv) { name = path_basename(arg); sfwrite(stkp,"b_",2); sfputr(stkp,name,0); errmsg = 0; addr = 0; if(dlete || liblist) for(n=(nlib?nlib:dlete); --n>=0;) { #if SHOPT_DYNAMIC if(!dlete && !liblist[n].dll) continue; if(dlete || (addr = (Shbltin_f)dlllook(liblist[n].dll,stkptr(stkp,flag)))) #else if(dlete) #endif /* SHOPT_DYNAMIC */ { if(np = sh_addbuiltin(arg, addr,pointerof(dlete))) { if(dlete || nv_isattr(np,BLT_SPC)) errmsg = "restricted name"; #if SHOPT_DYNAMIC else nv_onattr(np,liblist[n].attr); #endif /* SHOPT_DYNAMIC */ } break; } } if(!addr && (np = nv_search(arg,context->shp->bltin_tree,0))) { if(nv_isattr(np,BLT_SPC)) errmsg = "restricted name"; addr = (Shbltin_f)np->nvalue.bfp; } if(!dlete && !addr && !(np=sh_addbuiltin(arg,(Shbltin_f)0 ,0))) errmsg = "not found"; if(errmsg) { errormsg(SH_DICT,ERROR_exit(0),"%s: %s",*argv,errmsg); r = 1; } stkseek(stkp,flag); argv++; } return(r); } int b_set(int argc,register char *argv[],Shbltin_t *context) { struct tdata tdata; int was_monitor = sh_isoption(SH_MONITOR); memset(&tdata,0,sizeof(tdata)); tdata.sh = context->shp; tdata.prefix=0; if(argv[1]) { if(sh_argopts(argc,argv,tdata.sh) < 0) return(2); if(sh_isoption(SH_VERBOSE)) sh_onstate(SH_VERBOSE); else sh_offstate(SH_VERBOSE); if(sh_isoption(SH_MONITOR) && !was_monitor) sh_onstate(SH_MONITOR); else if(!sh_isoption(SH_MONITOR) && was_monitor) sh_offstate(SH_MONITOR); } else /*scan name chain and print*/ print_scan(sfstdout,0,tdata.sh->var_tree,0,&tdata); return(0); } /* * The removing of Shell variable names, aliases, and functions * is performed here. * Unset functions with unset -f * Non-existent items being deleted give non-zero exit status */ int b_unalias(int argc,register char *argv[],Shbltin_t *context) { Shell_t *shp = context->shp; return(unall(argc,argv,shp->alias_tree,shp)); } int b_unset(int argc,register char *argv[],Shbltin_t *context) { Shell_t *shp = context->shp; return(unall(argc,argv,shp->var_tree,shp)); } static int unall(int argc, char **argv, register Dt_t *troot, Shell_t* shp) { register Namval_t *np; register const char *name; volatile int r; Dt_t *dp; int nflag=0,all=0,isfun,jmpval; struct checkpt buff; NOT_USED(argc); if(troot==shp->alias_tree) { name = sh_optunalias; if(shp->subshell) troot = sh_subaliastree(0); } else name = sh_optunset; while(r = optget(argv,name)) switch(r) { case 'f': troot = sh_subfuntree(1); break; case 'a': all=1; break; case 'n': nflag = NV_NOREF; /* FALLTHROUGH */ case 'v': troot = shp->var_tree; break; case ':': errormsg(SH_DICT,2, "%s", opt_info.arg); break; case '?': errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg); return(2); } argv += opt_info.index; if(error_info.errors || (*argv==0 &&!all)) errormsg(SH_DICT,ERROR_usage(2),"%s",optusage(NIL(char*))); if(!troot) return(1); r = 0; if(troot==shp->var_tree) nflag |= NV_VARNAME; else nflag = NV_NOSCOPE; if(all) { dtclear(troot); return(r); } sh_pushcontext(shp,&buff,1); while(name = *argv++) { jmpval = sigsetjmp(buff.buff,0); np = 0; if(jmpval==0) { #if SHOPT_NAMESPACE if(shp->namespace && troot!=shp->var_tree) np = sh_fsearch(shp,name,nflag?HASH_NOSCOPE:0); if(!np) #endif /* SHOPT_NAMESPACE */ np=nv_open(name,troot,NV_NOADD|nflag); } else { r = 1; continue; } if(np) { if(is_abuiltin(np) || nv_isattr(np,NV_RDONLY)) { if(nv_isattr(np,NV_RDONLY)) errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np)); r = 1; continue; } isfun = is_afunction(np); if(troot==shp->var_tree) { Namarr_t *ap; #if SHOPT_FIXEDARRAY if((ap=nv_arrayptr(np)) && !ap->fixed && name[strlen(name)-1]==']' && !nv_getsub(np)) #else if(nv_isarray(np) && name[strlen(name)-1]==']' && !nv_getsub(np)) #endif /* SHOPT_FIXEDARRAY */ { r=1; continue; } if(shp->subshell) np=sh_assignok(np,0); } if(!nv_isnull(np) || nv_size(np) || nv_isattr(np,~(NV_MINIMAL|NV_NOFREE))) _nv_unset(np,0); if(troot==shp->var_tree && shp->st.real_fun && (dp=shp->var_tree->walk) && dp==shp->st.real_fun->sdict) nv_delete(np,dp,NV_NOFREE); else if(isfun && !(np->nvalue.rp && np->nvalue.rp->running)) nv_delete(np,troot,0); #if 0 /* causes unsetting local variable to expose global */ else if(shp->var_tree==troot && shp->var_tree!=shp->var_base && nv_search((char*)np,shp->var_tree,HASH_BUCKET|HASH_NOSCOPE)) nv_delete(np,shp->var_tree,0); #endif else nv_close(np); } else if(troot==shp->alias_tree) r = 1; } sh_popcontext(shp,&buff); return(r); } /* * print out the name and value of a name-value pair */ static int print_namval(Sfio_t *file,register Namval_t *np,register int flag, struct tdata *tp) { register char *cp; int indent=tp->indent, outname=0, isfun; sh_sigcheck(tp->sh); if(flag) flag = '\n'; if(tp->noref && nv_isref(np)) return(0); if(nv_isattr(np,NV_NOPRINT|NV_INTEGER)==NV_NOPRINT) { if(is_abuiltin(np) && strcmp(np->nvname,".sh.tilde")) sfputr(file,nv_name(np),'\n'); return(0); } if(nv_istable(np)) { print_value(file,np,tp); return(0); } isfun = is_afunction(np); if(tp->prefix) { outname = (*tp->prefix=='t' && (!nv_isnull(np) || nv_isattr(np,NV_FLOAT|NV_RDONLY|NV_BINARY|NV_RJUST|NV_NOPRINT))); if(indent && (isfun || outname || *tp->prefix!='t')) { sfnputc(file,'\t',indent); indent = 0; } if(!isfun) { if(*tp->prefix=='t') nv_attribute(np,tp->outfile,tp->prefix,tp->aflag); else sfputr(file,tp->prefix,' '); } } if(isfun) { Sfio_t *iop=0; char *fname=0; if(nv_isattr(np,NV_NOFREE)) return(0); if(!flag && !np->nvalue.ip) sfputr(file,"typeset -fu",' '); else if(!flag && !nv_isattr(np,NV_FPOSIX)) sfputr(file,"function",' '); cp = nv_name(np); if(tp->wctname) cp += strlen(tp->wctname)+1; sfputr(file,cp,-1); if(nv_isattr(np,NV_FPOSIX)) sfwrite(file,"()",2); if(np->nvalue.ip && np->nvalue.rp->hoffset>=0) fname = np->nvalue.rp->fname; else flag = '\n'; if(flag) { if(tp->pflag && np->nvalue.ip && np->nvalue.rp->hoffset>=0) sfprintf(file," #line %d %s\n",np->nvalue.rp->lineno,fname?sh_fmtq(fname):""); else sfputc(file, '\n'); } else { if(nv_isattr(np,NV_FTMP)) { fname = 0; iop = tp->sh->heredocs; } else if(fname) iop = sfopen(iop,fname,"r"); else if(tp->sh->gd->hist_ptr) iop = (tp->sh->gd->hist_ptr)->histfp; if(iop && sfseek(iop,(Sfoff_t)np->nvalue.rp->hoffset,SEEK_SET)>=0) sfmove(iop,file, nv_size(np), -1); else flag = '\n'; if(fname) sfclose(iop); } return(nv_size(np)+1); } if(nv_arrayptr(np)) { if(indent) sfnputc(file,'\t',indent); print_value(file,np,tp); return(0); } if(nv_isvtree(np)) nv_onattr(np,NV_EXPORT); if(cp=nv_getval(np)) { if(indent) sfnputc(file,'\t',indent); sfputr(file,nv_name(np),-1); if(!flag) flag = '='; sfputc(file,flag); if(flag != '\n') { if(nv_isref(np) && nv_refsub(np)) { sfputr(file,sh_fmtq(cp),-1); sfprintf(file,"[%s]\n", sh_fmtq(nv_refsub(np))); } else #if SHOPT_TYPEDEF sfputr(file,nv_isvtree(np)?cp:sh_fmtq(cp),'\n'); #else sfputr(file,sh_fmtq(cp),'\n'); #endif /* SHOPT_TYPEDEF */ } return(1); } else if(outname || (tp->scanmask && tp->scanroot==tp->sh->var_tree)) sfputr(file,nv_name(np),'\n'); return(0); } /* * print attributes at all nodes */ static void print_all(Sfio_t *file,Dt_t *root, struct tdata *tp) { tp->outfile = file; nv_scan(root, print_attribute, (void*)tp, 0, 0); } /* * print the attributes of name value pair give by */ static void print_attribute(register Namval_t *np,void *data) { register struct tdata *dp = (struct tdata*)data; nv_attribute(np,dp->outfile,dp->prefix,dp->aflag); } /* * print the nodes in tree which have attributes set * of