Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Bug#335481: zsh: zsh/sched waits for next return to prompt even with NOTIFY set



On Fri, 11 Aug 2006 14:03:27 -0600
"Jared K. Sorensen" <jksorensen@xxxxxxxxx> wrote:
> So there is no plan to "fix" the sched module to work without requiring a
> return at the prompt?

This is a long-standing problem, and as you say it makes sched a good
deal less useful than it might otherwise be.

I got a chance to look at it.  As we already do quite sophisticated
things while the line editor is waiting for shell input (key timeouts
and polling of file descriptors) it's not so difficult to expand this so
that a sched timer can fire at this point.  I haven't looked at
extending this to be fully asynchronous: it's not clear you want that,
since your terminal's in use by another process at that point, so it
would need to be optional, and I don't feel like messing around with
signal masks and SIGALRM.

I've tried to make it more generally useful (in particular for the
calendar functions I'm playing around with separately), so the patch
has the following visible effects.  Opinions welcome:


sched events will now fire while waiting for user input in zle.

As a side effect of the new mechanism I've upped the arbitrary limit on
key timeouts, which used to be 5 seconds, to (typically) 24 days, which
ought to be long enough ("I'm just on holiday for a few weeks, Dan, I'll
finish that key sequence when I get back").  I don't like arbitrary
limits but you can always argue they are saving the user from their own
stupidity.  There's no definite right answer (apart from using the
correct value in KEYTIMEOUT).

sched events are a little bit more neatly handled than before: the queue
is in time order, and I fixed a bug that deleting a sched job from
itself would cause a crash.  (I found it by inspecting the code but I've
just confirmed it.)

sched now accepts a number of seconds (when there's no ":" in the time),
either as a relative time or absolute time (counting from the epoch in
that case).  This fits in well with what zsh/datetime can provide.

"print" is now aware of being used to output to the terminal when the
line editor is active and will take appropriate action (equivalent to
"zle -I").  This is to make output from sched jobs more user friendly.
The only problem with this I can see is if the "print" is only being
used, say, to update a terminal emulator title bar, and the likely of
doing that at a point where you want to make it invisible to the user
that a function is being run isn't that great anyway so I can't see a
reason why this shouldn't be the default.  The option "-t" to print
turns it off, which is how to do the terminal emulator thing.


Internally, I've done the following:


The interface to prepromptfns is neater, and I've added timedfns for the
new facility, which still keeps sched at a slight difference
interfacewise; however timedfns needs to be visible in zle.  sched still
uses prepromptfns, too, since if a scheduled event has just gone off
before a prompt it saves printing the command line and immediately
trashing it.

get_rawbyte() has been rewritten to do timeouts more generally.  One
effect of this is that a key timeout will be restarted if a watched fd
(zle -F) becomes ready or if a timed function triggers while waiting for
input.  The effect of this ought to be unnoticeably small.

I've tried to make use of time_t a little more consistent.  It's used to
store 100ths of a second, too, so that I only need one test for the
range of the variable used.  I've tried to minimise range problems by
using a zlong to take the value from zstrtol, but actually I haven't
done any more range checking so an overflow in sched is possible.

I renamed the variable keytmout to do_keytmout because it's not actually
a timeout, it's a flag, and it's been confusing me for ages.

I've tried to make the trashzle() mechanism as self-standing as
possible.  It seems to work in the obvious cases (e.g. repeated "print"s
from a single sched event).

While monkeying with pointers, I fixed a warning from gcc in the
filesub() calls.  This isn't related to the rest.

Index: README
===================================================================
RCS file: /cvsroot/zsh/zsh/README,v
retrieving revision 1.36
diff -u -r1.36 README
--- README	4 Aug 2006 15:31:03 -0000	1.36
+++ README	7 Sep 2006 18:48:18 -0000
@@ -69,6 +69,12 @@
     are allowed in identifiers even though the shell will recognise
     alphanumeric multibyte characters.
 
+The sched builtin now keeps entries in time order.  This means that
+after adding an entry the index of an existing entry used for deletion
+may change, if that entry had a later time than the new entry.  However,
+deleting a entry with a later time will now never change the index of an
+entry with an earlier time, which could happen with the previous method.
+
 The completion style pine-directory must now be set to use completion
 for PINE mailbox folders; previously it had the default ~/mail.  This
 change was necessary because otherwise recursive directories under
Index: Doc/Zsh/builtins.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/builtins.yo,v
retrieving revision 1.86
diff -u -r1.86 builtins.yo
--- Doc/Zsh/builtins.yo	24 Jul 2006 22:00:20 -0000	1.86
+++ Doc/Zsh/builtins.yo	7 Sep 2006 18:48:19 -0000
@@ -797,7 +797,7 @@
 `tt(-)' in this context are swapped.
 )
 findex(print)
-xitem(tt(print) [ tt(-abcDilmnNoOpPrsz) ] [ tt(-u) var(n) ] [ tt(-f) var(format) ] [ tt(-C) var(cols) ])
+xitem(tt(print) [ tt(-abcDilmnNoOpPrstz) ] [ tt(-u) var(n) ] [ tt(-f) var(format) ] [ tt(-C) var(cols) ])
 item(  [ tt(-R) [ tt(-en) ]] [ var(arg) ... ])(
 With the `tt(-f)' option the arguments are printed as described by tt(printf).
 With no flags or with the flag `tt(-)', the arguments are printed on
@@ -878,6 +878,19 @@
 item(tt(-s))(
 Place the results in the history list instead of on the standard output.
 )
+item(tt(-t))(
+Sometimes the tt(print) or tt(echo) builtin may used to send output to
+the terminal while the line editor is active.  This can happen, for
+example, from within editor or completion widgets, or from within
+a command queued to run at a particular time by the tt(sched) builtin.
+In such cases the shell normally tries to arrange that the output
+is displayed cleanly by clearing the line by edited and redisplaying
+it later.  This behaviour can be disabled by using the tt(-t) option
+to tt(print).  This is useful, for example, if the arguments to tt(print)
+are only used to update the header line of the terminal emulator.
+
+This option is not necessary if output is not directed to the terminal.
+)
 item(tt(-u) var(n))(
 Print the arguments to file descriptor var(n).
 )
Index: Doc/Zsh/mod_sched.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/mod_sched.yo,v
retrieving revision 1.1.1.7
diff -u -r1.1.1.7 mod_sched.yo
--- Doc/Zsh/mod_sched.yo	20 Dec 1999 11:24:39 -0000	1.1.1.7
+++ Doc/Zsh/mod_sched.yo	7 Sep 2006 18:48:19 -0000
@@ -8,11 +8,33 @@
 cindex(timed execution)
 cindex(execution, timed)
 xitem(tt(sched) [tt(PLUS())]var(hh)tt(:)var(mm) var(command) ...)
+xitem(tt(sched) [tt(PLUS())]var(seconds) var(command) ...)
 item(tt(sched) [ tt(-)var(item) ])(
 Make an entry in the scheduled list of commands to execute.
-The time may be specified in either absolute or relative time.
+The time may be specified in either absolute or relative time,
+and either as hours and minutes separated by a colon, or seconds.
+An absolute number of seconds indicates the time since the epoch
+(1970/01/01 00:00); this is useful in combination with the features in
+the tt(zsh/datetime) module, see
+ifzman(the zsh/datetime module entry in zmanref(zshmodules))\
+ifnzman(noderef(The zsh/datetime Module))\
+.
+
 With no arguments, prints the list of scheduled commands.
 With the argument `tt(-)var(item)', removes the given item
-from the list.
+from the list.  The numbering of the list is continguous and entries are
+in time order, so the numbering can change when entries are added or
+deleted.
+
+Commands are executed either immediately before a prompt, or while
+the shell's line editor is waiting for input.  In the latter case
+it is useful to be able to produce output that does not interfere
+with the line being edited: the tt(print) builtin will automatically
+arrange for this.  In commands that produce output in other ways,
+placing the code:
+
+example(print -n '')
+
+at the start will have the correct effect.
 )
 enditem()
