static void printshfuncnode(HashNode hn, int printflags) { Shfunc f = (Shfunc) hn; char *t = 0; if ((printflags & PRINT_NAMEONLY) || ((printflags & PRINT_WHENCE_SIMPLE) && !(printflags & PRINT_WHENCE_FUNCDEF))) { zputs(f->node.nam, stdout); putchar('\n'); return; } if ((printflags & (PRINT_WHENCE_VERBOSE|PRINT_WHENCE_WORD)) && !(printflags & PRINT_WHENCE_FUNCDEF)) { nicezputs(f->node.nam, stdout); printf((printflags & PRINT_WHENCE_WORD) ? ": function\n" : " is a shell function\n"); return; } quotedzputs(f->node.nam, stdout); if (f->funcdef || f->node.flags & PM_UNDEFINED) { printf(" () {\n\t"); if (f->node.flags & PM_UNDEFINED) printf("%c undefined\n\t", hashchar); else t = getpermtext(f->funcdef, NULL, 1); if (f->node.flags & PM_TAGGED) printf("%c traced\n\t", hashchar); if (!t) { char *fopt = "Utkz"; int flgs[] = { PM_UNALIASED, PM_TAGGED, PM_KSHSTORED, PM_ZSHSTORED, 0 }; int fl;; zputs("builtin autoload -X", stdout); for (fl=0;fopt[fl];fl++) if (f->node.flags & flgs[fl]) putchar(fopt[fl]); } else { zputs(t, stdout); zsfree(t); if (f->funcdef->flags & EF_RUN) { printf("\n\t"); quotedzputs(f->node.nam, stdout); printf(" \"$@\""); } } printf("\n}\n"); } else { printf(" () { }\n"); } }
static void checksched(void) { time_t t; struct schedcmd *sch; if(!schedcmds) return; t = time(NULL); /* * List is ordered, so we only need to consider the * head element. */ while (schedcmds && schedcmds->time <= t) { /* * Remove the entry to be executed from the list * before execution: this makes quite sure that * the entry hasn't been monkeyed with when we * free it. */ sch = schedcmds; schedcmds = sch->next; /* * Delete from the timed function list now in case * the called code reschedules. */ scheddeltimed(); if ((sch->flags & SCHEDFLAG_TRASH_ZLE) && zleactive) zleentry(ZLE_CMD_TRASH); execstring(sch->cmd, 0, 0, "sched"); zsfree(sch->cmd); zfree(sch, sizeof(struct schedcmd)); /* * Fix time for future events. * I had this outside the loop, for a little extra efficiency. * However, it then occurred to me that having the list of * forthcoming entries up to date could be regarded as * a feature, and the inefficiency is negligible. * * Careful in case the code we called has already set * up a timed event; if it has, that'll be up to date since * we haven't changed the list here. */ if (schedcmds && !schedcmdtimed) { /* * We've already delete the function from the list. */ DPUTS(timedfns && firstnode(timedfns), "BUG: already timed fn (1)"); schedaddtimed(schedcmds->time); } } }
static void set_buffer(UNUSED(Param pm), char *x) { if(x) { setline(x, 0); zsfree(x); } else zlecs = zlell = 0; fixsuffix(); menucmp = 0; }
static void freepfuncs(Pfunc f) { Pfunc n; for (; f; f = n) { n = f->next; zsfree(f->name); zfree(f, sizeof(*f)); } }
mod_export void ignore_suffix(int l) { if (l) { char *tmp, sav; int sl = strlen(compsuffix); if ((l = sl - l) < 0) l = 0; tmp = tricat(compsuffix + l, compisuffix, ""); zsfree(compisuffix); compisuffix = tmp; sav = compsuffix[l]; compsuffix[l] = '\0'; tmp = ztrdup(compsuffix); compsuffix[l] = sav; zsfree(compsuffix); compsuffix = tmp; } }
mod_export void makesuffixstr(char *f, char *s, int n) { if (f) { zsfree(suffixfunc); suffixfunc = ztrdup(f); suffixfunclen = n; } else if (s) { int inv, i, z = 0; ZLE_STRING_T ws, lasts, wptr; if (*s == '^' || *s == '!') { inv = 1; s++; } else inv = 0; s = getkeystring(s, &i, GETKEYS_SUFFIX, &z); s = metafy(s, i, META_USEHEAP); ws = stringaszleline(s, 0, &i, NULL, NULL); /* Remove suffix on uninsertable characters if \- was given * * and the character class wasn't negated -- or vice versa. */ suffixnoinsrem = z ^ inv; suffixlen = n; lasts = wptr = ws; while (i) { if (i >= 3 && wptr[1] == ZWC('-')) { ZLE_CHAR_T str[2]; if (wptr > lasts) addsuffix(inv ? SUFTYP_NEGSTR : SUFTYP_POSSTR, 0, lasts, wptr - lasts, n); str[0] = *wptr; str[1] = wptr[2]; addsuffix(inv ? SUFTYP_NEGRNG : SUFTYP_POSRNG, 0, str, 2, n); wptr += 3; i -= 3; lasts = wptr; } else { wptr++; i--; } } if (wptr > lasts) addsuffix(inv ? SUFTYP_NEGSTR : SUFTYP_POSSTR, 0, lasts, wptr - lasts, n); free(ws); } else makesuffix(n); }
mod_export void ignore_prefix(int l) { if (l) { char *tmp, sav; int pl = strlen(compprefix); if (l > pl) l = pl; sav = compprefix[l]; compprefix[l] = '\0'; tmp = tricat(compiprefix, compprefix, ""); zsfree(compiprefix); compiprefix = tmp; compprefix[l] = sav; tmp = ztrdup(compprefix + l); zsfree(compprefix); compprefix = tmp; } }
static void freeshfuncnode(HashNode hn) { Shfunc shf = (Shfunc) hn; zsfree(shf->node.nam); if (shf->funcdef) freeeprog(shf->funcdef); if (shf->redir) freeeprog(shf->redir); zsfree(shf->filename); if (shf->sticky) { if (shf->sticky->n_on_opts) zfree(shf->sticky->on_opts, shf->sticky->n_on_opts * sizeof(*shf->sticky->on_opts)); if (shf->sticky->n_off_opts) zfree(shf->sticky->off_opts, shf->sticky->n_off_opts * sizeof(*shf->sticky->off_opts)); zfree(shf->sticky, sizeof(*shf->sticky)); } zfree(shf, sizeof(struct shfunc)); }
mod_export void addsuffixstring(int tp, int flags, char *chars, int lensuf) { int slen, alloclen; ZLE_STRING_T suffixstr; /* string needs to be writable... I've been regretting this for years.. */ chars = ztrdup(chars); suffixstr = stringaszleline(chars, 0, &slen, &alloclen, NULL); addsuffix(tp, flags, suffixstr, slen, lensuf); zfree(suffixstr, alloclen); zsfree(chars); }
static int domove(char *nam, MoveFunc movefn, char *p, char *q, int flags) { struct stat st; char *pbuf, *qbuf; pbuf = ztrdup(unmeta(p)); qbuf = unmeta(q); if(flags & MV_NODIRS) { errno = EISDIR; if(lstat(pbuf, &st) || S_ISDIR(st.st_mode)) { zwarnnam(nam, "%s: %e", p, errno); zsfree(pbuf); return 1; } } if(!lstat(qbuf, &st)) { int doit = flags & MV_FORCE; if(S_ISDIR(st.st_mode)) { zwarnnam(nam, "%s: cannot overwrite directory", q); zsfree(pbuf); return 1; } else if(flags & MV_INTERACTIVE) { nicezputs(nam, stderr); fputs(": replace `", stderr); nicezputs(q, stderr); fputs("'? ", stderr); fflush(stderr); if(!ask()) { zsfree(pbuf); return 0; } doit = 1; } else if((flags & MV_ASKNW) && !S_ISLNK(st.st_mode) && access(qbuf, W_OK)) { nicezputs(nam, stderr); fputs(": replace `", stderr); nicezputs(q, stderr); fprintf(stderr, "', overriding mode %04o? ", mode_to_octal(st.st_mode)); fflush(stderr); if(!ask()) { zsfree(pbuf); return 0; } doit = 1; } if(doit && !(flags & MV_ATOMIC)) unlink(qbuf); } if(movefn(pbuf, qbuf)) { zwarnnam(nam, "%s: %e", p, errno); zsfree(pbuf); return 1; } zsfree(pbuf); return 0; }
mod_export void freecmlist(Cmlist l) { Cmlist n; while (l) { n = l->next; freecmatcher(l->matcher); zsfree(l->str); zfree(l, sizeof(struct cmlist)); l = n; } }
int cleanup_(Module m) { struct schedcmd *sch, *schn; if (schedcmds) scheddeltimed(); for (sch = schedcmds; sch; sch = schn) { schn = sch->next; zsfree(sch->cmd); zfree(sch, sizeof(*sch)); } delprepromptfn(&checksched); return setfeatureenables(m, &module_features, NULL); }
static void scanfindfunc(char *seq, Thingy func, UNUSED(char *str), void *magic) { struct findfunc *ff = magic; if(func != ff->func) return; if (!ff->found++) ff->msg = appstr(ff->msg, " is on"); if(ff->found <= MAXFOUND) { char *b = bindztrdup(seq); ff->msg = appstr(ff->msg, " "); ff->msg = appstr(ff->msg, b); zsfree(b); } }
int whereis(UNUSED(char **args)) { struct findfunc ff; if (!(ff.func = executenamedcommand("Where is: "))) return 1; ff.found = 0; ff.msg = nicedup(ff.func->nam, 0); scankeymap(curkeymap, 1, scanfindfunc, &ff); if (!ff.found) ff.msg = appstr(ff.msg, " is not bound to any key"); else if(ff.found > MAXFOUND) ff.msg = appstr(ff.msg, " et al"); showmsg(ff.msg); zsfree(ff.msg); return 0; }
static void set_rbuffer(UNUSED(Param pm), char *x) { ZLE_STRING_T y; int len; if (x && *x != ZWC('\0')) y = stringaszleline(x, 0, &len, NULL, NULL); else y = ZWS(""), len = 0; sizeline(zlell = zlecs + len); ZS_memcpy(zleline + zlecs, y, len); zsfree(x); if (len) free(y); fixsuffix(); menucmp = 0; }
mod_export void deletehashtable(HashTable ht) { ht->emptytable(ht); #ifdef ZSH_HASH_DEBUG if(ht->next) ht->next->last = ht->last; else lastht = ht->last; if(ht->last) ht->last->next = ht->next; else firstht = ht->next; zsfree(ht->tablename); #endif /* ZSH_HASH_DEBUG */ zfree(ht->nodes, ht->hsize * sizeof(HashNode)); zfree(ht, sizeof(*ht)); }
char * bindztrdup(char *str) { int c, len = 1; char *buf, *ptr, *ret; for(ptr = str; *ptr; ptr++) { c = *ptr == Meta ? STOUC(*++ptr) ^ 32 : STOUC(*ptr); if(c & 0x80) { len += 3; c &= 0x7f; } if(c < 32 || c == 0x7f) { len++; c ^= 64; } len += c == '\\' || c == '^'; len++; } ptr = buf = zalloc(len); for(; *str; str++) { c = *str == Meta ? STOUC(*++str) ^ 32 : STOUC(*str); if(c & 0x80) { *ptr++ = '\\'; *ptr++ = 'M'; *ptr++ = '-'; c &= 0x7f; } if(c < 32 || c == 0x7f) { *ptr++ = '^'; c ^= 64; } if(c == '\\' || c == '^') *ptr++ = '\\'; *ptr++ = c; } *ptr = 0; ret = dquotedztrdup(buf); zsfree(buf); return ret; }
void printshfuncnode(HashNode hn, int printflags) { Shfunc f = (Shfunc) hn; char *t; if ((printflags & PRINT_NAMEONLY) || ((printflags & PRINT_WHENCE_SIMPLE) && !(printflags & PRINT_WHENCE_FUNCDEF))) { zputs(f->nam, stdout); putchar('\n'); return; } if ((printflags & PRINT_WHENCE_VERBOSE) && !(printflags & PRINT_WHENCE_FUNCDEF)) { nicezputs(f->nam, stdout); printf(" is a shell function\n"); return; } if (f->flags & PM_UNDEFINED) printf("undefined "); if (f->flags & PM_TAGGED) printf("traced "); if (!f->funcdef) { nicezputs(f->nam, stdout); printf(" () { }\n"); return; } t = getpermtext((void *) dupstruct((void *) f->funcdef)); quotedzputs(f->nam, stdout); printf(" () {\n\t"); zputs(t, stdout); printf("\n}\n"); zsfree(t); }
static void promptpath(char *p, int npath, int tilde) { char *modp = p; Nameddir nd; if (tilde && ((nd = finddir(p)))) modp = tricat("~", nd->node.nam, p + strlen(nd->dir)); if (npath) { char *sptr; if (npath > 0) { for (sptr = modp + strlen(modp); sptr > modp; sptr--) { if (*sptr == '/' && !--npath) { sptr++; break; } } if (*sptr == '/' && sptr[1] && sptr != modp) sptr++; stradd(sptr); } else { char cbu; for (sptr = modp+1; *sptr; sptr++) if (*sptr == '/' && !++npath) break; cbu = *sptr; *sptr = 0; stradd(modp); *sptr = cbu; } } else stradd(modp); if (p != modp) zsfree(modp); }
static void compunsetfn(Param pm, int exp) { if (exp) { if (pm->u.data) { if (PM_TYPE(pm->node.flags) == PM_SCALAR) { zsfree(*((char **) pm->u.data)); *((char **) pm->u.data) = ztrdup(""); } else if (PM_TYPE(pm->node.flags) == PM_ARRAY) { freearray(*((char ***) pm->u.data)); *((char ***) pm->u.data) = zshcalloc(sizeof(char *)); } else if (PM_TYPE(pm->node.flags) == PM_HASHED) { deleteparamtable(pm->u.hash); pm->u.hash = NULL; } } } else if (PM_TYPE(pm->node.flags) == PM_HASHED) { Param *p; int i; deletehashtable(pm->u.hash); pm->u.hash = NULL; for (p = compkpms, i = CP_KEYPARAMS; i--; p++) *p = NULL; } if (!exp) { Param *p; int i; for (p = comprpms, i = CP_REALPARAMS; i; p++, i--) if (*p == pm) { *p = NULL; break; } } }
void freehistdata(Histent he, int unlink) { if (!he) return; if (!(he->flags & (HIST_DUP | HIST_TMPSTORE))) removehashnode(histtab, he->text); zsfree(he->text); if (he->nwords) zfree(he->words, he->nwords*2*sizeof(short)); if (unlink) { if (!--histlinect) hist_ring = NULL; else { if (he == hist_ring) hist_ring = hist_ring->up; he->up->down = he->down; he->down->up = he->up; } } }
mod_export void iremovesuffix(ZLE_INT_T c, int keep) { if (suffixfunc) { Shfunc shfunc = getshfunc(suffixfunc); if (shfunc) { LinkList args = newlinklist(); char buf[20]; int osc = sfcontext; int wasmeta = (zlemetaline != 0); if (wasmeta) { /* * The suffix removal function runs as a normal * ZLE function, not a completion function, so * the line should be unmetafied if this was * called from completion. (It may not be since * we may decide to remove the suffix later.) */ unmetafy_line(); } sprintf(buf, "%d", suffixfunclen); addlinknode(args, suffixfunc); addlinknode(args, buf); startparamscope(); makezleparams(0); sfcontext = SFC_COMPLETE; doshfunc(shfunc, args, 1); sfcontext = osc; endparamscope(); if (wasmeta) metafy_line(); } zsfree(suffixfunc); suffixfunc = NULL; } else { int sl = 0, flags = 0; struct suffixset *ss; if (c == NO_INSERT_CHAR) { sl = suffixnoinsrem ? suffixlen : 0; } else { ZLE_CHAR_T ch = c; /* * Search for a match for ch in the suffix list. * We stop if we encounter a match in a positive or negative * list, using the suffix length specified or zero respectively. * If we reached the end and passed through a negative * list, we use the suffix length for that, else zero. * This would break if it were possible to have negative * sets with different suffix length: that's not supposed * to happen. */ int negsuflen = 0, found = 0; for (ss = suffixlist; ss; ss = ss->next) { switch (ss->tp) { case SUFTYP_POSSTR: if (ZS_memchr(ss->chars, ch, ss->lenstr)) { sl = ss->lensuf; found = 1; } break; case SUFTYP_NEGSTR: if (ZS_memchr(ss->chars, ch, ss->lenstr)) { sl = 0; found = 1; } else { negsuflen = ss->lensuf; } break; case SUFTYP_POSRNG: if (ss->chars[0] <= ch && ch <= ss->chars[1]) { sl = ss->lensuf; found = 1; } break; case SUFTYP_NEGRNG: if (ss->chars[0] <= ch && ch <= ss->chars[1]) { sl = 0; found = 1; } else { negsuflen = ss->lensuf; } break; } if (found) { flags = ss->flags; break; } } if (!found) sl = negsuflen; } if (sl) { /* must be shifting wide character lengths */ backdel(sl, CUT_RAW); if (flags & SUFFLAGS_SPACE) { /* Add a space and advance over it */ spaceinline(1); if (zlemetaline) { zlemetaline[zlemetacs++] = ' '; } else { zleline[zlecs++] = ZWC(' '); } } if (!keep) invalidatelist(); } } fixsuffix(); }
Thingy executenamedcommand(char *prmt) { Thingy cmd, retval = NULL; int l, len, feep = 0, listed = 0, curlist = 0; int ols = (listshown && validlist), olll = lastlistlen; char *cmdbuf, *ptr; char *okeymap = ztrdup(curkeymapname); clearlist = 1; /* prmt may be constant */ prmt = ztrdup(prmt); l = strlen(prmt); cmdbuf = (char *)zhalloc(l + NAMLEN + 2 #ifdef MULTIBYTE_SUPPORT + 2 * MB_CUR_MAX #endif ); strcpy(cmdbuf, prmt); zsfree(prmt); statusline = cmdbuf; selectlocalmap(command_keymap); selectkeymap("main", 1); ptr = cmdbuf += l; len = 0; for (;;) { *ptr = '_'; ptr[1] = '\0'; zrefresh(); if (!(cmd = getkeycmd()) || cmd == Th(z_sendbreak)) { statusline = NULL; selectkeymap(okeymap, 1); zsfree(okeymap); if ((listshown = ols)) { showinglist = -2; lastlistlen = olll; } else if (listed) clearlist = listshown = 1; retval = NULL; goto done; } if(cmd == Th(z_clearscreen)) { clearscreen(zlenoargs); if (curlist) { int zmultsav = zmult; zmult = 1; listlist(namedcmdll); showinglist = 0; zmult = zmultsav; } } else if(cmd == Th(z_redisplay)) { redisplay(zlenoargs); if (curlist) { int zmultsav = zmult; zmult = 1; listlist(namedcmdll); showinglist = 0; zmult = zmultsav; } } else if(cmd == Th(z_viquotedinsert)) { *ptr = '^'; zrefresh(); getfullchar(0); if(LASTFULLCHAR == ZLEEOF || !LASTFULLCHAR || len >= NAMLEN) feep = 1; else { int ret = zlecharasstring(LASTFULLCHAR, ptr); len += ret; ptr += ret; curlist = 0; } } else if(cmd == Th(z_quotedinsert)) { if(getfullchar(0) == ZLEEOF || !LASTFULLCHAR || len == NAMLEN) feep = 1; else { int ret = zlecharasstring(LASTFULLCHAR, ptr); len += ret; ptr += ret; curlist = 0; } } else if(cmd == Th(z_backwarddeletechar) || cmd == Th(z_vibackwarddeletechar)) { if (len) { ptr = backwardmetafiedchar(cmdbuf, ptr, NULL); len = ptr - cmdbuf; curlist = 0; } } else if(cmd == Th(z_killregion) || cmd == Th(z_backwardkillword) || cmd == Th(z_vibackwardkillword)) { if (len) curlist = 0; while (len) { convchar_t cc; ptr = backwardmetafiedchar(cmdbuf, ptr, &cc); len = ptr - cmdbuf; if (cc == ZWC('-')) break; } } else if(cmd == Th(z_killwholeline) || cmd == Th(z_vikillline) || cmd == Th(z_backwardkillline)) { len = 0; ptr = cmdbuf; if (listed) clearlist = listshown = 1; curlist = 0; } else if (cmd == Th(z_bracketedpaste)) { char *insert = bracketedstring(); size_t inslen = strlen(insert); if (len + inslen > NAMLEN) feep = 1; else { strcpy(ptr, insert); len += inslen; ptr += inslen; if (listed) { clearlist = listshown = 1; listed = 0; } else curlist = 0; } free(insert); } else { if(cmd == Th(z_acceptline) || cmd == Th(z_vicmdmode)) { Thingy r; unambiguous: *ptr = 0; r = rthingy(cmdbuf); if (!(r->flags & DISABLED)) { unrefthingy(r); statusline = NULL; selectkeymap(okeymap, 1); zsfree(okeymap); if ((listshown = ols)) { showinglist = -2; lastlistlen = olll; } else if (listed) clearlist = listshown = 1; retval = r; goto done; } unrefthingy(r); } if(cmd == Th(z_selfinsertunmeta)) { fixunmeta(); cmd = Th(z_selfinsert); } if (cmd == Th(z_listchoices) || cmd == Th(z_deletecharorlist) || cmd == Th(z_expandorcomplete) || cmd == Th(z_completeword) || cmd == Th(z_expandorcompleteprefix) || cmd == Th(z_vicmdmode) || cmd == Th(z_acceptline) || lastchar == ' ' || lastchar == '\t') { namedcmdambig = 100; namedcmdll = newlinklist(); *ptr = '\0'; namedcmdstr = cmdbuf; scanhashtable(thingytab, 1, 0, DISABLED, scancompcmd, 0); namedcmdstr = NULL; if (empty(namedcmdll)) { feep = 1; if (listed) clearlist = listshown = 1; curlist = 0; } else if (cmd == Th(z_listchoices) || cmd == Th(z_deletecharorlist)) { int zmultsav = zmult; *ptr = '_'; ptr[1] = '\0'; zmult = 1; listlist(namedcmdll); listed = curlist = 1; showinglist = 0; zmult = zmultsav; } else if (!nextnode(firstnode(namedcmdll))) { strcpy(ptr = cmdbuf, peekfirst(namedcmdll)); len = strlen(ptr); ptr += len; if (cmd == Th(z_acceptline) || cmd == Th(z_vicmdmode)) goto unambiguous; } else { strcpy(cmdbuf, peekfirst(namedcmdll)); ptr = cmdbuf + namedcmdambig; *ptr = '_'; ptr[1] = '\0'; if (isset(AUTOLIST) && !(isset(LISTAMBIGUOUS) && namedcmdambig > len)) { int zmultsav = zmult; if (isset(LISTBEEP)) feep = 1; zmult = 1; listlist(namedcmdll); listed = curlist = 1; showinglist = 0; zmult = zmultsav; } len = namedcmdambig; } } else { if (len == NAMLEN || cmd != Th(z_selfinsert)) feep = 1; else { #ifdef MULTIBYTE_SUPPORT if (!lastchar_wide_valid) getrestchar(lastchar, NULL, NULL); if (lastchar_wide == WEOF) feep = 1; else #endif if (ZC_icntrl(LASTFULLCHAR)) feep = 1; else { int ret = zlecharasstring(LASTFULLCHAR, ptr); len += ret; ptr += ret; if (listed) { clearlist = listshown = 1; listed = 0; } else curlist = 0; } } } } if (feep) handlefeep(zlenoargs); feep = 0; } done: selectlocalmap(NULL); return retval; }
static int bin_zselect(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) { #ifdef HAVE_SELECT int i, fd, fdsetind = 0, fdmax = 0, fdcount; fd_set fdset[3]; const char fdchar[3] = "rwe"; struct timeval tv, *tvptr = NULL; char *outarray = "reply", **outdata, **outptr; char *outhash = NULL; LinkList fdlist; for (i = 0; i < 3; i++) FD_ZERO(fdset+i); for (; *args; args++) { char *argptr = *args, *endptr; zlong tempnum; if (*argptr == '-') { for (argptr++; *argptr; argptr++) { switch (*argptr) { /* * Array name for reply, if not $reply. * This gets set to e.g. `-r 0 -w 1' if 0 is ready * for reading and 1 is ready for writing. */ case 'a': case 'A': i = *argptr; if (argptr[1]) argptr++; else if (args[1]) { argptr = *++args; } else { zwarnnam(nam, "argument expected after -%c", *argptr); return 1; } if (idigit(*argptr) || !isident(argptr)) { zwarnnam(nam, "invalid array name: %s", argptr); return 1; } if (i == 'a') outarray = argptr; else outhash = argptr; /* set argptr to next to last char because of increment */ while (argptr[1]) argptr++; break; /* Following numbers indicate fd's for reading */ case 'r': fdsetind = 0; break; /* Following numbers indicate fd's for writing */ case 'w': fdsetind = 1; break; /* Following numbers indicate fd's for errors */ case 'e': fdsetind = 2; break; /* * Get a timeout value in hundredths of a second * (same units as KEYTIMEOUT). 0 means just poll. * If not given, blocks indefinitely. */ case 't': if (argptr[1]) argptr++; else if (args[1]) { argptr = *++args; } else { zwarnnam(nam, "argument expected after -%c", *argptr); return 1; } if (!idigit(*argptr)) { zwarnnam(nam, "number expected after -t"); return 1; } tempnum = zstrtol(argptr, &endptr, 10); if (*endptr) { zwarnnam(nam, "garbage after -t argument: %s", endptr); return 1; } /* timevalue now active */ tvptr = &tv; tv.tv_sec = (long)(tempnum / 100); tv.tv_usec = (long)(tempnum % 100) * 10000L; /* remember argptr is incremented at end of loop */ argptr = endptr - 1; break; /* Digits following option without arguments are fd's. */ default: if (handle_digits(nam, argptr, fdset+fdsetind, &fdmax)) return 1; } } } else if (handle_digits(nam, argptr, fdset+fdsetind, &fdmax)) return 1; } errno = 0; do { i = select(fdmax, (SELECT_ARG_2_T)fdset, (SELECT_ARG_2_T)(fdset+1), (SELECT_ARG_2_T)(fdset+2), tvptr); } while (i < 0 && errno == EINTR && !errflag); if (i <= 0) { if (i < 0) zwarnnam(nam, "error on select: %e", errno); /* else no fd's set. Presumably a timeout. */ return 1; } /* * Make a linked list of all file descriptors which are ready. * These go into an array preceded by -r, -w or -e for read, write, * error as appropriate. Typically there will only be one set * so this looks rather like overkill. */ fdlist = znewlinklist(); for (i = 0; i < 3; i++) { int doneit = 0; for (fd = 0; fd < fdmax; fd++) { if (FD_ISSET(fd, fdset+i)) { char buf[BDIGBUFSIZE]; if (outhash) { /* * Key/value pairs; keys are fd's (as strings), * value is a (possibly improper) subset of "rwe". */ LinkNode nptr; int found = 0; convbase(buf, fd, 10); for (nptr = firstnode(fdlist); nptr; nptr = nextnode(nextnode(nptr))) { if (!strcmp((char *)getdata(nptr), buf)) { /* Already there, add new character. */ void **dataptr = getaddrdata(nextnode(nptr)); char *data = (char *)*dataptr, *ptr; found = 1; if (!strchr(data, fdchar[i])) { strcpy(buf, data); for (ptr = buf; *ptr; ptr++) ; *ptr++ = fdchar[i]; *ptr = '\0'; zsfree(data); *dataptr = ztrdup(buf); } break; } } if (!found) { /* Add new key/value pair. */ zaddlinknode(fdlist, ztrdup(buf)); buf[0] = fdchar[i]; buf[1] = '\0'; zaddlinknode(fdlist, ztrdup(buf)); } } else { /* List of fd's preceded by -r, -w, -e. */ if (!doneit) { buf[0] = '-'; buf[1] = fdchar[i]; buf[2] = 0; zaddlinknode(fdlist, ztrdup(buf)); doneit = 1; } convbase(buf, fd, 10); zaddlinknode(fdlist, ztrdup(buf)); } } } } /* convert list to array */ fdcount = countlinknodes(fdlist); outptr = outdata = (char **)zalloc((fdcount+1)*sizeof(char *)); while (nonempty(fdlist)) *outptr++ = getlinknode(fdlist); *outptr = NULL; /* and store in array parameter */ if (outhash) sethparam(outhash, outdata); else setaparam(outarray, outdata); freelinklist(fdlist, NULL); return 0; #else /* TODO: use poll */ zerrnam(nam, "your system does not implement the select system call."); return 2; #endif }
static int raw_getbyte(long do_keytmout, char *cptr) { int ret; struct ztmout tmout; #if defined(HAS_TIO) && \ (defined(sun) || (!defined(HAVE_POLL) && !defined(HAVE_SELECT))) struct ttyinfo ti; #endif #ifndef HAVE_POLL # ifdef HAVE_SELECT fd_set foofd, errfd; FD_ZERO(&errfd); # endif #endif calc_timeout(&tmout, do_keytmout); /* * Handle timeouts and watched fd's. If a watched fd or a function * timeout triggers we restart any key timeout. This is likely to * be harmless: the combination is extremely rare and a function * is likely to occupy the user for a little while anyway. We used * to make timeouts take precedence, but we can't now that the * timeouts may be external, so we may have both a permanent watched * fd and a long-term timeout. */ if ((nwatch || tmout.tp != ZTM_NONE)) { #if defined(HAVE_SELECT) || defined(HAVE_POLL) int i, errtry = 0, selret; # ifdef HAVE_POLL int nfds; struct pollfd *fds; # endif # if defined(HAS_TIO) && defined(sun) /* * Yes, I know this is complicated. Yes, I know we * already have three bits of code to poll the terminal * down below. No, I don't want to do this either. * However, it turns out on certain OSes, specifically * Solaris, that you can't poll typeahead for love nor * money without actually trying to read it. But * if we are trying to select (and we need to if we * are watching other fd's) we won't pick that up. * So we just try and read it without blocking in * the time-honoured (i.e. absurdly baroque) termios * fashion. */ gettyinfo(&ti); ti.tio.c_cc[VMIN] = 0; settyinfo(&ti); winch_unblock(); ret = read(SHTTY, cptr, 1); winch_block(); ti.tio.c_cc[VMIN] = 1; settyinfo(&ti); if (ret > 0) return 1; # endif # ifdef HAVE_POLL nfds = 1 + nwatch; /* First pollfd is SHTTY, following are the nwatch fds */ fds = zalloc(sizeof(struct pollfd) * nfds); fds[0].fd = SHTTY; /* * POLLIN, POLLIN, POLLIN, * Keep those fd's POLLIN... */ fds[0].events = POLLIN; for (i = 0; i < nwatch; i++) { fds[i+1].fd = watch_fds[i].fd; fds[i+1].events = POLLIN; } # endif for (;;) { # ifdef HAVE_POLL int poll_timeout; if (tmout.tp != ZTM_NONE) poll_timeout = tmout.exp100ths * 10; else poll_timeout = -1; winch_unblock(); selret = poll(fds, errtry ? 1 : nfds, poll_timeout); winch_block(); # else int fdmax = SHTTY; struct timeval *tvptr; struct timeval expire_tv; FD_ZERO(&foofd); FD_SET(SHTTY, &foofd); if (!errtry) { for (i = 0; i < nwatch; i++) { int fd = watch_fds[i].fd; if (FD_ISSET(fd, &errfd)) continue; FD_SET(fd, &foofd); if (fd > fdmax) fdmax = fd; } } FD_ZERO(&errfd); if (tmout.tp != ZTM_NONE) { expire_tv.tv_sec = tmout.exp100ths / 100; expire_tv.tv_usec = (tmout.exp100ths % 100) * 10000L; tvptr = &expire_tv; } else tvptr = NULL; winch_unblock(); selret = select(fdmax+1, (SELECT_ARG_2_T) & foofd, NULL, NULL, tvptr); winch_block(); # endif /* * Make sure a user interrupt gets passed on straight away. */ if (selret < 0 && (errflag || retflag || breaks || exit_pending)) break; /* * Try to avoid errors on our special fd's from * messing up reads from the terminal. Try first * with all fds, then try unsetting the special ones. */ if (selret < 0 && !errtry) { errtry = 1; continue; } if (selret == 0) { /* * Nothing ready and no error, so we timed out. */ switch (tmout.tp) { case ZTM_NONE: /* keeps compiler happy if not debugging */ #ifdef DEBUG dputs("BUG: timeout fired with no timeout set."); #endif /* treat as if a key timeout triggered */ /*FALLTHROUGH*/ case ZTM_KEY: /* Special value -2 signals nothing ready */ selret = -2; break; case ZTM_FUNC: while (firstnode(timedfns)) { Timedfn tfdat = (Timedfn)getdata(firstnode(timedfns)); /* * It's possible a previous function took * a long time to run (though it can't * call zle recursively), so recalculate * the time on each iteration. */ time_t now = time(NULL); if (tfdat->when > now) break; tfdat->func(); } /* Function may have messed up the display */ if (resetneeded) zrefresh(); /* We need to recalculate the timeout */ /*FALLTHROUGH*/ case ZTM_MAX: /* * Reached the limit of our range, but not the * actual timeout; recalculate the timeout. * We're cheating with the key timeout here: * if one clashed with a function timeout we * reconsider the key timeout from scratch. * The effect of this is microscopic. */ calc_timeout(&tmout, do_keytmout); break; } /* * If we handled the timeout successfully, * carry on. */ if (selret == 0) continue; } /* If error or unhandled timeout, give up. */ if (selret < 0) break; /* * If there's user input handle it straight away. * This improves the user's ability to handle exceptional * conditions like runaway output. */ if ( # ifdef HAVE_POLL (fds[0].revents & POLLIN) # else FD_ISSET(SHTTY, &foofd) # endif ) break; if (nwatch && !errtry) { /* * Copy the details of the watch fds in case the * user decides to delete one from inside the * handler function. */ int lnwatch = nwatch; Watch_fd lwatch_fds = zalloc(lnwatch*sizeof(struct watch_fd)); memcpy(lwatch_fds, watch_fds, lnwatch*sizeof(struct watch_fd)); for (i = 0; i < lnwatch; i++) lwatch_fds[i].func = ztrdup(lwatch_fds[i].func); for (i = 0; i < lnwatch; i++) { Watch_fd lwatch_fd = lwatch_fds + i; if ( # ifdef HAVE_POLL (fds[i+1].revents & (POLLIN|POLLERR|POLLHUP|POLLNVAL)) # else FD_ISSET(lwatch_fd->fd, &foofd) || FD_ISSET(lwatch_fd->fd, &errfd) # endif ) { /* Handle the fd. */ char *fdbuf; { char buf[BDIGBUFSIZE]; convbase(buf, lwatch_fd->fd, 10); fdbuf = ztrdup(buf); } if (lwatch_fd->widget) { zlecallhook(lwatch_fd->func, fdbuf); zsfree(fdbuf); } else { LinkList funcargs = znewlinklist(); zaddlinknode(funcargs, ztrdup(lwatch_fd->func)); zaddlinknode(funcargs, fdbuf); # ifdef HAVE_POLL # ifdef POLLERR if (fds[i+1].revents & POLLERR) zaddlinknode(funcargs, ztrdup("err")); # endif # ifdef POLLHUP if (fds[i+1].revents & POLLHUP) zaddlinknode(funcargs, ztrdup("hup")); # endif # ifdef POLLNVAL if (fds[i+1].revents & POLLNVAL) zaddlinknode(funcargs, ztrdup("nval")); # endif # else if (FD_ISSET(lwatch_fd->fd, &errfd)) zaddlinknode(funcargs, ztrdup("err")); # endif callhookfunc(lwatch_fd->func, funcargs, 0, NULL); freelinklist(funcargs, freestr); } if (errflag) { /* No sensible way of handling errors here */ errflag &= ~ERRFLAG_ERROR; /* * Paranoia: don't run the hooks again this * time. */ errtry = 1; } } } /* Function may have invalidated the display. */ if (resetneeded) zrefresh(); for (i = 0; i < lnwatch; i++) zsfree(lwatch_fds[i].func); zfree(lwatch_fds, lnwatch*sizeof(struct watch_fd)); # ifdef HAVE_POLL /* Function may have added or removed handlers */ nfds = 1 + nwatch; if (nfds > 1) { fds = zrealloc(fds, sizeof(struct pollfd) * nfds); for (i = 0; i < nwatch; i++) { /* * This is imperfect because it assumes fds[] and * watch_fds[] remain in sync, which may be false * if handlers are shuffled. However, it should * be harmless (e.g., produce one extra pass of * the loop) in the event they fall out of sync. */ if (fds[i+1].fd == watch_fds[i].fd && (fds[i+1].revents & (POLLERR|POLLHUP|POLLNVAL))) { fds[i+1].events = 0; /* Don't poll this */ } else { fds[i+1].fd = watch_fds[i].fd; fds[i+1].events = POLLIN; } fds[i+1].revents = 0; } } # endif } } # ifdef HAVE_POLL zfree(fds, sizeof(struct pollfd) * nfds); # endif if (selret < 0) return selret; #else # ifdef HAS_TIO ti = shttyinfo; ti.tio.c_lflag &= ~ICANON; ti.tio.c_cc[VMIN] = 0; ti.tio.c_cc[VTIME] = tmout.exp100ths / 10; # ifdef HAVE_TERMIOS_H tcsetattr(SHTTY, TCSANOW, &ti.tio); # else ioctl(SHTTY, TCSETA, &ti.tio); # endif winch_unblock(); ret = read(SHTTY, cptr, 1); winch_block(); # ifdef HAVE_TERMIOS_H tcsetattr(SHTTY, TCSANOW, &shttyinfo.tio); # else ioctl(SHTTY, TCSETA, &shttyinfo.tio); # endif return (ret <= 0) ? ret : *cptr; # endif #endif } winch_unblock(); ret = read(SHTTY, cptr, 1); winch_block(); return ret; }
int getvisrchstr(void) { char *sbuf = halloc(80); int sptr = 1, ret = 0, ssbuf = 80; int cmd; int *obindtab = bindtab; if (visrchstr) { zsfree(visrchstr); visrchstr = NULL; } clearlist = 1; statusline = sbuf; sbuf[0] = (visrchsense == -1) ? '?' : '/'; bindtab = mainbindtab; while (sptr) { sbuf[sptr] = '_'; statusll = sptr + 1; refresh(); if ((cmd = getkeycmd()) < 0 || cmd == z_sendbreak) { ret = 0; break; } if(cmd == z_magicspace) { c = ' '; cmd = z_selfinsert; } switch(cmd) { case z_redisplay: redisplay(); break; case z_clearscreen: clearscreen(); break; case z_acceptline: case z_vicmdmode: sbuf[sptr] = 0; visrchstr = metafy(sbuf + 1, sptr - 1, META_DUP); ret = 1; sptr = 0; break; case z_backwarddeletechar: case z_vibackwarddeletechar: sptr--; break; case z_backwardkillword: case z_vibackwardkillword: while(sptr != 1 && iblank(sbuf[sptr - 1])) sptr--; if(iident(sbuf[sptr - 1])) while(sptr != 1 && iident(sbuf[sptr - 1])) sptr--; else while(sptr != 1 && !iident(sbuf[sptr - 1]) && !iblank(sbuf[sptr - 1])) sptr--; break; case z_sendstring: sendstring(); break; case z_viquotedinsert: sbuf[sptr] = '^'; refresh(); /* fall through */ case z_quotedinsert: if ((c = getkey(0)) == EOF) { feep(); break; } goto ins; case z_selfinsertunmeta: c &= 0x7f; if(c == '\r') c = '\n'; case z_selfinsert: ins: if(sptr == ssbuf - 1) { char *newbuf = halloc(ssbuf *= 2); strcpy(newbuf, sbuf); statusline = sbuf = newbuf; } sbuf[sptr++] = c; break; default: feep(); } } statusline = NULL; bindtab = obindtab; return ret; }
static int bin_compadd(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) { struct cadata dat; char *p, **sp, *e, *m = NULL, *mstr = NULL; int dm; Cmatcher match = NULL; if (incompfunc != 1) { zwarnnam(name, "can only be called from completion function"); return 1; } dat.ipre = dat.isuf = dat.ppre = dat.psuf = dat.prpre = dat.mesg = dat.pre = dat.suf = dat.group = dat.rems = dat.remf = dat.disp = dat.ign = dat.exp = dat.apar = dat.opar = dat.dpar = NULL; dat.match = NULL; dat.flags = 0; dat.aflags = CAF_MATCH; dat.dummies = 0; for (; *argv && **argv == '-'; argv++) { if (!(*argv)[1]) { argv++; break; } for (p = *argv + 1; *p; p++) { sp = NULL; e = NULL; dm = 0; switch (*p) { case 'q': dat.flags |= CMF_REMOVE; break; case 'Q': dat.aflags |= CAF_QUOTE; break; case 'C': dat.aflags |= CAF_ALL; break; case 'f': dat.flags |= CMF_FILE; break; case 'e': dat.flags |= CMF_ISPAR; break; case 'a': dat.aflags |= CAF_ARRAYS; break; case 'k': dat.aflags |= CAF_ARRAYS|CAF_KEYS; break; case 'F': sp = &(dat.ign); e = "string expected after -%c"; break; case 'n': dat.flags |= CMF_NOLIST; break; case 'U': dat.aflags &= ~CAF_MATCH; break; case 'P': sp = &(dat.pre); e = "string expected after -%c"; break; case 'S': sp = &(dat.suf); e = "string expected after -%c"; break; case 'J': sp = &(dat.group); e = "group name expected after -%c"; break; case 'V': if (!dat.group) dat.aflags |= CAF_NOSORT; sp = &(dat.group); e = "group name expected after -%c"; break; case '1': if (!(dat.aflags & CAF_UNIQCON)) dat.aflags |= CAF_UNIQALL; break; case '2': if (!(dat.aflags & CAF_UNIQALL)) dat.aflags |= CAF_UNIQCON; break; case 'i': sp = &(dat.ipre); e = "string expected after -%c"; break; case 'I': sp = &(dat.isuf); e = "string expected after -%c"; break; case 'p': sp = &(dat.ppre); e = "string expected after -%c"; break; case 's': sp = &(dat.psuf); e = "string expected after -%c"; break; case 'W': sp = &(dat.prpre); e = "string expected after -%c"; break; case 'M': sp = &m; e = "matching specification expected after -%c"; dm = 1; break; case 'X': sp = &(dat.exp); e = "string expected after -%c"; break; case 'x': sp = &(dat.mesg); e = "string expected after -%c"; break; case 'r': dat.flags |= CMF_REMOVE; sp = &(dat.rems); e = "string expected after -%c"; break; case 'R': dat.flags |= CMF_REMOVE; sp = &(dat.remf); e = "function name expected after -%c"; break; case 'A': sp = &(dat.apar); e = "parameter name expected after -%c"; break; case 'O': sp = &(dat.opar); e = "parameter name expected after -%c"; break; case 'D': sp = &(dat.dpar); e = "parameter name expected after -%c"; break; case 'd': sp = &(dat.disp); e = "parameter name expected after -%c"; break; case 'l': dat.flags |= CMF_DISPLINE; break; case 'o': dat.flags |= CMF_MORDER; break; case 'E': if (p[1]) { dat.dummies = atoi(p + 1); p = "" - 1; } else if (argv[1]) { argv++; dat.dummies = atoi(*argv); p = "" - 1; } else { zwarnnam(name, "number expected after -%c", *p); zsfree(mstr); return 1; } if (dat.dummies < 0) { zwarnnam(name, "invalid number: %d", dat.dummies); zsfree(mstr); return 1; } break; case '-': argv++; goto ca_args; default: zwarnnam(name, "bad option: -%c", *p); zsfree(mstr); return 1; } if (sp) { if (p[1]) { if (!*sp) *sp = p + 1; p = "" - 1; } else if (argv[1]) { argv++; if (!*sp) *sp = *argv; p = "" - 1; } else { zwarnnam(name, e, *p); zsfree(mstr); return 1; } if (dm) { if (mstr) { char *tmp = tricat(mstr, " ", m); zsfree(mstr); mstr = tmp; } else mstr = ztrdup(m); m = NULL; } } } } ca_args: if (mstr && (match = parse_cmatcher(name, mstr)) == pcm_err) { zsfree(mstr); return 1; } zsfree(mstr); if (!*argv && !dat.group && !dat.mesg && !(dat.aflags & (CAF_NOSORT|CAF_UNIQALL|CAF_UNIQCON|CAF_ALL))) return 1; dat.match = match = cpcmatcher(match); dm = addmatches(&dat, argv); freecmatcher(match); return dm; }
int finish_(UNUSED(Module m)) { if (compwords) freearray(compwords); if (compredirs) freearray(compredirs); zsfree(compprefix); zsfree(compsuffix); zsfree(complastprefix); zsfree(complastsuffix); zsfree(compiprefix); zsfree(compisuffix); zsfree(compqiprefix); zsfree(compqisuffix); zsfree(compcontext); zsfree(compparameter); zsfree(compredirect); zsfree(compquote); zsfree(compqstack); zsfree(compquoting); zsfree(comprestore); zsfree(complist); zsfree(compinsert); zsfree(compexact); zsfree(compexactstr); zsfree(comppatmatch); zsfree(comppatinsert); zsfree(complastprompt); zsfree(comptoend); zsfree(compoldlist); zsfree(compoldins); zsfree(compvared); hascompmod = 0; return 0; }
static int comp_wrapper(Eprog prog, FuncWrap w, char *name) { if (incompfunc != 1) return 1; else { char *orest, *opre, *osuf, *oipre, *oisuf, **owords, **oredirs; char *oqipre, *oqisuf, *oq, *oqi, *oqs, *oaq; zlong ocur; unsigned int runset = 0, kunset = 0, m, sm; Param *pp; m = CP_WORDS | CP_REDIRS | CP_CURRENT | CP_PREFIX | CP_SUFFIX | CP_IPREFIX | CP_ISUFFIX | CP_QIPREFIX | CP_QISUFFIX; for (pp = comprpms, sm = 1; m; pp++, m >>= 1, sm <<= 1) { if ((m & 1) && ((*pp)->node.flags & PM_UNSET)) runset |= sm; } if (compkpms[CPN_RESTORE]->node.flags & PM_UNSET) kunset = CP_RESTORE; orest = comprestore; comprestore = ztrdup("auto"); ocur = compcurrent; opre = ztrdup(compprefix); osuf = ztrdup(compsuffix); oipre = ztrdup(compiprefix); oisuf = ztrdup(compisuffix); oqipre = ztrdup(compqiprefix); oqisuf = ztrdup(compqisuffix); oq = ztrdup(compquote); oqi = ztrdup(compquoting); oqs = ztrdup(compqstack); oaq = ztrdup(autoq); owords = zarrdup(compwords); oredirs = zarrdup(compredirs); runshfunc(prog, w, name); if (comprestore && !strcmp(comprestore, "auto")) { compcurrent = ocur; zsfree(compprefix); compprefix = opre; zsfree(compsuffix); compsuffix = osuf; zsfree(compiprefix); compiprefix = oipre; zsfree(compisuffix); compisuffix = oisuf; zsfree(compqiprefix); compqiprefix = oqipre; zsfree(compqisuffix); compqisuffix = oqisuf; zsfree(compquote); compquote = oq; zsfree(compquoting); compquoting = oqi; zsfree(compqstack); compqstack = oqs; zsfree(autoq); autoq = oaq; freearray(compwords); freearray(compredirs); compwords = owords; compredirs = oredirs; comp_setunset(CP_COMPSTATE | (~runset & (CP_WORDS | CP_REDIRS | CP_CURRENT | CP_PREFIX | CP_SUFFIX | CP_IPREFIX | CP_ISUFFIX | CP_QIPREFIX | CP_QISUFFIX)), (runset & CP_ALLREALS), (~kunset & CP_RESTORE), (kunset & CP_ALLKEYS)); } else { comp_setunset(CP_COMPSTATE, 0, (~kunset & CP_RESTORE), (kunset & CP_RESTORE)); zsfree(opre); zsfree(osuf); zsfree(oipre); zsfree(oisuf); zsfree(oqipre); zsfree(oqisuf); zsfree(oq); zsfree(oqi); zsfree(oqs); zsfree(oaq); freearray(owords); freearray(oredirs); } zsfree(comprestore); comprestore = orest; return 0; } }
enum loop_return loop(int toplevel, int justonce) { Eprog prog; int err, non_empty = 0; queue_signals(); pushheap(); if (!toplevel) zcontext_save(); for (;;) { freeheap(); if (stophist == 3) /* re-entry via preprompt() */ hend(NULL); hbegin(1); /* init history mech */ if (isset(SHINSTDIN)) { setblock_stdin(); if (interact && toplevel) { int hstop = stophist; stophist = 3; /* * Reset all errors including the interrupt error status * immediately, so preprompt runs regardless of what * just happened. We'll reset again below as a * precaution to ensure we get back to the command line * no matter what. */ errflag = 0; preprompt(); if (stophist != 3) hbegin(1); else stophist = hstop; /* * Reset all errors, including user interupts. * This is what allows ^C in an interactive shell * to return us to the command line. */ errflag = 0; } } use_exit_printed = 0; intr(); /* interrupts on */ lexinit(); /* initialize lexical state */ if (!(prog = parse_event(ENDINPUT))) { /* if we couldn't parse a list */ hend(NULL); if ((tok == ENDINPUT && !errflag) || (tok == LEXERR && (!isset(SHINSTDIN) || !toplevel)) || justonce) break; if (exit_pending) { /* * Something down there (a ZLE function?) decided * to exit when there was stuff to clear up. * Handle that now. */ stopmsg = 1; zexit(exit_pending >> 1, 0); } if (tok == LEXERR && !lastval) lastval = 1; continue; } if (hend(prog)) { enum lextok toksav = tok; non_empty = 1; if (toplevel && (getshfunc("preexec") || paramtab->getnode(paramtab, "preexec" HOOK_SUFFIX))) { LinkList args; char *cmdstr; /* * As we're about to freeheap() or popheap() * anyway, there's no gain in using permanent * storage here. */ args = newlinklist(); addlinknode(args, "preexec"); /* If curline got dumped from the history, we don't know * what the user typed. */ if (hist_ring && curline.histnum == curhist) addlinknode(args, hist_ring->node.nam); else addlinknode(args, ""); addlinknode(args, dupstring(getjobtext(prog, NULL))); addlinknode(args, cmdstr = getpermtext(prog, NULL, 0)); callhookfunc("preexec", args, 1, NULL); /* The only permanent storage is from getpermtext() */ zsfree(cmdstr); /* * Note this does *not* remove a user interrupt error * condition, even though we're at the top level loop: * that would be inconsistent with the case where * we didn't execute a preexec function. This is * an implementation detail that an interrupting user * does't care about. */ errflag &= ~ERRFLAG_ERROR; } if (stopmsg) /* unset 'you have stopped jobs' flag */ stopmsg--; execode(prog, 0, 0, toplevel ? "toplevel" : "file"); tok = toksav; if (toplevel) noexitct = 0; } if (ferror(stderr)) { zerr("write error"); clearerr(stderr); } if (subsh) /* how'd we get this far in a subshell? */ exit(lastval); if (((!interact || sourcelevel) && errflag) || retflag) break; if (isset(SINGLECOMMAND) && toplevel) { dont_queue_signals(); if (sigtrapped[SIGEXIT]) dotrap(SIGEXIT); exit(lastval); } if (justonce) break; }