about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTanaka Akira <akr@users.sourceforge.net>1999-08-02 16:52:12 +0000
committerTanaka Akira <akr@users.sourceforge.net>1999-08-02 16:52:12 +0000
commit3a903f4839911204f04b4d2777a189941c9e5c06 (patch)
treef3fec85e8dc8d6e328ff734b1f6f7136361f03a5
parent8de5876e8eb2af62f69ca03cdbbf11d731aba389 (diff)
downloadzsh-3a903f4839911204f04b4d2777a189941c9e5c06.tar.gz
zsh-3a903f4839911204f04b4d2777a189941c9e5c06.tar.xz
zsh-3a903f4839911204f04b4d2777a189941c9e5c06.zip
zsh-workers:7349
-rw-r--r--Src/loop.c136
-rw-r--r--Src/signals.c175
2 files changed, 256 insertions, 55 deletions
diff --git a/Src/loop.c b/Src/loop.c
index 95ec4832a..3432c384f 100644
--- a/Src/loop.c
+++ b/Src/loop.c
@@ -44,22 +44,26 @@ int contflag;
  
 /**/
 int breaks;
- 
+
 /**/
 int
-execfor(Cmd cmd)
+execfor(Cmd cmd, LinkList args, int flags)
 {
-    List list;
     Forcmd node;
     char *str;
-    int val = 0;
-    LinkList args;
+    zlong val = 0;
 
     node = cmd->u.forcmd;
-    args = cmd->args;
     if (node->condition) {
-	str = node->name;
+	str = dupstring(node->name);
 	singsub(&str);
+	if (isset(XTRACE)) {
+	    char *str2 = dupstring(str);
+	    untokenize(str2);
+	    printprompt4();
+	    fprintf(stderr, "%s\n", str2);
+	    fflush(stderr);
+	}
 	if (!errflag)
 	    matheval(str);
 	if (errflag)
@@ -69,11 +73,12 @@ execfor(Cmd cmd)
 
 	args = newlinklist();
 	for (x = pparams; *x; x++)
-	    addlinknode(args, ztrdup(*x));
+	    addlinknode(args, dupstring(*x));
     }
     lastval = 0;
     loops++;
     pushheap();
+    cmdpush(CS_FOR);
     for (;;) {
 	if (node->condition) {
 	    str = dupstring(node->condition);
@@ -81,9 +86,14 @@ execfor(Cmd cmd)
 	    if (!errflag) {
 		while (iblank(*str))
 		    str++;
-		if (*str)
+		if (*str) {
+		    if (isset(XTRACE)) {
+			printprompt4();
+			fprintf(stderr, "%s\n", str);
+			fflush(stderr);
+		    }
 		    val = matheval(str);
-		else
+		} else
 		    val = 1;
 	    }
 	    if (errflag) {
@@ -95,13 +105,17 @@ execfor(Cmd cmd)
 	    if (!val)
 		break;
 	} else {
-	    str = (char *) ugetnode(args);
-	    if (!str)
+	    if (!args || !(str = (char *) ugetnode(args)))
 		break;
+	    if (isset(XTRACE)) {
+		printprompt4();
+		fprintf(stderr, "%s=%s\n", node->name, str);
+		fflush(stderr);
+	    }
 	    setsparam(node->name, ztrdup(str));
 	}
-	list = (List) dupstruct(node->list);
-	execlist(list, 1, (cmd->flags & CFLAG_EXEC) && empty(args));
+	execlist(node->list, 1,
+		 (flags & CFLAG_EXEC) && args && empty(args));
 	if (breaks) {
 	    breaks--;
 	    if (breaks || !contflag)
@@ -110,6 +124,11 @@ execfor(Cmd cmd)
 	}
 	if (node->condition && !errflag) {
 	    str = dupstring(node->advance);
+	    if (isset(XTRACE)) {
+		printprompt4();
+		fprintf(stderr, "%s\n", str);
+		fflush(stderr);
+	    }
 	    singsub(&str);
 	    if (!errflag)
 		matheval(str);
@@ -123,44 +142,49 @@ execfor(Cmd cmd)
 	freeheap();
     }
     popheap();
+    cmdpop();
     loops--;
     return lastval;
 }
 
 /**/
 int
-execselect(Cmd cmd)
+execselect(Cmd cmd, LinkList args, int flags)
 {
-    List list;
     Forcmd node;
     char *str, *s;
-    LinkList args;
     LinkNode n;
     int i;
     FILE *inp;
+    size_t more;
 
     node = cmd->u.forcmd;
-    args = cmd->args;
     if (!node->inflag) {
 	char **x;
 
 	args = newlinklist();
 	for (x = pparams; *x; x++)
-	    addlinknode(args, ztrdup(*x));
+	    addlinknode(args, dupstring(*x));
     }
-    if (empty(args))
+    if (!args || empty(args))
 	return 1;
     loops++;
     lastval = 0;
     pushheap();
+    cmdpush(CS_SELECT);
     inp = fdopen(dup((SHTTY == -1) ? 0 : SHTTY), "r");
-    selectlist(args);
+    more = selectlist(args, 0);
     for (;;) {
 	for (;;) {
 	    if (empty(bufstack)) {
 	    	if (interact && SHTTY != -1 && isset(USEZLE)) {
+		    int oef = errflag;
+
 		    isfirstln = 1;
 		    str = (char *)zleread(prompt3, NULL, 0);
+		    if (errflag)
+			str = NULL;
+		    errflag = oef;
 	    	} else {
 		    str = promptexpand(prompt3, 0, NULL, NULL);
 		    zputs(str, stderr);
@@ -181,7 +205,7 @@ execselect(Cmd cmd)
 		*s = '\0';
 	    if (*str)
 	      break;
-	    selectlist(args);
+	    more = selectlist(args, more);
 	}
 	setsparam("REPLY", ztrdup(str));
 	i = atoi(str);
@@ -195,8 +219,7 @@ execselect(Cmd cmd)
 		str = "";
 	}
 	setsparam(node->name, ztrdup(str));
-	list = (List) dupstruct(node->list);
-	execlist(list, 1, 0);
+	execlist(node->list, 1, 0);
 	freeheap();
 	if (breaks) {
 	    breaks--;
@@ -208,6 +231,7 @@ execselect(Cmd cmd)
 	    break;
     }
   done:
+    cmdpop();
     popheap();
     fclose(inp);
     loops--;
@@ -217,8 +241,8 @@ execselect(Cmd cmd)
 /* And this is used to print select lists. */
 
 /**/
-static void
-selectlist(LinkList l)
+size_t
+selectlist(LinkList l, size_t start)
 {
     size_t longest = 1, fct, fw = 0, colsz, t0, t1, ct;
     LinkNode n;
@@ -245,7 +269,7 @@ selectlist(LinkList l)
     else
 	fw = (columns - 1) / fct;
     colsz = (ct + fct - 1) / fct;
-    for (t1 = 0; t1 != colsz; t1++) {
+    for (t1 = start; t1 != colsz && t1 - start < lines - 2; t1++) {
 	ap = arr + t1;
 	do {
 	    int t2 = strlen(*ap) + 2, t3;
@@ -271,13 +295,14 @@ selectlist(LinkList l)
        }
        while (*ap);*/
     fflush(stderr);
+
+    return t1 < colsz ? t1 : 0;
 }
 
 /**/
 int
-execwhile(Cmd cmd)
+execwhile(Cmd cmd, LinkList args, int flags)
 {
-    List list;
     struct whilecmd *node;
     int olderrexit, oldval;
 
@@ -285,11 +310,11 @@ execwhile(Cmd cmd)
     node = cmd->u.whilecmd;
     oldval = 0;
     pushheap();
+    cmdpush(node->cond ? CS_UNTIL : CS_WHILE);
     loops++;
     for (;;) {
-	list = (List) dupstruct(node->cont);
 	noerrexit = 1;
-	execlist(list, 1, 0);
+	execlist(node->cont, 1, 0);
 	noerrexit = olderrexit;
 	if (!((lastval == 0) ^ node->cond)) {
 	    if (breaks)
@@ -297,8 +322,7 @@ execwhile(Cmd cmd)
 	    lastval = oldval;
 	    break;
 	}
-	list = (List) dupstruct(node->loop);
-	execlist(list, 1, 0);
+	execlist(node->loop, 1, 0);
 	if (breaks) {
 	    breaks--;
 	    if (breaks || !contflag)
@@ -312,6 +336,7 @@ execwhile(Cmd cmd)
 	}
 	oldval = lastval;
     }
+    cmdpop();
     popheap();
     loops--;
     return lastval;
@@ -319,22 +344,21 @@ execwhile(Cmd cmd)
 
 /**/
 int
-execrepeat(Cmd cmd)
+execrepeat(Cmd cmd, LinkList args, int flags)
 {
-    List list;
     int count;
 
     lastval = 0;
-    if (empty(cmd->args) || nextnode(firstnode(cmd->args))) {
+    if (!args || empty(args) || nextnode(firstnode(args))) {
 	zerr("bad argument for repeat", NULL, 0);
 	return 1;
     }
-    count = atoi(peekfirst(cmd->args));
+    count = atoi(peekfirst(args));
     pushheap();
+    cmdpush(CS_REPEAT);
     loops++;
     while (count--) {
-	list = (List) dupstruct(cmd->u.list);
-	execlist(list, 1, 0);
+	execlist(cmd->u.list, 1, 0);
 	freeheap();
 	if (breaks) {
 	    breaks--;
@@ -347,6 +371,7 @@ execrepeat(Cmd cmd)
 	    break;
 	}
     }
+    cmdpop();
     popheap();
     loops--;
     return lastval;
@@ -354,10 +379,10 @@ execrepeat(Cmd cmd)
 
 /**/
 int
-execif(Cmd cmd)
+execif(Cmd cmd, LinkList args, int flags)
 {
     struct ifcmd *node;
-    int olderrexit;
+    int olderrexit, s = 0;
     List *i, *t;
 
     olderrexit = noerrexit;
@@ -368,17 +393,22 @@ execif(Cmd cmd)
     if (!noerrexit)
 	noerrexit = 1;
     while (*i) {
+	cmdpush(s ? CS_ELIF : CS_IF);
 	execlist(*i, 1, 0);
+	cmdpop();
 	if (!lastval)
 	    break;
+	s = 1;
 	i++;
 	t++;
     }
     noerrexit = olderrexit;
 
-    if (*t)
-	execlist(*t, 1, cmd->flags & CFLAG_EXEC);
-    else
+    if (*t) {
+	cmdpush(*i ? (s ? CS_ELIFTHEN : CS_IFTHEN) : CS_ELSE);
+	execlist(*t, 1, flags & CFLAG_EXEC);
+	cmdpop();
+    } else
 	lastval = 0;
 
     return lastval;
@@ -386,7 +416,7 @@ execif(Cmd cmd)
 
 /**/
 int
-execcase(Cmd cmd)
+execcase(Cmd cmd, LinkList args, int flags)
 {
     struct casecmd *node;
     char *word;
@@ -397,25 +427,33 @@ execcase(Cmd cmd)
     l = node->lists;
     p = node->pats;
 
-    word = *p++;
+    word = dupstring(*p++);
     singsub(&word);
     untokenize(word);
     lastval = 0;
 
     if (node) {
+	cmdpush(CS_CASE);
 	while (*p) {
-	    char *pat = *p + 1;
+	    char *pat = dupstring(*p + 1);
 	    singsub(&pat);
+	    if (isset(XTRACE)) {
+		char *pat2 = dupstring(pat);
+		untokenize(pat2);
+		printprompt4();
+		fprintf(stderr, "case %s (%s)\n", word, pat2);
+		fflush(stderr);
+	    }
 	    if (matchpat(word, pat)) {
 		do {
-		    execlist(*l++, 1, **p == ';' && (cmd->flags & CFLAG_EXEC));
+		    execlist(*l++, 1, **p == ';' && (flags & CFLAG_EXEC));
 		} while(**p++ == '&' && *p);
 		break;
 	    }
 	    p++;
 	    l++;
 	}
+	cmdpop();
     }
     return lastval;
 }
-
diff --git a/Src/signals.c b/Src/signals.c
index 65bac0f52..583933f14 100644
--- a/Src/signals.c
+++ b/Src/signals.c
@@ -129,10 +129,9 @@ intr(void)
         install_handler(SIGINT);
 }
 
-#if 0
 /* disable ^C interrupts */
  
-/**/
+#if 0 /**/
 void
 nointr(void)
 {
@@ -505,7 +504,7 @@ handler(int sig)
 
 #ifdef SIGWINCH
     case SIGWINCH:
-        adjustwinsize();  /* check window size and adjust */
+        adjustwinsize(1);  /* check window size and adjust */
 	if (sigtrapped[SIGWINCH])
 	    dotrap(SIGWINCH);
         break;
@@ -587,7 +586,10 @@ killjb(Job jn, int sig)
  
                 for (pn = jn->procs; pn->next; pn = pn->next)
                     err = kill(pn->pid, sig);
- 
+
+		if (!jobtab[jn->other].procs && pn)
+		    err = kill(pn->pid, sig);
+
                 return err;
             }
  
@@ -603,6 +605,61 @@ killjb(Job jn, int sig)
     return err;
 }
 
+/*
+ * List for saving traps.  We don't usually have that many traps
+ * at once, so just use a linked list.
+ */
+struct savetrap {
+    int sig, flags, local;
+    void *list;
+};
+
+static LinkList savetraps;
+
+/* Flag to unsettrap not to free the structs, which we're keeping */
+
+/**/
+int notrapfree;
+
+/*
+ * Save the current trap and unset it.
+ */
+
+static void
+dosavetrap(int sig, int level)
+{
+    struct savetrap *st;
+    st = (struct savetrap *)zalloc(sizeof(*st));
+    st->sig = sig;
+    st->local = level;
+    notrapfree++;
+    if ((st->flags = sigtrapped[sig]) & ZSIG_FUNC) {
+	/*
+	 * Get the old function: this assumes we haven't added
+	 * the new one yet.
+	 */
+	char func[20];
+	sprintf(func, "TRAP%s", sigs[sig]);
+	/* We call removehashnode() directly because otherwise
+	 * removeshfuncnode() would be called which in turn would
+	 * call us again so that we would end up with a NULL pointer
+	 * instead of the list for the trap. */
+	st->list = removehashnode(shfunctab, func);
+    } else {
+	st->list = sigfuncs[sig];
+	unsettrap(sig);
+    }
+    notrapfree--;
+    PERMALLOC {
+	if (!savetraps)
+	    savetraps = newlinklist();
+	/*
+	 * Put this at the front of the list
+	 */
+	insertlinknode(savetraps, (LinkNode)savetraps, st);
+    } LASTALLOC;
+}
+
 /**/
 int
 settrap(int sig, List l)
@@ -613,7 +670,15 @@ settrap(int sig, List l)
         zerr("can't trap SIG%s in interactive shells", sigs[sig], 0);
         return 1;
     }
-    if (sigfuncs[sig])
+    /*
+     * Note that we save the trap here even if there isn't an existing
+     * one, to aid in removing this one.  However, if there's
+     * already one at the current locallevel we just overwrite it.
+     */
+    if (isset(LOCALTRAPS) && locallevel &&
+	(!sigtrapped[sig] || locallevel > (sigtrapped[sig] >> ZSIG_SHIFT))) {
+	dosavetrap(sig, locallevel);
+    } else if (sigfuncs[sig])
 	unsettrap(sig);
     sigfuncs[sig] = l;
     if (!l) {
@@ -633,6 +698,12 @@ settrap(int sig, List l)
             sig != SIGCHLD)
             install_handler(sig);
     }
+    /*
+     * Note that introducing the locallevel does not affect whether
+     * sigtrapped[sig] is zero or not, i.e. a test without a mask
+     * works just the same.
+     */
+    sigtrapped[sig] |= (locallevel << ZSIG_SHIFT);
     return 0;
 }
 
@@ -646,6 +717,19 @@ unsettrap(int sig)
 	(jobbing && (sig == SIGTTOU || sig == SIGTSTP || sig == SIGTTIN))) {
         return;
     }
+    if (isset(LOCALTRAPS) && locallevel &&
+	sigtrapped[sig] && locallevel > (sigtrapped[sig] >> ZSIG_SHIFT)) {
+	/*
+	 * This calls unsettrap recursively to do any dirty work, so
+	 * make sure this bit doesn't happen:  a bit messy, but hard
+	 * to avoid.
+	 */
+	int oldlt = opts[LOCALTRAPS];
+	opts[LOCALTRAPS] = 0;
+	dosavetrap(sig, locallevel);
+	opts[LOCALTRAPS] = oldlt;
+	return;
+    }
     sigtrapped[sig] = 0;
     if (sig == SIGINT && interact) {
 	/* PWS 1995/05/16:  added test for interactive, also noholdintr() *
@@ -660,6 +744,8 @@ unsettrap(int sig)
 #endif
              sig != SIGCHLD)
         signal_default(sig);
+    if (notrapfree)
+	return;
     if (trapped & ZSIG_FUNC) {
 	char func[20];
 	HashNode hn;
@@ -673,6 +759,83 @@ unsettrap(int sig)
     }
 }
 
+/**/
+void
+starttrapscope(void)
+{
+    /*
+     * SIGEXIT needs to be restored at the current locallevel,
+     * so give it the next higher one.
+     */
+    if (sigtrapped[SIGEXIT])
+	dosavetrap(SIGEXIT, locallevel+1);
+}
+
+/*
+ * Reset traps after the end of a function: must be called after
+ * endparamscope() so that the locallevel has been decremented.
+ */
+
+/**/
+void
+endtrapscope(void)
+{
+    LinkNode ln;
+    struct savetrap *st;
+    int exittr;
+    void *exitfn = NULL;
+
+    /*
+     * Remember the exit trap, but don't run it until
+     * after all the other traps have been put back.
+     */
+    if ((exittr = sigtrapped[SIGEXIT])) {
+	notrapfree++;
+	if (exittr & ZSIG_FUNC) {
+	    exitfn = shfunctab->removenode(shfunctab, "TRAPEXIT");
+	} else {
+	    exitfn = sigfuncs[SIGEXIT];
+	    unsettrap(SIGEXIT);
+	}
+	notrapfree--;
+    }
+
+    if (savetraps) {
+	while ((ln = firstnode(savetraps)) &&
+	       (st = (struct savetrap *) ln->dat) &&
+	       st->local > locallevel) {
+	    int sig = st->sig;
+
+	    remnode(savetraps, ln);
+
+	    if (sigtrapped[sig])
+		unsettrap(sig);
+	    if (st->flags) {
+		List list = (st->flags & ZSIG_FUNC) ?
+		    ((Shfunc) st->list)->funcdef : (List) st->list;
+		/* prevent settrap from saving this */
+		int oldlt = opts[LOCALTRAPS];
+		opts[LOCALTRAPS] = 0;
+		settrap(sig, list);
+		opts[LOCALTRAPS] = oldlt;
+		if ((sigtrapped[sig] = st->flags) & ZSIG_FUNC)
+		    shfunctab->addnode(shfunctab, ((Shfunc)st->list)->nam,
+				       (Shfunc) st->list);
+	    }
+	    zfree(st, sizeof(*st));
+	}
+    }
+
+    if (exittr) {
+	dotrapargs(SIGEXIT, &exittr, (exittr & ZSIG_FUNC) ?
+		   ((Shfunc)exitfn)->funcdef : (List) exitfn);
+	if (exittr & ZSIG_FUNC)
+	    shfunctab->freenode((HashNode)exitfn);
+	else
+	    freestruct(exitfn);
+    }
+}
+
 /* Execute a trap function for a given signal, possibly
  * with non-standard sigtrapped & sigfuncs values
  */
@@ -720,7 +883,7 @@ dotrapargs(int sig, int *sigtr, void *sigfn)
 	freelinklist(args, (FreeFunc) NULL);
 	zsfree(name);
     } else HEAPALLOC {
-	execlist(dupstruct(sigfn), 1, 0);
+	execlist(sigfn, 1, 0);
     } LASTALLOC;
     if (trapreturn > 0)
 	trapret = trapreturn;