Exemplo n.º 1
0
Arquivo: math.c Projeto: blueyed/zsh
static mnumber
getcvar(char *s)
{
    char *t;
    mnumber mn;
    mn.type = MN_INTEGER;

    queue_signals();
    if (!(t = getsparam(s)))
	mn.u.l = 0;
    else {
#ifdef MULTIBYTE_SUPPORT
	if (isset(MULTIBYTE)) {
	    wint_t wc;
	    (void)mb_metacharlenconv(t, &wc);
	    if (wc != WEOF) {
		mn.u.l = (zlong)wc;
		unqueue_signals();
		return mn;
	    }
	}
#endif
	mn.u.l = STOUC(*t == Meta ? t[1] ^ 32 : *t);
    }
    unqueue_signals();
    return mn;
}
Exemplo n.º 2
0
static void
gdbmhashsetfn(Param pm, HashTable ht)
{
    int i;
    HashNode hn;
    GDBM_FILE dbf;
    datum key, content;

    if (!pm->u.hash || pm->u.hash == ht)
	return;

    if (!(dbf = (GDBM_FILE)(pm->u.hash->tmpdata)))
	return;

    key = gdbm_firstkey(dbf);
    while (key.dptr) {
	queue_signals();
	(void)gdbm_delete(dbf, key);
	free(key.dptr);
	unqueue_signals();
	key = gdbm_firstkey(dbf);
    }

    /* just deleted everything, clean up */
    (void)gdbm_reorganize(dbf);

    if (!ht)
	return;

    for (i = 0; i < ht->hsize; i++)
	for (hn = ht->nodes[i]; hn; hn = hn->next) {
	    struct value v;

	    v.isarr = v.flags = v.start = 0;
	    v.end = -1;
	    v.arr = NULL;
	    v.pm = (Param) hn;

	    key.dptr = v.pm->node.nam;
	    key.dsize = strlen(key.dptr) + 1;

	    queue_signals();

	    content.dptr = getstrvalue(&v);
	    content.dsize = strlen(content.dptr) + 1;

	    (void)gdbm_store(dbf, key, content, GDBM_REPLACE);	

	    unqueue_signals();
	}
}
Exemplo n.º 3
0
Arquivo: text.c Projeto: blueyed/zsh
char *
getjobtext(Eprog prog, Wordcode c)
{
    static char jbuf[JOBTEXTSIZE];

    struct estate s;

    queue_signals();

    if (!c)
	c = prog->prog;

    useeprog(prog);		/* mark as used */
    s.prog = prog;
    s.pc = c;
    s.strs = prog->strs;

    tindent = 0;
    tnewlins = 0;
    tbuf = NULL;
    tptr = jbuf;
    tlim = tptr + JOBTEXTSIZE - 1;
    tjob = 1;
    gettext2(&s);
    *tptr = '\0';
    freeeprog(prog);		/* mark as unused */
    untokenize(jbuf);

    unqueue_signals();

    return jbuf;
}
Exemplo n.º 4
0
Arquivo: text.c Projeto: blueyed/zsh
mod_export char *
getpermtext(Eprog prog, Wordcode c, int start_indent)
{
    struct estate s;

    queue_signals();

    if (!c)
	c = prog->prog;

    useeprog(prog);		/* mark as used */

    s.prog = prog;
    s.pc = c;
    s.strs = prog->strs;

    tindent = start_indent;
    tnewlins = 1;
    tbuf = (char *)zalloc(tsiz = 32);
    tptr = tbuf;
    tlim = tbuf + tsiz;
    tjob = 0;
    if (prog->len)
	gettext2(&s);
    *tptr = '\0';
    freeeprog(prog);		/* mark as unused */
    untokenize(tbuf);

    unqueue_signals();

    return tbuf;
}
Exemplo n.º 5
0
static int
bin_zuntie(char *nam, char **args, Options ops, UNUSED(int func))
{
    Param pm;
    char *pmname;
    int ret = 0;

    for (pmname = *args; *args++; pmname = *args) {
	pm = (Param) paramtab->getnode(paramtab, pmname);
	if(!pm) {
	    zwarnnam(nam, "cannot untie %s", pmname);
	    ret = 1;
	    continue;
	}
	if (pm->gsu.h != &gdbm_hash_gsu) {
	    zwarnnam(nam, "not a tied gdbm hash: %s", pmname);
	    ret = 1;
	    continue;
	}

	queue_signals();
	if (OPT_ISSET(ops,'u'))
	    gdbmuntie(pm);	/* clear read-only-ness */
	if (unsetparam_pm(pm, 0, 1)) {
	    /* assume already reported */
	    ret = 1;
	}
	unqueue_signals();
    }

    return ret;
}
Exemplo n.º 6
0
static int
bin_private(char *nam, char **args, LinkList assigns, Options ops, int func)
{
    int from_typeset = 1;
    makeprivate_error = 0;

    if (!OPT_ISSET(ops, 'P'))
        return bin_typeset(nam, args, assigns, ops, func);
    else if (OPT_ISSET(ops, 'T')) {
        zwarn("bad option: -T");
        return 1;
    }

    if (locallevel == 0) {
        if (isset(WARNCREATEGLOBAL))
            zwarnnam(nam, "invalid local scope, using globals");
        return bin_typeset("private", args, assigns, ops, func);
    }

    ops->ind['g'] = 2;	/* force bin_typeset() to behave as "local" */

    queue_signals();
    fakelevel = locallevel;
    startparamscope();
    from_typeset = bin_typeset("private", args, assigns, ops, func);
    scanhashtable(paramtab, 0, 0, 0, makeprivate, 0);
    endparamscope();
    fakelevel = 0;
    unqueue_signals();

    return makeprivate_error | from_typeset;
}
Exemplo n.º 7
0
Arquivo: mem.c Projeto: oldfaber/wzsh
void *
halloc(size_t size)
{
    Heap h;
    size_t n;

    size = (size + H_ISIZE - 1) & ~(H_ISIZE - 1);

#if defined(ZSH_MEM) && defined(ZSH_MEM_DEBUG)
    h_m[size < 1024 ? (size / H_ISIZE) : 1024]++;
#endif

    /* find a heap with enough free space */

    for (h = heaps; h; h = h->next) {
	if (HEAP_ARENA_SIZE >= (n = size + h->used)) {
	    h->used = n;
	    return arena(h) + n - size;
	}
    }

    {
	Heap hp;
        /* not found, allocate new heap */
#ifdef ZSH_MEM
	static int called = 0;
	void *foo = called ? (void *)malloc(HEAPFREE) : NULL;
            /* tricky, see above */
#endif

	queue_signals();
	n = HEAP_ARENA_SIZE > size ? HEAP_ARENA_SIZE : size;
	for (hp = NULL, h = heaps; h; hp = h, h = h->next);

	h = (Heap) zalloc(n + sizeof(*h));

#ifdef ZSH_MEM
	if (called)
	    zfree(foo, HEAPFREE);
	called = 1;
#endif

	h->used = size;
	h->next = NULL;
	h->sp = NULL;

	if (hp)
	    hp->next = h;
	else
	    heaps = h;

	unqueue_signals();
	return arena(h);
    }
}
Exemplo n.º 8
0
int
bin_hashinfo(char *nam, char **args, Options ops, int func)
{
    HashTable ht;

    printf("----------------------------------------------------\n");
    queue_signals();
    for(ht = firstht; ht; ht = ht->next) {
	ht->printinfo(ht);
	printf("----------------------------------------------------\n");
    }
    unqueue_signals();
    return 0;
}
Exemplo n.º 9
0
mod_export void
old_heaps(Heap old)
{
    Heap h, n;

    queue_signals();
    for (h = heaps; h; h = n) {
	n = h->next;
	DPUTS(h->sp, "BUG: old_heaps() with pushed heaps");
#ifdef ZSH_HEAP_DEBUG
	if (heap_debug_verbosity & HDV_FREE) {
	    fprintf(stderr, "HEAP DEBUG: heap " HEAPID_FMT
		    "freed in old_heaps().\n", h->heap_id);
	}
#endif
#ifdef USE_MMAP
	munmap((void *) h, h->size);
#else
	zfree(h, HEAPSIZE);
#endif
#ifdef ZSH_VALGRIND
	VALGRIND_DESTROY_MEMPOOL((char *)h);
#endif
    }
    heaps = old;
#ifdef ZSH_HEAP_DEBUG
    if (heap_debug_verbosity & HDV_OLD) {
	fprintf(stderr, "HEAP DEBUG: heap " HEAPID_FMT
		"restored.\n", heaps->heap_id);
    }
    {
	Heap myold = heaps_saved ? getlinknode(heaps_saved) : NULL;
	if (old != myold)
	{
	    fprintf(stderr, "HEAP DEBUG: invalid old heap " HEAPID_FMT
		    ", expecting " HEAPID_FMT ".\n", old->heap_id,
		    myold->heap_id);
	}
    }
#endif
    fheap = NULL;
    unqueue_signals();
}
Exemplo n.º 10
0
mod_export Heap
new_heaps(void)
{
    Heap h;

    queue_signals();
    h = heaps;

    fheap = heaps = NULL;
    unqueue_signals();

#ifdef ZSH_HEAP_DEBUG
    if (heap_debug_verbosity & HDV_NEW) {
	fprintf(stderr, "HEAP DEBUG: heap " HEAPID_FMT
		" saved, new heaps created.\n", h->heap_id);
    }
    if (!heaps_saved)
	heaps_saved = znewlinklist();
    zpushnode(heaps_saved, h);
#endif
    return h;
}
Exemplo n.º 11
0
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;
}
Exemplo n.º 12
0
int
execzlefunc(Thingy func, char **args, int set_bindk)
{
    int r = 0, ret = 0, remetafy = 0;
    Widget w;
    Thingy save_bindk = bindk;

    if (set_bindk)
	bindk = func;
    if (zlemetaline) {
	unmetafy_line();
	remetafy = 1;
    }

    if(func->flags & DISABLED) {
	/* this thingy is not the name of a widget */
	char *nm = nicedup(func->nam, 0);
	char *msg = tricat("No such widget `", nm, "'");

	zsfree(nm);
	showmsg(msg);
	zsfree(msg);
	ret = 1;
    } else if((w = func->widget)->flags & (WIDGET_INT|WIDGET_NCOMP)) {
	int wflags = w->flags;

	/*
	 * The rule is that "zle -N" widgets suppress EOF warnings.  When
	 * a "zle -N" widget invokes "zle another-widget" we pass through
	 * this code again, but with actual arguments rather than with the
	 * zlenoargs placeholder.
	 */
	if (keybuf[0] == eofchar && !keybuf[1] && args == zlenoargs &&
	    !zlell && isfirstln && (zlereadflags & ZLRF_IGNOREEOF)) {
	    showmsg((!islogin) ? "zsh: use 'exit' to exit." :
		    "zsh: use 'logout' to logout.");
	    use_exit_printed = 1;
	    eofsent = 1;
	    ret = 1;
	} else {
	    if(!(wflags & ZLE_KEEPSUFFIX))
		removesuffix();
	    if(!(wflags & ZLE_MENUCMP)) {
		fixsuffix();
		invalidatelist();
	    }
	    if (wflags & ZLE_LINEMOVE)
		vilinerange = 1;
	    if(!(wflags & ZLE_LASTCOL))
		lastcol = -1;
	    if (wflags & WIDGET_NCOMP) {
		int atcurhist = histline == curhist;
		compwidget = w;
		ret = completecall(args);
		if (atcurhist)
		    histline = curhist;
	    } else if (!w->u.fn) {
		handlefeep(zlenoargs);
	    } else {
		queue_signals();
		ret = w->u.fn(args);
		unqueue_signals();
	    }
	    if (!(wflags & ZLE_NOTCOMMAND))
		lastcmd = wflags;
	}
	r = 1;
    } else {
	Shfunc shf = (Shfunc) shfunctab->getnode(shfunctab, w->u.fnnam);

	if (!shf) {
	    /* the shell function doesn't exist */
	    char *nm = nicedup(w->u.fnnam, 0);
	    char *msg = tricat("No such shell function `", nm, "'");

	    zsfree(nm);
	    showmsg(msg);
	    zsfree(msg);
	    ret = 1;
	} else {
	    int osc = sfcontext, osi = movefd(0);
	    int oxt = isset(XTRACE);
	    LinkList largs = NULL;

	    if (*args) {
		largs = newlinklist();
		addlinknode(largs, dupstring(w->u.fnnam));
		while (*args)
		    addlinknode(largs, dupstring(*args++));
	    }
	    startparamscope();
	    makezleparams(0);
	    sfcontext = SFC_WIDGET;
	    opts[XTRACE] = 0;
	    ret = doshfunc(shf, largs, 1);
	    opts[XTRACE] = oxt;
	    sfcontext = osc;
	    endparamscope();
	    lastcmd = w->flags;
	    w->flags = 0;
	    r = 1;
	    redup(osi, 0);
	}
    }
    if (r) {
	unrefthingy(lbindk);
	refthingy(func);
	lbindk = func;
    }
    if (set_bindk)
	bindk = save_bindk;
    /*
     * Goodness knows where the user's left us; make sure
     * it's not on a combining character that won't be displayed
     * directly.
     */
    CCRIGHT();
    if (remetafy)
	metafy_line();
    return ret;
}
Exemplo n.º 13
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;
}
Exemplo n.º 14
0
static int
putpromptchar(int doprint, int endchar, unsigned int *txtchangep)
{
    char *ss, *hostnam;
    int t0, arg, test, sep, j, numjobs;
    struct tm *tm;
    struct timezone dummy_tz;
    struct timeval tv;
    time_t timet;
    Nameddir nd;

    for (; *bv->fm && *bv->fm != endchar; bv->fm++) {
	arg = 0;
	if (*bv->fm == '%' && isset(PROMPTPERCENT)) {
	    int minus = 0;
	    bv->fm++;
	    if (*bv->fm == '-') {
		minus = 1;
		bv->fm++;
	    }
	    if (idigit(*bv->fm)) {
		arg = zstrtol(bv->fm, &bv->fm, 10);
		if (minus)
		    arg *= -1;
	    } else if (minus)
		arg = -1;
	    if (*bv->fm == '(') {
		int tc, otruncwidth;

		if (idigit(*++bv->fm)) {
		    arg = zstrtol(bv->fm, &bv->fm, 10);
		} else if (arg < 0) {
		    /* negative numbers don't make sense here */
		    arg *= -1;
		}
		test = 0;
		ss = pwd;
		switch (tc = *bv->fm) {
		case 'c':
		case '.':
		case '~':
		    if ((nd = finddir(ss))) {
			arg--;
			ss += strlen(nd->dir);
		    } /*FALLTHROUGH*/
		case '/':
		case 'C':
		    /* `/' gives 0, `/any' gives 1, etc. */
		    if (*ss++ == '/' && *ss)
			arg--;
		    for (; *ss; ss++)
			if (*ss == '/')
			    arg--;
		    if (arg <= 0)
			test = 1;
		    break;
		case 't':
		case 'T':
		case 'd':
		case 'D':
		case 'w':
		    timet = time(NULL);
		    tm = localtime(&timet);
		    switch (tc) {
		    case 't':
			test = (arg == tm->tm_min);
			break;
		    case 'T':
			test = (arg == tm->tm_hour);
			break;
		    case 'd':
			test = (arg == tm->tm_mday);
			break;
		    case 'D':
			test = (arg == tm->tm_mon);
			break;
		    case 'w':
			test = (arg == tm->tm_wday);
			break;
		    }
		    break;
		case '?':
		    if (lastval == arg)
			test = 1;
		    break;
		case '#':
		    if (geteuid() == (uid_t)arg)
			test = 1;
		    break;
		case 'g':
		    if (getegid() == (gid_t)arg)
			test = 1;
		    break;
		case 'j':
		    for (numjobs = 0, j = 1; j <= maxjob; j++)
			if (jobtab[j].stat && jobtab[j].procs &&
		    	    !(jobtab[j].stat & STAT_NOPRINT)) numjobs++;
		    if (numjobs >= arg)
		    	test = 1;
		    break;
		case 'l':
		    *bv->bp = '\0';
		    countprompt(bv->bufline, &t0, 0, 0);
		    if (minus)
			t0 = zterm_columns - t0;
		    if (t0 >= arg)
			test = 1;
		    break;
		case 'e':
		    {
			Funcstack fsptr = funcstack;
			test = arg;
			while (fsptr && test > 0) {
			    test--;
			    fsptr = fsptr->prev;
			}
			test = !test;
		    }
		    break;
		case 'L':
		    if (shlvl >= arg)
			test = 1;
		    break;
		case 'S':
		    if (time(NULL) - shtimer.tv_sec >= arg)
			test = 1;
		    break;
		case 'v':
		    if (arrlen(psvar) >= arg)
			test = 1;
		    break;
		case 'V':
		    if (arrlen(psvar) >= arg) {
			if (*psvar[(arg ? arg : 1) - 1])
			    test = 1;
		    }
		    break;
		case '_':
		    test = (cmdsp >= arg);
		    break;
		case '!':
		    test = privasserted();
		    break;
		default:
		    test = -1;
		    break;
		}
		if (!*bv->fm || !(sep = *++bv->fm))
		    return 0;
		bv->fm++;
		/* Don't do the current truncation until we get back */
		otruncwidth = bv->truncwidth;
		bv->truncwidth = 0;
		if (!putpromptchar(test == 1 && doprint, sep,
				   txtchangep) || !*++bv->fm ||
		    !putpromptchar(test == 0 && doprint, ')',
				   txtchangep)) {
		    bv->truncwidth = otruncwidth;
		    return 0;
		}
		bv->truncwidth = otruncwidth;
		continue;
	    }
	    if (!doprint)
		switch(*bv->fm) {
		  case '[':
		    while(idigit(*++bv->fm));
		    while(*++bv->fm != ']');
		    continue;
		  case '<':
		    while(*++bv->fm != '<');
		    continue;
		  case '>':
		    while(*++bv->fm != '>');
		    continue;
		  case 'D':
		    if(bv->fm[1]=='{')
			while(*++bv->fm != '}');
		    continue;
		  default:
		    continue;
		}
	    switch (*bv->fm) {
	    case '~':
		promptpath(pwd, arg, 1);
		break;
	    case 'd':
	    case '/':
		promptpath(pwd, arg, 0);
		break;
	    case 'c':
	    case '.':
		promptpath(pwd, arg ? arg : 1, 1);
		break;
	    case 'C':
		promptpath(pwd, arg ? arg : 1, 0);
		break;
	    case 'N':
		promptpath(scriptname ? scriptname : argzero, arg, 0);
		break;
	    case 'h':
	    case '!':
		addbufspc(DIGBUFSIZE);
		convbase(bv->bp, curhist, 10);
		bv->bp += strlen(bv->bp);
		break;
	    case 'j':
		for (numjobs = 0, j = 1; j <= maxjob; j++)
		    if (jobtab[j].stat && jobtab[j].procs &&
		    	!(jobtab[j].stat & STAT_NOPRINT)) numjobs++;
		addbufspc(DIGBUFSIZE);
		sprintf(bv->bp, "%d", numjobs);
		bv->bp += strlen(bv->bp);
		break;
	    case 'M':
		queue_signals();
		if ((hostnam = getsparam("HOST")))
		    stradd(hostnam);
		unqueue_signals();
		break;
	    case 'm':
		if (!arg)
		    arg++;
		queue_signals();
		if (!(hostnam = getsparam("HOST")))
		    break;
		if (arg < 0) {
		    for (ss = hostnam + strlen(hostnam); ss > hostnam; ss--)
			if (ss[-1] == '.' && !++arg)
			    break;
		    stradd(ss);
		} else {
		    for (ss = hostnam; *ss; ss++)
			if (*ss == '.' && !--arg)
			    break;
		    stradd(*ss ? dupstrpfx(hostnam, ss - hostnam) : hostnam);
		}
		unqueue_signals();
		break;
	    case 'S':
		txtchangeset(txtchangep, TXTSTANDOUT, TXTNOSTANDOUT);
		txtset(TXTSTANDOUT);
		tsetcap(TCSTANDOUTBEG, TSC_PROMPT);
		break;
	    case 's':
		txtchangeset(txtchangep, TXTNOSTANDOUT, TXTSTANDOUT);
		txtunset(TXTSTANDOUT);
		tsetcap(TCSTANDOUTEND, TSC_PROMPT|TSC_DIRTY);
		break;
	    case 'B':
		txtchangeset(txtchangep, TXTBOLDFACE, TXTNOBOLDFACE);
		txtset(TXTBOLDFACE);
		tsetcap(TCBOLDFACEBEG, TSC_PROMPT|TSC_DIRTY);
		break;
	    case 'b':
		txtchangeset(txtchangep, TXTNOBOLDFACE, TXTBOLDFACE);
		txtchangeset(txtchangep, TXTNOSTANDOUT, TXTSTANDOUT);
		txtchangeset(txtchangep, TXTNOUNDERLINE, TXTUNDERLINE);
		txtunset(TXTBOLDFACE);
		tsetcap(TCALLATTRSOFF, TSC_PROMPT|TSC_DIRTY);
		break;
	    case 'U':
		txtchangeset(txtchangep, TXTUNDERLINE, TXTNOUNDERLINE);
		txtset(TXTUNDERLINE);
		tsetcap(TCUNDERLINEBEG, TSC_PROMPT);
		break;
	    case 'u':
		txtchangeset(txtchangep, TXTNOUNDERLINE, TXTUNDERLINE);
		txtunset(TXTUNDERLINE);
		tsetcap(TCUNDERLINEEND, TSC_PROMPT|TSC_DIRTY);
		break;
	    case 'F':
		arg = parsecolorchar(arg, 1);
		if (arg >= 0 && !(arg & TXTNOFGCOLOUR)) {
		    txtchangeset(txtchangep, arg & TXT_ATTR_FG_ON_MASK,
				 TXTNOFGCOLOUR);
		    txtset(arg & TXT_ATTR_FG_ON_MASK);
		    set_colour_attribute(arg, COL_SEQ_FG, TSC_PROMPT);
		    break;
		}
		/* else FALLTHROUGH */
	    case 'f':
		txtchangeset(txtchangep, TXTNOFGCOLOUR, TXT_ATTR_FG_ON_MASK);
		txtunset(TXT_ATTR_FG_ON_MASK);
		set_colour_attribute(TXTNOFGCOLOUR, COL_SEQ_FG, TSC_PROMPT);
		break;
	    case 'K':
		arg = parsecolorchar(arg, 0);
		if (arg >= 0 && !(arg & TXTNOBGCOLOUR)) {
		    txtchangeset(txtchangep, arg & TXT_ATTR_BG_ON_MASK,
				 TXTNOBGCOLOUR);
		    txtset(arg & TXT_ATTR_BG_ON_MASK);
		    set_colour_attribute(arg, COL_SEQ_BG, TSC_PROMPT);
		    break;
		}
		/* else FALLTHROUGH */
	    case 'k':
		txtchangeset(txtchangep, TXTNOBGCOLOUR, TXT_ATTR_BG_ON_MASK);
		txtunset(TXT_ATTR_BG_ON_MASK);
		set_colour_attribute(TXTNOBGCOLOUR, COL_SEQ_BG, TSC_PROMPT);
		break;
	    case '[':
		if (idigit(*++bv->fm))
		    arg = zstrtol(bv->fm, &bv->fm, 10);
		if (!prompttrunc(arg, ']', doprint, endchar, txtchangep))
		    return *bv->fm;
		break;
	    case '<':
	    case '>':
		/* Test (minus) here so -0 means "at the right margin" */
		if (minus) {
		    *bv->bp = '\0';
		    countprompt(bv->bufline, &t0, 0, 0);
		    arg = zterm_columns - t0 + arg;
		    if (arg <= 0)
			arg = 1;
		}
		if (!prompttrunc(arg, *bv->fm, doprint, endchar, txtchangep))
		    return *bv->fm;
		break;
	    case '{': /*}*/
		if (!bv->dontcount++) {
		    addbufspc(1);
		    *bv->bp++ = Inpar;
		}
		if (arg <= 0)
		    break;
		/* else */
		/* FALLTHROUGH */
	    case 'G':
		if (arg > 0) {
		    addbufspc(arg);
		    while (arg--)
			*bv->bp++ = Nularg;
		} else {
		    addbufspc(1);
		    *bv->bp++ = Nularg;
		}
		break;
	    case /*{*/ '}':
		if (bv->trunccount && bv->trunccount >= bv->dontcount)
		    return *bv->fm;
		if (bv->dontcount && !--bv->dontcount) {
		    addbufspc(1);
		    *bv->bp++ = Outpar;
		}
		break;
	    case 't':
	    case '@':
	    case 'T':
	    case '*':
	    case 'w':
	    case 'W':
	    case 'D':
		{
		    char *tmfmt, *dd, *tmbuf = NULL;

		    switch (*bv->fm) {
		    case 'T':
			tmfmt = "%K:%M";
			break;
		    case '*':
			tmfmt = "%K:%M:%S";
			break;
		    case 'w':
			tmfmt = "%a %f";
			break;
		    case 'W':
			tmfmt = "%m/%d/%y";
			break;
		    case 'D':
			if (bv->fm[1] == '{' /*}*/) {
			    for (ss = bv->fm + 2; *ss && *ss != /*{*/ '}'; ss++)
				if(*ss == '\\' && ss[1])
				    ss++;
			    dd = tmfmt = tmbuf = zalloc(ss - bv->fm);
			    for (ss = bv->fm + 2; *ss && *ss != /*{*/ '}';
				 ss++) {
				if(*ss == '\\' && ss[1])
				    ss++;
				*dd++ = *ss;
			    }
			    *dd = 0;
			    bv->fm = ss - !*ss;
			    if (!*tmfmt) {
				free(tmbuf);
				continue;
			    }
			} else
			    tmfmt = "%y-%m-%d";
			break;
		    default:
			tmfmt = "%l:%M%p";
			break;
		    }
		    gettimeofday(&tv, &dummy_tz);
		    tm = localtime(&tv.tv_sec);
		    /*
		     * Hack because strftime won't say how
		     * much space it actually needs.  Try to add it
		     * a few times until it works.  Some formats don't
		     * actually have a length, so we could go on for
		     * ever.
		     */
		    for(j = 0, t0 = strlen(tmfmt)*8; j < 3; j++, t0*=2) {
			addbufspc(t0);
			if (ztrftime(bv->bp, t0, tmfmt, tm, tv.tv_usec) >= 0)
			    break;
		    }
		    /* There is enough room for this because addbufspc(t0)
		     * allocates room for t0 * 2 bytes. */
		    metafy(bv->bp, -1, META_NOALLOC);
		    bv->bp += strlen(bv->bp);
		    zsfree(tmbuf);
		    break;
		}
	    case 'n':
		stradd(get_username());
		break;
	    case 'l':
		if (*ttystrname) {
                   ss = (strncmp(ttystrname, "/dev/tty", 8) ?
                           ttystrname + 5 : ttystrname + 8);
		    stradd(ss);
		} else
		    stradd("()");
		break;
	    case 'y':
		if (*ttystrname) {
		    ss = (strncmp(ttystrname, "/dev/", 5) ?
			    ttystrname : ttystrname + 5);
		    stradd(ss);
		} else
		    stradd("()");
		break;
	    case 'L':
		addbufspc(DIGBUFSIZE);
#if defined(ZLONG_IS_LONG_LONG) && defined(PRINTF_HAS_LLD)
		sprintf(bv->bp, "%lld", shlvl);
#else
		sprintf(bv->bp, "%ld", (long)shlvl);
#endif
		bv->bp += strlen(bv->bp);
		break;
	    case '?':
		addbufspc(DIGBUFSIZE);
#if defined(ZLONG_IS_LONG_LONG) && defined(PRINTF_HAS_LLD)
		sprintf(bv->bp, "%lld", lastval);
#else
		sprintf(bv->bp, "%ld", (long)lastval);
#endif
		bv->bp += strlen(bv->bp);
		break;
	    case '%':
	    case ')':
		addbufspc(1);
		*bv->bp++ = *bv->fm;
		break;
	    case '#':
		addbufspc(1);
		*bv->bp++ = privasserted() ? '#' : '%';
		break;
	    case 'v':
		if (!arg)
		    arg = 1;
		else if (arg < 0)
		    arg += arrlen(psvar) + 1;
		if (arg > 0 && arrlen(psvar) >= arg)
		    stradd(psvar[arg - 1]);
		break;
	    case 'E':
                tsetcap(TCCLEAREOL, TSC_PROMPT);
		break;
	    case '^':
		if (cmdsp) {
		    if (arg >= 0) {
			if (arg > cmdsp || arg == 0)
			    arg = cmdsp;
			for (t0 = cmdsp - 1; arg--; t0--) {
			    stradd(cmdnames[cmdstack[t0]]);
			    if (arg) {
				addbufspc(1);
				*bv->bp++=' ';
			    }
			}
		    } else {
			arg = -arg;
			if (arg > cmdsp)
			    arg = cmdsp;
			for (t0 = arg - 1; arg--; t0--) {
			    stradd(cmdnames[cmdstack[t0]]);
			    if (arg) {
				addbufspc(1);
				*bv->bp++=' ';
			    }
			}
		    }
		}
		break;
	    case '_':
		if (cmdsp) {
		    if (arg >= 0) {
			if (arg > cmdsp || arg == 0)
			    arg = cmdsp;
			for (t0 = cmdsp - arg; arg--; t0++) {
			    stradd(cmdnames[cmdstack[t0]]);
			    if (arg) {
				addbufspc(1);
				*bv->bp++=' ';
			    }
			}
		    } else {
			arg = -arg;
			if (arg > cmdsp)
			    arg = cmdsp;
			for (t0 = 0; arg--; t0++) {
			    stradd(cmdnames[cmdstack[t0]]);
			    if (arg) {
				addbufspc(1);
				*bv->bp++=' ';
			    }
			}
		    }
		}
		break;
	    case 'r':
		if(bv->rstring)
		    stradd(bv->rstring);
		break;
	    case 'R':
		if(bv->Rstring)
		    stradd(bv->Rstring);
		break;
	    case 'e':
	    {
		int depth = 0;
		Funcstack fsptr = funcstack;
		while (fsptr) {
		    depth++;
		    fsptr = fsptr->prev;
		}
		addbufspc(DIGBUFSIZE);
		sprintf(bv->bp, "%d", depth);
		bv->bp += strlen(bv->bp);
		break;
	    }
	    case 'I':
		if (funcstack && funcstack->tp != FS_SOURCE &&
		    !IN_EVAL_TRAP()) {
		    /*
		     * We're in a function or an eval with
		     * EVALLINENO.  Calculate the line number in
		     * the file.
		     */
		    zlong flineno = lineno + funcstack->flineno;
		    /* take account of eval line nos. starting at 1 */
		    if (funcstack->tp == FS_EVAL)
			lineno--;
		    addbufspc(DIGBUFSIZE);
#if defined(ZLONG_IS_LONG_LONG) && defined(PRINTF_HAS_LLD)
		    sprintf(bv->bp, "%lld", flineno);
#else
		    sprintf(bv->bp, "%ld", (long)flineno);
#endif
		    bv->bp += strlen(bv->bp);
		    break;
		}
		/* else we're in a file and lineno is already correct */
		/* FALLTHROUGH */
	    case 'i':
		addbufspc(DIGBUFSIZE);
#if defined(ZLONG_IS_LONG_LONG) && defined(PRINTF_HAS_LLD)
		sprintf(bv->bp, "%lld", lineno);
#else
		sprintf(bv->bp, "%ld", (long)lineno);
#endif
		bv->bp += strlen(bv->bp);
		break;
	    case 'x':
		if (funcstack && funcstack->tp != FS_SOURCE &&
		    !IN_EVAL_TRAP())
		    promptpath(funcstack->filename ? funcstack->filename : "",
			       arg, 0);
		else
		    promptpath(scriptfilename ? scriptfilename : argzero,
			       arg, 0);
		break;
	    case '\0':
		return 0;
	    case Meta:
		bv->fm++;
		break;
	    }
	} else if(*bv->fm == '!' && isset(PROMPTBANG)) {
	    if(doprint) {
		if(bv->fm[1] == '!') {
		    bv->fm++;
		    addbufspc(1);
		    pputc('!');
		} else {
		    addbufspc(DIGBUFSIZE);
		    convbase(bv->bp, curhist, 10);
		    bv->bp += strlen(bv->bp);
		}
	    }
	} else {
	    char c = *bv->fm == Meta ? *++bv->fm ^ 32 : *bv->fm;

	    if (doprint) {
		addbufspc(1);
		pputc(c);
	    }
	}
    }

    return *bv->fm;
}
Exemplo n.º 15
0
Arquivo: text.c Projeto: blueyed/zsh
void
getredirs(LinkList redirs)
{
    LinkNode n;
    static char *fstr[] =
    {
	">", ">|", ">>", ">>|", "&>", "&>|", "&>>", "&>>|", "<>", "<",
	"<<", "<<-", "<<<", "<&", ">&", NULL /* >&- */, "<", ">"
    };

    queue_signals();

    taddchr(' ');
    for (n = firstnode(redirs); n; incnode(n)) {
	Redir f = (Redir) getdata(n);

	switch (f->type) {
	case REDIR_WRITE:
	case REDIR_WRITENOW:
	case REDIR_APP:
	case REDIR_APPNOW:
	case REDIR_ERRWRITE:
	case REDIR_ERRWRITENOW:
	case REDIR_ERRAPP:
	case REDIR_ERRAPPNOW:
	case REDIR_READ:
	case REDIR_READWRITE:
	case REDIR_HERESTR:
	case REDIR_MERGEIN:
	case REDIR_MERGEOUT:
	case REDIR_INPIPE:
	case REDIR_OUTPIPE:
	    if (f->varid) {
		taddchr('{');
		taddstr(f->varid);
		taddchr('}');
	    } else if (f->fd1 != (IS_READFD(f->type) ? 0 : 1))
		taddchr('0' + f->fd1);
	    if (f->type == REDIR_HERESTR &&
		(f->flags & REDIRF_FROM_HEREDOC)) {
		if (tnewlins) {
		    /*
		     * Strings that came from here-documents are converted
		     * to here strings without quotation, so convert them
		     * back.
		     */
		    taddstr(fstr[REDIR_HEREDOC]);
		    taddstr(f->here_terminator);
		    taddpending(f->name, f->munged_here_terminator);
		} else {
		    int fnamelen, sav;
		    taddstr(fstr[REDIR_HERESTR]);
		    /*
		     * Just a quick and dirty representation.
		     * Remove a terminating newline, if any.
		     */
		    fnamelen = strlen(f->name);
		    if (fnamelen > 0 && f->name[fnamelen-1] == '\n') {
			sav = 1;
			f->name[fnamelen-1] = '\0';
		    } else
			sav = 0;
		    /*
		     * Strings that came from here-documents are converted
		     * to here strings without quotation, so add that
		     * now.  If tokens are present we need to do double quoting.
		     */
		    if (!has_token(f->name)) {
			taddchr('\'');
			taddstr(quotestring(f->name, NULL, QT_SINGLE));
			taddchr('\'');
		    } else {
			taddchr('"');
			taddstr(quotestring(f->name, NULL, QT_DOUBLE));
			taddchr('"');
		    }
		    if (sav)
			f->name[fnamelen-1] = '\n';
		}
	    } else {
		taddstr(fstr[f->type]);
		if (f->type != REDIR_MERGEIN && f->type != REDIR_MERGEOUT)
		    taddchr(' ');
		taddstr(f->name);
	    }
	    taddchr(' ');
	    break;
#ifdef DEBUG
	case REDIR_CLOSE:
	    DPUTS(1, "BUG: CLOSE in getredirs()");
	    taddchr(f->fd1 + '0');
	    taddstr(">&- ");
	    break;
	default:
	    DPUTS(1, "BUG: unknown redirection in getredirs()");
#endif
	}
    }
    tptr--;

    unqueue_signals();
}
Exemplo n.º 16
0
int
execcase(Estate state, int do_exec)
{
    Wordcode end, next;
    wordcode code = state->pc[-1];
    char *word, *pat;
    int npat, save, nalts, ialt, patok, anypatok;
    Patprog *spprog, pprog;

    end = state->pc + WC_CASE_SKIP(code);

    word = ecgetstr(state, EC_DUP, NULL);
    singsub(&word);
    untokenize(word);
    anypatok = 0;

    cmdpush(CS_CASE);
    while (state->pc < end) {
	code = *state->pc++;
	if (wc_code(code) != WC_CASE)
	    break;

	save = 0;
	next = state->pc + WC_CASE_SKIP(code);
	nalts = *state->pc++;
	ialt = patok = 0;

	if (isset(XTRACE)) {
	    printprompt4();
	    fprintf(xtrerr, "case %s (", word);
	}

	while (!patok && nalts) {
	    npat = state->pc[1];
	    spprog = state->prog->pats + npat;
	    pprog = NULL;
	    pat = NULL;

	    queue_signals();

	    if (isset(XTRACE)) {
		int htok = 0;
		pat = dupstring(ecrawstr(state->prog, state->pc, &htok));
		if (htok)
		    singsub(&pat);

		if (ialt++)
		    fprintf(stderr, " | ");
		quote_tokenized_output(pat, xtrerr);
	    }

	    if (*spprog != dummy_patprog1 && *spprog != dummy_patprog2)
		pprog = *spprog;

	    if (!pprog) {
		if (!pat) {
		    char *opat;
		    int htok = 0;

		    pat = dupstring(opat = ecrawstr(state->prog,
						    state->pc, &htok));
		    if (htok)
			singsub(&pat);
		    save = (!(state->prog->flags & EF_HEAP) &&
			    !strcmp(pat, opat) && *spprog != dummy_patprog2);
		}
		if (!(pprog = patcompile(pat, (save ? PAT_ZDUP : PAT_STATIC),
					 NULL)))
		    zerr("bad pattern: %s", pat);
		else if (save)
		    *spprog = pprog;
	    }
	    if (pprog && pattry(pprog, word))
		patok = anypatok = 1;
	    state->pc += 2;
	    nalts--;

	    unqueue_signals();
	}
	state->pc += 2 * nalts;
	if (isset(XTRACE)) {
	    fprintf(xtrerr, ")\n");
	    fflush(xtrerr);
	}
	if (patok) {
	    execlist(state, 1, ((WC_CASE_TYPE(code) == WC_CASE_OR) &&
				do_exec));
	    while (!retflag && wc_code(code) == WC_CASE &&
		   WC_CASE_TYPE(code) == WC_CASE_AND && state->pc < end) {
		state->pc = next;
		code = *state->pc++;
		next = state->pc + WC_CASE_SKIP(code);
		nalts = *state->pc++;
		state->pc += 2 * nalts;
		execlist(state, 1, ((WC_CASE_TYPE(code) == WC_CASE_OR) &&
				    do_exec));
	    }
	    if (WC_CASE_TYPE(code) != WC_CASE_TESTAND)
		break;
	}
	state->pc = next;
    }
    cmdpop();

    state->pc = end;

    if (!anypatok)
	lastval = 0;
    this_noerrexit = 1;

    return lastval;
}