Index: Src/builtin.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/builtin.c,v
retrieving revision 1.160
diff -u -r1.160 builtin.c
--- Src/builtin.c	24 Jul 2006 22:00:20 -0000	1.160
+++ Src/builtin.c	7 Sep 2006 18:48:21 -0000
@@ -99,7 +99,7 @@
 #endif
 
     BUILTIN("popd", 0, bin_cd, 0, 1, BIN_POPD, NULL, NULL),
-    BUILTIN("print", BINF_PRINTOPTS, bin_print, 0, -1, BIN_PRINT, "abcC:Df:ilmnNoOpPrRsu:z-", NULL),
+    BUILTIN("print", BINF_PRINTOPTS, bin_print, 0, -1, BIN_PRINT, "abcC:Df:ilmnNoOpPrRstu:z-", NULL),
     BUILTIN("printf", 0, bin_print, 1, -1, BIN_PRINTF, NULL, NULL),
     BUILTIN("pushd", BINF_SKIPINVALID | BINF_SKIPDASH | BINF_DASHDASHVALID, bin_cd, 0, 2, BIN_PUSHD, "sPL", NULL),
     BUILTIN("pushln", 0, bin_print, 0, -1, BIN_PRINT, NULL, "-nz"),
@@ -3460,7 +3460,7 @@
 {
     int flen, width, prec, type, argc, n, narg, curlen = 0;
     int nnl = 0, fmttrunc = 0, ret = 0, maxarg = 0;
-    int flags[5], *len;
+    int flags[5], *len, output_to_fout;
     char *start, *endptr, *c, *d, *flag, *buf, spec[13], *fmt = NULL;
     char **first, **argp, *curarg, *flagch = "0+- #", save = '\0', nullstr = '\0';
     size_t rcount, count = 0;
@@ -3595,6 +3595,27 @@
 	}
     }
 
+    /*
+     * Is output going to FILE *fout?
+     * It isn't if we're printing to the zle line or to the
+     * shell history.  Otherwise it is (I think).
+     */
+    output_to_fout = !OPT_ISSET(ops, 'z') && !OPT_ISSET(ops, 's');
+
+    if (zleactive && output_to_fout && !OPT_ISSET(ops, 't') &&
+	/*
+	 * The following checks if fout is associated with the
+	 * shell's terminal.  It's a little clumsy but saves argument.
+	 */
+	isatty(fileno(fout)) && !strcmp(ttystrname, ttyname(fileno(fout)))) {
+	/*
+	 * If zle is active, we want to take action to avoid
+	 * our output messing up the line being edited, so arrange to
+	 * have it cleared and redrawn.
+	 */
+	trashzleptr();
+    }
+
     /* -o and -O -- sort the arguments */
     if (OPT_ISSET(ops,'o')) {
 	if (fmt && !*args) return 0;
@@ -3773,7 +3794,7 @@
 	return ret;
     }
     
