static void* stkpush(Stk_t* sp, size_t size) { Stk_frame_t* f; Stk_pos_t p; stknew(sp, &p); size = sizeof(Stk_frame_t) + sizeof(size_t) + size - 1; if (!(f = (Stk_frame_t*)stkalloc(sp, sizeof(Stk_frame_t) + sizeof(Stk_frame_t*) + size - 1))) return 0; f->pos = p; stkframe(sp) = f; return f->data; }
static struct dolnod *r_comlist(Shell_t *shp) { register struct dolnod *dol=0; register long l; register char **argv; if((l=sfgetl(infile))>0) { dol = (struct dolnod*)stkalloc(shp->stk,sizeof(struct dolnod) + sizeof(char*)*(l+ARG_SPARE)); dol->dolnum = l; dol->dolbot = ARG_SPARE; argv = dol->dolval+ARG_SPARE; while(*argv++ = r_string(shp->stk)); } return(dol); }
static char *r_string(Stk_t *stkp) { register Sfio_t *in = infile; register unsigned long l = sfgetu(in); register char *ptr; if(l == 0) return(NIL(char*)); ptr = stkalloc(stkp,(unsigned)l); if(--l > 0) { if(sfread(in,ptr,(size_t)l)!=(size_t)l) return(NIL(char*)); ccmaps(ptr, l, CC_ASCII, CC_NATIVE); } ptr[l] = 0; return(ptr); }
/* * read in a shell tree */ static Shnode_t *r_tree(Shell_t *shp) { long l = sfgetl(infile); register int type; register Shnode_t *t=0; if(l<0) return(t); type = l; switch(type&COMMSK) { case TTIME: case TPAR: t = getnode(shp->stk,parnod); t->par.partre = r_tree(shp); break; case TCOM: t = getnode(shp->stk,comnod); t->tre.tretyp = type; r_comarg(shp,(struct comnod*)t); break; case TSETIO: case TFORK: t = getnode(shp->stk,forknod); t->fork.forkline = sfgetu(infile); t->fork.forktre = r_tree(shp); t->fork.forkio = r_redirect(shp); break; case TIF: t = getnode(shp->stk,ifnod); t->if_.iftre = r_tree(shp); t->if_.thtre = r_tree(shp); t->if_.eltre = r_tree(shp); break; case TWH: t = getnode(shp->stk,whnod); t->wh.whinc = (struct arithnod*)r_tree(shp); t->wh.whtre = r_tree(shp); t->wh.dotre = r_tree(shp); break; case TLST: case TAND: case TORF: case TFIL: t = getnode(shp->stk,lstnod); t->lst.lstlef = r_tree(shp); t->lst.lstrit = r_tree(shp); break; case TARITH: t = getnode(shp->stk,arithnod); t->ar.arline = sfgetu(infile); t->ar.arexpr = r_arg(shp); t->ar.arcomp = 0; if((t->ar.arexpr)->argflag&ARG_RAW) t->ar.arcomp = sh_arithcomp((t->ar.arexpr)->argval); break; case TFOR: t = getnode(shp->stk,fornod); t->for_.forline = 0; if(type&FLINENO) t->for_.forline = sfgetu(infile); t->for_.fortre = r_tree(shp); t->for_.fornam = r_string(shp->stk); t->for_.forlst = (struct comnod*)r_tree(shp); break; case TSW: t = getnode(shp->stk,swnod); t->sw.swline = 0; if(type&FLINENO) t->sw.swline = sfgetu(infile); t->sw.swarg = r_arg(shp); if(type&COMSCAN) t->sw.swio = r_redirect(shp); else t->sw.swio = 0; t->sw.swlst = r_switch(shp); break; case TFUN: { Stak_t *savstak; struct slnod *slp; struct functnod *fp; t = getnode(shp->stk,functnod); t->funct.functloc = -1; t->funct.functline = sfgetu(infile); t->funct.functnam = r_string(shp->stk); savstak = stakcreate(STAK_SMALL); savstak = stakinstall(savstak, 0); slp = (struct slnod*)stkalloc(shp->stk,sizeof(struct slnod)+sizeof(struct functnod)); slp->slchild = 0; slp->slnext = shp->st.staklist; shp->st.staklist = 0; fp = (struct functnod*)(slp+1); memset(fp, 0, sizeof(*fp)); fp->functtyp = TFUN|FAMP; if(shp->st.filename) fp->functnam = stkcopy(shp->stk,shp->st.filename); t->funct.functtre = r_tree(shp); t->funct.functstak = slp; slp->slptr = stakinstall(savstak,0); slp->slchild = shp->st.staklist; t->funct.functargs = (struct comnod*)r_tree(shp); break; } case TTST: t = getnode(shp->stk,tstnod); t->tst.tstline = sfgetu(infile); if((type&TPAREN)==TPAREN) t->lst.lstlef = r_tree(shp); else { t->lst.lstlef = (Shnode_t*)r_arg(shp); if((type&TBINARY)) t->lst.lstrit = (Shnode_t*)r_arg(shp); } } if(t) t->tre.tretyp = type; return(t); }
// // 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; }