int B_login(int argc,char *argv[],void *extra) { struct checkpt *pp; register struct login *logp=0; register Shell_t *shp; const char *pname; if(argc) shp = ((Shbltin_t*)extra)->shp; else { logp = (struct login*)extra; shp = logp->sh; } pp = (struct checkpt*)shp->jmplist; if(sh_isoption(SH_RESTRICTED)) errormsg(SH_DICT,ERROR_exit(1),e_restricted,argv[0]); else { register struct argnod *arg=shp->envlist; register Namval_t* np; register char *cp; if(shp->subshell && !shp->subshare) sh_subfork(); if(logp && logp->clear) { #ifdef _ENV_H env_close(shp->env); shp->env = env_open((char**)0,3); #else nv_scan(shp->var_tree,noexport,0,NV_EXPORT,NV_EXPORT); #endif } while(arg) { if((cp=strchr(arg->argval,'=')) && (*cp=0,np=nv_search(arg->argval,shp->var_tree,0))) { nv_onattr(np,NV_EXPORT); sh_envput(shp->env,np); } if(cp) *cp = '='; arg=arg->argnxt.ap; } pname = argv[0]; if(logp && logp->arg0) argv[0] = logp->arg0; #ifdef JOBS if(job_close(shp) < 0) return(1); #endif /* JOBS */ /* force bad exec to terminate shell */ pp->mode = SH_JMPEXIT; sh_sigreset(2); sh_freeup(shp); path_exec(pname,argv,NIL(struct argnod*)); sh_done(shp,0); } return(1); }
static void r_comarg(Shell_t *shp,struct comnod *com) { char *cmdname=0; com->comio = r_redirect(shp); com->comset = r_arg(shp); com->comstate = 0; if(com->comtyp&COMSCAN) { com->comarg = r_arg(shp); if(com->comarg->argflag==ARG_RAW) cmdname = com->comarg->argval; } else if(com->comarg = (struct argnod*)r_comlist(shp)) cmdname = ((struct dolnod*)(com->comarg))->dolval[ARG_SPARE]; com->comline = sfgetu(infile); com->comnamq = 0; if(cmdname) { char *cp; com->comnamp = (void*)nv_search(cmdname,shp->fun_tree,0); if(com->comnamp && (cp =strrchr(cmdname+1,'.'))) { *cp = 0; com->comnamp = (void*)nv_open(cmdname,shp->var_tree,NV_VARNAME|NV_NOADD|NV_NOARRAY); *cp = '.'; } } else com->comnamp = 0; }
// // Look for edit macro named _i. If found, puts the macro definition into lookahead buffer and // returns 1. // int ed_macro(Edit_t *ep, int i) { char *out; Namval_t *np; genchar buff[LOOKAHEAD + 1]; if (i != '@') ep->e_macro[1] = i; // Undocumented feature, macros of the form <ESC>[c evoke alias __c. if (i == '_') { ep->e_macro[2] = ed_getchar(ep, 1); } else { ep->e_macro[2] = 0; } if (isalnum(i) && (np = nv_search(ep->e_macro, ep->sh->alias_tree, 0)) && (out = nv_getval(np))) { // Copy to buff in internal representation. int c = 0; if (strlen(out) > LOOKAHEAD) { c = out[LOOKAHEAD]; out[LOOKAHEAD] = 0; } i = ed_internal(out, buff); if (c) out[LOOKAHEAD] = c; while (i-- > 0) ed_ungetchar(ep, buff[i]); return 1; } return 0; }
void lib_init(int flag, void* context) { Shell_t *shp = ((Shbltin_t*)context)->shp; Namval_t *mp,*bp; if(flag) return; bp = sh_addbuiltin(shp,"Enum", enum_create, (void*)0); mp = nv_search("typeset",shp->bltin_tree,0); nv_onattr(bp,nv_isattr(mp,NV_PUBLIC)); }
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); }
// // Builtin `login`. // int B_login(int argc, char *argv[], Shbltin_t *context) { checkpt_t *pp; struct login *logp = NULL; Shell_t *shp; const char *pname; if (argc) { shp = context->shp; } else { logp = (struct login *)context; shp = logp->sh; } pp = shp->jmplist; if (sh_isoption(shp, SH_RESTRICTED)) { errormsg(SH_DICT, ERROR_exit(1), e_restricted, argv[0]); __builtin_unreachable(); } else { struct argnod *arg = shp->envlist; Namval_t *np; char *cp; if (shp->subshell && !shp->subshare) sh_subfork(); if (logp && logp->clear) { nv_scan(shp->var_tree, noexport, 0, NV_EXPORT, NV_EXPORT); } while (arg) { cp = strchr(arg->argval, '='); if (cp && (*cp = 0, np = nv_search(arg->argval, shp->var_tree, 0))) { nv_onattr(np, NV_EXPORT); sh_envput(shp, np); } if (cp) *cp = '='; arg = arg->argnxt.ap; } pname = argv[0]; if (logp && logp->arg0) argv[0] = logp->arg0; #ifdef JOBS if (job_close(shp) < 0) return 1; #endif // JOBS // Force bad exec to terminate shell. pp->mode = SH_JMPEXIT; sh_sigreset(shp, 2); sh_freeup(shp); path_exec(shp, pname, argv, NULL); sh_done(shp, 0); } return 1; }
int b_dot_cmd(register int n,char *argv[],void* extra) { register char *script; register Namval_t *np; register int jmpval; register Shell_t *shp = ((Shbltin_t*)extra)->shp; struct sh_scoped savst, *prevscope = shp->st.self; char *filename=0; int fd; struct dolnod *argsave=0, *saveargfor; struct checkpt buff; Sfio_t *iop=0; short level; while (n = optget(argv,sh_optdot)) switch (n) { 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; script = *argv; if(error_info.errors || !script) errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0)); if(shp->dot_depth+1 > DOTMAX) errormsg(SH_DICT,ERROR_exit(1),e_toodeep,script); if(!(np=shp->posix_fun)) { /* check for KornShell style function first */ np = nv_search(script,shp->fun_tree,0); if(np && is_afunction(np) && !nv_isattr(np,NV_FPOSIX)) { if(!np->nvalue.ip) { path_search(script,NIL(Pathcomp_t**),0); if(np->nvalue.ip) { if(nv_isattr(np,NV_FPOSIX)) np = 0; } else errormsg(SH_DICT,ERROR_exit(1),e_found,script); } }
static int acctinit(History_t *hp) { register char *cp, *acctfile; Namval_t *np = nv_search("ACCTFILE",((Shell_t*)hp->histshell)->var_tree,0); if(!np || !(acctfile=nv_getval(np))) return(0); if(!(cp = getlogin())) { struct passwd *userinfo = getpwuid(getuid()); if(userinfo) cp = userinfo->pw_name; else cp = "unknown"; } logname = strdup(cp); if((acctfd=sh_open(acctfile, O_BINARY|O_WRONLY|O_APPEND|O_CREAT,S_IRUSR|S_IWUSR))>=0 && (unsigned)acctfd < 10) { int n; if((n = fcntl(acctfd, F_DUPFD, 10)) >= 0) { close(acctfd); acctfd = n; } } if(acctfd < 0) { acctfd = 0; return(0); } if(sh_isdevfd(acctfile)) { char newfile[16]; sfsprintf(newfile,sizeof(newfile),"%.8s%d\0",e_devfdNN,acctfd); nv_putval(np,newfile,NV_RDONLY); } else fcntl(acctfd,F_SETFD,FD_CLOEXEC); return(1); }
/* * look for edit macro named _i * if found, puts the macro definition into lookahead buffer and returns 1 */ int ed_macro(Edit_t *ep, register int i) { register char *out; Namval_t *np; genchar buff[LOOKAHEAD+1]; if(i != '@') ep->e_macro[1] = i; /* undocumented feature, macros of the form <ESC>[c evoke alias __c */ if(i=='_') ep->e_macro[2] = ed_getchar(ep,1); else ep->e_macro[2] = 0; if (isalnum(i)&&(np=nv_search(ep->e_macro,ep->sh->alias_tree,HASH_SCOPE))&&(out=nv_getval(np))) { #if SHOPT_MULTIBYTE /* copy to buff in internal representation */ int c = 0; if( strlen(out) > LOOKAHEAD ) { c = out[LOOKAHEAD]; out[LOOKAHEAD] = 0; } i = ed_internal(out,buff); if(c) out[LOOKAHEAD] = c; #else strncpy((char*)buff,out,LOOKAHEAD); buff[LOOKAHEAD] = 0; i = strlen((char*)buff); #endif /* SHOPT_MULTIBYTE */ while(i-- > 0) ed_ungetchar(ep,buff[i]); return(1); } return(0); }
void ed_setup(register Edit_t *ep, int fd, int reedit) { Shell_t *shp = ep->sh; register char *pp; register char *last, *prev; char *ppmax; int myquote = 0, n; register int qlen = 1, qwid; char inquote = 0; ep->e_fd = fd; ep->e_multiline = sh_isoption(SH_MULTILINE)!=0; #ifdef SIGWINCH if(!(shp->sigflag[SIGWINCH]&SH_SIGFAULT)) { signal(SIGWINCH,sh_fault); shp->sigflag[SIGWINCH] |= SH_SIGFAULT; } pp = shp->st.trapcom[SIGWINCH]; shp->st.trapcom[SIGWINCH] = 0; sh_fault(SIGWINCH); shp->st.trapcom[SIGWINCH] = pp; ep->sh->winch = 0; #endif #if SHOPT_EDPREDICT ep->hlist = 0; ep->nhlist = 0; ep->hoff = 0; #endif /* SHOPT_EDPREDICT */ #if KSHELL ep->e_stkptr = stakptr(0); ep->e_stkoff = staktell(); if(!(last = shp->prompt)) last = ""; shp->prompt = 0; #else last = ep->e_prbuff; #endif /* KSHELL */ if(shp->gd->hist_ptr) { register History_t *hp = shp->gd->hist_ptr; ep->e_hismax = hist_max(hp); ep->e_hismin = hist_min(hp); } else { ep->e_hismax = ep->e_hismin = ep->e_hloff = 0; } ep->e_hline = ep->e_hismax; if(!sh_isoption(SH_VI) && !sh_isoption(SH_EMACS) && !sh_isoption(SH_GMACS)) ep->e_wsize = MAXLINE; else ep->e_wsize = ed_window()-2; ep->e_winsz = ep->e_wsize+2; ep->e_crlf = 1; ep->e_plen = 0; pp = ep->e_prompt; ppmax = pp+PRSIZE-1; *pp++ = '\r'; { register int c; while(prev = last, c = mbchar(last)) switch(c) { case ESC: { int skip=0; ep->e_crlf = 0; *pp++ = c; for(n=1; c = *last++; n++) { if(pp < ppmax) *pp++ = c; if(c=='\a' || c==ESC || c=='\r') break; if(skip || (c>='0' && c<='9')) { skip = 0; continue; } if(n>1 && c==';') skip = 1; else if(n>2 || (c!= '[' && c!= ']')) break; } if(c==0 || c==ESC || c=='\r') last--; qlen += (n+1); break; } case '\b': if(pp>ep->e_prompt+1) pp--; break; case '\r': if(pp == (ep->e_prompt+2)) /* quote char */ myquote = *(pp-1); /*FALLTHROUGH*/ case '\n': /* start again */ ep->e_crlf = 1; qlen = 1; inquote = 0; pp = ep->e_prompt+1; break; case '\t': /* expand tabs */ while((pp-ep->e_prompt)%TABSIZE) { if(pp >= ppmax) break; *pp++ = ' '; } break; case '\a': /* cut out bells */ break; default: if(c==myquote) { qlen += inquote; inquote ^= 1; } if(pp < ppmax) { if(inquote) qlen++; else if(!is_print(c)) ep->e_crlf = 0; if((qwid = last - prev) > 1) qlen += qwid - mbwidth(c); while(prev < last && pp < ppmax) *pp++ = *prev++; } break; } } if(pp-ep->e_prompt > qlen) ep->e_plen = pp - ep->e_prompt - qlen; *pp = 0; if(!ep->e_multiline && (ep->e_wsize -= ep->e_plen) < 7) { register int shift = 7-ep->e_wsize; ep->e_wsize = 7; pp = ep->e_prompt+1; strcpy(pp,pp+shift); ep->e_plen -= shift; last[-ep->e_plen-2] = '\r'; } sfsync(sfstderr); if(fd == sffileno(sfstderr)) { /* can't use output buffer when reading from stderr */ static char *buff; if(!buff) buff = (char*)malloc(MAXLINE); ep->e_outbase = ep->e_outptr = buff; ep->e_outlast = ep->e_outptr + MAXLINE; return; } qlen = sfset(sfstderr,SF_READ,0); /* make sure SF_READ not on */ ep->e_outbase = ep->e_outptr = (char*)sfreserve(sfstderr,SF_UNBOUND,SF_LOCKR); ep->e_outlast = ep->e_outptr + sfvalue(sfstderr); if(qlen) sfset(sfstderr,SF_READ,1); sfwrite(sfstderr,ep->e_outptr,0); ep->e_eol = reedit; if(ep->e_multiline) { #ifdef _cmd_tput char *term; if(!ep->e_term) ep->e_term = nv_search("TERM",shp->var_tree,0); if(ep->e_term && (term=nv_getval(ep->e_term)) && strlen(term)<sizeof(ep->e_termname) && strcmp(term,ep->e_termname)) { sh_trap(".sh.subscript=$(tput cuu1 2>/dev/null)",0); if(pp=nv_getval(SH_SUBSCRNOD)) strncpy(CURSOR_UP,pp,sizeof(CURSOR_UP)-1); nv_unset(SH_SUBSCRNOD); strcpy(ep->e_termname,term); } #endif ep->e_wsize = MAXLINE - (ep->e_plen+1); } if(ep->e_default && (pp = nv_getval(ep->e_default))) { n = strlen(pp); if(n > LOOKAHEAD) n = LOOKAHEAD; ep->e_lookahead = n; while(n-- > 0) ep->e_lbuf[n] = *pp++; ep->e_default = 0; } }
int ed_expand(Edit_t *ep, char outbuff[],int *cur,int *eol,int mode, int count) { struct comnod *comptr; struct argnod *ap; register char *out; char *av[2], *begin , *dir=0; int addstar=0, rval=0, var=0, strip=1; int nomarkdirs = !sh_isoption(SH_MARKDIRS); sh_onstate(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 { stakset(ep->e_stkptr,ep->e_stkoff); ep->e_nlist = 0; } } comptr = (struct comnod*)stakalloc(sizeof(struct comnod)); ap = (struct argnod*)stakseek(ARGVAL); #if SHOPT_MULTIBYTE { register int c = *cur; register genchar *cp; /* adjust cur */ cp = (genchar *)outbuff + *cur; c = *cp; *cp = 0; *cur = ed_external((genchar*)outbuff,(char*)stakptr(0)); *cp = c; *eol = ed_external((genchar*)outbuff,outbuff); } #endif /* SHOPT_MULTIBYTE */ out = outbuff + *cur + (sh_isoption(SH_VI)!=0); if(out[-1]=='"' || out[-1]=='\'') { rval = -(sh_isoption(SH_VI)!=0); goto done; } comptr->comtyp = COMSCAN; comptr->comarg = ap; ap->argflag = (ARG_MAC|ARG_EXP); ap->argnxt.ap = 0; ap->argchn.cp = 0; { register int c; char *last = out; c = *(unsigned char*)out; var = mode; begin = out = find_begin(outbuff,last,0,&var); /* addstar set to zero if * should not be added */ if(var=='$') { stakputs("${!"); stakwrite(out,last-out); stakputs("@}"); out = last; } else { addstar = '*'; while(out < last) { c = *(unsigned char*)out; if(isexp(c)) addstar = 0; if (c == '/') { if(addstar == 0) strip = 0; dir = out+1; } stakputc(c); out++; } } if(mode=='?') mode = '*'; if(var!='$' && mode=='\\' && out[-1]!='*') addstar = '*'; if(*begin=='~' && !strchr(begin,'/')) addstar = 0; stakputc(addstar); ap = (struct argnod*)stakfreeze(1); } if(mode!='*') sh_onoption(SH_MARKDIRS); { register char **com; char *cp=begin, *left=0, *saveout="."; int nocase=0,narg,cmd_completion=0; register int size='x'; while(cp>outbuff && ((size=cp[-1])==' ' || size=='\t')) cp--; if(!var && !strchr(ap->argval,'/') && (((cp==outbuff&&ep->sh->nextprompt==1) || (strchr(";&|(",size)) && (cp==outbuff+1||size=='('||cp[-2]!='>') && *begin!='~' ))) { cmd_completion=1; sh_onstate(SH_COMPLETE); } if(ep->e_nlist) { narg = 1; com = av; if(dir) begin += (dir-begin); } else { com = sh_argbuild(ep->sh,&narg,comptr,0); /* special handling for leading quotes */ if(begin>outbuff && (begin[-1]=='"' || begin[-1]=='\'')) begin--; } sh_offstate(SH_COMPLETE); /* allow a search to be aborted */ if(ep->sh->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) { register char **ptrcom; for(ptrcom=com;*ptrcom;ptrcom++) /* trim directory prefix */ *ptrcom = path_basename(*ptrcom); } sfputc(sfstderr,'\n'); sh_menu(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; saveout = begin; } if(saveout=astconf("PATH_ATTRIBUTES",saveout,(char*)0)) nocase = (strchr(saveout,'c')!=0); if(dir) *dir = c; /* just expand until name is unique */ size += strlen(*com); } else { size += narg; { char **savcom = com; while (*com) size += strlen(cp=fmtx(*com++)); com = savcom; } } /* 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=stakcopy(out); if(cmd_completion && mode=='\\') out = strcopy(begin,path_basename(cp= *com++)); else if(mode=='*') { if(ep->e_nlist && dir && var) { if(*cp==var) cp++; else *begin++ = var; out = strcopy(begin,cp); var = 0; } else out = strcopy(begin,fmtx(*com)); com++; } else out = strcopy(begin,*com++); if(mode=='\\') { saveout= ++out; while (*com && *begin) { if(cmd_completion) out = overlaid(begin,path_basename(*com++),nocase); else out = overlaid(begin,*com++,nocase); } 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(ep->sh->pathlist,cp,'/')) && (np=nv_search(begin,ep->sh->track_tree,NV_ADD))) path_alias(np,pp); out = strcopy(begin,cp); } /* add quotes if necessary */ if((cp=fmtx(begin))!=begin) out = strcopy(begin,cp); if(var=='$' && begin[-1]=='{') *out = '}'; else *out = ' '; *++out = 0; } else if((cp=fmtx(begin))!=begin) { out = strcopy(begin,cp); if(out[-1] =='"' || out[-1]=='\'') *--out = 0; } if(*begin==0) ed_ringbell(); } else { while (*com) { *out++ = ' '; out = strcopy(out,fmtx(*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 = strcopy(out,left); *eol = (out-outbuff); } done: sh_offstate(SH_FCOMPLETE); if(!ep->e_nlist) stakset(ep->e_stkptr,ep->e_stkoff); if(nomarkdirs) sh_offoption(SH_MARKDIRS); #if SHOPT_MULTIBYTE { register int c,n=0; /* first re-adjust cur */ c = outbuff[*cur]; outbuff[*cur] = 0; for(out=outbuff; *out;n++) mbchar(out); outbuff[*cur] = c; *cur = n; outbuff[*eol+1] = 0; *eol = ed_internal(outbuff,(genchar*)outbuff); } #endif /* SHOPT_MULTIBYTE */ return(rval); }
static int whence(Shell_t *shp,char **argv, register int flags) { register const char *name; register Namval_t *np; register const char *cp; register int aflag,r=0; register const char *msg; int tofree; Dt_t *root; Namval_t *nq; char *notused; Pathcomp_t *pp=0; int notrack = 1; if(flags&Q_FLAG) flags &= ~A_FLAG; while(name= *argv++) { tofree=0; aflag = ((flags&A_FLAG)!=0); cp = 0; np = 0; if(flags&P_FLAG) goto search; if(flags&Q_FLAG) goto bltins; /* reserved words first */ if(sh_lookup(name,shtab_reserved)) { sfprintf(sfstdout,"%s%s\n",name,(flags&V_FLAG)?sh_translate(is_reserved):""); if(!aflag) continue; aflag++; } /* non-tracked aliases */ if((np=nv_search(name,shp->alias_tree,0)) && !nv_isnull(np) && !(notrack=nv_isattr(np,NV_TAGGED)) && (cp=nv_getval(np))) { if(flags&V_FLAG) { if(nv_isattr(np,NV_EXPORT)) msg = sh_translate(is_xalias); else msg = sh_translate(is_alias); sfprintf(sfstdout,msg,name); } sfputr(sfstdout,sh_fmtq(cp),'\n'); if(!aflag) continue; cp = 0; aflag++; } /* built-ins and functions next */ bltins: root = (flags&F_FLAG)?shp->bltin_tree:shp->fun_tree; if(np= nv_bfsearch(name, root, &nq, ¬used)) { if(is_abuiltin(np) && nv_isnull(np)) goto search; cp = ""; if(flags&V_FLAG) { if(nv_isnull(np)) cp = sh_translate(is_ufunction); else if(is_abuiltin(np)) { if(nv_isattr(np,BLT_SPC)) cp = sh_translate(is_spcbuiltin); else cp = sh_translate(is_builtin); } else cp = sh_translate(is_function); } if(flags&Q_FLAG) continue; sfprintf(sfstdout,"%s%s\n",name,cp); if(!aflag) continue; cp = 0; aflag++; } search: if(sh_isstate(SH_DEFPATH)) { cp=0; notrack=1; } do { if(path_search(shp,name,&pp,2+(aflag>1))) { cp = name; if((flags&P_FLAG) && *cp!='/') cp = 0; } else { cp = stakptr(PATH_OFFSET); if(*cp==0) cp = 0; else if(*cp!='/') { cp = path_fullname(shp,cp); tofree=1; } } if(flags&Q_FLAG) { pp = 0; r |= !cp; } else if(cp) { if(flags&V_FLAG) { if(*cp!= '/') { if(!np && (np=nv_search(name,shp->track_tree,0))) sfprintf(sfstdout,"%s %s %s/%s\n",name,sh_translate(is_talias),path_pwd(shp,0),cp); else if(!np || nv_isnull(np)) sfprintf(sfstdout,"%s%s\n",name,sh_translate(is_ufunction)); continue; } sfputr(sfstdout,sh_fmtq(name),' '); /* built-in version of program */ if(*cp=='/' && (np=nv_search(cp,shp->bltin_tree,0))) msg = sh_translate(is_builtver); /* tracked aliases next */ else if(aflag>1 || !notrack || strchr(name,'/')) msg = sh_translate("is"); else msg = sh_translate(is_talias); sfputr(sfstdout,msg,' '); } sfputr(sfstdout,sh_fmtq(cp),'\n'); if(aflag) { if(aflag<=1) aflag++; if (pp) pp = pp->next; } else pp = 0; if(tofree) { free((char*)cp); tofree = 0; } } else if(aflag<=1) { r |= 1; if(flags&V_FLAG) errormsg(SH_DICT,ERROR_exit(0),e_found,sh_fmtq(name)); } } while(pp); } return(r); }
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; }
// // 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_dot_cmd(int n, char *argv[], Shbltin_t *context) { char *script; Namval_t *np; int jmpval; Shell_t *shp = context->shp; struct sh_scoped savst, *prevscope = shp->st.self; int fd; char *filename = NULL; char *buffer = NULL; struct dolnod *saveargfor = NULL; volatile struct dolnod *argsave = NULL; checkpt_t buff; Sfio_t *iop = NULL; short level; Optdisc_t disc; memset(&disc, 0, sizeof(disc)); disc.version = OPT_VERSION; opt_info.disc = &disc; while ((n = optget(argv, sh_optdot))) { switch (n) { case ':': { errormsg(SH_DICT, 2, "%s", opt_info.arg); break; } case '?': { errormsg(SH_DICT, ERROR_usage(0), "%s", opt_info.arg); return 2; } default: { break; } } } argv += opt_info.index; script = *argv; if (error_info.errors || !script) { errormsg(SH_DICT, ERROR_usage(2), "%s", optusage(NULL)); __builtin_unreachable(); } if (shp->dot_depth + 1 > DOTMAX) { errormsg(SH_DICT, ERROR_exit(1), e_toodeep, script); __builtin_unreachable(); } np = shp->posix_fun; if (!np) { // Check for KornShell style function first. np = nv_search(script, shp->fun_tree, 0); if (np && is_afunction(np) && !nv_isattr(np, NV_FPOSIX)) { if (!FETCH_VT(np->nvalue, ip)) { // TODO: Replace this with a comment explaining why the return value of this // path_search() call is ignored. At the time I wrote this (2019-03-16) no unit test // exercises this statement. I added the void cast to silence Coverity Scan 253792. (void)path_search(shp, script, NULL, 0); if (FETCH_VT(np->nvalue, ip)) { if (nv_isattr(np, NV_FPOSIX)) np = NULL; } else { errormsg(SH_DICT, ERROR_exit(1), e_found, script); __builtin_unreachable(); } } } else { np = NULL; } if (!np) { fd = path_open(shp, script, path_get(shp, script)); if (fd < 0) { errormsg(SH_DICT, ERROR_system(1), e_open, script); __builtin_unreachable(); } filename = path_fullname(shp, stkptr(shp->stk, PATH_OFFSET)); } } *prevscope = shp->st; shp->st.lineno = np ? ((struct functnod *)nv_funtree(np))->functline : 1; shp->st.var_local = shp->st.save_tree = shp->var_tree; if (filename) { shp->st.filename = filename; shp->st.lineno = 1; } level = shp->fn_depth + shp->dot_depth + 1; nv_putval(SH_LEVELNOD, (char *)&level, NV_INT16); shp->st.prevst = prevscope; shp->st.self = &savst; shp->topscope = (Shscope_t *)shp->st.self; prevscope->save_tree = shp->var_tree; if (np) { struct Ufunction *rp = FETCH_VT(np->nvalue, rp); shp->st.filename = strdup(rp->fname ? rp->fname : ""); } nv_putval(SH_PATHNAMENOD, shp->st.filename, NV_NOFREE); shp->posix_fun = NULL; if (np || argv[1]) argsave = sh_argnew(shp, argv, &saveargfor); sh_pushcontext(shp, &buff, SH_JMPDOT); jmpval = sigsetjmp(buff.buff, 0); if (jmpval == 0) { shp->dot_depth++; if (np) { sh_exec(shp, (Shnode_t *)(nv_funtree(np)), sh_isstate(shp, SH_ERREXIT)); } else { buffer = malloc(IOBSIZE + 1); iop = sfnew(NULL, buffer, IOBSIZE, fd, SF_READ); sh_offstate(shp, SH_NOFORK); sh_eval(shp, iop, sh_isstate(shp, SH_PROFILE) ? SH_FUNEVAL : 0); } } sh_popcontext(shp, &buff); if (buffer) free(buffer); if (!np) { free(shp->st.filename); shp->st.filename = NULL; } shp->dot_depth--; if ((np || argv[1]) && jmpval != SH_JMPSCRIPT) { sh_argreset(shp, (struct dolnod *)argsave, saveargfor); } else { prevscope->dolc = shp->st.dolc; prevscope->dolv = shp->st.dolv; } if (shp->st.self != &savst) *shp->st.self = shp->st; // Only restore the top Shscope_t portion for posix functions. memcpy(&shp->st, prevscope, sizeof(Shscope_t)); shp->topscope = (Shscope_t *)prevscope; nv_putval(SH_PATHNAMENOD, shp->st.filename, NV_NOFREE); if (jmpval && jmpval != SH_JMPFUN) siglongjmp(shp->jmplist->buff, jmpval); return shp->exitval; }