-    if (OPT_ISSET(ops,'z') || OPT_ISSET(ops,'s')) {
+    if (!output_to_fout) {
 #ifdef HAVE_OPEN_MEMSTREAM
     	if ((fout = open_memstream(&buf, &mcount)) == NULL)
 	    zwarnnam(name, "open_memstream failed");
@@ -4055,7 +4076,7 @@
 	/* if there are remaining args, reuse format string */
     } while (*argp && argp != first && !fmttrunc && !OPT_ISSET(ops,'r'));
 
-    if (OPT_ISSET(ops,'z') || OPT_ISSET(ops,'s')) {
+    if (!output_to_fout) {
 #ifdef HAVE_OPEN_MEMSTREAM
 	putc(0, fout);
 	fflush(fout);
Index: Src/init.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/init.c,v
retrieving revision 1.66
diff -u -r1.66 init.c
--- Src/init.c	30 May 2006 22:35:03 -0000	1.66
+++ Src/init.c	7 Sep 2006 18:48:22 -0000
@@ -869,7 +869,6 @@
     nohistsave = 1;
     dirstack = znewlinklist();
     bufstack = znewlinklist();
-    prepromptfns = znewlinklist();
     hsubl = hsubr = NULL;
     lastpid = 0;
     bshin = SHIN ? fdopen(SHIN, "r") : stdin;
Index: Src/subst.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/subst.c,v
retrieving revision 1.55
diff -u -r1.55 subst.c
--- Src/subst.c	24 Jul 2006 22:00:21 -0000	1.55
+++ Src/subst.c	7 Sep 2006 18:48:23 -0000
@@ -70,9 +70,24 @@
 		return;
 	    }
 	} else {
-	    if (isset(SHFILEEXPANSION))
-		filesub((char **)getaddrdata(node),
-			flags & (PF_TYPESET|PF_ASSIGN));
+	    if (isset(SHFILEEXPANSION)) {
+		/*
+		 * Here and below we avoid taking the address
+		 * of a void * and then pretending it's a char **
+		 * instead of a void ** by a little inefficiency.
+		 * This could be avoided with some extra linked list
+		 * machinery, but that would need quite a lot of work
+		 * to ensure consistency.  What we really need is
+		 * templates...
+		 */
+		char *cptr = (char *)getdata(node);
+		filesub(&cptr, flags & (PF_TYPESET|PF_ASSIGN));
+		/*
+		 * The assignment is so simple it's not worth
+		 * testing if cptr changed...
+		 */
+		setdata(node, cptr);
+	    }
 	    if (!(node = stringsubst(list, node, flags & PF_SINGLE, asssub))) {
 		unqueue_signals();
 		return;
@@ -92,9 +107,11 @@
 		    xpandbraces(list, &node);
 		}
 	    }
-	    if (unset(SHFILEEXPANSION))
-		filesub((char **)getaddrdata(node),
-			flags & (PF_TYPESET|PF_ASSIGN));
+	    if (unset(SHFILEEXPANSION)) {
+		char *cptr = (char *)getdata(node);
+		filesub(&cptr, flags & (PF_TYPESET|PF_ASSIGN));
+		setdata(node, cptr);
+	    }
 	} else if (!(flags & PF_SINGLE) && !keep)
 	    uremnode(list, node);
 	if (errflag) {
Index: Src/utils.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/utils.c,v
retrieving revision 1.134
diff -u -r1.134 utils.c
--- Src/utils.c	11 Aug 2006 21:30:38 -0000	1.134
+++ Src/utils.c	7 Sep 2006 18:48:25 -0000
@@ -911,10 +911,136 @@
     return 1;
 }
 
-/* extra functions to call before displaying the prompt */
+/*
+ * Extra functions to call before displaying the prompt.
+ * The data is a Prepromptfn.
+ */
+
+static LinkList prepromptfns;
+
+/* Add a function to the list of pre-prompt functions. */
+
+/**/
+mod_export void
+addprepromptfn(voidvoidfnptr_t func)
+{
+    Prepromptfn ppdat = (Prepromptfn)zalloc(sizeof(struct prepromptfn));
+    ppdat->func = func;
+    if (!prepromptfns)
+	prepromptfns = znewlinklist();
+    zaddlinknode(prepromptfns, ppdat);
+}
+
+/* Remove a function from the list of pre-prompt functions. */
+
+/**/
+mod_export void
+delprepromptfn(voidvoidfnptr_t func)
+{
+    LinkNode ln;
+
+    for (ln = firstnode(prepromptfns); ln; ln = nextnode(ln)) {
+	Prepromptfn ppdat = (Prepromptfn)getdata(ln);
+	if (ppdat->func == func) {
+	    (void)remnode(prepromptfns, ln);
+	    zfree(ppdat, sizeof(struct prepromptfn));
+	    return;
+	}
+    }
+#ifdef DEBUG
+    dputs("BUG: failed to delete node from prepromptfns");
+#endif
+}
+
+/*
+ * Functions to call at a particular time even if not at
+ * the prompt.  This is handled by zle.  The data is a
+ * Timedfn.  The functions must be in time order, but this
+ * is enforced by addtimedfn().
+ */
+
+/**/
+mod_export LinkList timedfns;
+
+/* Add a function to the list of timed functions. */
+
+/**/
+mod_export void
+addtimedfn(voidvoidfnptr_t func, time_t when)
+{
+    Timedfn tfdat = (Timedfn)zalloc(sizeof(struct timedfn));
+    tfdat->func = func;
+    tfdat->when = when;
+
+    if (!timedfns) {
+	timedfns = znewlinklist();
+	zaddlinknode(timedfns, tfdat);
+    } else {
+	LinkNode ln = firstnode(timedfns);
+
+	/*
+	 * Insert the new element in the linked list.  We do
+	 * rather too much work here since the standard
+	 * functions insert after a given node, whereas we
+	 * want to insert the new data before the first element
+	 * with a greater time.
+	 *
+	 * In practice, the only use of timed functions is
+	 * sched, which only adds the one function; so this
+	 * whole branch isn't used beyond the following block.
+	 */
+	if (!ln) {
+	    zaddlinknode(timedfns, tfdat);
+	    return;
+	}
+	for (;;) {
+	    Timedfn tfdat2;
+	    LinkNode next = nextnode(ln);
+	    if (!next) {
+		zaddlinknode(timedfns, tfdat);
+		return;
+	    }
+	    tfdat2 = (Timedfn)getdata(next);
+	    if (when < tfdat2->when) {
+		zinsertlinknode(timedfns, ln, tfdat);
+		return;
+	    }
+	    ln = next;
+	}
+    }
+}
+
+/*
+ * Delete a function from the list of timed functions.
+ * Note that if the function apperas multiple times only
+ * the first occurrence will be removed.
+ *
+ * Note also that when zle calls the function it does *not*
+ * automatically delete the entry from the list.  That must
+ * be done by the function called.  This is recommended as otherwise
+ * the function will keep being called immediately.  (It just so
+ * happens this "feature" fits in well with the only current use
+ * of timed functions.)
+ */
 
 /**/
