static int bin_getattr(char *nam, char **argv, Options ops, UNUSED(int func)) { int ret = 0; int val_len = 0, attr_len = 0, slen; char *value, *file = argv[0], *attr = argv[1], *param = argv[2]; int symlink = OPT_ISSET(ops, 'h'); unmetafy(file, &slen); unmetafy(attr, NULL); val_len = xgetxattr(file, attr, NULL, 0, symlink); if (val_len == 0) { if (param) unsetparam(param); return 0; } if (val_len > 0) { value = (char *)zalloc(val_len+1); attr_len = xgetxattr(file, attr, value, val_len, symlink); if (attr_len > 0 && attr_len <= val_len) { value[attr_len] = '\0'; if (param) setsparam(param, metafy(value, attr_len, META_DUP)); else printf("%s\n", value); } zfree(value, val_len+1); } if (val_len < 0 || attr_len < 0 || attr_len > val_len) { zwarnnam(nam, "%s: %e", metafy(file, slen, META_NOALLOC), errno); ret = 1 + ((val_len > 0 && attr_len > val_len) || attr_len < 0); } return ret; }
int bracketedpaste(char **args) { char *pbuf = bracketedstring(); if (*args) { setsparam(*args, pbuf); } else { int n; ZLE_STRING_T wpaste; wpaste = stringaszleline((zmult == 1) ? pbuf : quotestring(pbuf, NULL, QT_SINGLE_OPTIONAL), 0, &n, NULL, NULL); cuttext(wpaste, n, CUT_REPLACE); if (!(zmod.flags & MOD_VIBUF)) { kct = -1; kctbuf = &cutbuf; zmult = 1; if (region_active) killregion(zlenoargs); yankcs = yankb = zlecs; doinsert(wpaste, n); yanke = zlecs; } free(pbuf); free(wpaste); } return 0; }
static int bin_listattr(char *nam, char **argv, Options ops, UNUSED(int func)) { int ret = 0; int val_len, list_len = 0, slen; char *value, *file = argv[0], *param = argv[1]; int symlink = OPT_ISSET(ops, 'h'); unmetafy(file, &slen); val_len = xlistxattr(file, NULL, 0, symlink); if (val_len == 0) { if (param) unsetparam(param); return 0; } if (val_len > 0) { value = (char *)zalloc(val_len+1); list_len = xlistxattr(file, value, val_len, symlink); if (list_len > 0 && list_len <= val_len) { char *p = value; if (param) { if (strlen(value) + 1 == list_len) setsparam(param, metafy(value, list_len-1, META_DUP)); else { int arrlen = 0; char **array = NULL, **arrptr = NULL; while (p < &value[list_len]) { arrlen++; p += strlen(p) + 1; } arrptr = array = (char **)zshcalloc((arrlen+1) * sizeof(char *)); p = value; while (p < &value[list_len]) { *arrptr++ = metafy(p, -1, META_DUP); p += strlen(p) + 1; } setaparam(param, array); } } else while (p < &value[list_len]) { printf("%s\n", p); p += strlen(p) + 1; } } zfree(value, val_len+1); } if (val_len < 0 || list_len < 0 || list_len > val_len) { zwarnnam(nam, "%s: %e", metafy(file, slen, META_NOALLOC), errno); ret = 1 + (list_len > val_len || list_len < 0); } return ret; }
static int bin_strftime(char *nam, char **argv, Options ops, UNUSED(int func)) { int bufsize, x; char *endptr = NULL, *scalar = NULL, *buffer; time_t secs; struct tm *t; if (OPT_ISSET(ops,'s')) { scalar = OPT_ARG(ops, 's'); if (!isident(scalar)) { zwarnnam(nam, "not an identifier: %s", scalar); return 1; } } if (OPT_ISSET(ops, 'r')) return reverse_strftime(nam, argv, scalar, OPT_ISSET(ops, 'q')); errno = 0; secs = (time_t)strtoul(argv[1], &endptr, 10); if (errno != 0) { zwarnnam(nam, "%s: %e", argv[1], errno); return 1; } else if (*endptr != '\0') { zwarnnam(nam, "%s: invalid decimal number", argv[1]); return 1; } t = localtime(&secs); if (!t) { zwarnnam(nam, "%s: unable to convert to time", argv[1]); return 1; } bufsize = strlen(argv[0]) * 8; buffer = zalloc(bufsize); for (x=0; x < 4; x++) { if (ztrftime(buffer, bufsize, argv[0], t) >= 0) break; buffer = zrealloc(buffer, bufsize *= 2); } if (scalar) { setsparam(scalar, metafy(buffer, -1, META_DUP)); } else { printf("%s\n", buffer); } zfree(buffer, bufsize); return 0; }
static int bin_syserror(char *nam, char **args, Options ops, UNUSED(int func)) { int num = 0; char *errvar = NULL, *msg, *pfx = "", *str; /* variable in which to write error message */ if (OPT_ISSET(ops, 'e')) { errvar = OPT_ARG(ops, 'e'); if (!isident(errvar)) { zwarnnam(nam, "not an identifier: %s", errvar); return 1; } } /* prefix for error message */ if (OPT_ISSET(ops, 'p')) pfx = OPT_ARG(ops, 'p'); if (!*args) num = errno; else { char *ptr = *args; while (*ptr && idigit(*ptr)) ptr++; if (!*ptr && ptr > *args) num = atoi(*args); else { const char **eptr; for (eptr = sys_errnames; *eptr; eptr++) { if (!strcmp(*eptr, *args)) { num = (eptr - sys_errnames) + 1; break; } } if (!*eptr) return 2; } } msg = strerror(num); if (errvar) { str = (char *)zalloc(strlen(msg) + strlen(pfx) + 1); sprintf(str, "%s%s", pfx, msg); setsparam(errvar, str); } else { fprintf(stderr, "%s%s\n", pfx, msg); } return 0; }
static int bin_strftime(char *nam, char **argv, Options ops, int func) { int result = 1; char *tz = getsparam("TZ"); startparamscope(); if (tz && *tz) { Param pm = createparam("TZ", PM_LOCAL|PM_SCALAR|PM_EXPORTED); if (pm) pm->level = locallevel; /* because createparam() doesn't */ setsparam("TZ", ztrdup(tz)); } result = output_strftime(nam, argv, ops, func); endparamscope(); return result; }
static int newptycmd(char *nam, char *pname, char **args, int echo, int nblock) { Ptycmd p; int master, slave, pid, oineval = ineval, ret; char *oscriptname = scriptname, syncch; Eprog prog; /* code borrowed from bin_eval() */ ineval = !isset(EVALLINENO); if (!ineval) scriptname = "(zpty)"; prog = parse_string(zjoin(args, ' ', 1), 0); if (!prog) { errflag &= ~ERRFLAG_ERROR; scriptname = oscriptname; ineval = oineval; return 1; } if (get_pty(1, &master)) { zwarnnam(nam, "can't open pseudo terminal: %e", errno); scriptname = oscriptname; ineval = oineval; return 1; } if ((pid = fork()) == -1) { zwarnnam(nam, "can't create pty command %s: %e", pname, errno); close(master); scriptname = oscriptname; ineval = oineval; return 1; } else if (!pid) { /* This code copied from the clone module, except for getting * * the descriptor from get_pty() and duplicating it to 0/1/2. */ deletehookfunc("exit", ptyhook); clearjobtab(0); ppid = getppid(); mypid = getpid(); #ifdef HAVE_SETSID if (setsid() != mypid) { zwarnnam(nam, "failed to create new session: %e", errno); #endif #ifdef TIOCNOTTY if (ioctl(SHTTY, TIOCNOTTY, 0)) zwarnnam(nam, "%e", errno); setpgrp(0L, mypid); #endif #ifdef HAVE_SETSID } #endif if (get_pty(0, &slave)) exit(1); SHTTY = slave; attachtty(mypid); #ifdef TIOCGWINSZ /* Set the window size before associating with the terminal * * so that we don't get hit with a SIGWINCH. I'm paranoid. */ if (interact) { struct ttyinfo info; if (ioctl(slave, TIOCGWINSZ, (char *) &info.winsize) == 0) { info.winsize.ws_row = zterm_lines; info.winsize.ws_col = zterm_columns; ioctl(slave, TIOCSWINSZ, (char *) &info.winsize); } } #endif /* TIOCGWINSZ */ if (!echo) { struct ttyinfo info; if (!ptygettyinfo(slave, &info)) { #ifdef HAVE_TERMIOS_H info.tio.c_lflag &= ~ECHO; #else #ifdef HAVE_TERMIO_H info.tio.c_lflag &= ~ECHO; #else info.tio.lmodes &= ~ECHO; /**** dunno if this is right */ #endif #endif ptysettyinfo(slave, &info); } } #ifdef TIOCSCTTY ioctl(slave, TIOCSCTTY, 0); #endif close(0); close(1); close(2); dup2(slave, 0); dup2(slave, 1); dup2(slave, 2); closem(FDT_UNUSED, 0); close(slave); close(master); close(coprocin); close(coprocout); init_io(NULL); setsparam("TTY", ztrdup(ttystrname)); opts[INTERACTIVE] = 0; syncch = 0; do { ret = write(1, &syncch, 1); } while (ret != 1 && ( #ifdef EWOULDBLOCK errno == EWOULDBLOCK || #else #ifdef EAGAIN errno == EAGAIN || #endif #endif errno == EINTR)); execode(prog, 1, 0, "zpty"); stopmsg = 2; mypid = 0; /* trick to ensure we _exit() */ zexit(lastval, 0); } master = movefd(master); if (master == -1) { zerrnam(nam, "cannot duplicate fd %d: %e", master, errno); scriptname = oscriptname; ineval = oineval; return 1; } p = (Ptycmd) zalloc(sizeof(*p)); p->name = ztrdup(pname); p->args = zarrdup(args); p->fd = master; p->pid = pid; p->echo = echo; p->nblock = nblock; p->fin = 0; p->read = -1; p->old = NULL; p->olen = 0; p->next = ptycmds; ptycmds = p; if (nblock) ptynonblock(master); scriptname = oscriptname; ineval = oineval; do { ret = read(master, &syncch, 1); } while (ret != 1 && ( #ifdef EWOULDBLOCK errno == EWOULDBLOCK || #else #ifdef EAGAIN errno == EAGAIN || #endif #endif errno == EINTR)); setiparam_no_convert("REPLY", (zlong)master); return 0; }
int execfor(Estate state, int do_exec) { Wordcode end, loop; wordcode code = state->pc[-1]; int iscond = (WC_FOR_TYPE(code) == WC_FOR_COND), ctok = 0, atok = 0; int last = 0; char *name, *str, *cond = NULL, *advance = NULL; zlong val = 0; LinkList vars = NULL, args = NULL; int old_simple_pline = simple_pline; /* See comments in execwhile() */ simple_pline = 1; end = state->pc + WC_FOR_SKIP(code); if (iscond) { str = dupstring(ecgetstr(state, EC_NODUP, NULL)); singsub(&str); if (isset(XTRACE)) { char *str2 = dupstring(str); untokenize(str2); printprompt4(); fprintf(xtrerr, "%s\n", str2); fflush(xtrerr); } if (!errflag) { matheval(str); } if (errflag) { state->pc = end; simple_pline = old_simple_pline; return 1; } cond = ecgetstr(state, EC_NODUP, &ctok); advance = ecgetstr(state, EC_NODUP, &atok); } else { vars = ecgetlist(state, *state->pc++, EC_NODUP, NULL); if (WC_FOR_TYPE(code) == WC_FOR_LIST) { int htok = 0; if (!(args = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok))) { state->pc = end; simple_pline = old_simple_pline; return 0; } if (htok) { execsubst(args); if (errflag) { state->pc = end; simple_pline = old_simple_pline; return 1; } } } else { char **x; args = newlinklist(); for (x = pparams; *x; x++) addlinknode(args, dupstring(*x)); } } if (!args || empty(args)) lastval = 0; loops++; pushheap(); cmdpush(CS_FOR); loop = state->pc; while (!last) { if (iscond) { if (ctok) { str = dupstring(cond); singsub(&str); } else str = cond; if (!errflag) { while (iblank(*str)) str++; if (*str) { if (isset(XTRACE)) { printprompt4(); fprintf(xtrerr, "%s\n", str); fflush(xtrerr); } val = mathevali(str); } else val = 1; } if (errflag) { if (breaks) breaks--; lastval = 1; break; } if (!val) break; } else { LinkNode node; int count = 0; for (node = firstnode(vars); node; incnode(node)) { name = (char *)getdata(node); if (!args || !(str = (char *) ugetnode(args))) { if (count) { str = ""; last = 1; } else break; } if (isset(XTRACE)) { printprompt4(); fprintf(xtrerr, "%s=%s\n", name, str); fflush(xtrerr); } setsparam(name, ztrdup(str)); count++; } if (!count) break; } state->pc = loop; execlist(state, 1, do_exec && args && empty(args)); if (breaks) { breaks--; if (breaks || !contflag) break; contflag = 0; } if (retflag) break; if (iscond && !errflag) { if (atok) { str = dupstring(advance); singsub(&str); } else str = advance; if (isset(XTRACE)) { printprompt4(); fprintf(xtrerr, "%s\n", str); fflush(xtrerr); } if (!errflag) matheval(str); } if (errflag) { if (breaks) breaks--; lastval = 1; break; } freeheap(); } popheap(); cmdpop(); loops--; simple_pline = old_simple_pline; state->pc = end; return lastval; }
int execselect(Estate state, UNUSED(int do_exec)) { Wordcode end, loop; wordcode code = state->pc[-1]; char *str, *s, *name; LinkNode n; int i, usezle; FILE *inp; size_t more; LinkList args; int old_simple_pline = simple_pline; /* See comments in execwhile() */ simple_pline = 1; end = state->pc + WC_FOR_SKIP(code); name = ecgetstr(state, EC_NODUP, NULL); if (WC_SELECT_TYPE(code) == WC_SELECT_PPARAM) { char **x; args = newlinklist(); for (x = pparams; *x; x++) addlinknode(args, dupstring(*x)); } else { int htok = 0; if (!(args = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok))) { state->pc = end; simple_pline = old_simple_pline; return 0; } if (htok) { execsubst(args); if (errflag) { state->pc = end; simple_pline = old_simple_pline; return 1; } } } if (!args || empty(args)) { state->pc = end; simple_pline = old_simple_pline; return 0; } loops++; pushheap(); cmdpush(CS_SELECT); usezle = interact && SHTTY != -1 && isset(USEZLE); inp = fdopen(dup(usezle ? SHTTY : 0), "r"); more = selectlist(args, 0); loop = state->pc; for (;;) { for (;;) { if (empty(bufstack)) { if (usezle) { int oef = errflag; isfirstln = 1; str = zleentry(ZLE_CMD_READ, &prompt3, NULL, 0, ZLCON_SELECT); if (errflag) str = NULL; /* Keep any user interrupt error status */ errflag = oef | (errflag & ERRFLAG_INT); } else { str = promptexpand(prompt3, 0, NULL, NULL, NULL); zputs(str, stderr); free(str); fflush(stderr); str = fgets(zhalloc(256), 256, inp); } } else str = (char *)getlinknode(bufstack); if (!str && !errflag) setsparam("REPLY", ztrdup("")); /* EOF (user pressed Ctrl+D) */ if (!str || errflag) { if (breaks) breaks--; fprintf(stderr, "\n"); fflush(stderr); goto done; } if ((s = strchr(str, '\n'))) *s = '\0'; if (*str) break; more = selectlist(args, more); } setsparam("REPLY", ztrdup(str)); i = atoi(str); if (!i) str = ""; else { for (i--, n = firstnode(args); n && i; incnode(n), i--); if (n) str = (char *) getdata(n); else str = ""; } setsparam(name, ztrdup(str)); state->pc = loop; execlist(state, 1, 0); freeheap(); if (breaks) { breaks--; if (breaks || !contflag) break; contflag = 0; } if (retflag || errflag) break; } done: cmdpop(); popheap(); fclose(inp); loops--; simple_pline = old_simple_pline; state->pc = end; return lastval; }
static int zpcre_get_substrings(char *arg, int *ovec, int ret, char *matchvar, char *substravar, int want_offset_pair, int matchedinarr, int want_begin_end) { char **captures, *match_all, **matches; char offset_all[50]; int capture_start = 1; if (matchedinarr) capture_start = 0; if (matchvar == NULL) matchvar = "MATCH"; if (substravar == NULL) substravar = "match"; /* captures[0] will be entire matched string, [1] first substring */ if (!pcre_get_substring_list(arg, ovec, ret, (const char ***)&captures)) { int nelem = arrlen(captures)-1; /* Set to the offsets of the complete match */ if (want_offset_pair) { sprintf(offset_all, "%d %d", ovec[0], ovec[1]); setsparam("ZPCRE_OP", ztrdup(offset_all)); } match_all = metafy(captures[0], -1, META_DUP); setsparam(matchvar, match_all); /* * If we're setting match, mbegin, mend we only do * so if there were parenthesised matches, for consistency * (c.f. regex.c). */ if (!want_begin_end || nelem) { char **x, **y; y = &captures[capture_start]; matches = x = (char **) zalloc(sizeof(char *) * (arrlen(y) + 1)); do { if (*y) *x++ = metafy(*y, -1, META_DUP); else *x++ = NULL; } while (*y++); setaparam(substravar, matches); } if (want_begin_end) { char *ptr = arg; zlong offs = 0; /* Count the characters before the match */ MB_METACHARINIT(); while (ptr < arg + ovec[0]) { offs++; ptr += MB_METACHARLEN(ptr); } setiparam("MBEGIN", offs + !isset(KSHARRAYS)); /* Add on the characters in the match */ while (ptr < arg + ovec[1]) { offs++; ptr += MB_METACHARLEN(ptr); } setiparam("MEND", offs + !isset(KSHARRAYS) - 1); if (nelem) { char **mbegin, **mend, **bptr, **eptr; int i, *ipair; bptr = mbegin = zalloc(sizeof(char*)*(nelem+1)); eptr = mend = zalloc(sizeof(char*)*(nelem+1)); for (ipair = ovec + 2, i = 0; i < nelem; ipair += 2, i++, bptr++, eptr++) { char buf[DIGBUFSIZE]; ptr = arg; offs = 0; /* Find the start offset */ MB_METACHARINIT(); while (ptr < arg + ipair[0]) { offs++; ptr += MB_METACHARLEN(ptr); } convbase(buf, offs + !isset(KSHARRAYS), 10); *bptr = ztrdup(buf); /* Continue to the end offset */ while (ptr < arg + ipair[1]) { offs++; ptr += MB_METACHARLEN(ptr); } convbase(buf, offs + !isset(KSHARRAYS) - 1, 10); *eptr = ztrdup(buf); } *bptr = *eptr = NULL; setaparam("mbegin", mbegin); setaparam("mend", mend); } } pcre_free_substring_list((const char **)captures); } return 0; }
char * zleread(char **lp, char **rp, int flags, int context, char *init, char *finish) { char *s, **bracket; int old_errno = errno; int tmout = getiparam("TMOUT"); #if defined(HAVE_POLL) || defined(HAVE_SELECT) /* may not be set, but that's OK since getiparam() returns 0 == off */ baud = getiparam("BAUD"); costmult = (baud) ? 3840000L / baud : 0; #endif /* ZLE doesn't currently work recursively. This is needed in case a * * select loop is used in a function called from ZLE. vared handles * * this differently itself. */ if(zleactive) { char *pptbuf; int pptlen; pptbuf = unmetafy(promptexpand(lp ? *lp : NULL, 0, NULL, NULL, &pmpt_attr), &pptlen); write_loop(2, pptbuf, pptlen); free(pptbuf); return shingetline(); } /* * The current status is what we need if we are going * to display a prompt. We'll remember it here for * use further in. */ pre_zle_status = lastval; keytimeout = (time_t)getiparam("KEYTIMEOUT"); if (!shout) { if (SHTTY != -1) init_shout(); if (!shout) return NULL; /* We could be smarter and default to a system read. */ /* If we just got a new shout, make sure the terminal is set up. */ if (termflags & TERM_UNKNOWN) init_term(); } fflush(shout); fflush(stderr); intr(); insmode = unset(OVERSTRIKE); eofsent = 0; resetneeded = 0; fetchttyinfo = 0; trashedzle = 0; raw_lp = lp; lpromptbuf = promptexpand(lp ? *lp : NULL, 1, NULL, NULL, &pmpt_attr); raw_rp = rp; rpmpt_attr = pmpt_attr; rpromptbuf = promptexpand(rp ? *rp : NULL, 1, NULL, NULL, &rpmpt_attr); free_prepostdisplay(); zlereadflags = flags; zlecontext = context; histline = curhist; vistartchange = -1; zleline = (ZLE_STRING_T)zalloc(((linesz = 256) + 2) * ZLE_CHAR_SIZE); *zleline = ZWC('\0'); virangeflag = lastcmd = done = zlecs = zlell = mark = 0; vichgflag = 0; viinsbegin = 0; statusline = NULL; selectkeymap("main", 1); initundo(); fixsuffix(); if ((s = getlinknode(bufstack))) { setline(s, ZSL_TOEND); zsfree(s); if (stackcs != -1) { zlecs = stackcs; stackcs = -1; if (zlecs > zlell) zlecs = zlell; CCLEFT(); } if (stackhist != -1) { histline = stackhist; stackhist = -1; } handleundo(); } /* * If main is linked to the viins keymap, we need to register * explicitly that we're now in vi insert mode as there's * no user operation to indicate this. */ if (openkeymap("main") == openkeymap("viins")) viinsert_init(); selectlocalmap(NULL); if (isset(PROMPTCR)) putc('\r', shout); if (tmout) alarm(tmout); /* * On some windowing systems we may enter this function before the * terminal is fully opened and sized, resulting in an infinite * series of SIGWINCH when the handler prints the prompt before we * have done so here. Therefore, hold any such signal until the * first full refresh has completed. The important bit is that the * handler must not see zleactive = 1 until ZLE really is active. * See the end of adjustwinsize() in Src/utils.c */ queue_signals(); zleactive = 1; resetneeded = 1; /* * Start of the main zle read. * Fully reset error conditions, including user interrupt. */ errflag = retflag = 0; lastcol = -1; initmodifier(&zmod); prefixflag = 0; zrefresh(); unqueue_signals(); /* Should now be safe to acknowledge SIGWINCH */ zlecallhook(init, NULL); if ((bracket = getaparam("zle_bracketed_paste")) && arrlen(bracket) == 2) fputs(*bracket, shout); zrefresh(); zlecore(); if (errflag) setsparam((zlecontext == ZLCON_VARED) ? "ZLE_VARED_ABORTED" : "ZLE_LINE_ABORTED", zlegetline(NULL, NULL)); if ((bracket = getaparam("zle_bracketed_paste")) && arrlen(bracket) == 2) fputs(bracket[1], shout); if (done && !exit_pending && !errflag) zlecallhook(finish, NULL); statusline = NULL; invalidatelist(); trashzle(); free(lpromptbuf); free(rpromptbuf); zleactive = zlereadflags = lastlistlen = zlecontext = 0; alarm(0); freeundo(); if (eofsent || errflag || exit_pending) { s = NULL; } else { zleline[zlell++] = ZWC('\n'); s = zlegetline(NULL, NULL); } free(zleline); zleline = NULL; forget_edits(); errno = old_errno; /* highlight no longer valid */ set_region_highlight(NULL, NULL); return s; }
static int bin_vared(char *name, char **args, Options ops, UNUSED(int func)) { char *s, *t, *ova = varedarg; struct value vbuf; Value v; Param pm = 0; int ifl; int type = PM_SCALAR, obreaks = breaks, haso = 0, oSHTTY = 0; char *p1, *p2, *main_keymapname, *vicmd_keymapname, *init, *finish; Keymap main_keymapsave = NULL, vicmd_keymapsave = NULL; FILE *oshout = NULL; if ((interact && unset(USEZLE)) || !strcmp(term, "emacs")) { zwarnnam(name, "ZLE not enabled"); return 1; } if (zleactive) { zwarnnam(name, "ZLE cannot be used recursively (yet)"); return 1; } if (OPT_ISSET(ops,'A')) { if (OPT_ISSET(ops, 'a')) { zwarnnam(name, "specify only one of -a and -A"); return 1; } type = PM_HASHED; } else if (OPT_ISSET(ops,'a')) type = PM_ARRAY; p1 = OPT_ARG_SAFE(ops,'p'); p2 = OPT_ARG_SAFE(ops,'r'); main_keymapname = OPT_ARG_SAFE(ops,'M'); vicmd_keymapname = OPT_ARG_SAFE(ops,'m'); init = OPT_ARG_SAFE(ops,'i'); finish = OPT_ARG_SAFE(ops,'f'); if (type != PM_SCALAR && !OPT_ISSET(ops,'c')) { zwarnnam(name, "-%s ignored", type == PM_ARRAY ? "a" : "A"); } /* handle non-existent parameter */ s = args[0]; queue_signals(); v = fetchvalue(&vbuf, &s, (!OPT_ISSET(ops,'c') || type == PM_SCALAR), SCANPM_WANTKEYS|SCANPM_WANTVALS|SCANPM_MATCHMANY); if (!v && !OPT_ISSET(ops,'c')) { unqueue_signals(); zwarnnam(name, "no such variable: %s", args[0]); return 1; } else if (v) { if (*s) { zwarnnam(name, "not an identifier: `%s'", args[0]); return 1; } if (v->isarr) { /* Array: check for separators and quote them. */ char **arr = getarrvalue(v), **aptr, **tmparr, **tptr; tptr = tmparr = (char **)zhalloc(sizeof(char *)*(arrlen(arr)+1)); for (aptr = arr; *aptr; aptr++) { int sepcount = 0, clen; convchar_t c; /* * See if this word contains a separator character * or backslash */ MB_METACHARINIT(); for (t = *aptr; *t; ) { if (*t == '\\') { t++; sepcount++; } else { t += MB_METACHARLENCONV(t, &c); if (WC_ZISTYPE(c, ISEP)) sepcount++; } } if (sepcount) { /* Yes, so allocate enough space to quote it. */ char *newstr, *nptr; newstr = zhalloc(strlen(*aptr)+sepcount+1); /* Go through string quoting separators */ MB_METACHARINIT(); for (t = *aptr, nptr = newstr; *t; ) { if (*t == '\\') { *nptr++ = '\\'; *nptr++ = *t++; } else { clen = MB_METACHARLENCONV(t, &c); if (WC_ZISTYPE(c, ISEP)) *nptr++ = '\\'; while (clen--) *nptr++ = *t++; } } *nptr = '\0'; /* Stick this into the array of words to join up */ *tptr++ = newstr; } else *tptr++ = *aptr; /* No, keep original array element */ } *tptr = NULL; s = sepjoin(tmparr, NULL, 0); } else { s = ztrdup(getstrvalue(v)); } unqueue_signals(); } else if (*s) { unqueue_signals(); zwarnnam(name, "invalid parameter name: %s", args[0]); return 1; } else { unqueue_signals(); s = ztrdup(s); } if (SHTTY == -1 || OPT_ISSET(ops,'t')) { /* need to open /dev/tty specially */ oSHTTY = SHTTY; if ((SHTTY = open(OPT_ISSET(ops,'t') ? OPT_ARG(ops,'t') : "/dev/tty", O_RDWR|O_NOCTTY)) == -1) { zwarnnam(name, "can't access terminal"); zsfree(s); return 1; } if (!isatty(SHTTY)) { zwarnnam(name, "%s: not a terminal", OPT_ARG(ops,'t')); close(SHTTY); SHTTY = oSHTTY; zsfree(s); return 1; } oshout = shout; init_shout(); haso = 1; } /* edit the parameter value */ zpushnode(bufstack, s); if (main_keymapname && savekeymap(name, "main", main_keymapname, &main_keymapsave)) main_keymapname = NULL; if (vicmd_keymapname && savekeymap(name, "vicmd", vicmd_keymapname, &vicmd_keymapsave)) vicmd_keymapname = NULL; varedarg = *args; ifl = isfirstln; if (OPT_ISSET(ops,'h')) hbegin(2); isfirstln = OPT_ISSET(ops,'e'); t = zleread(&p1, &p2, OPT_ISSET(ops,'h') ? ZLRF_HISTORY : 0, ZLCON_VARED, init ? init : "zle-line-init", finish ? finish : "zle-line-finish"); if (OPT_ISSET(ops,'h')) hend(NULL); isfirstln = ifl; varedarg = ova; restorekeymap(name, "main", main_keymapname, main_keymapsave); restorekeymap(name, "vicmd", vicmd_keymapname, vicmd_keymapsave); if (haso) { fclose(shout); /* close(SHTTY) */ shout = oshout; SHTTY = oSHTTY; } if (!t || errflag) { /* error in editing */ errflag &= ~ERRFLAG_ERROR; breaks = obreaks; if (t) zsfree(t); return 1; } /* strip off trailing newline, if any */ if (t[strlen(t) - 1] == '\n') t[strlen(t) - 1] = '\0'; /* final assignment of parameter value */ if (OPT_ISSET(ops,'c')) { unsetparam(args[0]); createparam(args[0], type); } queue_signals(); pm = (Param) paramtab->getnode(paramtab, args[0]); if (pm && (PM_TYPE(pm->node.flags) & (PM_ARRAY|PM_HASHED))) { char **a; /* * Use spacesplit with fourth argument 1: identify quoted separators, * and unquote. This duplicates the string, so we still need to free. */ a = spacesplit(t, 1, 0, 1); zsfree(t); if (PM_TYPE(pm->node.flags) == PM_ARRAY) setaparam(args[0], a); else sethparam(args[0], a); } else setsparam(args[0], t); unqueue_signals(); return 0; }
static int bin_sysread(char *nam, char **args, Options ops, UNUSED(int func)) { int infd = 0, outfd = -1, bufsize = SYSREAD_BUFSIZE, count; char *outvar = NULL, *countvar = NULL, *inbuf; /* -i: input file descriptor if not stdin */ if (OPT_ISSET(ops, 'i')) { infd = getposint(OPT_ARG(ops, 'i'), nam); if (infd < 0) return 1; } /* -o: output file descriptor, else store in REPLY */ if (OPT_ISSET(ops, 'o')) { if (*args) { zwarnnam(nam, "no argument allowed with -o"); return 1; } outfd = getposint(OPT_ARG(ops, 'o'), nam); if (outfd < 0) return 1; } /* -s: buffer size if not default SYSREAD_BUFSIZE */ if (OPT_ISSET(ops, 's')) { bufsize = getposint(OPT_ARG(ops, 's'), nam); if (bufsize < 0) return 1; } /* -c: name of variable to store count of transferred bytes */ if (OPT_ISSET(ops, 'c')) { countvar = OPT_ARG(ops, 'c'); if (!isident(countvar)) { zwarnnam(nam, "not an identifier: %s", countvar); return 1; } } if (*args) { /* * Variable in which to store result if doing a plain read. * Default variable if not specified is REPLY. * If writing, only stuff we couldn't write is stored here, * no default in that case (we just discard it if no variable). */ outvar = *args; if (!isident(outvar)) { zwarnnam(nam, "not an identifier: %s", outvar); return 1; } } inbuf = zhalloc(bufsize); #if defined(HAVE_POLL) || defined(HAVE_SELECT) /* -t: timeout */ if (OPT_ISSET(ops, 't')) { # ifdef HAVE_POLL struct pollfd poll_fd; mnumber to_mn; int to_int, ret; poll_fd.fd = infd; poll_fd.events = POLLIN; to_mn = matheval(OPT_ARG(ops, 't')); if (errflag) return 1; if (to_mn.type == MN_FLOAT) to_int = (int) (1000 * to_mn.u.d); else to_int = 1000 * (int)to_mn.u.l; while ((ret = poll(&poll_fd, 1, to_int)) < 0) { if (errno != EINTR || errflag || retflag || breaks || contflag) break; } if (ret <= 0) { /* treat non-timeout error as error on read */ return ret ? 2 : 4; } # else /* using select */ struct timeval select_tv; fd_set fds; mnumber to_mn; int ret; FD_ZERO(&fds); FD_SET(infd, &fds); to_mn = matheval(OPT_ARG(ops, 't')); if (errflag) return 1; if (to_mn.type == MN_FLOAT) { select_tv.tv_sec = (int) to_mn.u.d; select_tv.tv_usec = (int) ((to_mn.u.d - select_tv.tv_sec) * 1e6); } else { select_tv.tv_sec = (int) to_mn.u.l; select_tv.tv_usec = 0; } while ((ret = select(infd+1, (SELECT_ARG_2_T) &fds, NULL, NULL,&select_tv)) < 1) { if (errno != EINTR || errflag || retflag || breaks || contflag) break; } if (ret <= 0) { /* treat non-timeout error as error on read */ return ret ? 2 : 4; } # endif } #endif while ((count = read(infd, inbuf, bufsize)) < 0) { if (errno != EINTR || errflag || retflag || breaks || contflag) break; } if (countvar) setiparam(countvar, count); if (count < 0) return 2; if (outfd >= 0) { if (!count) return 5; while (count > 0) { int ret; ret = write(outfd, inbuf, count); if (ret < 0) { if (errno == EINTR && !errflag && !retflag && !breaks && !contflag) continue; if (outvar) setsparam(outvar, metafy(inbuf, count, META_DUP)); if (countvar) setiparam(countvar, count); return 3; } inbuf += ret; count -= ret; } return 0; } if (!outvar) outvar = "REPLY"; /* do this even if we read zero bytes */ setsparam(outvar, metafy(inbuf, count, META_DUP)); return count ? 0 : 5; }
static int ptyread(char *nam, Ptycmd cmd, char **args, int noblock, int mustmatch) { int blen, used, seen = 0, ret = 0, matchok = 0; char *buf; Patprog prog = NULL; if (*args && args[1]) { char *p; if (args[2]) { zwarnnam(nam, "too many arguments"); return 1; } p = dupstring(args[1]); tokenize(p); remnulargs(p); /* Signals handlers might stomp PAT_STATIC */ if (!(prog = patcompile(p, PAT_ZDUP, NULL))) { zwarnnam(nam, "bad pattern: %s", args[1]); return 1; } } else fflush(stdout); if (cmd->old) { used = cmd->olen; buf = (char *) zhalloc((blen = 256 + used) + 1); memcpy(buf, cmd->old, cmd->olen); zfree(cmd->old, cmd->olen); cmd->old = NULL; cmd->olen = 0; } else { used = 0; buf = (char *) zhalloc((blen = 256) + 1); } if (cmd->read != -1) { buf[used] = (char) cmd->read; buf[used + 1] = '\0'; seen = used = 1; cmd->read = -1; } do { if (noblock && cmd->read == -1) { int pollret; /* * Check there is data available. Borrowed from * poll_read() in utils.c and simplified. */ #ifdef HAVE_SELECT fd_set foofd; struct timeval expire_tv; expire_tv.tv_sec = 0; expire_tv.tv_usec = 0; FD_ZERO(&foofd); FD_SET(cmd->fd, &foofd); pollret = select(cmd->fd+1, (SELECT_ARG_2_T) &foofd, NULL, NULL, &expire_tv); #else #ifdef FIONREAD if (ioctl(cmd->fd, FIONREAD, (char *) &val) == 0) pollret = (val > 0); #endif #endif if (pollret < 0) { /* * See read_poll() for this. * Last despairing effort to poll: attempt to * set nonblocking I/O and actually read the * character. cmd->read stores the character read. */ long mode; if (setblock_fd(0, cmd->fd, &mode)) pollret = read(cmd->fd, &cmd->read, 1); if (mode != -1) fcntl(cmd->fd, F_SETFL, mode); } if (pollret == 0) break; } if (!ret) { checkptycmd(cmd); if (cmd->fin) break; } if (cmd->read != -1 || (ret = read(cmd->fd, buf + used, 1)) == 1) { int readchar; if (cmd->read != -1) { ret = 1; readchar = cmd->read; cmd->read = -1; } else readchar = STOUC(buf[used]); if (imeta(readchar)) { buf[used++] = Meta; buf[used++] = (char) (readchar ^ 32); } else buf[used++] = (char) readchar; seen = 1; if (used >= blen-1) { if (!*args) { buf[used] = '\0'; unmetafy(buf, &used); write_loop(1, buf, used); used = 0; } else { buf = hrealloc(buf, blen, blen << 1); blen <<= 1; } } } buf[used] = '\0'; if (!prog) { if (ret <= 0 || (*args && buf[used - 1] == '\n' && (used < 2 || buf[used-2] != Meta))) break; } else { if (ret < 0 #ifdef EWOULDBLOCK && errno != EWOULDBLOCK #else #ifdef EAGAIN && errno != EAGAIN #endif #endif ) break; } } while (!(errflag || breaks || retflag || contflag) && used < READ_MAX && !(prog && ret && (matchok = pattry(prog, buf)))); if (prog && ret < 0 && #ifdef EWOULDBLOCK errno == EWOULDBLOCK #else #ifdef EAGAIN errno == EAGAIN #endif #endif ) { cmd->old = (char *) zalloc(cmd->olen = used); memcpy(cmd->old, buf, cmd->olen); return 1; } if (*args) setsparam(*args, ztrdup(buf)); else if (used) { unmetafy(buf, &used); write_loop(1, buf, used); } { int ret = cmd->fin + 1; if (seen && (!prog || matchok || !mustmatch)) ret = 0; if (prog) freepatprog(prog); return ret; } }
static int bin_clone(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) { int ttyfd, pid, cttyfd; unmetafy(*args, NULL); ttyfd = open(*args, O_RDWR|O_NOCTTY); if (ttyfd < 0) { zwarnnam(nam, "%s: %e", *args, errno); return 1; } pid = fork(); if (!pid) { clearjobtab(0); ppid = getppid(); mypid = getpid(); #ifdef HAVE_SETSID if (setsid() != mypid) zwarnnam(nam, "failed to create new session: %e", NULL, errno); #elif defined(TIOCNOTTY) if (ioctl(SHTTY, TIOCNOTTY, 0)) zwarnnam(*args, "%e", NULL, errno); setpgrp(0L, mypid); #endif dup2(ttyfd,0); dup2(ttyfd,1); dup2(ttyfd,2); if (ttyfd > 2) close(ttyfd); closem(0); close(coprocin); close(coprocout); /* Acquire a controlling terminal */ cttyfd = open(*args, O_RDWR); if (cttyfd == -1) zwarnnam(nam, "%e", NULL, errno); else { #ifdef TIOCSCTTY ioctl(cttyfd, TIOCSCTTY, 0); #endif close(cttyfd); } /* check if we acquired the tty successfully */ cttyfd = open("/dev/tty", O_RDWR); if (cttyfd == -1) zwarnnam(nam, "could not make %s my controlling tty, job control " "disabled", *args, 0); else close(cttyfd); /* Clear mygrp so that acquire_pgrp() gets the new process group. * (acquire_pgrp() is called from init_io()) */ mypgrp = 0; init_io(); setsparam("TTY", ztrdup(ttystrname)); } close(ttyfd); if (pid < 0) { zerrnam(nam, "fork failed: %e", NULL, errno); return 1; } lastpid = pid; return 0; }
static int zcond_regex_match(char **a, int id) { regex_t re; regmatch_t *m, *matches = NULL; size_t matchessz = 0; char *lhstr, *lhstr_zshmeta, *rhre, *rhre_zshmeta, *s, **arr, **x; int r, n, return_value, rcflags, reflags, nelem, start; lhstr_zshmeta = cond_str(a,0,0); rhre_zshmeta = cond_str(a,1,0); rcflags = reflags = 0; return_value = 0; /* 1 => matched successfully */ lhstr = ztrdup(lhstr_zshmeta); unmetafy(lhstr, NULL); rhre = ztrdup(rhre_zshmeta); unmetafy(rhre, NULL); switch(id) { case ZREGEX_EXTENDED: rcflags |= REG_EXTENDED; if (!isset(CASEMATCH)) rcflags |= REG_ICASE; r = regcomp(&re, rhre, rcflags); if (r) { zregex_regerrwarn(r, &re, "failed to compile regex"); break; } /* re.re_nsub is number of parenthesized groups, we also need * 1 for the 0 offset, which is the entire matched portion */ if ((int)re.re_nsub < 0) { zwarn("INTERNAL ERROR: regcomp() returned " "negative subpattern count %d", (int)re.re_nsub); break; } matchessz = (re.re_nsub + 1) * sizeof(regmatch_t); matches = zalloc(matchessz); r = regexec(&re, lhstr, re.re_nsub+1, matches, reflags); if (r == REG_NOMATCH) ; /* We do nothing when we fail to match. */ else if (r == 0) { return_value = 1; if (isset(BASHREMATCH)) { start = 0; nelem = re.re_nsub + 1; } else { start = 1; nelem = re.re_nsub; } arr = NULL; /* bogus gcc warning of used uninitialised */ /* entire matched portion + re_nsub substrings + NULL */ if (nelem) { arr = x = (char **) zalloc(sizeof(char *) * (nelem + 1)); for (m = matches + start, n = start; n <= (int)re.re_nsub; ++n, ++m, ++x) { *x = metafy(lhstr + m->rm_so, m->rm_eo - m->rm_so, META_DUP); } *x = NULL; } if (isset(BASHREMATCH)) { setaparam("BASH_REMATCH", arr); } else { zlong offs; char *ptr; int clen, leftlen; m = matches; s = metafy(lhstr + m->rm_so, m->rm_eo - m->rm_so, META_DUP); setsparam("MATCH", s); /* * Count the characters before the match. */ ptr = lhstr; leftlen = m->rm_so; offs = 0; MB_CHARINIT(); while (leftlen) { offs++; clen = MB_CHARLEN(ptr, leftlen); ptr += clen; leftlen -= clen; } setiparam("MBEGIN", offs + !isset(KSHARRAYS)); /* * Add on the characters in the match. */ leftlen = m->rm_eo - m->rm_so; while (leftlen) { offs++; clen = MB_CHARLEN(ptr, leftlen); ptr += clen; leftlen -= clen; } setiparam("MEND", offs + !isset(KSHARRAYS) - 1); if (nelem) { char **mbegin, **mend, **bptr, **eptr; bptr = mbegin = (char **)zalloc(sizeof(char *)*(nelem+1)); eptr = mend = (char **)zalloc(sizeof(char *)*(nelem+1)); for (m = matches + start, n = 0; n < nelem; ++n, ++m, ++bptr, ++eptr) { char buf[DIGBUFSIZE]; if (m->rm_so < 0 || m->rm_eo < 0) { *bptr = ztrdup("-1"); *eptr = ztrdup("-1"); continue; } ptr = lhstr; leftlen = m->rm_so; offs = 0; /* Find the start offset */ MB_CHARINIT(); while (leftlen) { offs++; clen = MB_CHARLEN(ptr, leftlen); ptr += clen; leftlen -= clen; } convbase(buf, offs + !isset(KSHARRAYS), 10); *bptr = ztrdup(buf); /* Continue to the end offset */ leftlen = m->rm_eo - m->rm_so; while (leftlen ) { offs++; clen = MB_CHARLEN(ptr, leftlen); ptr += clen; leftlen -= clen; } convbase(buf, offs + !isset(KSHARRAYS) - 1, 10); *eptr = ztrdup(buf); } *bptr = *eptr = NULL; setaparam("match", arr); setaparam("mbegin", mbegin); setaparam("mend", mend); } } } else zregex_regerrwarn(r, &re, "regex matching error"); break; default: DPUTS(1, "bad regex option"); return_value = 0; goto CLEAN_BASEMETA; } if (matches) zfree(matches, matchessz); regfree(&re); CLEAN_BASEMETA: free(lhstr); free(rhre); return return_value; }
char * zleread(char **lp, char **rp, int flags, int context) { char *s; int old_errno = errno; int tmout = getiparam("TMOUT"); #if defined(HAVE_POLL) || defined(HAVE_SELECT) /* may not be set, but that's OK since getiparam() returns 0 == off */ baud = getiparam("BAUD"); costmult = (baud) ? 3840000L / baud : 0; #endif /* ZLE doesn't currently work recursively. This is needed in case a * * select loop is used in a function called from ZLE. vared handles * * this differently itself. */ if(zleactive) { char *pptbuf; int pptlen; pptbuf = unmetafy(promptexpand(lp ? *lp : NULL, 0, NULL, NULL, &pmpt_attr), &pptlen); write_loop(2, pptbuf, pptlen); free(pptbuf); return shingetline(); } /* * The current status is what we need if we are going * to display a prompt. We'll remember it here for * use further in. */ pre_zle_status = lastval; keytimeout = (time_t)getiparam("KEYTIMEOUT"); if (!shout) { if (SHTTY != -1) init_shout(); if (!shout) return NULL; /* We could be smarter and default to a system read. */ /* If we just got a new shout, make sure the terminal is set up. */ if (termflags & TERM_UNKNOWN) init_term(); } fflush(shout); fflush(stderr); intr(); insmode = unset(OVERSTRIKE); eofsent = 0; resetneeded = 0; fetchttyinfo = 0; trashedzle = 0; raw_lp = lp; lpromptbuf = promptexpand(lp ? *lp : NULL, 1, NULL, NULL, &pmpt_attr); raw_rp = rp; rpmpt_attr = pmpt_attr; rpromptbuf = promptexpand(rp ? *rp : NULL, 1, NULL, NULL, &rpmpt_attr); free_prepostdisplay(); zlereadflags = flags; zlecontext = context; histline = curhist; undoing = 1; zleline = (ZLE_STRING_T)zalloc(((linesz = 256) + 2) * ZLE_CHAR_SIZE); *zleline = ZWC('\0'); virangeflag = lastcmd = done = zlecs = zlell = mark = 0; vichgflag = 0; viinsbegin = 0; statusline = NULL; selectkeymap("main", 1); selectlocalmap(NULL); fixsuffix(); if ((s = getlinknode(bufstack))) { setline(s, ZSL_TOEND); zsfree(s); if (stackcs != -1) { zlecs = stackcs; stackcs = -1; if (zlecs > zlell) zlecs = zlell; CCLEFT(); } if (stackhist != -1) { histline = stackhist; stackhist = -1; } } initundo(); if (isset(PROMPTCR)) putc('\r', shout); if (tmout) alarm(tmout); zleactive = 1; resetneeded = 1; errflag = retflag = 0; lastcol = -1; initmodifier(&zmod); prefixflag = 0; zrefresh(); zlecallhook("zle-line-init", NULL); zlecore(); if (errflag) setsparam("ZLE_LINE_ABORTED", zlegetline(NULL, NULL)); if (done && !exit_pending && !errflag) zlecallhook("zle-line-finish", NULL); statusline = NULL; invalidatelist(); trashzle(); free(lpromptbuf); free(rpromptbuf); zleactive = zlereadflags = lastlistlen = zlecontext = 0; alarm(0); freeundo(); if (eofsent) { s = NULL; } else { zleline[zlell++] = ZWC('\n'); s = zlegetline(NULL, NULL); } free(zleline); zleline = NULL; forget_edits(); errno = old_errno; /* highlight no longer valid */ set_region_highlight(NULL, NULL); return s; }