-mod_export LinkList prepromptfns;
+mod_export void
+deltimedfn(voidvoidfnptr_t func)
+{
+    LinkNode ln;
+
+    for (ln = firstnode(timedfns); ln; ln = nextnode(ln)) {
+	Timedfn ppdat = (Timedfn)getdata(ln);
+	if (ppdat->func == func) {
+	    (void)remnode(timedfns, ln);
+	    zfree(ppdat, sizeof(struct timedfn));
+	    return;
+	}
+    }
+#ifdef DEBUG
+    dputs("BUG: failed to delete node from timedfns");
+#endif
+}
 
 /* the last time we checked mail */
 
@@ -1027,10 +1153,12 @@
 	lastmailcheck = time(NULL);
     }
 
-    /* Some people have claimed that C performs type    *
-     * checking, but they were later found to be lying. */
-    for(ln = firstnode(prepromptfns); ln; ln = nextnode(ln))
-	(**(void (**) _((void)))getdata(ln))();
+    if (prepromptfns) {
+	for(ln = firstnode(prepromptfns); ln; ln = nextnode(ln)) {
+	    Prepromptfn ppnode = (Prepromptfn)getdata(ln);
+	    ppnode->func();
+	}
+    }
 }
 
 /**/
Index: Src/zsh.h
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/zsh.h,v
retrieving revision 1.95
diff -u -r1.95 zsh.h
--- Src/zsh.h	11 Aug 2006 21:30:38 -0000	1.95
+++ Src/zsh.h	7 Sep 2006 18:48:25 -0000
@@ -333,40 +333,38 @@
 /* Abstract types for zsh */
 /**************************/
 
-typedef struct linknode  *LinkNode;
-typedef union  linkroot  *LinkList;
-typedef struct hashnode  *HashNode;
-typedef struct hashtable *HashTable;
-
-typedef struct optname   *Optname;
-typedef struct reswd     *Reswd;
 typedef struct alias     *Alias;
-typedef struct param     *Param;
-typedef struct paramdef  *Paramdef;
+typedef struct asgment   *Asgment;
+typedef struct builtin   *Builtin;
 typedef struct cmdnam    *Cmdnam;
-typedef struct shfunc    *Shfunc;
+typedef struct complist  *Complist;
+typedef struct conddef   *Conddef;
 typedef struct funcstack *Funcstack;
 typedef struct funcwrap  *FuncWrap;
-typedef struct options	 *Options;
-typedef struct builtin   *Builtin;
-typedef struct nameddir  *Nameddir;
-typedef struct module    *Module;
-typedef struct linkedmod *Linkedmod;
-
-typedef struct patprog   *Patprog;
-typedef struct process   *Process;
-typedef struct job       *Job;
-typedef struct value     *Value;
-typedef struct conddef   *Conddef;
-typedef struct redir     *Redir;
-typedef struct complist  *Complist;
+typedef struct hashnode  *HashNode;
+typedef struct hashtable *HashTable;
 typedef struct heap      *Heap;
 typedef struct heapstack *Heapstack;
 typedef struct histent   *Histent;
 typedef struct hookdef   *Hookdef;
-
-typedef struct asgment   *Asgment;
-
+typedef struct job       *Job;
+typedef struct linkedmod *Linkedmod;
+typedef struct linknode  *LinkNode;
+typedef union  linkroot  *LinkList;
+typedef struct module    *Module;
+typedef struct nameddir  *Nameddir;
+typedef struct options	 *Options;
+typedef struct optname   *Optname;
+typedef struct param     *Param;
+typedef struct paramdef  *Paramdef;
+typedef struct patprog   *Patprog;
+typedef struct prepromptfn *Prepromptfn;
+typedef struct process   *Process;
+typedef struct redir     *Redir;
+typedef struct reswd     *Reswd;
+typedef struct shfunc    *Shfunc;
+typedef struct timedfn   *Timedfn;
+typedef struct value     *Value;
 
 /********************************/
 /* Definitions for linked lists */
@@ -432,6 +430,28 @@
         __n0.dat = (void *) (V0); \
     } while (0)
 
+/*************************************/
+/* Specific elements of linked lists */
+/*************************************/
+
+typedef void (*voidvoidfnptr_t) _((void));
+
+/*
+ * Element of the prepromptfns list.
+ */
+struct prepromptfn {
+    voidvoidfnptr_t func;
+};
+
+
+/*
+ * Element of the timedfns list.
+ */
+struct timedfn {
+    voidvoidfnptr_t func;
+    time_t when;
+};
+
 /********************************/
 /* Definitions for syntax trees */
 /********************************/
Index: Src/Builtins/sched.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Builtins/sched.c,v
retrieving revision 1.5
diff -u -r1.5 sched.c
--- Src/Builtins/sched.c	30 May 2006 22:35:03 -0000	1.5
+++ Src/Builtins/sched.c	7 Sep 2006 18:48:25 -0000
@@ -44,6 +44,49 @@
  
 static struct schedcmd *schedcmds;
 
+/* Check scheduled commands; call this function from time to time. */
+
+/**/
+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;
+
+	execstring(sch->cmd, 0, 0);
+	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.
+	 */
+	deltimedfn(checksched);
+	if (schedcmds)
+	    addtimedfn(checksched, schedcmds->time);
+    }
+}
+
 /**/
 static int
 bin_sched(UNUSED(char *nam), char **argv, UNUSED(Options ops), UNUSED(int func))
@@ -64,13 +107,20 @@
 	    zwarnnam("sched", "usage for delete: sched -<item#>.");
 	    return 1;
 	}
-	for (schl = (struct schedcmd *)&schedcmds, sch = schedcmds, sn--;
+	for (schl = NULL, sch = schedcmds, sn--;
 	     sch && sn; sch = (schl = sch)->next, sn--);
 	if (!sch) {
 	    zwarnnam("sched", "not that many entries");
 	    return 1;
 	}
-	schl->next = sch->next;
+	if (schl)
+	    schl->next = sch->next;
+	else {
+	    deltimedfn(checksched);
+	    schedcmds = sch->next;
+	    if (schedcmds)
+		addtimedfn(checksched, schedcmds->time);
+	}
 	zsfree(sch->cmd);
 	zfree(sch, sizeof(struct schedcmd));
 
@@ -98,85 +148,95 @@
     /* The first argument specifies the time to schedule the command for.  The
     remaining arguments form the command. */
     if (*s == '+') {
-	/* + introduces a relative time.  The rest of the argument is an
-	hour:minute offset from the current time.  Once the hour and minute
-	numbers have been extracted, and the format verified, the resulting
-	offset is simply added to the current time. */
-	h = zstrtol(s + 1, &s, 10);
-	if (*s != ':') {
-	    zwarnnam("sched", "bad time specifier");
-	    return 1;
-	}
-	m = zstrtol(s + 1, &s, 10);
-	if (*s) {
+	/*
+	 * + introduces a relative time.  The rest of the argument may be an
+	 * hour:minute offset from the current time.  Once the hour and minute
+	 * numbers have been extracted, and the format verified, the resulting
+	 * offset is simply added to the current time.
+	 */
+	zlong zl = zstrtol(s + 1, &s, 10);
+	if (*s == ':') {
+	    m = zstrtol(s + 1, &s, 10);
+	    if (*s) {
+		zwarnnam("sched", "bad time specifier");
+		return 1;
+	    }
+	    t = time(NULL) + (long)zl * 3600 + m * 60;
+	} else if (!*s) {
+	    /*
+	     * Alternatively, it may simply be a number of seconds.
+	     * This is here for consistency with absolute times.
+	     */
+	    t = time(NULL) + (time_t)zl;
+	} else {
 	    zwarnnam("sched", "bad time specifier");
 	    return 1;
 	}
-	t = time(NULL) + h * 3600 + m * 60;
     } else {
-	/* If there is no +, an absolute time of day must have been given.
-	This is in hour:minute format, optionally followed by a string starting
-	with `a' or `p' (for a.m. or p.m.).  Characters after the `a' or `p'
-	are ignored. */
-	h = zstrtol(s, &s, 10);
-	if (*s != ':') {
-	    zwarnnam("sched", "bad time specifier");
-	    return 1;
-	}
-	m = zstrtol(s + 1, &s, 10);
-	if (*s && *s != 'a' && *s != 'A' && *s != 'p' && *s != 'P') {
+	/*
+	 * If there is no +, an absolute time must have been given.
+	 * This may be in hour:minute format, optionally followed by a string
+	 * starting with `a' or `p' (for a.m. or p.m.).  Characters after the
+	 * `a' or `p' are ignored.
+	 */
+	zlong zl = zstrtol(s, &s, 10);
+	if (*s == ':') {
+	    h = (long)zl;
+	    m = zstrtol(s + 1, &s, 10);
+	    if (*s && *s != 'a' && *s != 'A' && *s != 'p' && *s != 'P') {
+		zwarnnam("sched", "bad time specifier");
+		return 1;
+	    }
+	    t = time(NULL);
+	    tm = localtime(&t);
+	    t -= tm->tm_sec + tm->tm_min * 60 + tm->tm_hour * 3600;
+	    if (*s == 'p' || *s == 'P')
+		h += 12;
+	    t += h * 3600 + m * 60;
+	    /*
+	     * If the specified time is before the current time, it must refer
+	     * to tomorrow.
+	     */
+	    if (t < time(NULL))
+		t += 3600 * 24;
+	} else if (!*s) {
+	    /*
+	     * Otherwise, it must be a raw time specifier.
+	     */
+	    t = (long)zl;
+	} else {
 	    zwarnnam("sched", "bad time specifier");
 	    return 1;
 	}
-	t = time(NULL);
-	tm = localtime(&t);
-	t -= tm->tm_sec + tm->tm_min * 60 + tm->tm_hour * 3600;
-	if (*s == 'p' || *s == 'P')
-	    h += 12;
-	t += h * 3600 + m * 60;
-	/* If the specified time is before the current time, it must refer to
-	tomorrow. */
-	if (t < time(NULL))
-	    t += 3600 * 24;
     }
     /* The time has been calculated; now add the new entry to the linked list
     of scheduled commands. */
-    sch = (struct schedcmd *) zshcalloc(sizeof *sch);
+    sch = (struct schedcmd *) zalloc(sizeof *sch);
     sch->time = t;
     sch->cmd = zjoin(argv, ' ', 0);
-    sch->next = NULL;
-    for (sch2 = (struct schedcmd *)&schedcmds; sch2->next; sch2 = sch2->next);
-    sch2->next = sch;
-    return 0;
-}
-
-/* Check scheduled commands; call this function from time to time. */
-
-/**/
-static void
-checksched(void)
-{
-    time_t t;
-    struct schedcmd *sch, *schl;
-
-    if(!schedcmds)
-	return;
-    t = time(NULL);
-    for (schl = (struct schedcmd *)&schedcmds, sch = schedcmds; sch;
-	 sch = (schl = sch)->next) {
-	if (sch->time <= t) {
-	    execstring(sch->cmd, 0, 0);
-	    schl->next = sch->next;
-	    zsfree(sch->cmd);
-	    zfree(sch, sizeof(struct schedcmd));
-	    sch = schl;
+    /* Insert into list in time order */
+    if (schedcmds) {
+	if (sch->time < schedcmds->time) {
+	    deltimedfn(checksched);
+	    sch->next = schedcmds;
+	    schedcmds = sch;
+	    addtimedfn(checksched, t);
+	} else {
+	    for (sch2 = schedcmds;
+		 sch2->next && sch2->next->time < sch->time;
+		 sch2 = sch2->next)
+		;
+	    sch->next = sch2->next;
+	    sch2->next = sch;
 	}
+    } else {
+	sch->next = NULL;
+	schedcmds = sch;
+	addtimedfn(checksched, t);
     }
+    return 0;
 }
 
-static void (*p_checksched) _((void)) = checksched;
-static struct linknode n_checksched = { NULL, NULL, &p_checksched };
-
 static struct builtin bintab[] = {
     BUILTIN("sched", 0, bin_sched, 0, -1, 0, NULL, NULL),
 };
@@ -194,7 +254,7 @@
 {
     if(!addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)))
 	return 1;
-    uaddlinknode(prepromptfns, &n_checksched);
+    addprepromptfn(&checksched);
     return 0;
 }
 
@@ -209,7 +269,7 @@
 	zsfree(sch->cmd);
 	zfree(sch, sizeof(*sch));
     }
-    uremnode(prepromptfns, &n_checksched);
+    delprepromptfn(&checksched);
     deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
     return 0;
 }
Index: Src/Zle/zle_main.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/zle_main.c,v
retrieving revision 1.89
diff -u -r1.89 zle_main.c
--- Src/Zle/zle_main.c	24 Jul 2006 22:00:21 -0000	1.89
+++ Src/Zle/zle_main.c	7 Sep 2006 18:48:26 -0000
@@ -122,7 +122,11 @@
 mod_export int eofchar;
 
 static int eofsent;
-static long keytimeout;
+/*
+ * Key timeout in hundredths of a second:  we use time_t so
+ * that we only have the limits on one integer type to worry about.
+ */
+static time_t keytimeout;
 
 #if defined(HAVE_SELECT) || defined(HAVE_POLL)
 /* Terminal baud rate */
@@ -387,11 +391,110 @@
 # define read    breakread
 #endif
 
+/*
+ * Possible forms of timeout.
+ */
+enum ztmouttp {
+    /* No timeout in use. */
+    ZTM_NONE,
+    /*
+     * Key timeout in use (do_keytmout flag set).  If this goes off
+     * we return without anything being read.
+     */
+    ZTM_KEY,
+    /*
+     * Function timeout in use (from timedfns list).
+     * If this goes off we call any functions which have reached
+     * the time and then continue processing.
+     */
+    ZTM_FUNC,
+    /*
+     * Timeout hit the maximum allowed; if it fires we
+     * need to recalculate.  As we may use poll() for the timeout,
+     * which takes an int value in milliseconds, we might need this
+     * for times long in the future.  (We make no attempt to extend
+     * the range of time beyond that of time_t, however; that seems
+     * like a losing battle.)
+     *
+     * For key timeouts we just limit the value to
+     * ZMAXTIMEOUT; that's already absurdly large.
+     *
+     * The following is the maximum signed range over 1024 (2^10), which
+     * is a little more convenient than 1000, but done differently
+     * to avoid problems with unsigned integers.  We assume 8-bit bytes;
+     * there's no general way to fix up if that's wrong.
+     */
+    ZTM_MAX
+#define	ZMAXTIMEOUT	((time_t)(1 << (sizeof(time_t)*8-11)))
+};
+
+struct ztmout {
+    /* Type of timeout setting, see enum above */
+    enum ztmouttp tp;
+    /*
+     * Value for timeout in 100ths of a second if type is not ZTM_NONE.
+     */
+    time_t exp100ths;
+};
+
+/*
+ * See if we need a timeout either for a key press or for a
+ * timed function.
+ */
+
+static void
+calc_timeout(struct ztmout *tmoutp, int do_keytmout)
+{
+    if (do_keytmout && keytimeout > 0) {
+	if (keytimeout > ZMAXTIMEOUT * 100 /* 24 days for a keypress???? */)
+	    tmoutp->exp100ths = ZMAXTIMEOUT * 100;
+	else
+	    tmoutp->exp100ths = keytimeout;
+	tmoutp->tp = ZTM_KEY;
+    } else
+	tmoutp->tp = ZTM_NONE;
+
+    if (timedfns) {
+	for (;;) {
+	    LinkNode tfnode = firstnode(timedfns);
+	    Timedfn tfdat;
+	    time_t diff, exp100ths;
+
+	    if (!tfnode)
+		break;
+
+	    tfdat = (Timedfn)getdata(tfnode);
+	    diff = tfdat->when - time(NULL);
+	    if (diff < 0) {
+		/* Already due; call it and rescan. */
+		tfdat->func();
+		continue;
+	    }
+
+	    if (diff > ZMAXTIMEOUT) {
+		tmoutp->exp100ths = ZMAXTIMEOUT * 100;
+		tmoutp->tp = ZTM_MAX;
+	    } else if (diff > 0) {
+		exp100ths = diff * 100;
+		if (tmoutp->tp != ZTM_KEY ||
+		    exp100ths < tmoutp->exp100ths) {
+		    tmoutp->exp100ths = exp100ths;
+		    tmoutp->tp = ZTM_FUNC;
+		}
+	    }
+	    break;
+	}
+	/* In case we called a function which messed up the display... */
+	if (resetneeded)
+	    zrefresh();
+    }
+}
+
 static int
-raw_getbyte(int keytmout, char *cptr)
+raw_getbyte(int do_keytmout, char *cptr)
 {
-    long exp100ths;
     int ret;
+    struct ztmout tmout;
 #if defined(HAS_TIO) && \
   (defined(sun) || (!defined(HAVE_POLL) && !defined(HAVE_SELECT)))
     struct ttyinfo ti;
@@ -402,204 +505,254 @@
 # endif
 #endif
 
+    calc_timeout(&tmout, do_keytmout);
+
     /*
-     * Handle timeouts and watched fd's.  We only do one at once;
-     * key timeouts take precedence.  This saves tricky timing
-     * problems with the key timeout.
+     * 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 || keytmout)
+    if ((nwatch || tmout.tp != ZTM_NONE)
 #ifdef FIONREAD
 	&& ! delayzsetterm
 #endif
 	) {
-	if (!keytmout || keytimeout <= 0)
-	    exp100ths = 0;
-	else if (keytimeout > 500)
-	    exp100ths = 500;
-	else
-	    exp100ths = keytimeout;
 #if defined(HAVE_SELECT) || defined(HAVE_POLL)
-	if (!keytmout || exp100ths) {
-	    int i, errtry = 0, selret;
+	int i, errtry = 0, selret;
 # ifdef HAVE_POLL
-	    int poll_timeout;
-	    int nfds;
-	    struct pollfd *fds;
-# else
-	    int fdmax;
-	    struct timeval *tvptr;
-	    struct timeval expire_tv;
+	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);
-	    ret = read(SHTTY, cptr, 1);
-	    ti.tio.c_cc[VMIN] = 1;
-	    settyinfo(&ti);
-	    if (ret > 0)
-		return 1;
+	/*
+	 * 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);
+	ret = read(SHTTY, cptr, 1);
+	ti.tio.c_cc[VMIN] = 1;
+	settyinfo(&ti);
+	if (ret > 0)
+	    return 1;
 # endif
 # ifdef HAVE_POLL
-	    nfds = keytmout ? 1 : 1 + nwatch;
-	    /* First pollfd is SHTTY, following are the nwatch fds */
-	    fds = zalloc(sizeof(struct pollfd) * nfds);
-	    if (exp100ths)
-		poll_timeout = exp100ths * 10;
+	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];
+	    fds[i+1].events = POLLIN;
+	}
+# endif
+	do {
+# ifdef HAVE_POLL
+	    int poll_timeout;
+
+	    if (tmout.tp != ZTM_NONE)
+		poll_timeout = tmout.exp100ths * 10;
 	    else
 		poll_timeout = -1;
 
-	    fds[0].fd = SHTTY;
-	    /*
-	     * POLLIN, POLLIN, POLLIN,
-	     * Keep those fd's POLLIN...
-	     */
-	    fds[0].events = POLLIN;
-	    if (!keytmout) {
+	    selret = poll(fds, errtry ? 1 : nfds, poll_timeout);
+# 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++) {
-		    fds[i+1].fd = watch_fds[i];
-		    fds[i+1].events = POLLIN;
+		    int fd = watch_fds[i];
+		    FD_SET(fd, &foofd);
+		    if (fd > fdmax)
+			fdmax = fd;
 		}
 	    }
-# else
-	    fdmax = SHTTY;
-	    tvptr = NULL;
-	    if (exp100ths) {
-		expire_tv.tv_sec = exp100ths / 100;
-		expire_tv.tv_usec = (exp100ths % 100) * 10000L;
+
+	    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;
+
+	    selret = select(fdmax+1, (SELECT_ARG_2_T) & foofd,
+			    NULL, NULL, tvptr);
 # endif
-	    do {
-# ifdef HAVE_POLL
-		selret = poll(fds, errtry ? 1 : nfds, poll_timeout);
-# else
-		FD_ZERO(&foofd);
-		FD_SET(SHTTY, &foofd);
-		if (!keytmout && !errtry) {
-		    for (i = 0; i < nwatch; i++) {
-			int fd = watch_fds[i];
-			FD_SET(fd, &foofd);
-			if (fd > fdmax)
-			    fdmax = fd;
-		    }
-		}
-		selret = select(fdmax+1, (SELECT_ARG_2_T) & foofd,
-				NULL, NULL, tvptr);
-# endif
-		/*
-		 * Make sure a user interrupt gets passed on straight away.
-		 */
-		if (selret < 0 && errflag)
-		    break;
+	    /*
+	     * Make sure a user interrupt gets passed on straight away.
+	     */
+	    if (selret < 0 && errflag)
+		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) {
 		/*
-		 * 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.
+		 * Nothing ready and no error, so we timed out.
 		 */
-		if (selret < 0 && !keytmout && !errtry) {
-		    errtry = 1;
-		    continue;
-		}
-		if (selret == 0) {
+		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;
-		}
-		if (selret < 0)
 		    break;
-		if (!keytmout && nwatch) {
+
+		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:
 		    /*
-		     * Copy the details of the watch fds in case the
-		     * user decides to delete one from inside the
-		     * handler function.
+		     * 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.
 		     */
-		    int lnwatch = nwatch;
-		    int *lwatch_fds = zalloc(lnwatch*sizeof(int));
-		    char **lwatch_funcs = zarrdup(watch_funcs);
-		    memcpy(lwatch_fds, watch_fds, lnwatch*sizeof(int));
-		    for (i = 0; i < lnwatch; i++) {
-			if (
+		    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 (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;
+		int *lwatch_fds = zalloc(lnwatch*sizeof(int));
+		char **lwatch_funcs = zarrdup(watch_funcs);
+		memcpy(lwatch_fds, watch_fds, lnwatch*sizeof(int));
+		for (i = 0; i < lnwatch; i++) {
+		    if (
 # ifdef HAVE_POLL
-			    (fds[i+1].revents & POLLIN)
+			(fds[i+1].revents & POLLIN)
 # else
-			    FD_ISSET(lwatch_fds[i], &foofd)
+			FD_ISSET(lwatch_fds[i], &foofd)
 # endif
-			    ) {
-			    /* Handle the fd. */
-			    LinkList funcargs = znewlinklist();
-			    zaddlinknode(funcargs, ztrdup(lwatch_funcs[i]));
-			    {
-				char buf[BDIGBUFSIZE];
-				convbase(buf, lwatch_fds[i], 10);
-				zaddlinknode(funcargs, ztrdup(buf));
-			    }
+			) {
+			/* Handle the fd. */
+			LinkList funcargs = znewlinklist();
+			zaddlinknode(funcargs, ztrdup(lwatch_funcs[i]));
+			{
+			    char buf[BDIGBUFSIZE];
+			    convbase(buf, lwatch_fds[i], 10);
+			    zaddlinknode(funcargs, ztrdup(buf));
+			}
 # ifdef HAVE_POLL
 #  ifdef POLLERR
-			    if (fds[i+1].revents & POLLERR)
-				zaddlinknode(funcargs, ztrdup("err"));
+			if (fds[i+1].revents & POLLERR)
+			    zaddlinknode(funcargs, ztrdup("err"));
 #  endif
 #  ifdef POLLHUP
-			    if (fds[i+1].revents & POLLHUP)
-				zaddlinknode(funcargs, ztrdup("hup"));
+			if (fds[i+1].revents & POLLHUP)
+			    zaddlinknode(funcargs, ztrdup("hup"));
 #  endif
 #  ifdef POLLNVAL
-			    if (fds[i+1].revents & POLLNVAL)
-				zaddlinknode(funcargs, ztrdup("nval"));
+			if (fds[i+1].revents & POLLNVAL)
+			    zaddlinknode(funcargs, ztrdup("nval"));
 #  endif
 # endif
 
 
-			    callhookfunc(lwatch_funcs[i], funcargs);
-			    if (errflag) {
-				/* No sensible way of handling errors here */
-				errflag = 0;
-				/*
-				 * Paranoia: don't run the hooks again this
-				 * time.
-				 */
-				errtry = 1;
-			    }
-			    freelinklist(funcargs, freestr);
+			callhookfunc(lwatch_funcs[i], funcargs);
+			if (errflag) {
+			    /* No sensible way of handling errors here */
+			    errflag = 0;
+			    /*
+			     * Paranoia: don't run the hooks again this
+			     * time.
+			     */
+			    errtry = 1;
 			}
+			freelinklist(funcargs, freestr);
 		    }
-		    /* Function may have invalidated the display. */
-		    if (resetneeded)
-			zrefresh();
-		    zfree(lwatch_fds, lnwatch*sizeof(int));
-		    freearray(lwatch_funcs);
 		}
-	    } while (!
+		/* Function may have invalidated the display. */
+		if (resetneeded)
+		    zrefresh();
+		zfree(lwatch_fds, lnwatch*sizeof(int));
+		freearray(lwatch_funcs);
+	    }
+	} while (!
 # ifdef HAVE_POLL
-		     (fds[0].revents & POLLIN)
+		 (fds[0].revents & POLLIN)
 # else
-		     FD_ISSET(SHTTY, &foofd)
+		 FD_ISSET(SHTTY, &foofd)
 # endif
-		);
+		 );
 # ifdef HAVE_POLL
-	    zfree(fds, sizeof(struct pollfd) * nfds);
+	zfree(fds, sizeof(struct pollfd) * nfds);
 # endif
-	    if (selret < 0)
-		return selret;
-	}
+	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] = exp100ths / 10;
+	ti.tio.c_cc[VTIME] = tmout.exp100ths / 10;
 #  ifdef HAVE_TERMIOS_H
 	tcsetattr(SHTTY, TCSANOW, &ti.tio);
 #  else
@@ -623,7 +776,7 @@
 
 /**/
 mod_export int
-getbyte(int keytmout, int *timeout)
+getbyte(int do_keytmout, int *timeout)
 {
     char cc;
     unsigned int ret;
@@ -656,7 +809,7 @@
 	for (;;) {
 	    int q = queue_signal_level();
 	    dont_queue_signals();
-	    r = raw_getbyte(keytmout, &cc);
+	    r = raw_getbyte(do_keytmout, &cc);
 	    restore_queue_signals(q);
 	    if (r == -2) {
 		/* timeout */
@@ -733,9 +886,9 @@
 
 /**/
 mod_export ZLE_INT_T
-getfullchar(int keytmout)
+getfullchar(int do_keytmout)
 {
-    int inchar = getbyte(keytmout, NULL);
+    int inchar = getbyte(do_keytmout, NULL);
 
 #ifdef MULTIBYTE_SUPPORT
     return getrestchar(inchar);
@@ -938,7 +1091,7 @@
 	return shingetline();
     }
 
-    keytimeout = getiparam("KEYTIMEOUT");
+    keytimeout = (time_t)getiparam("KEYTIMEOUT");
     if (!shout) {
 	if (SHTTY != -1)
 	    init_shout();
@@ -1551,7 +1704,7 @@
 mod_export void
 trashzle(void)
 {
-    if (zleactive) {
+    if (zleactive && !trashedzle) {
 	/* This zrefresh() is just to get the main editor display right and *
 	 * get the cursor in the right place.  For that reason, we disable  *
 	 * list display (which would otherwise result in infinite           *
Index: Src/Zle/zle_thingy.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/zle_thingy.c,v
retrieving revision 1.29
diff -u -r1.29 zle_thingy.c
--- Src/Zle/zle_thingy.c	30 May 2006 22:35:04 -0000	1.29
+++ Src/Zle/zle_thingy.c	7 Sep 2006 18:48:26 -0000
@@ -721,8 +721,7 @@
      * true if a completion widget is active.
      */
     if (zleactive) {
-	if (!trashedzle)
-	    trashzle();
+	trashzle();
 	return 0;
     } else
 	return 1;

-- 
Peter Stephenson <p.w.stephenson@xxxxxxxxxxxx>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/



Messages sorted by: Reverse Date, Date, Thread, Author