1 /*
2  * hist.c - history expansion
3  *
4  * This file is part of zsh, the Z shell.
5  *
6  * Copyright (c) 1992-1997 Paul Falstad
7  * All rights reserved.
8  *
9  * Permission is hereby granted, without written agreement and without
10  * license or royalty fees, to use, copy, modify, and distribute this
11  * software and to distribute modified versions of this software for any
12  * purpose, provided that the above copyright notice and the following
13  * two paragraphs appear in all copies of this software.
14  *
15  * In no event shall Paul Falstad or the Zsh Development Group be liable
16  * to any party for direct, indirect, special, incidental, or consequential
17  * damages arising out of the use of this software and its documentation,
18  * even if Paul Falstad and the Zsh Development Group have been advised of
19  * the possibility of such damage.
20  *
21  * Paul Falstad and the Zsh Development Group specifically disclaim any
22  * warranties, including, but not limited to, the implied warranties of
23  * merchantability and fitness for a particular purpose.  The software
24  * provided hereunder is on an "as is" basis, and Paul Falstad and the
25  * Zsh Development Group have no obligation to provide maintenance,
26  * support, updates, enhancements, or modifications.
27  *
28  */
29 
30 #include "zsh.mdh"
31 #include "hist.pro"
32 
33 /* Functions to call for getting/ungetting a character and for history
34  * word control. */
35 
36 /**/
37 mod_export int (*hgetc) _((void));
38 
39 /**/
40 void (*hungetc) _((int));
41 
42 /**/
43 void (*hwaddc) _((int));
44 
45 /**/
46 void (*hwbegin) _((int));
47 
48 /**/
49 void (*hwabort) _((void));
50 
51 /**/
52 void (*hwend) _((void));
53 
54 /**/
55 void (*addtoline) _((int));
56 
57 /* != 0 means history substitution is turned off */
58 
59 /**/
60 mod_export int stophist;
61 
62 /* if != 0, we are expanding the current line */
63 
64 /**/
65 mod_export int expanding;
66 
67 /* these are used to modify the cursor position during expansion */
68 
69 /**/
70 mod_export int excs, exlast;
71 
72 /*
73  * Current history event number
74  *
75  * Note on curhist: with history inactive, this points to the
76  * last line actually added to the history list.  With history active,
77  * the line does not get added to the list until hend(), if at all.
78  * However, curhist is incremented to reflect the current line anyway
79  * and a temporary history entry is inserted while the user is editing.
80  * If the resulting line was not added to the list, a flag is set so
81  * that curhist will be decremented in hbegin().
82  *
83  * Note curhist is passed to zle on variable length argument list:
84  * type must match that retrieved in zle_main_entry.
85  */
86 
87 /**/
88 mod_export zlong curhist;
89 
90 /**/
91 struct histent curline;
92 
93 /* current line count of allocated history entries */
94 
95 /**/
96 zlong histlinect;
97 
98 /* The history lines are kept in a hash, and also doubly-linked in a ring */
99 
100 /**/
101 HashTable histtab;
102 /**/
103 mod_export Histent hist_ring;
104 
105 /* capacity of history lists */
106 
107 /**/
108 zlong histsiz;
109 
110 /* desired history-file size (in lines) */
111 
112 /**/
113 zlong savehistsiz;
114 
115 /* if = 1, we have performed history substitution on the current line *
116  * if = 2, we have used the 'p' modifier                              */
117 
118 /**/
119 int histdone;
120 
121 /* state of the history mechanism */
122 
123 /**/
124 int histactive;
125 
126 /* Current setting of the associated option, but sometimes also includes
127  * the setting of the HIST_SAVE_NO_DUPS option. */
128 
129 /**/
130 int hist_ignore_all_dups;
131 
132 /* What flags (if any) we should skip when moving through the history */
133 
134 /**/
135 mod_export int hist_skip_flags;
136 
137 /* Bits of histactive variable */
138 #define HA_ACTIVE	(1<<0)	/* History mechanism is active */
139 #define HA_NOINC	(1<<1)	/* Don't store, curhist not incremented */
140 #define HA_INWORD       (1<<2)  /* We're inside a word, don't add
141 				   start and end markers */
142 #define HA_UNGET        (1<<3)  /* Recursively ungetting */
143 
144 /* Array of word beginnings and endings in current history line. */
145 
146 /**/
147 short *chwords;
148 
149 /* Max, actual position in chwords.
150  * nwords = chwordpos/2 because we record beginning and end of words.
151  */
152 
153 /**/
154 int chwordlen, chwordpos;
155 
156 /* the last l for s/l/r/ history substitution */
157 
158 /**/
159 char *hsubl;
160 
161 /* the last r for s/l/r/ history substitution */
162 
163 /**/
164 char *hsubr;
165 
166 /* pointer into the history line */
167 
168 /**/
169 mod_export char *hptr;
170 
171 /* the current history line */
172 
173 /**/
174 mod_export char *chline;
175 
176 /*
177  * The current history line as seen by ZLE.
178  * We modify chline for use in other contexts while ZLE may
179  * still be running; ZLE should see only the top-level value.
180  *
181  * To avoid having to modify this every time we modify chline,
182  * we set it when we push the stack, and unset it when we pop
183  * the appropriate value off the stack.  As it's never modified
184  * on the stack this is the only maintenance we ever do on it.
185  * In return, ZLE has to check both zle_chline and (if that's
186  * NULL) chline to get the current value.
187  */
188 
189 /**/
190 mod_export char *zle_chline;
191 
192 /* true if the last character returned by hgetc was an escaped bangchar *
193  * if it is set and NOBANGHIST is unset hwaddc escapes bangchars        */
194 
195 /**/
196 int qbang;
197 
198 /* max size of histline */
199 
200 /**/
201 int hlinesz;
202 
203 /* default event (usually curhist-1, that is, "!!") */
204 
205 static zlong defev;
206 
207 /*
208  * Flag that we stopped reading line when we got to a comment,
209  * but we want to keep it in the histofy even if there were no words
210  * (i.e. the comment was the entire line).
211  */
212 static int hist_keep_comment;
213 
214 /* Remember the last line in the history file so we can find it again. */
215 static struct histfile_stats {
216     char *text;
217     time_t stim, mtim;
218     off_t fpos, fsiz;
219     int interrupted;
220     zlong next_write_ev;
221 } lasthist;
222 
223 static struct histsave {
224     struct histfile_stats lasthist;
225     char *histfile;
226     HashTable histtab;
227     Histent hist_ring;
228     zlong curhist;
229     zlong histlinect;
230     zlong histsiz;
231     zlong savehistsiz;
232     int locallevel;
233 } *histsave_stack;
234 static int histsave_stack_size = 0;
235 static int histsave_stack_pos = 0;
236 
237 static zlong histfile_linect;
238 
239 /* save history context */
240 
241 /**/
242 void
hist_context_save(struct hist_stack * hs,int toplevel)243 hist_context_save(struct hist_stack *hs, int toplevel)
244 {
245     if (toplevel) {
246 	/* top level, make this version visible to ZLE */
247 	zle_chline = chline;
248 	/* ensure line stored is NULL-terminated */
249 	if (hptr)
250 	    *hptr = '\0';
251     }
252     hs->histactive = histactive;
253     hs->histdone = histdone;
254     hs->stophist = stophist;
255     hs->hline = chline;
256     hs->hptr = hptr;
257     hs->chwords = chwords;
258     hs->chwordlen = chwordlen;
259     hs->chwordpos = chwordpos;
260     hs->hgetc = hgetc;
261     hs->hungetc = hungetc;
262     hs->hwaddc = hwaddc;
263     hs->hwbegin = hwbegin;
264     hs->hwabort = hwabort;
265     hs->hwend = hwend;
266     hs->addtoline = addtoline;
267     hs->hlinesz = hlinesz;
268     hs->defev = defev;
269     hs->hist_keep_comment = hist_keep_comment;
270     /*
271      * We save and restore the command stack with history
272      * as it's visible to the user interactively, so if
273      * we're preserving history state we'll continue to
274      * show the current set of commands from input.
275      */
276     hs->cstack = cmdstack;
277     hs->csp = cmdsp;
278 
279     stophist = 0;
280     chline = NULL;
281     hptr = NULL;
282     histactive = 0;
283     cmdstack = (unsigned char *)zalloc(CMDSTACKSZ);
284     cmdsp = 0;
285 }
286 
287 /* restore history context */
288 
289 /**/
290 void
hist_context_restore(const struct hist_stack * hs,int toplevel)291 hist_context_restore(const struct hist_stack *hs, int toplevel)
292 {
293     if (toplevel) {
294 	/* Back to top level: don't need special ZLE value */
295 	DPUTS(hs->hline != zle_chline, "BUG: Ouch, wrong chline for ZLE");
296 	zle_chline = NULL;
297     }
298     histactive = hs->histactive;
299     histdone = hs->histdone;
300     stophist = hs->stophist;
301     chline = hs->hline;
302     hptr = hs->hptr;
303     chwords = hs->chwords;
304     chwordlen = hs->chwordlen;
305     chwordpos = hs->chwordpos;
306     hgetc = hs->hgetc;
307     hungetc = hs->hungetc;
308     hwaddc = hs->hwaddc;
309     hwbegin = hs->hwbegin;
310     hwabort = hs->hwabort;
311     hwend = hs->hwend;
312     addtoline = hs->addtoline;
313     hlinesz = hs->hlinesz;
314     defev = hs->defev;
315     hist_keep_comment = hs->hist_keep_comment;
316     if (cmdstack)
317 	zfree(cmdstack, CMDSTACKSZ);
318     cmdstack = hs->cstack;
319     cmdsp = hs->csp;
320 }
321 
322 /*
323  * Mark that the current level of history is within a word whatever
324  * characters turn up, or turn that mode off.  This is used for nested
325  * parsing of substitutions.
326  *
327  * The caller takes care only to turn this on or off at the start
328  * or end of recursive use of the same mode, so a single flag is
329  * good enough here.
330  */
331 
332 /**/
333 void
hist_in_word(int yesno)334 hist_in_word(int yesno)
335 {
336     if (yesno)
337 	histactive |= HA_INWORD;
338     else
339 	histactive &= ~HA_INWORD;
340 }
341 
342 /* add a character to the current history word */
343 
344 static void
ihwaddc(int c)345 ihwaddc(int c)
346 {
347     /* Only if history line exists and lexing has not finished. */
348     if (chline && !(errflag || lexstop) &&
349 	/*
350 	 * If we're reading inside a word for command substitution
351 	 * we allow the lexer to expand aliases but don't deal
352 	 * with them here.  Note matching code in ihungetc().
353 	 * TBD: it might be neater to deal with all aliases in this
354 	 * fashion as we never need the expansion in the history
355 	 * line, only in the lexer and above.
356 	 */
357 	(inbufflags & (INP_ALIAS|INP_HIST)) != INP_ALIAS) {
358 	/* Quote un-expanded bangs in the history line. */
359 	if (c == bangchar && stophist < 2 && qbang)
360 	    /* If qbang is not set, we do not escape this bangchar as it's *
361 	     * not necessary (e.g. it's a bang in !=, or it is followed    *
362 	     * by a space). Roughly speaking, qbang is zero only if the    *
363 	     * history interpreter has already digested this bang and      *
364 	     * found that it is not necessary to escape it.                */
365 	    hwaddc('\\');
366 	*hptr++ = c;
367 
368 	/* Resize history line if necessary */
369 	if (hptr - chline >= hlinesz) {
370 	    int oldsiz = hlinesz;
371 
372 	    chline = realloc(chline, hlinesz = oldsiz + 64);
373 	    hptr = chline + oldsiz;
374 	}
375     }
376 }
377 
378 /* This function adds a character to the zle input line. It is used when *
379  * zsh expands history (see doexpandhist() in zle_tricky.c). It also     *
380  * calculates the new cursor position after the expansion. It is called  *
381  * from hgetc() and from gettok() in lex.c for characters in comments.   */
382 
383 /**/
384 void
iaddtoline(int c)385 iaddtoline(int c)
386 {
387     if (!expanding || lexstop)
388 	return;
389     if (qbang && c == bangchar && stophist < 2) {
390 	exlast--;
391 	zleentry(ZLE_CMD_ADD_TO_LINE, '\\');
392     }
393     if (excs > zlemetacs) {
394 	excs += 1 + inbufct - exlast;
395 	if (excs < zlemetacs)
396 	    /* this case could be handled better but it is    *
397 	     * so rare that it does not worth it              */
398 	    excs = zlemetacs;
399     }
400     exlast = inbufct;
401     zleentry(ZLE_CMD_ADD_TO_LINE, itok(c) ? ztokens[c - Pound] : c);
402 }
403 
404 
405 static int
ihgetc(void)406 ihgetc(void)
407 {
408     int c = ingetc();
409 
410     if (exit_pending)
411     {
412 	lexstop = 1;
413 	errflag |= ERRFLAG_ERROR;
414 	return ' ';
415     }
416     qbang = 0;
417     if (!stophist && !(inbufflags & INP_ALIAS)) {
418 	/* If necessary, expand history characters. */
419 	c = histsubchar(c);
420 	if (c < 0) {
421 	    /* bad expansion */
422 	    lexstop = 1;
423 	    errflag |= ERRFLAG_ERROR;
424 	    return ' ';
425 	}
426     }
427     if ((inbufflags & INP_HIST) && !stophist) {
428 	/* the current character c came from a history expansion          *
429 	 * (inbufflags & INP_HIST) and history is not disabled            *
430 	 * (e.g. we are not inside single quotes). In that case, \!       *
431 	 * should be treated as ! (since this \! came from a previous     *
432 	 * history line where \ was used to escape the bang). So if       *
433 	 * c == '\\' we fetch one more character to see if it's a bang,   *
434 	 * and if it is not, we unget it and reset c back to '\\'         */
435 	qbang = 0;
436 	if (c == '\\' && !(qbang = (c = ingetc()) == bangchar))
437 	    safeinungetc(c), c = '\\';
438     } else if (stophist || (inbufflags & INP_ALIAS))
439 	/* If the result is a bangchar which came from history or alias  *
440 	 * expansion, we treat it as an escaped bangchar, unless history *
441 	 * is disabled. If stophist == 1 it only means that history is   *
442 	 * temporarily disabled by a !" which won't appear in the        *
443 	 * history, so we still have an escaped bang. stophist > 1 if    *
444 	 * history is disabled with NOBANGHIST or by someone else (e.g.  *
445 	 * when the lexer scans single quoted text).                     */
446 	qbang = c == bangchar && (stophist < 2);
447     hwaddc(c);
448     addtoline(c);
449 
450     return c;
451 }
452 
453 /**/
454 static void
safeinungetc(int c)455 safeinungetc(int c)
456 {
457     if (lexstop)
458 	lexstop = 0;
459     else
460 	inungetc(c);
461 }
462 
463 /**/
464 void
herrflush(void)465 herrflush(void)
466 {
467     inpopalias();
468 
469     if (lexstop)
470 	return;
471     /*
472      * The lex_add_raw test is needed if we are parsing a command
473      * substitution when expanding history for ZLE: strin is set but we
474      * need to finish off the input because the string we are reading is
475      * going to be used directly in the line that goes to ZLE.
476      *
477      * Note that this is a side effect --- this is not the usual reason
478      * for testing lex_add_raw which is to add the text to a different
479      * buffer used when we are actually parsing the command substitution
480      * (nothing to do with ZLE).  Sorry.
481      */
482     while (inbufct && (!strin || lex_add_raw)) {
483 	int c = ingetc();
484 	if (!lexstop) {
485 	    hwaddc(c);
486 	    addtoline(c);
487 	}
488     }
489 }
490 
491 /*
492  * Extract :s/foo/bar/ delimiters and arguments
493  *
494  * The first character expected is the first delimiter.
495  * The arguments are stored in the hsubl and hsubr variables.
496  *
497  * subline is the part of the command line to be matched.
498  *
499  * If a ':' was found but was not followed by a 'G',
500  * *cflagp is set to 1 and the input is backed up to the
501  * character following the colon.
502  */
503 
504 /**/
505 static int
getsubsargs(UNUSED (char * subline),int * gbalp,int * cflagp)506 getsubsargs(UNUSED(char *subline), int *gbalp, int *cflagp)
507 {
508     int del, follow;
509     char *ptr1, *ptr2;
510 
511     del = ingetc();
512     ptr1 = hdynread2(del);
513     if (!ptr1)
514 	return 1;
515     ptr2 = hdynread2(del);
516     if (strlen(ptr1)) {
517 	zsfree(hsubl);
518 	hsubl = ptr1;
519     } else if (!hsubl) {		/* fail silently on this */
520 	zsfree(ptr1);
521 	zsfree(ptr2);
522 	return 0;
523     }
524     zsfree(hsubr);
525     hsubr = ptr2;
526     follow = ingetc();
527     if (follow == ':') {
528 	follow = ingetc();
529 	if (follow == 'G')
530 	    *gbalp = 1;
531 	else {
532 	    inungetc(follow);
533 	    *cflagp = 1;
534 	}
535     } else
536 	inungetc(follow);
537     return 0;
538 }
539 
540 /* Get the maximum no. of words for a history entry. */
541 
542 /**/
543 static int
getargc(Histent ehist)544 getargc(Histent ehist)
545 {
546     return ehist->nwords ? ehist->nwords-1 : 0;
547 }
548 
549 /**/
550 static int
substfailed(void)551 substfailed(void)
552 {
553     herrflush();
554     zerr("substitution failed");
555     return -1;
556 }
557 
558 /*
559  * Return a count given by decimal digits after a modifier.
560  */
561 static int
digitcount(void)562 digitcount(void)
563 {
564     int c = ingetc(), count;
565 
566     if (idigit(c)) {
567 	count = 0;
568 	do {
569 	    count = 10 * count + (c - '0');
570 	    c = ingetc();
571 	} while (idigit(c));
572     }
573     else
574 	count = 0;
575     inungetc(c);
576     return count;
577 }
578 
579 /* Perform history substitution, returning the next character afterwards. */
580 
581 /**/
582 static int
histsubchar(int c)583 histsubchar(int c)
584 {
585     int farg, evset = -1, larg, argc, cflag = 0, bflag = 0;
586     zlong ev;
587     static int marg = -1;
588     static zlong mev = -1;
589     char *buf, *ptr;
590     char *sline;
591     int lexraw_mark;
592     Histent ehist;
593     size_t buflen;
594 
595     /*
596      * If accumulating raw input for use in command substitution,
597      * we don't want the history text, so mark it for later removal.
598      * It would be better to do this at a level above the history
599      * and below the lexer --- but there isn't one.
600      *
601      * Include the character we are attempting to substitute.
602      */
603     lexraw_mark = zshlex_raw_mark(-1);
604 
605     /* look, no goto's */
606     if (isfirstch && c == hatchar) {
607 	int gbal = 0;
608 
609 	/* Line begins ^foo^bar */
610 	isfirstch = 0;
611 	inungetc(hatchar);
612 	if (!(ehist = gethist(defev))
613 	    || !(sline = getargs(ehist, 0, getargc(ehist))))
614 	    return -1;
615 
616 	if (getsubsargs(sline, &gbal, &cflag))
617 	    return substfailed();
618 	if (!hsubl)
619 	    return -1;
620 	if (subst(&sline, hsubl, hsubr, gbal))
621 	    return substfailed();
622     } else {
623 	/* Line doesn't begin ^foo^bar */
624 	if (c != ' ')
625 	    isfirstch = 0;
626 	if (c == '\\') {
627 	    int g = ingetc();
628 
629 	    if (g != bangchar)
630 		safeinungetc(g);
631 	    else {
632 		qbang = 1;
633 		return bangchar;
634 	    }
635 	}
636 	if (c != bangchar)
637 	    return c;
638 	*hptr = '\0';
639 	if ((c = ingetc()) == '{') {
640 	    bflag = cflag = 1;
641 	    c = ingetc();
642 	}
643 	if (c == '\"') {
644 	    stophist = 1;
645 	    return ingetc();
646 	}
647 	if ((!cflag && inblank(c)) || c == '=' || c == '(' || lexstop) {
648 	    safeinungetc(c);
649 	    return bangchar;
650 	}
651 	cflag = 0;
652 	ptr = buf = zhalloc(buflen = 265);
653 
654 	/* get event number */
655 
656 	queue_signals();
657 	if (c == '?') {
658 	    for (;;) {
659 		c = ingetc();
660 		if (c == '?' || c == '\n' || lexstop)
661 		    break;
662 		else {
663 		    *ptr++ = c;
664 		    if (ptr == buf + buflen) {
665 			buf = hrealloc(buf, buflen, 2 * buflen);
666 			ptr = buf + buflen;
667 			buflen *= 2;
668 		    }
669 		}
670 	    }
671 	    if (c != '\n' && !lexstop)
672 		c = ingetc();
673 	    *ptr = '\0';
674 	    mev = ev = hconsearch(hsubl = ztrdup(buf), &marg);
675 	    evset = 0;
676 	    if (ev == -1) {
677 		herrflush();
678 		unqueue_signals();
679 		zerr("no such event: %s", buf);
680 		return -1;
681 	    }
682 	} else {
683 	    zlong t0;
684 
685 	    for (;;) {
686 		if (inblank(c) || c == ';' || c == ':' || c == '^' ||
687 		    c == '$' || c == '*' || c == '%' || c == '}' ||
688 		    c == '\'' || c == '"' || c == '`' || lexstop)
689 		    break;
690 		if (ptr != buf) {
691 		    if (c == '-')
692 			break;
693 		    if ((idigit(buf[0]) || buf[0] == '-') && !idigit(c))
694 			break;
695 		}
696 		*ptr++ = c;
697 		if (ptr == buf + buflen) {
698 		    buf = hrealloc(buf, buflen, 2 * buflen);
699 		    ptr = buf + buflen;
700 		    buflen *= 2;
701 		}
702 		if (c == '#' || c == bangchar) {
703 		    c = ingetc();
704 		    break;
705 		}
706 		c = ingetc();
707 	    }
708 	    if (ptr == buf &&
709 		(c == '}' ||  c == ';' || c == '\'' || c == '"' || c == '`')) {
710 	      /* Neither event nor word designator, no expansion */
711 	      safeinungetc(c);
712 	      unqueue_signals();
713 	      return bangchar;
714 	    }
715 	    *ptr = 0;
716 	    if (!*buf) {
717 		if (c != '%') {
718 		    if (isset(CSHJUNKIEHISTORY))
719 			ev = addhistnum(curhist,-1,HIST_FOREIGN);
720 		    else
721 			ev = defev;
722 		    if (c == ':' && evset == -1)
723 			evset = 0;
724 		    else
725 			evset = 1;
726 		} else {
727 		    if (marg != -1)
728 			ev = mev;
729 		    else
730 			ev = defev;
731 		    evset = 0;
732 		}
733 	    } else if ((t0 = zstrtol(buf, NULL, 10))) {
734 		ev = (t0 < 0) ? addhistnum(curhist,t0,HIST_FOREIGN) : t0;
735 		evset = 1;
736 	    } else if ((unsigned)*buf == bangchar) {
737 		ev = addhistnum(curhist,-1,HIST_FOREIGN);
738 		evset = 1;
739 	    } else if (*buf == '#') {
740 		ev = curhist;
741 		evset = 1;
742 	    } else if ((ev = hcomsearch(buf)) == -1) {
743 		herrflush();
744 		unqueue_signals();
745 		zerr("event not found: %s", buf);
746 		return -1;
747 	    } else
748 		evset = 1;
749 	}
750 
751 	/* get the event */
752 
753 	if (!(ehist = gethist(defev = ev))) {
754 	    unqueue_signals();
755 	    return -1;
756 	}
757 	/* extract the relevant arguments */
758 
759 	argc = getargc(ehist);
760 	if (c == ':') {
761 	    cflag = 1;
762 	    c = ingetc();
763 	    if (c == '%' && marg != -1) {
764 		if (!evset) {
765 		    ehist = gethist(defev = mev);
766 		    argc = getargc(ehist);
767 		} else {
768 		    herrflush();
769 		    unqueue_signals();
770 		    zerr("ambiguous history reference");
771 		    return -1;
772 		}
773 
774 	    }
775 	}
776 	if (c == '*') {
777 	    farg = 1;
778 	    larg = argc;
779 	    cflag = 0;
780 	} else {
781 	    inungetc(c);
782 	    larg = farg = getargspec(argc, marg, evset);
783 	    if (larg == -2) {
784 		unqueue_signals();
785 		return -1;
786 	    }
787 	    if (farg != -1)
788 		cflag = 0;
789 	    c = ingetc();
790 	    if (c == '*') {
791 		cflag = 0;
792 		larg = argc;
793 	    } else if (c == '-') {
794 		cflag = 0;
795 		larg = getargspec(argc, marg, evset);
796 		if (larg == -2) {
797 		    unqueue_signals();
798 		    return -1;
799 		}
800 		if (larg == -1)
801 		    larg = argc - 1;
802 	    } else
803 		inungetc(c);
804 	}
805 	if (farg == -1)
806 	    farg = 0;
807 	if (larg == -1)
808 	    larg = argc;
809 	if (!(sline = getargs(ehist, farg, larg))) {
810 	    unqueue_signals();
811 	    return -1;
812 	}
813 	unqueue_signals();
814     }
815 
816     /* do the modifiers */
817 
818     for (;;) {
819 	c = (cflag) ? ':' : ingetc();
820 	cflag = 0;
821 	if (c == ':') {
822 	    int gbal = 0;
823 
824 	    if ((c = ingetc()) == 'g') {
825 		gbal = 1;
826 		c = ingetc();
827 		if (c != 's' && c != '&') {
828 		    zerr("'s' or '&' modifier expected after 'g'");
829 		    return -1;
830 		}
831 	    }
832 	    switch (c) {
833 	    case 'p':
834 		histdone = HISTFLAG_DONE | HISTFLAG_NOEXEC;
835 		break;
836 	    case 'a':
837 		if (!chabspath(&sline)) {
838 		    herrflush();
839 		    zerr("modifier failed: a");
840 		    return -1;
841 		}
842 		break;
843 
844 	    case 'A':
845 		if (!chrealpath(&sline)) {
846 		    herrflush();
847 		    zerr("modifier failed: A");
848 		    return -1;
849 		}
850 		break;
851 	    case 'c':
852 		if (!(sline = equalsubstr(sline, 0, 0))) {
853 		    herrflush();
854 		    zerr("modifier failed: c");
855 		    return -1;
856 		}
857 		break;
858 	    case 'h':
859 		if (!remtpath(&sline, digitcount())) {
860 		    herrflush();
861 		    zerr("modifier failed: h");
862 		    return -1;
863 		}
864 		break;
865 	    case 'e':
866 		if (!rembutext(&sline)) {
867 		    herrflush();
868 		    zerr("modifier failed: e");
869 		    return -1;
870 		}
871 		break;
872 	    case 'r':
873 		if (!remtext(&sline)) {
874 		    herrflush();
875 		    zerr("modifier failed: r");
876 		    return -1;
877 		}
878 		break;
879 	    case 't':
880 		if (!remlpaths(&sline, digitcount())) {
881 		    herrflush();
882 		    zerr("modifier failed: t");
883 		    return -1;
884 		}
885 		break;
886 	    case 's':
887 		if (getsubsargs(sline, &gbal, &cflag))
888 		    return -1; /* fall through */
889 	    case '&':
890 		if (hsubl && hsubr) {
891 		    if (subst(&sline, hsubl, hsubr, gbal))
892 			return substfailed();
893 		} else {
894 		    herrflush();
895 		    zerr("no previous substitution");
896 		    return -1;
897 		}
898 		break;
899 	    case 'q':
900 		quote(&sline);
901 		break;
902 	    case 'Q':
903 		{
904 		    int one = noerrs, oef = errflag;
905 
906 		    noerrs = 1;
907 		    parse_subst_string(sline);
908 		    noerrs = one;
909 		    errflag = oef | (errflag & ERRFLAG_INT);
910 		    remnulargs(sline);
911 		    untokenize(sline);
912 		}
913 		break;
914 	    case 'x':
915 		quotebreak(&sline);
916 		break;
917 	    case 'l':
918 		sline = casemodify(sline, CASMOD_LOWER);
919 		break;
920 	    case 'u':
921 		sline = casemodify(sline, CASMOD_UPPER);
922 		break;
923 	    case 'P':
924 		if (*sline != '/') {
925 		    char *here = zgetcwd();
926 		    if (here[strlen(here)-1] != '/')
927 			sline = zhtricat(metafy(here, -1, META_HEAPDUP), "/", sline);
928 		    else
929 			sline = dyncat(here, sline);
930 		}
931 		sline = xsymlink(sline, 1);
932 		break;
933 	    default:
934 		herrflush();
935 		zerr("illegal modifier: %c", c);
936 		return -1;
937 	    }
938 	} else {
939 	    if (c != '}' || !bflag)
940 		inungetc(c);
941 	    if (c != '}' && bflag) {
942 		zerr("'}' expected");
943 		return -1;
944 	    }
945 	    break;
946 	}
947     }
948 
949     zshlex_raw_back_to_mark(lexraw_mark);
950 
951     /*
952      * Push the expanded value onto the input stack,
953      * marking this as a history word for purposes of the alias stack.
954      */
955 
956     lexstop = 0;
957     /* this function is called only called from hgetc and only if      *
958      * !(inbufflags & INP_ALIAS). History expansion should never be    *
959      * done with INP_ALIAS (to prevent recursive history expansion and *
960      * histoty expansion of aliases). Escapes are not removed here.    *
961      * This is now handled in hgetc.                                   */
962     inpush(sline, INP_HIST, NULL); /* sline from heap, don't free */
963     histdone |= HISTFLAG_DONE;
964     if (isset(HISTVERIFY))
965 	histdone |= HISTFLAG_NOEXEC | HISTFLAG_RECALL;
966 
967     /* Don't try and re-expand line. */
968     return ingetc();
969 }
970 
971 /* unget a char and remove it from chline. It can only be used *
972  * to unget a character returned by hgetc.                     */
973 
974 static void
ihungetc(int c)975 ihungetc(int c)
976 {
977     int doit = 1;
978 
979     while (!lexstop && !errflag) {
980 	if (hptr[-1] != (char) c && stophist < 4 &&
981 	    hptr > chline + 1 && hptr[-1] == '\n' && hptr[-2] == '\\' &&
982 	    !(histactive & HA_UNGET) &&
983 	    (inbufflags & (INP_ALIAS|INP_HIST)) != INP_ALIAS) {
984 	    histactive |= HA_UNGET;
985 	    hungetc('\n');
986 	    hungetc('\\');
987 	    histactive &= ~HA_UNGET;
988 	}
989 
990 	if (expanding) {
991 	    zlemetacs--;
992 	    zlemetall--;
993 	    exlast++;
994 	}
995 	if ((inbufflags & (INP_ALIAS|INP_HIST)) != INP_ALIAS) {
996 	    DPUTS(hptr <= chline, "BUG: hungetc attempted at buffer start");
997 	    hptr--;
998 	    DPUTS(*hptr != (char) c, "BUG: wrong character in hungetc() ");
999 	    qbang = (c == bangchar && stophist < 2 &&
1000 		     hptr > chline && hptr[-1] == '\\');
1001 	} else {
1002 	    /* No active bangs in aliases */
1003 	    qbang = 0;
1004 	}
1005 	if (doit)
1006 	    inungetc(c);
1007 	if (!qbang)
1008 	    return;
1009 	doit = !stophist && ((inbufflags & INP_HIST) ||
1010 				 !(inbufflags & INP_ALIAS));
1011 	c = '\\';
1012     }
1013 }
1014 
1015 /* begin reading a string */
1016 
1017 /**/
1018 mod_export void
strinbeg(int dohist)1019 strinbeg(int dohist)
1020 {
1021     strin++;
1022     hbegin(dohist);
1023     lexinit();
1024     /*
1025      * Also initialise some variables owned by the parser but
1026      * used for communication between the parser and lexer.
1027      */
1028     init_parse_status();
1029 }
1030 
1031 /* done reading a string */
1032 
1033 /**/
1034 mod_export void
strinend(void)1035 strinend(void)
1036 {
1037     hend(NULL);
1038     DPUTS(!strin, "BUG: strinend() called without strinbeg()");
1039     strin--;
1040     isfirstch = 1;
1041     histdone = 0;
1042 }
1043 
1044 /* dummy functions to use instead of hwaddc(), hwbegin(), and hwend() when
1045  * they aren't needed */
1046 
1047 static void
nohw(UNUSED (int c))1048 nohw(UNUSED(int c))
1049 {
1050 }
1051 
1052 static void
nohwabort(void)1053 nohwabort(void)
1054 {
1055 }
1056 
1057 static void
nohwe(void)1058 nohwe(void)
1059 {
1060 }
1061 
1062 /* these functions handle adding/removing curline to/from the hist_ring */
1063 
1064 static void
linkcurline(void)1065 linkcurline(void)
1066 {
1067     if (!hist_ring)
1068 	hist_ring = curline.up = curline.down = &curline;
1069     else {
1070 	curline.up = hist_ring;
1071 	curline.down = hist_ring->down;
1072 	hist_ring->down = hist_ring->down->up = &curline;
1073 	hist_ring = &curline;
1074     }
1075     curline.histnum = ++curhist;
1076 }
1077 
1078 static void
unlinkcurline(void)1079 unlinkcurline(void)
1080 {
1081     curline.up->down = curline.down;
1082     curline.down->up = curline.up;
1083     if (hist_ring == &curline) {
1084 	if (!histlinect)
1085 	    hist_ring = NULL;
1086 	else
1087 	    hist_ring = curline.up;
1088     }
1089     curhist--;
1090 }
1091 
1092 /* initialize the history mechanism */
1093 
1094 /**/
1095 mod_export void
hbegin(int dohist)1096 hbegin(int dohist)
1097 {
1098     char *hf;
1099 
1100     isfirstln = isfirstch = 1;
1101     errflag &= ~ERRFLAG_ERROR;
1102     histdone = 0;
1103     if (!dohist)
1104 	stophist = 2;
1105     else if (dohist != 2)
1106 	stophist = (!interact || unset(SHINSTDIN)) ? 2 : 0;
1107     else
1108 	stophist = 0;
1109     /*
1110      * pws: We used to test for "|| (inbufflags & INP_ALIAS)"
1111      * in this test, but at this point we don't have input
1112      * set up so this can trigger unnecessarily.
1113      * I don't see how the test at this point could ever be
1114      * useful, since we only get here when we're initialising
1115      * the history mechanism, before we've done any input.
1116      *
1117      * (I also don't see any point where this function is called with
1118      * dohist=0.)
1119      */
1120     if (stophist == 2) {
1121 	chline = hptr = NULL;
1122 	hlinesz = 0;
1123 	chwords = NULL;
1124 	chwordlen = 0;
1125 	hgetc = ingetc;
1126 	hungetc = inungetc;
1127 	hwaddc = nohw;
1128 	hwbegin = nohw;
1129 	hwabort = nohwabort;
1130 	hwend = nohwe;
1131 	addtoline = nohw;
1132     } else {
1133 	chline = hptr = zshcalloc(hlinesz = 64);
1134 	chwords = zalloc((chwordlen = 64) * sizeof(short));
1135 	hgetc = ihgetc;
1136 	hungetc = ihungetc;
1137 	hwaddc = ihwaddc;
1138 	hwbegin = ihwbegin;
1139 	hwabort = ihwabort;
1140 	hwend = ihwend;
1141 	addtoline = iaddtoline;
1142 	if (!isset(BANGHIST))
1143 	    stophist = 4;
1144     }
1145     chwordpos = 0;
1146 
1147     if (hist_ring && !hist_ring->ftim && !strin)
1148 	hist_ring->ftim = time(NULL);
1149     if ((dohist == 2 || (interact && isset(SHINSTDIN))) && !strin) {
1150 	histactive = HA_ACTIVE;
1151 	attachtty(mypgrp);
1152 	linkcurline();
1153 	defev = addhistnum(curhist, -1, HIST_FOREIGN);
1154     } else
1155 	histactive = HA_ACTIVE | HA_NOINC;
1156 
1157     /*
1158      * For INCAPPENDHISTORYTIME, when interactive, save the history here
1159      * as it gives a better estimate of the times of commands.
1160      *
1161      * If INCAPPENDHISTORY is also set we've already done it.
1162      *
1163      * If SHAREHISTORY is also set continue to do so in the
1164      * standard place, because that's safer about reading and
1165      * rewriting history atomically.
1166      *
1167      * The histsave_stack_pos test won't usually fail here.
1168      * We need to test the opposite for the hend() case because we
1169      * need to save in the history file we've switched to, but then
1170      * we pop immediately after that so the variable becomes zero.
1171      * We will already have saved the line and restored the history
1172      * so that (correctly) nothing happens here.  But it shows
1173      * I thought about it.
1174      */
1175     if (isset(INCAPPENDHISTORYTIME) && !isset(SHAREHISTORY) &&
1176 	!isset(INCAPPENDHISTORY) &&
1177 	!(histactive & HA_NOINC) && !strin && histsave_stack_pos == 0) {
1178 	hf = getsparam("HISTFILE");
1179 	savehistfile(hf, 0, HFILE_USE_OPTIONS | HFILE_FAST);
1180     }
1181 }
1182 
1183 /**/
1184 void
histreduceblanks(void)1185 histreduceblanks(void)
1186 {
1187     int i, len, pos, needblank, spacecount = 0, trunc_ok;
1188     char *lastptr, *ptr;
1189 
1190     if (isset(HISTIGNORESPACE))
1191 	while (chline[spacecount] == ' ') spacecount++;
1192 
1193     for (i = 0, len = spacecount; i < chwordpos; i += 2) {
1194 	len += chwords[i+1] - chwords[i]
1195 	     + (i > 0 && chwords[i] > chwords[i-1]);
1196     }
1197     if (chline[len] == '\0')
1198 	return;
1199 
1200     /* Remember where the delimited words end */
1201     if (chwordpos)
1202 	lastptr = chline + chwords[chwordpos-1];
1203     else
1204 	lastptr = chline;
1205 
1206     for (i = 0, pos = spacecount; i < chwordpos; i += 2) {
1207 	len = chwords[i+1] - chwords[i];
1208 	needblank = (i < chwordpos-2 && chwords[i+2] > chwords[i+1]);
1209 	if (pos != chwords[i]) {
1210 	    memmove(chline + pos, chline + chwords[i], len + needblank);
1211 	    chwords[i] = pos;
1212 	    chwords[i+1] = chwords[i] + len;
1213 	}
1214 	pos += len + needblank;
1215     }
1216 
1217     /*
1218      * A terminating comment isn't recorded as a word.
1219      * Only truncate the line if just whitespace remains.
1220      */
1221     trunc_ok = 1;
1222     for (ptr = lastptr; *ptr; ptr++) {
1223 	if (!inblank(*ptr)) {
1224 	    trunc_ok = 0;
1225 	    break;
1226 	}
1227     }
1228     if (trunc_ok) {
1229 	chline[pos] = '\0';
1230     } else {
1231 	ptr = chline + pos;
1232 	if (ptr < lastptr)
1233 	    while ((*ptr++ = *lastptr++))
1234 		;
1235     }
1236 }
1237 
1238 /**/
1239 void
histremovedups(void)1240 histremovedups(void)
1241 {
1242     Histent he, next;
1243     for (he = hist_ring; he; he = next) {
1244 	next = up_histent(he);
1245 	if (he->node.flags & HIST_DUP)
1246 	    freehistnode(&he->node);
1247     }
1248 }
1249 
1250 /**/
1251 mod_export zlong
addhistnum(zlong hl,int n,int xflags)1252 addhistnum(zlong hl, int n, int xflags)
1253 {
1254     int dir = n < 0? -1 : n > 0? 1 : 0;
1255     Histent he = gethistent(hl, dir);
1256 
1257     if (!he)
1258 	return 0;
1259     if (he->histnum != hl)
1260 	n -= dir;
1261     if (n)
1262 	he = movehistent(he, n, xflags);
1263     if (!he)
1264 	return dir < 0? firsthist() - 1 : curhist + 1;
1265     return he->histnum;
1266 }
1267 
1268 /**/
1269 mod_export Histent
movehistent(Histent he,int n,int xflags)1270 movehistent(Histent he, int n, int xflags)
1271 {
1272     while (n < 0) {
1273 	if (!(he = up_histent(he)))
1274 	    return NULL;
1275 	if (!(he->node.flags & xflags))
1276 	    n++;
1277     }
1278     while (n > 0) {
1279 	if (!(he = down_histent(he)))
1280 	    return NULL;
1281 	if (!(he->node.flags & xflags))
1282 	    n--;
1283     }
1284     checkcurline(he);
1285     return he;
1286 }
1287 
1288 /**/
1289 mod_export Histent
up_histent(Histent he)1290 up_histent(Histent he)
1291 {
1292     return !he || he->up == hist_ring? NULL : he->up;
1293 }
1294 
1295 /**/
1296 mod_export Histent
down_histent(Histent he)1297 down_histent(Histent he)
1298 {
1299     return he == hist_ring? NULL : he->down;
1300 }
1301 
1302 /**/
1303 mod_export Histent
gethistent(zlong ev,int nearmatch)1304 gethistent(zlong ev, int nearmatch)
1305 {
1306     Histent he;
1307 
1308     if (!hist_ring)
1309 	return NULL;
1310 
1311     if (ev - hist_ring->down->histnum < hist_ring->histnum - ev) {
1312 	for (he = hist_ring->down; he->histnum < ev; he = he->down) ;
1313 	if (he->histnum != ev) {
1314 	    if (nearmatch == 0
1315 	     || (nearmatch < 0 && (he = up_histent(he)) == NULL))
1316 		return NULL;
1317 	}
1318     }
1319     else {
1320 	for (he = hist_ring; he->histnum > ev; he = he->up) ;
1321 	if (he->histnum != ev) {
1322 	    if (nearmatch == 0
1323 	     || (nearmatch > 0 && (he = down_histent(he)) == NULL))
1324 		return NULL;
1325 	}
1326     }
1327 
1328     checkcurline(he);
1329     return he;
1330 }
1331 
1332 static void
putoldhistentryontop(short keep_going)1333 putoldhistentryontop(short keep_going)
1334 {
1335     static Histent next = NULL;
1336     Histent he = (keep_going || !hist_ring) ? next : hist_ring->down;
1337     if (he)
1338 	next = he->down;
1339     else
1340 	return;
1341     if (isset(HISTEXPIREDUPSFIRST) && !(he->node.flags & HIST_DUP)) {
1342 	static zlong max_unique_ct = 0;
1343 	if (!keep_going)
1344 	    max_unique_ct = savehistsiz;
1345 	do {
1346 	    if (max_unique_ct-- <= 0 || he == hist_ring) {
1347 		max_unique_ct = 0;
1348 		he = hist_ring->down;
1349 		next = hist_ring;
1350 		break;
1351 	    }
1352 	    he = next;
1353 	    next = he->down;
1354 	} while (!(he->node.flags & HIST_DUP));
1355     }
1356     if (he != hist_ring->down) {
1357 	he->up->down = he->down;
1358 	he->down->up = he->up;
1359 	he->up = hist_ring;
1360 	he->down = hist_ring->down;
1361 	hist_ring->down = he->down->up = he;
1362     }
1363     hist_ring = he;
1364 }
1365 
1366 /**/
1367 Histent
prepnexthistent(void)1368 prepnexthistent(void)
1369 {
1370     Histent he;
1371     int curline_in_ring = hist_ring == &curline;
1372 
1373     if (curline_in_ring)
1374 	unlinkcurline();
1375     if (hist_ring && hist_ring->node.flags & HIST_TMPSTORE) {
1376 	curhist--;
1377 	freehistnode(&hist_ring->node);
1378     }
1379 
1380     if (histlinect < histsiz || !hist_ring) {
1381 	he = (Histent)zshcalloc(sizeof *he);
1382 	if (!hist_ring)
1383 	    hist_ring = he->up = he->down = he;
1384 	else {
1385 	    he->up = hist_ring;
1386 	    he->down = hist_ring->down;
1387 	    hist_ring->down = he->down->up = he;
1388 	    hist_ring = he;
1389 	}
1390 	histlinect++;
1391     }
1392     else {
1393 	putoldhistentryontop(0);
1394 	freehistdata(hist_ring, 0);
1395 	he = hist_ring;
1396     }
1397     he->histnum = ++curhist;
1398     if (curline_in_ring)
1399 	linkcurline();
1400     return he;
1401 }
1402 
1403 /* A helper function for hend() */
1404 
1405 static int
should_ignore_line(Eprog prog)1406 should_ignore_line(Eprog prog)
1407 {
1408     if (isset(HISTIGNORESPACE)) {
1409 	if (*chline == ' ' || aliasspaceflag)
1410 	    return 1;
1411     }
1412 
1413     if (!prog)
1414 	return 0;
1415 
1416     if (isset(HISTNOFUNCTIONS)) {
1417 	Wordcode pc = prog->prog;
1418 	wordcode code = *pc;
1419 	if (wc_code(code) == WC_LIST && WC_LIST_TYPE(code) & Z_SIMPLE
1420 	 && wc_code(pc[2]) == WC_FUNCDEF)
1421 	    return 1;
1422     }
1423 
1424     if (isset(HISTNOSTORE)) {
1425 	char *b = getjobtext(prog, NULL);
1426 	int saw_builtin;
1427 	if (*b == 'b' && strncmp(b,"builtin ",8) == 0) {
1428 	    b += 8;
1429 	    saw_builtin = 1;
1430 	} else
1431 	    saw_builtin = 0;
1432 	if (*b == 'h' && strncmp(b,"history",7) == 0 && (!b[7] || b[7] == ' ')
1433 	 && (saw_builtin || !shfunctab->getnode(shfunctab,"history")))
1434 	    return 1;
1435 	if (*b == 'r' && (!b[1] || b[1] == ' ')
1436 	 && (saw_builtin || !shfunctab->getnode(shfunctab,"r")))
1437 	    return 1;
1438 	if (*b == 'f' && b[1] == 'c' && b[2] == ' ' && b[3] == '-'
1439 	 && (saw_builtin || !shfunctab->getnode(shfunctab,"fc"))) {
1440 	    b += 3;
1441 	    do {
1442 		if (*++b == 'l')
1443 		    return 1;
1444 	    } while (ialpha(*b));
1445 	}
1446     }
1447 
1448     return 0;
1449 }
1450 
1451 /* say we're done using the history mechanism */
1452 
1453 /**/
1454 mod_export int
hend(Eprog prog)1455 hend(Eprog prog)
1456 {
1457     int flag, hookret, stack_pos = histsave_stack_pos;
1458     /*
1459      * save:
1460      * 0: don't save
1461      * 1: save normally
1462      * -1: save temporarily, delete after next line
1463      * -2: save internally but mark for not writing
1464      */
1465     int save = 1;
1466     char *hf;
1467 
1468     DPUTS(stophist != 2 && !(inbufflags & INP_ALIAS) && !chline,
1469 	  "BUG: chline is NULL in hend()");
1470     queue_signals();
1471     if (histdone & HISTFLAG_SETTY)
1472 	settyinfo(&shttyinfo);
1473     if (!(histactive & HA_NOINC))
1474 	unlinkcurline();
1475     if (histactive & HA_NOINC) {
1476 	zfree(chline, hlinesz);
1477 	zfree(chwords, chwordlen*sizeof(short));
1478 	chline = hptr = NULL;
1479 	chwords = NULL;
1480 	histactive = 0;
1481 	unqueue_signals();
1482 	return 1;
1483     }
1484     if (hist_ignore_all_dups != isset(HISTIGNOREALLDUPS)
1485      && (hist_ignore_all_dups = isset(HISTIGNOREALLDUPS)) != 0)
1486 	histremovedups();
1487 
1488     if (hptr) {
1489 	/*
1490 	 * Added the following in case the test "hptr < chline + 1"
1491 	 * is more than just paranoia.
1492 	 */
1493 	DPUTS(hptr < chline, "History end pointer off start of line");
1494 	*hptr = '\0';
1495     }
1496     if (*chline) {
1497 	LinkList hookargs = newlinklist();
1498 	int save_errflag = errflag;
1499 	errflag = 0;
1500 
1501 	addlinknode(hookargs, "zshaddhistory");
1502 	addlinknode(hookargs, chline);
1503 	callhookfunc("zshaddhistory", hookargs, 1, &hookret);
1504 
1505 	errflag &= ~ERRFLAG_ERROR;
1506 	errflag |= save_errflag;
1507     }
1508     /* For history sharing, lock history file once for both read and write */
1509     hf = getsparam("HISTFILE");
1510     if (isset(SHAREHISTORY) && !lockhistfile(hf, 0)) {
1511 	readhistfile(hf, 0, HFILE_USE_OPTIONS | HFILE_FAST);
1512 	curline.histnum = curhist+1;
1513     }
1514     flag = histdone;
1515     histdone = 0;
1516     if (hptr < chline + 1)
1517 	save = 0;
1518     else {
1519 	if (hptr[-1] == '\n') {
1520 	    if (chline[1]) {
1521 		*--hptr = '\0';
1522 	    } else
1523 		save = 0;
1524 	}
1525 	if (chwordpos <= 2 && !hist_keep_comment)
1526 	    save = 0;
1527 	else if (should_ignore_line(prog))
1528 	    save = -1;
1529 	else if (hookret == 2)
1530 	    save = -2;
1531 	else if (hookret)
1532 	    save = -1;
1533     }
1534     if (flag & (HISTFLAG_DONE | HISTFLAG_RECALL)) {
1535 	char *ptr;
1536 
1537 	ptr = ztrdup(chline);
1538 	if ((flag & (HISTFLAG_DONE | HISTFLAG_RECALL)) == HISTFLAG_DONE) {
1539 	    zputs(ptr, shout);
1540 	    fputc('\n', shout);
1541 	    fflush(shout);
1542 	}
1543 	if (flag & HISTFLAG_RECALL) {
1544 	    zpushnode(bufstack, ptr);
1545 	    save = 0;
1546 	} else
1547 	    zsfree(ptr);
1548     }
1549     if (save || *chline == ' ') {
1550 	Histent he;
1551 	for (he = hist_ring; he && he->node.flags & HIST_FOREIGN;
1552 	     he = up_histent(he)) ;
1553 	if (he && he->node.flags & HIST_TMPSTORE) {
1554 	    if (he == hist_ring)
1555 		curline.histnum = curhist--;
1556 	    freehistnode(&he->node);
1557 	}
1558     }
1559     if (save) {
1560 	Histent he;
1561 	int newflags;
1562 
1563 #ifdef DEBUG
1564 	/* debugging only */
1565 	if (chwordpos%2) {
1566 	    hwend();
1567 	    DPUTS(1, "BUG: uncompleted line in history");
1568 	}
1569 #endif
1570 	/* get rid of pesky \n which we've already nulled out */
1571 	if (chwordpos > 1 && !chline[chwords[chwordpos-2]]) {
1572 	    chwordpos -= 2;
1573 	    /* strip superfluous blanks, if desired */
1574 	    if (isset(HISTREDUCEBLANKS))
1575 		histreduceblanks();
1576 	}
1577 	if (save == -1)
1578 	    newflags = HIST_TMPSTORE;
1579 	else if (save == -2)
1580 	    newflags = HIST_NOWRITE;
1581 	else
1582 	    newflags = 0;
1583 	if ((isset(HISTIGNOREDUPS) || isset(HISTIGNOREALLDUPS)) && save > 0
1584 	 && hist_ring && histstrcmp(chline, hist_ring->node.nam) == 0) {
1585 	    /* This history entry compares the same as the previous.
1586 	     * In case minor changes were made, we overwrite the
1587 	     * previous one with the current one.  This also gets the
1588 	     * timestamp right.  Perhaps, preserve the HIST_OLD flag.
1589 	     */
1590 	    he = hist_ring;
1591 	    newflags |= he->node.flags & HIST_OLD; /* Avoid re-saving */
1592 	    freehistdata(he, 0);
1593 	    curline.histnum = curhist;
1594 	} else
1595 	    he = prepnexthistent();
1596 
1597 	he->node.nam = ztrdup(chline);
1598 	he->stim = time(NULL);
1599 	he->ftim = 0L;
1600 	he->node.flags = newflags;
1601 
1602 	if ((he->nwords = chwordpos/2)) {
1603 	    he->words = (short *)zalloc(chwordpos * sizeof(short));
1604 	    memcpy(he->words, chwords, chwordpos * sizeof(short));
1605 	}
1606 	if (!(newflags & HIST_TMPSTORE))
1607 	    addhistnode(histtab, he->node.nam, he);
1608     }
1609     zfree(chline, hlinesz);
1610     zfree(chwords, chwordlen*sizeof(short));
1611     chline = hptr = NULL;
1612     chwords = NULL;
1613     histactive = 0;
1614     /*
1615      * For normal INCAPPENDHISTORY case and reasoning, see hbegin().
1616      */
1617     if (isset(SHAREHISTORY) ? histfileIsLocked() :
1618 	(isset(INCAPPENDHISTORY) || (isset(INCAPPENDHISTORYTIME) &&
1619 				     histsave_stack_pos != 0)))
1620 	savehistfile(hf, 0, HFILE_USE_OPTIONS | HFILE_FAST);
1621     unlockhistfile(hf); /* It's OK to call this even if we aren't locked */
1622     /*
1623      * No good reason for the user to push the history more than once, but
1624      * it's easy to be tidy...
1625      */
1626     while (histsave_stack_pos > stack_pos)
1627 	pophiststack();
1628     hist_keep_comment = 0;
1629     unqueue_signals();
1630     return !(flag & HISTFLAG_NOEXEC || errflag);
1631 }
1632 
1633 /* begin a word */
1634 
1635 /**/
1636 void
ihwbegin(int offset)1637 ihwbegin(int offset)
1638 {
1639     if (stophist == 2 || (histactive & HA_INWORD) ||
1640 	(inbufflags & (INP_ALIAS|INP_HIST)) == INP_ALIAS)
1641 	return;
1642     if (chwordpos%2)
1643 	chwordpos--;	/* make sure we're on a word start, not end */
1644     chwords[chwordpos++] = hptr - chline + offset;
1645 }
1646 
1647 /* Abort current history word, not needed */
1648 
1649 /**/
1650 void
ihwabort(void)1651 ihwabort(void)
1652 {
1653     if (chwordpos%2)
1654 	chwordpos--;
1655     hist_keep_comment = 1;
1656 }
1657 
1658 /* add a word to the history List */
1659 
1660 /**/
1661 void
ihwend(void)1662 ihwend(void)
1663 {
1664     if (stophist == 2 || (histactive & HA_INWORD) ||
1665 	(inbufflags & (INP_ALIAS|INP_HIST)) == INP_ALIAS)
1666 	return;
1667     if (chwordpos%2 && chline) {
1668 	/* end of word reached and we've already begun a word */
1669 	if (hptr > chline + chwords[chwordpos-1]) {
1670 	    chwords[chwordpos++] = hptr - chline;
1671 	    if (chwordpos >= chwordlen) {
1672 		chwords = (short *) realloc(chwords,
1673 					    (chwordlen += 32) *
1674 					    sizeof(short));
1675 	    }
1676 	} else {
1677 	    /* scrub that last word, it doesn't exist */
1678 	    chwordpos--;
1679 	}
1680     }
1681 }
1682 
1683 /* Go back to immediately after the last word, skipping space. */
1684 
1685 /**/
1686 void
histbackword(void)1687 histbackword(void)
1688 {
1689     if (!(chwordpos%2) && chwordpos)
1690 	hptr = chline + chwords[chwordpos-1];
1691 }
1692 
1693 /* Get the start and end point of the current history word */
1694 
1695 /**/
1696 static void
hwget(char ** startptr)1697 hwget(char **startptr)
1698 {
1699     int pos = chwordpos - 2;
1700 
1701 #ifdef DEBUG
1702     /* debugging only */
1703     if (!chwordpos) {
1704 	/* no words available */
1705 	DPUTS(1, "BUG: hwget() called with no words");
1706 	*startptr = "";
1707 	return;
1708     }
1709     else if (chwordpos%2) {
1710 	DPUTS(1, "BUG: hwget() called in middle of word");
1711 	*startptr = "";
1712 	return;
1713     }
1714 #endif
1715 
1716     *startptr = chline + chwords[pos];
1717     chline[chwords[++pos]] = '\0';
1718 }
1719 
1720 /* Replace the current history word with rep, if different */
1721 
1722 /**/
1723 void
hwrep(char * rep)1724 hwrep(char *rep)
1725 {
1726     char *start;
1727     hwget(&start);
1728 
1729     if (!strcmp(rep, start))
1730 	return;
1731 
1732     hptr = start;
1733     chwordpos = chwordpos - 2;
1734     hwbegin(0);
1735     qbang = 1;
1736     while (*rep)
1737 	hwaddc(*rep++);
1738     hwend();
1739 }
1740 
1741 /* Get the entire current line, deleting it in the history. */
1742 
1743 /**/
1744 mod_export char *
hgetline(void)1745 hgetline(void)
1746 {
1747     /* Currently only used by pushlineoredit().
1748      * It's necessary to prevent that from getting too pally with
1749      * the history code.
1750      */
1751     char *ret;
1752 
1753     if (!chline || hptr == chline)
1754 	return NULL;
1755     *hptr = '\0';
1756     ret = dupstring(chline);
1757 
1758     /* reset line */
1759     hptr = chline;
1760     chwordpos = 0;
1761 
1762     return ret;
1763 }
1764 
1765 /* get an argument specification */
1766 
1767 /**/
1768 static int
getargspec(int argc,int marg,int evset)1769 getargspec(int argc, int marg, int evset)
1770 {
1771     int c, ret = -1;
1772 
1773     if ((c = ingetc()) == '0')
1774 	return 0;
1775     if (idigit(c)) {
1776 	ret = 0;
1777 	while (idigit(c)) {
1778 	    ret = ret * 10 + c - '0';
1779 	    c = ingetc();
1780 	}
1781 	inungetc(c);
1782     } else if (c == '^')
1783 	ret = 1;
1784     else if (c == '$')
1785 	ret = argc;
1786     else if (c == '%') {
1787 	if (evset) {
1788 	    herrflush();
1789 	    zerr("Ambiguous history reference");
1790 	    return -2;
1791 	}
1792 	if (marg == -1) {
1793 	    herrflush();
1794 	    zerr("%% with no previous word matched");
1795 	    return -2;
1796 	}
1797 	ret = marg;
1798     } else
1799 	inungetc(c);
1800     return ret;
1801 }
1802 
1803 /* do ?foo? search */
1804 
1805 /**/
1806 static zlong
hconsearch(char * str,int * marg)1807 hconsearch(char *str, int *marg)
1808 {
1809     int t1 = 0;
1810     char *s;
1811     Histent he;
1812 
1813     for (he = up_histent(hist_ring); he; he = up_histent(he)) {
1814 	if (he->node.flags & HIST_FOREIGN)
1815 	    continue;
1816 	if ((s = strstr(he->node.nam, str))) {
1817 	    int pos = s - he->node.nam;
1818 	    while (t1 < he->nwords && he->words[2*t1] <= pos)
1819 		t1++;
1820 	    *marg = t1 - 1;
1821 	    return he->histnum;
1822 	}
1823     }
1824     return -1;
1825 }
1826 
1827 /* do !foo search */
1828 
1829 /**/
1830 zlong
hcomsearch(char * str)1831 hcomsearch(char *str)
1832 {
1833     Histent he;
1834     int len = strlen(str);
1835 
1836     for (he = up_histent(hist_ring); he; he = up_histent(he)) {
1837 	if (he->node.flags & HIST_FOREIGN)
1838 	    continue;
1839 	if (strncmp(he->node.nam, str, len) == 0)
1840 	    return he->histnum;
1841     }
1842     return -1;
1843 }
1844 
1845 /* various utilities for : modifiers */
1846 
1847 /**/
1848 int
chabspath(char ** junkptr)1849 chabspath(char **junkptr)
1850 {
1851     char *current, *dest;
1852 
1853     if (!**junkptr)
1854 	return 1;
1855 
1856     if (**junkptr != '/') {
1857 	*junkptr = zhtricat(metafy(zgetcwd(), -1, META_HEAPDUP), "/", *junkptr);
1858     }
1859 
1860     current = *junkptr;
1861     dest = *junkptr;
1862 
1863 #ifdef HAVE_SUPERROOT
1864     while (*current == '/' && current[1] == '.' && current[2] == '.' &&
1865 	   (!current[3] || current[3] == '/')) {
1866 	*dest++ = '/';
1867 	*dest++ = '.';
1868 	*dest++ = '.';
1869 	current += 3;
1870     }
1871 #endif
1872 
1873     for (;;) {
1874 	if (*current == '/') {
1875 #ifdef __CYGWIN__
1876 	    if (current == *junkptr && current[1] == '/')
1877 		*dest++ = *current++;
1878 #endif
1879 	    *dest++ = *current++;
1880 	    while (*current == '/')
1881 		current++;
1882 	} else if (!*current) {
1883 	    while (dest > *junkptr + 1 && dest[-1] == '/')
1884 		dest--;
1885 	    *dest = '\0';
1886 	    break;
1887 	} else if (current[0] == '.' && current[1] == '.' &&
1888 		   (!current[2] || current[2] == '/')) {
1889 		if (current == *junkptr || dest == *junkptr) {
1890 		    *dest++ = '.';
1891 		    *dest++ = '.';
1892 		    current += 2;
1893 		} else if (dest > *junkptr + 2 &&
1894 			   !strncmp(dest - 3, "../", 3)) {
1895 		    *dest++ = '.';
1896 		    *dest++ = '.';
1897 		    current += 2;
1898 		} else if (dest > *junkptr + 1) {
1899 		    *dest = '\0';
1900 		    for (dest--;
1901 			 dest > *junkptr + 1 && dest[-1] != '/';
1902 			 dest--);
1903 		    if (dest[-1] != '/')
1904 			dest--;
1905 		    current += 2;
1906 		    if (*current == '/')
1907 			current++;
1908 		} else if (dest == *junkptr + 1) {
1909 		    /* This might break with Cygwin's leading double slashes? */
1910 		    current += 2;
1911 		} else {
1912 		    return 0;
1913 		}
1914 	} else if (current[0] == '.' && (current[1] == '/' || !current[1])) {
1915 	     while (*++current == '/');
1916 	} else {
1917 	    while (*current != '/' && *current != '\0')
1918 		if ((*dest++ = *current++) == Meta)
1919 		    *dest++ = *current++;
1920 	}
1921     }
1922     return 1;
1923 }
1924 
1925 /**/
1926 int
chrealpath(char ** junkptr)1927 chrealpath(char **junkptr)
1928 {
1929     char *str;
1930 #ifdef HAVE_REALPATH
1931 # ifdef REALPATH_ACCEPTS_NULL
1932     char *lastpos, *nonreal, *real;
1933 # else
1934     char *lastpos, *nonreal, pathbuf[PATH_MAX+1];
1935     char *real = pathbuf;
1936 # endif
1937 #endif
1938 
1939     if (!**junkptr)
1940 	return 1;
1941 
1942     /* Notice that this means ..'s are applied before symlinks are resolved! */
1943     if (!chabspath(junkptr))
1944 	return 0;
1945 
1946 #ifndef HAVE_REALPATH
1947     return 1;
1948 #else
1949     /*
1950      * Notice that this means you cannot pass relative paths into this
1951      * function!
1952      */
1953     if (**junkptr != '/')
1954 	return 0;
1955 
1956     unmetafy(*junkptr, NULL);
1957 
1958     lastpos = strend(*junkptr);
1959     nonreal = lastpos + 1;
1960 
1961     while (!
1962 #ifdef REALPATH_ACCEPTS_NULL
1963 	   /* realpath() with a NULL second argument uses malloc() to get
1964 	    * memory so we don't need to worry about overflowing PATH_MAX */
1965 	   (real = realpath(*junkptr, NULL))
1966 #else
1967 	   realpath(*junkptr, real)
1968 #endif
1969 	) {
1970 	if (errno == EINVAL || errno == ENOMEM)
1971 	    return 0;
1972 
1973 	if (nonreal == *junkptr) {
1974 #ifndef REALPATH_ACCEPTS_NULL
1975 	    real = NULL;
1976 #endif
1977 	    break;
1978 	}
1979 
1980 	while (*nonreal != '/' && nonreal >= *junkptr)
1981 	    nonreal--;
1982 	*nonreal = '\0';
1983     }
1984 
1985     str = nonreal;
1986     while (str <= lastpos) {
1987 	if (*str == '\0')
1988 	    *str = '/';
1989 	str++;
1990     }
1991 
1992     if (real) {
1993 	*junkptr = metafy(str = bicat(real, nonreal), -1, META_HEAPDUP);
1994 	zsfree(str);
1995 #ifdef REALPATH_ACCEPTS_NULL
1996 	free(real);
1997 #endif
1998     } else {
1999 	*junkptr = metafy(nonreal, lastpos - nonreal + 1, META_HEAPDUP);
2000     }
2001 #endif
2002 
2003     return 1;
2004 }
2005 
2006 /**/
2007 int
remtpath(char ** junkptr,int count)2008 remtpath(char **junkptr, int count)
2009 {
2010     char *str = strend(*junkptr);
2011 
2012     /* ignore trailing slashes */
2013     while (str >= *junkptr && IS_DIRSEP(*str))
2014 	--str;
2015     if (!count) {
2016 	/* skip filename */
2017 	while (str >= *junkptr && !IS_DIRSEP(*str))
2018 	    --str;
2019     }
2020     if (str < *junkptr) {
2021 	if (IS_DIRSEP(**junkptr))
2022 	    *junkptr = dupstring ("/");
2023 	else
2024 	    *junkptr = dupstring (".");
2025 
2026 	return 0;
2027     }
2028 
2029     if (count)
2030     {
2031 	/*
2032 	 * Return this many components, so start from the front.
2033 	 * Leading slash counts as one component, consistent with
2034 	 * behaviour of repeated applications of :h.
2035 	 */
2036 	char *strp = *junkptr;
2037 	while (strp < str) {
2038 	    if (IS_DIRSEP(*strp)) {
2039 		if (--count <= 0) {
2040 		    if (strp == *junkptr)
2041 			++strp;
2042 		    *strp = '\0';
2043 		    return 1;
2044 		}
2045 		/* Count consecutive separators as one */
2046 		while (IS_DIRSEP(strp[1]))
2047 		    ++strp;
2048 	    }
2049 	    ++strp;
2050 	}
2051 
2052 	/* Full string needed */
2053 	return 1;
2054     }
2055 
2056     /* repeated slashes are considered like a single slash */
2057     while (str > *junkptr && IS_DIRSEP(str[-1]))
2058 	--str;
2059     /* never erase the root slash */
2060     if (str == *junkptr) {
2061 	++str;
2062 	/* Leading doubled slashes (`//') have a special meaning on cygwin
2063 	   and some old flavor of UNIX, so we do not assimilate them to
2064 	   a single slash.  However a greater number is ok to squeeze. */
2065 	if (IS_DIRSEP(*str) && !IS_DIRSEP(str[1]))
2066 	    ++str;
2067     }
2068     *str = '\0';
2069     return 1;
2070 }
2071 
2072 /**/
2073 int
remtext(char ** junkptr)2074 remtext(char **junkptr)
2075 {
2076     char *str;
2077 
2078     for (str = strend(*junkptr); str >= *junkptr && !IS_DIRSEP(*str); --str)
2079 	if (*str == '.') {
2080 	    *str = '\0';
2081 	    return 1;
2082 	}
2083     return 0;
2084 }
2085 
2086 /**/
2087 int
rembutext(char ** junkptr)2088 rembutext(char **junkptr)
2089 {
2090     char *str;
2091 
2092     for (str = strend(*junkptr); str >= *junkptr && !IS_DIRSEP(*str); --str)
2093 	if (*str == '.') {
2094 	    *junkptr = dupstring(str + 1); /* .xx or xx? */
2095 	    return 1;
2096 	}
2097     /* no extension */
2098     *junkptr = dupstring ("");
2099     return 0;
2100 }
2101 
2102 /**/
2103 mod_export int
remlpaths(char ** junkptr,int count)2104 remlpaths(char **junkptr, int count)
2105 {
2106     char *str = strend(*junkptr);
2107 
2108     if (IS_DIRSEP(*str)) {
2109 	/* remove trailing slashes */
2110 	while (str >= *junkptr && IS_DIRSEP(*str))
2111 	    --str;
2112 	str[1] = '\0';
2113     }
2114     for (;;) {
2115 	for (; str >= *junkptr; --str) {
2116 	    if (IS_DIRSEP(*str)) {
2117 		if (--count > 0) {
2118 		    if (str > *junkptr) {
2119 			--str;
2120 			break;
2121 		    } else {
2122 			/* Whole string needed */
2123 			return 1;
2124 		    }
2125 		}
2126 		*str = '\0';
2127 		*junkptr = dupstring(str + 1);
2128 		return 1;
2129 	    }
2130 	}
2131 	/* Count consecutive separators as 1 */
2132 	while (str >= *junkptr && IS_DIRSEP(*str))
2133 	    --str;
2134 	if (str <= *junkptr)
2135 	    break;
2136     }
2137     return 0;
2138 }
2139 
2140 /*
2141  * Return modified version of str from the heap with modification
2142  * according to one of the CASMOD_* types defined in zsh.h; CASMOD_NONE
2143  * is not handled, for obvious reasons.
2144  */
2145 
2146 /**/
2147 char *
casemodify(char * str,int how)2148 casemodify(char *str, int how)
2149 {
2150     char *str2 = zhalloc(2 * strlen(str) + 1);
2151     char *ptr2 = str2;
2152     int nextupper = 1;
2153 
2154 #ifdef MULTIBYTE_SUPPORT
2155     if (isset(MULTIBYTE)) {
2156 	VARARR(char, mbstr, MB_CUR_MAX);
2157 	mbstate_t ps;
2158 
2159 	mb_charinit();
2160 	memset(&ps, 0, sizeof(ps));
2161 	while (*str) {
2162 	    wint_t wc;
2163 	    int len = mb_metacharlenconv(str, &wc), mod = 0, len2;
2164 	    /*
2165 	     * wc is set to WEOF if the start of str couldn't be
2166 	     * converted.  Presumably WEOF doesn't match iswlower(), but
2167 	     * better be safe.
2168 	     */
2169 	    if (wc == WEOF) {
2170 		while (len--)
2171 		    *ptr2++ = *str++;
2172 		/* not alphanumeric */
2173 		nextupper = 1;
2174 		continue;
2175 	    }
2176 	    switch (how) {
2177 	    case CASMOD_LOWER:
2178 		if (iswupper(wc)) {
2179 		    wc = towlower(wc);
2180 		    mod = 1;
2181 		}
2182 		break;
2183 
2184 	    case CASMOD_UPPER:
2185 		if (iswlower(wc)) {
2186 		    wc = towupper(wc);
2187 		    mod = 1;
2188 		}
2189 		break;
2190 
2191 	    case CASMOD_CAPS:
2192 	    default:		/* shuts up compiler */
2193 		if (IS_COMBINING(wc))
2194 			break;
2195 		if (!iswalnum(wc))
2196 		    nextupper = 1;
2197 		else if (nextupper) {
2198 		    if (iswlower(wc)) {
2199 			wc = towupper(wc);
2200 			mod = 1;
2201 		    }
2202 		    nextupper = 0;
2203 		} else if (iswupper(wc)) {
2204 		    wc = towlower(wc);
2205 		    mod = 1;
2206 		}
2207 		break;
2208 	    }
2209 	    if (mod && (len2 = wcrtomb(mbstr, wc, &ps)) > 0) {
2210 		char *mbptr;
2211 
2212 		for (mbptr = mbstr; mbptr < mbstr + len2; mbptr++) {
2213 		    if (imeta(STOUC(*mbptr))) {
2214 			*ptr2++ = Meta;
2215 			*ptr2++ = *mbptr ^ 32;
2216 		    } else
2217 			*ptr2++ = *mbptr;
2218 		}
2219 		str += len;
2220 	    } else {
2221 		while (len--)
2222 		    *ptr2++ = *str++;
2223 	    }
2224 	}
2225     }
2226     else
2227 #endif
2228 	while (*str) {
2229 	    int c;
2230 	    if (*str == Meta) {
2231 		c = str[1] ^ 32;
2232 		str += 2;
2233 	    } else
2234 		c = *str++;
2235 	    switch (how) {
2236 	    case CASMOD_LOWER:
2237 		if (isupper(c))
2238 		    c = tolower(c);
2239 		break;
2240 
2241 	    case CASMOD_UPPER:
2242 		if (islower(c))
2243 		    c = toupper(c);
2244 		break;
2245 
2246 	    case CASMOD_CAPS:
2247 	    default:		/* shuts up compiler */
2248 		if (!ialnum(c))
2249 		    nextupper = 1;
2250 		else if (nextupper) {
2251 		    if (islower(c))
2252 			c = toupper(c);
2253 		    nextupper = 0;
2254 		} else if (isupper(c))
2255 		    c = tolower(c);
2256 		break;
2257 	    }
2258 	    if (imeta(c)) {
2259 		*ptr2++ = Meta;
2260 		*ptr2++ = c ^ 32;
2261 	    } else
2262 		*ptr2++ = c;
2263 	}
2264     *ptr2 = '\0';
2265     return str2;
2266 }
2267 
2268 
2269 /*
2270  * Substitute "in" for "out" in "*strptr" and update "*strptr".
2271  * If "gbal", do global substitution.
2272  *
2273  * This returns a result from the heap.  There seems to have
2274  * been some confusion on this point.
2275  */
2276 
2277 /**/
2278 int
subst(char ** strptr,char * in,char * out,int gbal)2279 subst(char **strptr, char *in, char *out, int gbal)
2280 {
2281     char *str = *strptr, *substcut, *sptr;
2282     int off, inlen, outlen;
2283 
2284     if (!*in)
2285 	in = str, gbal = 0;
2286 
2287     if (isset(HISTSUBSTPATTERN)) {
2288 	int fl = SUB_LONG|SUB_REST|SUB_RETFAIL;
2289 	char *oldin = in;
2290 	if (gbal)
2291 	    fl |= SUB_GLOBAL;
2292 	if (*in == '#' || *in == Pound) {
2293 	    /* anchor at head, flag needed if SUB_END is also set */
2294 	    fl |= SUB_START;
2295 	    in++;
2296 	}
2297 	if (*in == '%') {
2298 	    /* anchor at tail */
2299 	    in++;
2300 	    fl |= SUB_END;
2301 	}
2302 	if (in == oldin) {
2303 	    /* no anchor, substring match */
2304 	    fl |= SUB_SUBSTR;
2305 	}
2306 	if (in == str)
2307 	    in = dupstring(in);
2308 	if (parse_subst_string(in) || errflag)
2309 	    return 1;
2310 	if (parse_subst_string(out) || errflag)
2311 	    return 1;
2312 	singsub(&in);
2313 	if (getmatch(strptr, in, fl, 1, out))
2314 	    return 0;
2315     } else {
2316 	if ((substcut = (char *)strstr(str, in))) {
2317 	    inlen = strlen(in);
2318 	    sptr = convamps(out, in, inlen);
2319 	    outlen = strlen(sptr);
2320 
2321 	    do {
2322 		*substcut = '\0';
2323 		off = substcut - *strptr + outlen;
2324 		substcut += inlen;
2325 		*strptr = zhtricat(*strptr, sptr, substcut);
2326 		str = (char *)*strptr + off;
2327 	    } while (gbal && (substcut = (char *)strstr(str, in)));
2328 
2329 	    return 0;
2330 	}
2331     }
2332 
2333     return 1;
2334 }
2335 
2336 /**/
2337 static char *
convamps(char * out,char * in,int inlen)2338 convamps(char *out, char *in, int inlen)
2339 {
2340     char *ptr, *ret, *pp;
2341     int slen, sdup = 0;
2342 
2343     for (ptr = out, slen = 0; *ptr; ptr++, slen++)
2344 	if (*ptr == '\\')
2345 	    ptr++, sdup = 1;
2346 	else if (*ptr == '&')
2347 	    slen += inlen - 1, sdup = 1;
2348     if (!sdup)
2349 	return out;
2350     ret = pp = (char *) zhalloc(slen + 1);
2351     for (ptr = out; *ptr; ptr++)
2352 	if (*ptr == '\\')
2353 	    *pp++ = *++ptr;
2354 	else if (*ptr == '&') {
2355 	    strcpy(pp, in);
2356 	    pp += inlen;
2357 	} else
2358 	    *pp++ = *ptr;
2359     *pp = '\0';
2360     return ret;
2361 }
2362 
2363 /**/
2364 mod_export void
checkcurline(Histent he)2365 checkcurline(Histent he)
2366 {
2367     if (he->histnum == curhist && (histactive & HA_ACTIVE)) {
2368 	curline.node.nam = chline;
2369 	curline.nwords = chwordpos/2;
2370 	curline.words = chwords;
2371     }
2372 }
2373 
2374 /**/
2375 mod_export Histent
quietgethist(int ev)2376 quietgethist(int ev)
2377 {
2378     return gethistent(ev, GETHIST_EXACT);
2379 }
2380 
2381 /**/
2382 static Histent
gethist(int ev)2383 gethist(int ev)
2384 {
2385     Histent ret;
2386 
2387     ret = quietgethist(ev);
2388     if (!ret) {
2389 	herrflush();
2390 	zerr("no such event: %d", ev);
2391     }
2392     return ret;
2393 }
2394 
2395 /**/
2396 static char *
getargs(Histent elist,int arg1,int arg2)2397 getargs(Histent elist, int arg1, int arg2)
2398 {
2399     short *words = elist->words;
2400     int pos1, pos2, nwords = elist->nwords;
2401 
2402     if (arg2 < arg1 || arg1 >= nwords || arg2 >= nwords) {
2403 	/* remember, argN is indexed from 0, nwords is total no. of words */
2404 	herrflush();
2405 	zerr("no such word in event");
2406 	return NULL;
2407     }
2408 
2409     /* optimization for accessing entire history event */
2410     if (arg1 == 0 && arg2 == nwords - 1)
2411 	return dupstring(elist->node.nam);
2412 
2413     pos1 = words[2*arg1];
2414     pos2 = words[2*arg2+1];
2415 
2416     /* a word has to be at least one character long, so if the position
2417      * of a word is less than its index, we've overflowed our signed
2418      * short integer word range and the recorded position is garbage. */
2419     if (pos1 < 0 || pos1 < arg1 || pos2 < 0 || pos2 < arg2) {
2420 	herrflush();
2421 	zerr("history event too long, can't index requested words");
2422 	return NULL;
2423     }
2424     return dupstrpfx(elist->node.nam + pos1, pos2 - pos1);
2425 }
2426 
2427 /**/
2428 static int
quote(char ** tr)2429 quote(char **tr)
2430 {
2431     char *ptr, *rptr, **str = tr;
2432     int len = 3;
2433     int inquotes = 0;
2434 
2435     for (ptr = *str; *ptr; ptr++, len++)
2436 	if (*ptr == '\'') {
2437 	    len += 3;
2438 	    if (!inquotes)
2439 		inquotes = 1;
2440 	    else
2441 		inquotes = 0;
2442 	} else if (inblank(*ptr) && !inquotes && ptr[-1] != '\\')
2443 	    len += 2;
2444     ptr = *str;
2445     *str = rptr = (char *) zhalloc(len);
2446     *rptr++ = '\'';
2447     for (; *ptr; ptr++)
2448 	if (*ptr == '\'') {
2449 	    if (!inquotes)
2450 		inquotes = 1;
2451 	    else
2452 		inquotes = 0;
2453 	    *rptr++ = '\'';
2454 	    *rptr++ = '\\';
2455 	    *rptr++ = '\'';
2456 	    *rptr++ = '\'';
2457 	} else if (inblank(*ptr) && !inquotes && ptr[-1] != '\\') {
2458 	    *rptr++ = '\'';
2459 	    *rptr++ = *ptr;
2460 	    *rptr++ = '\'';
2461 	} else
2462 	    *rptr++ = *ptr;
2463     *rptr++ = '\'';
2464     *rptr++ = 0;
2465     return 0;
2466 }
2467 
2468 /**/
2469 static int
quotebreak(char ** tr)2470 quotebreak(char **tr)
2471 {
2472     char *ptr, *rptr, **str = tr;
2473     int len = 3;
2474 
2475     for (ptr = *str; *ptr; ptr++, len++)
2476 	if (*ptr == '\'')
2477 	    len += 3;
2478 	else if (inblank(*ptr))
2479 	    len += 2;
2480     ptr = *str;
2481     *str = rptr = (char *) zhalloc(len);
2482     *rptr++ = '\'';
2483     for (; *ptr;)
2484 	if (*ptr == '\'') {
2485 	    *rptr++ = '\'';
2486 	    *rptr++ = '\\';
2487 	    *rptr++ = '\'';
2488 	    *rptr++ = '\'';
2489 	    ptr++;
2490 	} else if (inblank(*ptr)) {
2491 	    *rptr++ = '\'';
2492 	    *rptr++ = *ptr++;
2493 	    *rptr++ = '\'';
2494 	} else
2495 	    *rptr++ = *ptr++;
2496     *rptr++ = '\'';
2497     *rptr++ = '\0';
2498     return 0;
2499 }
2500 
2501 /* read an arbitrary amount of data into a buffer until stop is found */
2502 
2503 #if 0 /**/
2504 char *
2505 hdynread(int stop)
2506 {
2507     int bsiz = 256, ct = 0, c;
2508     char *buf = (char *)zalloc(bsiz), *ptr;
2509 
2510     ptr = buf;
2511     while ((c = ingetc()) != stop && c != '\n' && !lexstop) {
2512 	if (c == '\\')
2513 	    c = ingetc();
2514 	*ptr++ = c;
2515 	if (++ct == bsiz) {
2516 	    buf = realloc(buf, bsiz *= 2);
2517 	    ptr = buf + ct;
2518 	}
2519     }
2520     *ptr = 0;
2521     if (c == '\n') {
2522 	inungetc('\n');
2523 	zerr("delimiter expected");
2524 	zfree(buf, bsiz);
2525 	return NULL;
2526     }
2527     return buf;
2528 }
2529 #endif
2530 
2531 /**/
2532 static char *
hdynread2(int stop)2533 hdynread2(int stop)
2534 {
2535     int bsiz = 256, ct = 0, c;
2536     char *buf = (char *)zalloc(bsiz), *ptr;
2537 
2538     ptr = buf;
2539     while ((c = ingetc()) != stop && c != '\n' && !lexstop) {
2540 	if (c == '\\')
2541 	    c = ingetc();
2542 	*ptr++ = c;
2543 	if (++ct == bsiz) {
2544 	    buf = realloc(buf, bsiz *= 2);
2545 	    ptr = buf + ct;
2546 	}
2547     }
2548     *ptr = 0;
2549     if (c == '\n')
2550 	inungetc('\n');
2551     return buf;
2552 }
2553 
2554 /**/
2555 void
inithist(void)2556 inithist(void)
2557 {
2558     createhisttable();
2559 }
2560 
2561 /**/
2562 void
resizehistents(void)2563 resizehistents(void)
2564 {
2565     if (histlinect > histsiz) {
2566 	/* The reason we don't just call freehistnode(hist_ring->down) is
2567 	 * so that we can honor the HISTEXPIREDUPSFIRST setting. */
2568 	putoldhistentryontop(0);
2569 	freehistnode(&hist_ring->node);
2570 	while (histlinect > histsiz) {
2571 	    putoldhistentryontop(1);
2572 	    freehistnode(&hist_ring->node);
2573 	}
2574     }
2575 }
2576 
2577 static int
readhistline(int start,char ** bufp,int * bufsiz,FILE * in)2578 readhistline(int start, char **bufp, int *bufsiz, FILE *in)
2579 {
2580     char *buf = *bufp;
2581     if (fgets(buf + start, *bufsiz - start, in)) {
2582 	int len = start + strlen(buf + start);
2583 	if (len == start)
2584 	    return -1;
2585 	if (buf[len - 1] != '\n') {
2586 	    if (!feof(in)) {
2587 		if (len < (*bufsiz) - 1)
2588 		    return -1;
2589 		*bufp = zrealloc(buf, 2 * (*bufsiz));
2590 		*bufsiz = 2 * (*bufsiz);
2591 		return readhistline(len, bufp, bufsiz, in);
2592 	    }
2593 	}
2594 	else {
2595 	    buf[len - 1] = '\0';
2596 	    if (len > 1 && buf[len - 2] == '\\') {
2597 		buf[--len - 1] = '\n';
2598 		if (!feof(in))
2599 		    return readhistline(len, bufp, bufsiz, in);
2600 	    }
2601 	}
2602 	return len;
2603     }
2604     return 0;
2605 }
2606 
2607 /**/
2608 void
readhistfile(char * fn,int err,int readflags)2609 readhistfile(char *fn, int err, int readflags)
2610 {
2611     char *buf, *start = NULL;
2612     FILE *in;
2613     Histent he;
2614     time_t stim, ftim, tim = time(NULL);
2615     off_t fpos;
2616     short *words;
2617     struct stat sb;
2618     int nwordpos, nwords, bufsiz;
2619     int searching, newflags, l, ret, uselex;
2620 
2621     if (!fn && !(fn = getsparam("HISTFILE")))
2622 	return;
2623     if (stat(unmeta(fn), &sb) < 0 ||
2624 	sb.st_size == 0)
2625 	return;
2626     if (readflags & HFILE_FAST) {
2627 	if (!lasthist.interrupted &&
2628 	    ((lasthist.fsiz == sb.st_size && lasthist.mtim == sb.st_mtime)
2629 	     || lockhistfile(fn, 0)))
2630 	    return;
2631 	lasthist.fsiz = sb.st_size;
2632 	lasthist.mtim = sb.st_mtime;
2633 	lasthist.interrupted = 0;
2634     } else if ((ret = lockhistfile(fn, 1))) {
2635 	if (ret == 2) {
2636 	    zwarn("locking failed for %s: %e: reading anyway", fn, errno);
2637 	} else {
2638 	    zerr("locking failed for %s: %e", fn, errno);
2639 	    return;
2640 	}
2641     }
2642     if ((in = fopen(unmeta(fn), "r"))) {
2643 	nwords = 64;
2644 	words = (short *)zalloc(nwords*sizeof(short));
2645 	bufsiz = 1024;
2646 	buf = zalloc(bufsiz);
2647 
2648 	pushheap();
2649 	if (readflags & HFILE_FAST && lasthist.text) {
2650 	    if (lasthist.fpos < lasthist.fsiz) {
2651 		fseek(in, lasthist.fpos, 0);
2652 		searching = 1;
2653 	    }
2654 	    else {
2655 		histfile_linect = 0;
2656 		searching = -1;
2657 	    }
2658 	} else
2659 	    searching = 0;
2660 
2661 	newflags = HIST_OLD | HIST_READ;
2662 	if (readflags & HFILE_FAST)
2663 	    newflags |= HIST_FOREIGN;
2664 	if (readflags & HFILE_SKIPOLD
2665 	 || (hist_ignore_all_dups && newflags & hist_skip_flags))
2666 	    newflags |= HIST_MAKEUNIQUE;
2667 	while (fpos = ftell(in), (l = readhistline(0, &buf, &bufsiz, in))) {
2668 	    char *pt;
2669 	    int remeta = 0;
2670 
2671 	    if (l < 0) {
2672 		zerr("corrupt history file %s", fn);
2673 		break;
2674 	    }
2675 
2676 	    /*
2677 	     * Handle the special case that we're reading from an
2678 	     * old shell with fewer meta characters, so we need to
2679 	     * metafy some more.  (It's not clear why the history
2680 	     * file is metafied at all; some would say this is plain
2681 	     * stupid.  But we're stuck with it now without some
2682 	     * hairy workarounds for compatibility).
2683 	     *
2684 	     * This is rare so doesn't need to be that efficient; just
2685 	     * allocate space off the heap.
2686 	     */
2687 	    for (pt = buf; *pt; pt++) {
2688 		if (*pt == Meta && pt[1])
2689 		    pt++;
2690 		else if (imeta(*pt)) {
2691 		    remeta = 1;
2692 		    break;
2693 		}
2694 	    }
2695 	    if (remeta) {
2696 		unmetafy(buf, &remeta);
2697 		pt = metafy(buf, remeta, META_USEHEAP);
2698 	    } else {
2699 		pt = buf;
2700 	    }
2701 
2702 	    if (*pt == ':') {
2703 		pt++;
2704 		stim = zstrtol(pt, NULL, 0);
2705 		for (; *pt != ':' && *pt; pt++);
2706 		if (*pt) {
2707 		    pt++;
2708 		    ftim = zstrtol(pt, NULL, 0);
2709 		    for (; *pt != ';' && *pt; pt++);
2710 		    if (*pt)
2711 			pt++;
2712 		} else
2713 		    ftim = stim;
2714 	    } else {
2715 		if (*pt == '\\' && pt[1] == ':')
2716 		    pt++;
2717 		stim = ftim = 0;
2718 	    }
2719 
2720 	    if (searching) {
2721 		if (searching > 0) {
2722 		    if (stim == lasthist.stim
2723 		     && histstrcmp(pt, lasthist.text) == 0)
2724 			searching = 0;
2725 		    else {
2726 			fseek(in, 0, 0);
2727 			histfile_linect = 0;
2728 			searching = -1;
2729 		    }
2730 		    continue;
2731 		}
2732 		else if (stim < lasthist.stim) {
2733 		    histfile_linect++;
2734 		    continue;
2735 		}
2736 		searching = 0;
2737 	    }
2738 
2739 	    if (readflags & HFILE_USE_OPTIONS) {
2740 		histfile_linect++;
2741 		lasthist.fpos = fpos;
2742 		lasthist.stim = stim;
2743 	    }
2744 
2745 	    he = prepnexthistent();
2746 	    he->node.nam = ztrdup(pt);
2747 	    he->node.flags = newflags;
2748 	    if ((he->stim = stim) == 0)
2749 		he->stim = he->ftim = tim;
2750 	    else if (ftim < stim)
2751 		he->ftim = stim + ftim;
2752 	    else
2753 		he->ftim = ftim;
2754 
2755 	    /*
2756 	     * Divide up the words.
2757 	     */
2758 	    start = pt;
2759 	    uselex = isset(HISTLEXWORDS) && !(readflags & HFILE_FAST);
2760 	    histsplitwords(pt, &words, &nwords, &nwordpos, uselex);
2761 
2762 	    he->nwords = nwordpos/2;
2763 	    if (he->nwords) {
2764 		he->words = (short *)zalloc(nwordpos*sizeof(short));
2765 		memcpy(he->words, words, nwordpos*sizeof(short));
2766 	    } else
2767 		he->words = (short *)NULL;
2768 	    addhistnode(histtab, he->node.nam, he);
2769 	    if (he->node.flags & HIST_DUP) {
2770 		freehistnode(&he->node);
2771 		curhist--;
2772 	    }
2773 	    /*
2774 	     * Do this last out of paranoia in case use of
2775 	     * heap is disguised...
2776 	     */
2777 	    if (uselex || remeta)
2778 		freeheap();
2779 	    if (errflag & ERRFLAG_INT) {
2780 		/* Can't assume fast read next time if interrupted. */
2781 		lasthist.interrupted = 1;
2782 		break;
2783 	    }
2784 	}
2785 	if (start && readflags & HFILE_USE_OPTIONS) {
2786 	    zsfree(lasthist.text);
2787 	    lasthist.text = ztrdup(start);
2788 	}
2789 	zfree(words, nwords*sizeof(short));
2790 	zfree(buf, bufsiz);
2791 
2792 	popheap();
2793 	fclose(in);
2794     } else if (err)
2795 	zerr("can't read history file %s", fn);
2796 
2797     unlockhistfile(fn);
2798 
2799     if (zleactive)
2800 	zleentry(ZLE_CMD_SET_HIST_LINE, curhist);
2801 }
2802 
2803 #ifdef HAVE_FCNTL_H
2804 static int flock_fd = -1;
2805 
2806 /*
2807  * Lock file using fcntl().  Return 0 on success, 1 on failure of
2808  * locking mechanism, 2 on permanent failure (e.g. permission).
2809  */
2810 
2811 static int
flockhistfile(char * fn,int keep_trying)2812 flockhistfile(char *fn, int keep_trying)
2813 {
2814     struct flock lck;
2815     long sleep_us = 0x10000; /* about 67 ms */
2816     time_t end_time;
2817 
2818     if (flock_fd >= 0)
2819 	return 0; /* already locked */
2820 
2821     if ((flock_fd = open(unmeta(fn), O_RDWR | O_NOCTTY)) < 0)
2822 	return errno == ENOENT ? 0 : 2; /* "successfully" locked missing file */
2823 
2824     lck.l_type = F_WRLCK;
2825     lck.l_whence = SEEK_SET;
2826     lck.l_start = 0;
2827     lck.l_len = 0;  /* lock the whole file */
2828 
2829     /*
2830      * Timeout is ten seconds.
2831      */
2832     end_time = time(NULL) + (time_t)10;
2833     while (fcntl(flock_fd, F_SETLKW, &lck) == -1) {
2834 	if (!keep_trying || time(NULL) >= end_time ||
2835 	    /*
2836 	     * Randomise wait to minimise clashes with shells exiting at
2837 	     * the same time.
2838 	     */
2839 	    !zsleep_random(sleep_us, end_time)) {
2840 	    close(flock_fd);
2841 	    flock_fd = -1;
2842 	    return 1;
2843 	}
2844 	sleep_us <<= 1;
2845     }
2846 
2847     return 0;
2848 }
2849 #endif
2850 
2851 /**/
2852 void
savehistfile(char * fn,int err,int writeflags)2853 savehistfile(char *fn, int err, int writeflags)
2854 {
2855     char *t, *tmpfile, *start = NULL;
2856     FILE *out;
2857     Histent he;
2858     zlong xcurhist = curhist - !!(histactive & HA_ACTIVE);
2859     int extended_history = isset(EXTENDEDHISTORY);
2860     int ret;
2861 
2862     if (!interact || savehistsiz <= 0 || !hist_ring
2863      || (!fn && !(fn = getsparam("HISTFILE"))))
2864 	return;
2865     if (writeflags & HFILE_FAST) {
2866 	he = gethistent(lasthist.next_write_ev, GETHIST_DOWNWARD);
2867 	while (he && he->node.flags & HIST_OLD) {
2868 	    lasthist.next_write_ev = he->histnum + 1;
2869 	    he = down_histent(he);
2870 	}
2871 	if (!he || lockhistfile(fn, 0))
2872 	    return;
2873 	if (histfile_linect > savehistsiz + savehistsiz / 5)
2874 	    writeflags &= ~HFILE_FAST;
2875     }
2876     else {
2877 	if (lockhistfile(fn, 1)) {
2878 	    zerr("locking failed for %s: %e", fn, errno);
2879 	    return;
2880 	}
2881 	he = hist_ring->down;
2882     }
2883     if (writeflags & HFILE_USE_OPTIONS) {
2884 	if (isset(APPENDHISTORY) || isset(INCAPPENDHISTORY)
2885 	 || isset(INCAPPENDHISTORYTIME) || isset(SHAREHISTORY))
2886 	    writeflags |= HFILE_APPEND | HFILE_SKIPOLD;
2887 	else
2888 	    histfile_linect = 0;
2889 	if (isset(HISTSAVENODUPS))
2890 	    writeflags |= HFILE_SKIPDUPS;
2891 	if (isset(SHAREHISTORY))
2892 	    extended_history = 1;
2893     }
2894     errno = 0;
2895     if (writeflags & HFILE_APPEND) {
2896 	int fd = open(unmeta(fn), O_CREAT | O_WRONLY | O_APPEND | O_NOCTTY, 0600);
2897 	tmpfile = NULL;
2898 	out = fd >= 0 ? fdopen(fd, "a") : NULL;
2899     } else if (!isset(HISTSAVEBYCOPY)) {
2900 	int fd = open(unmeta(fn), O_CREAT | O_WRONLY | O_TRUNC | O_NOCTTY, 0600);
2901 	tmpfile = NULL;
2902 	out = fd >= 0 ? fdopen(fd, "w") : NULL;
2903     } else {
2904 	tmpfile = bicat(unmeta(fn), ".new");
2905 	if (unlink(tmpfile) < 0 && errno != ENOENT)
2906 	    out = NULL;
2907 	else {
2908 	    struct stat sb;
2909 	    int old_exists = stat(unmeta(fn), &sb) == 0;
2910 	    uid_t euid = geteuid();
2911 
2912 	    if (old_exists
2913 #if defined HAVE_FCHMOD && defined HAVE_FCHOWN
2914 	     && euid
2915 #endif
2916 	     && sb.st_uid != euid) {
2917 		free(tmpfile);
2918 		tmpfile = NULL;
2919 		if (err) {
2920 		    if (isset(APPENDHISTORY) || isset(INCAPPENDHISTORY)
2921 		     || isset(INCAPPENDHISTORYTIME) || isset(SHAREHISTORY))
2922 			zerr("rewriting %s would change its ownership -- skipped", fn);
2923 		    else
2924 			zerr("rewriting %s would change its ownership -- history not saved", fn);
2925 		    err = 0; /* Don't report a generic error below. */
2926 		}
2927 		out = NULL;
2928 	    } else {
2929 		int fd = open(tmpfile, O_CREAT | O_WRONLY | O_EXCL, 0600);
2930 		if (fd >=0) {
2931 		    out = fdopen(fd, "w");
2932 		    if (!out)
2933 			close(fd);
2934 		} else
2935 		    out = NULL;
2936 	    }
2937 
2938 #ifdef HAVE_FCHMOD
2939 	    if (old_exists && out) {
2940 #ifdef HAVE_FCHOWN
2941 		if (fchown(fileno(out), sb.st_uid, sb.st_gid) < 0) {} /* IGNORE FAILURE */
2942 #endif
2943 		if (fchmod(fileno(out), sb.st_mode) < 0) {} /* IGNORE FAILURE */
2944 	    }
2945 #endif
2946 	}
2947     }
2948     if (out) {
2949 	char *history_ignore;
2950 	Patprog histpat = NULL;
2951 
2952 	pushheap();
2953 
2954 	if ((history_ignore = getsparam("HISTORY_IGNORE")) != NULL) {
2955 	    tokenize(history_ignore = dupstring(history_ignore));
2956 	    remnulargs(history_ignore);
2957 	    histpat = patcompile(history_ignore, 0, NULL);
2958 	}
2959 
2960 	ret = 0;
2961 	for (; he && he->histnum <= xcurhist; he = down_histent(he)) {
2962 	    int count_backslashes = 0;
2963 
2964 	    if ((writeflags & HFILE_SKIPDUPS && he->node.flags & HIST_DUP)
2965 	     || (writeflags & HFILE_SKIPFOREIGN && he->node.flags & HIST_FOREIGN)
2966 	     || he->node.flags & HIST_TMPSTORE)
2967 		continue;
2968 	    if (histpat &&
2969 		pattry(histpat, metafy(he->node.nam, -1, META_HEAPDUP))) {
2970 		continue;
2971 	    }
2972 	    if (writeflags & HFILE_SKIPOLD) {
2973 		if (he->node.flags & (HIST_OLD|HIST_NOWRITE))
2974 		    continue;
2975 		he->node.flags |= HIST_OLD;
2976 		if (writeflags & HFILE_USE_OPTIONS)
2977 		    lasthist.next_write_ev = he->histnum + 1;
2978 	    }
2979 	    if (writeflags & HFILE_USE_OPTIONS) {
2980 		lasthist.fpos = ftell(out);
2981 		lasthist.stim = he->stim;
2982 		histfile_linect++;
2983 	    }
2984 	    t = start = he->node.nam;
2985 	    if (extended_history) {
2986 		ret = fprintf(out, ": %ld:%ld;", (long)he->stim,
2987 			      he->ftim? (long)(he->ftim - he->stim) : 0L);
2988 	    } else if (*t == ':')
2989 		ret = fputc('\\', out);
2990 
2991 	    for (; ret >= 0 && *t; t++) {
2992 		if (*t == '\n')
2993 		    if ((ret = fputc('\\', out)) < 0)
2994 			break;
2995 		if (*t == '\\')
2996 		    count_backslashes++;
2997 		else
2998 		    count_backslashes = 0;
2999 		if ((ret = fputc(*t, out)) < 0)
3000 		    break;
3001 	    }
3002 	    if (ret < 0)
3003 	    	break;
3004 	    if (count_backslashes && (count_backslashes % 2 == 0))
3005 		if ((ret = fputc(' ', out)) < 0)
3006 		    break;
3007 	    if (ret < 0 || (ret = fputc('\n', out)) < 0)
3008 		break;
3009 	}
3010 	if (ret >= 0 && start && writeflags & HFILE_USE_OPTIONS) {
3011 	    struct stat sb;
3012 	    if ((ret = fflush(out)) >= 0) {
3013 		if (fstat(fileno(out), &sb) == 0) {
3014 		    lasthist.fsiz = sb.st_size;
3015 		    lasthist.mtim = sb.st_mtime;
3016 		}
3017 		zsfree(lasthist.text);
3018 		lasthist.text = ztrdup(start);
3019 	    }
3020 	}
3021 	if (fclose(out) < 0 && ret >= 0)
3022 	    ret = -1;
3023 	if (ret >= 0) {
3024 	    if (tmpfile) {
3025 		if (rename(tmpfile, unmeta(fn)) < 0) {
3026 		    zerr("can't rename %s.new to $HISTFILE", fn);
3027 		    ret = -1;
3028 		    err = 0;
3029 #ifdef HAVE_FCNTL_H
3030 		} else {
3031 		    /* We renamed over the locked HISTFILE, so close fd.
3032 		     * If we do more writing, we'll get a lock then. */
3033 		    if (flock_fd >= 0) {
3034 			close(flock_fd);
3035 			flock_fd = -1;
3036 		    }
3037 #endif
3038 		}
3039 	    }
3040 
3041 	    if (ret >= 0 && writeflags & HFILE_SKIPOLD
3042 		&& !(writeflags & (HFILE_FAST | HFILE_NO_REWRITE))) {
3043 		int remember_histactive = histactive;
3044 
3045 		/* Zeroing histactive avoids unnecessary munging of curline. */
3046 		histactive = 0;
3047 		/* The NULL leaves HISTFILE alone, preserving fn's value. */
3048 		pushhiststack(NULL, savehistsiz, savehistsiz, -1);
3049 
3050 		hist_ignore_all_dups |= isset(HISTSAVENODUPS);
3051 		readhistfile(fn, err, 0);
3052 		hist_ignore_all_dups = isset(HISTIGNOREALLDUPS);
3053 		if (histlinect)
3054 		    savehistfile(fn, err, 0);
3055 
3056 		pophiststack();
3057 		histactive = remember_histactive;
3058 	    }
3059 	}
3060 
3061 	popheap();
3062     } else
3063 	ret = -1;
3064 
3065     if (ret < 0 && err) {
3066 	if (tmpfile)
3067 	    zerr("failed to write history file %s.new: %e", fn, errno);
3068 	else
3069 	    zerr("failed to write history file %s: %e", fn, errno);
3070     }
3071     if (tmpfile)
3072 	free(tmpfile);
3073 
3074     unlockhistfile(fn);
3075 }
3076 
3077 static int lockhistct;
3078 
3079 static int
checklocktime(char * lockfile,long * sleep_usp,time_t then)3080 checklocktime(char *lockfile, long *sleep_usp, time_t then)
3081 {
3082     time_t now = time(NULL);
3083 
3084     if (now + 10 < then) {
3085 	/* File is more than 10 seconds in the future? */
3086 	errno = EEXIST;
3087 	return -1;
3088     }
3089 
3090     if (now - then < 10) {
3091 	/*
3092 	 * To give the effect of a gradually increasing backoff,
3093 	 * we'll sleep a period based on the time we've spent so far.
3094 	 */
3095 	DPUTS(now < then, "time flowing backwards through history");
3096 	/*
3097 	 * Randomise to minimise clashes with shells exiting at the same
3098 	 * time.
3099 	 */
3100 	(void)zsleep_random(*sleep_usp, then + 10);
3101 	*sleep_usp <<= 1;
3102     } else
3103 	unlink(lockfile);
3104 
3105     return 0;
3106 }
3107 
3108 /*
3109  * Lock history file.  Return 0 on success, 1 on failure to lock this
3110  * time, 2 on permanent failure (e.g. permission).
3111  */
3112 
3113 /**/
3114 int
lockhistfile(char * fn,int keep_trying)3115 lockhistfile(char *fn, int keep_trying)
3116 {
3117     int ct = lockhistct;
3118     int ret = 0;
3119     long sleep_us = 0x10000; /* about 67 ms */
3120 
3121     if (!fn && !(fn = getsparam("HISTFILE")))
3122 	return 1;
3123 
3124     if (!lockhistct++) {
3125 	struct stat sb;
3126 	int fd;
3127 	char *lockfile;
3128 #ifdef HAVE_LINK
3129 # ifdef HAVE_SYMLINK
3130 	char pidbuf[32], *lnk;
3131 # else
3132 	char *tmpfile;
3133 # endif
3134 #endif
3135 
3136 #ifdef HAVE_FCNTL_H
3137 	if (isset(HISTFCNTLLOCK))
3138 	    return flockhistfile(fn, keep_trying);
3139 #endif
3140 
3141 	lockfile = bicat(unmeta(fn), ".LOCK");
3142 	/* NOTE: only use symlink locking on a link()-having host in order to
3143 	 * avoid a change from open()-based locking to symlink()-based. */
3144 #ifdef HAVE_LINK
3145 # ifdef HAVE_SYMLINK
3146 	sprintf(pidbuf, "/pid-%ld/host-", (long)mypid);
3147 	lnk = getsparam("HOST");
3148 	lnk = bicat(pidbuf, lnk ? lnk : "");
3149 	/* We'll abuse fd as our success flag. */
3150 	while ((fd = symlink(lnk, lockfile)) < 0) {
3151 	    if (errno != EEXIST) {
3152 		ret = 2;
3153 		break;
3154 	    } else if (!keep_trying) {
3155 		ret = 1;
3156 		break;
3157 	    }
3158 	    if (lstat(lockfile, &sb) < 0) {
3159 		if (errno == ENOENT)
3160 		    continue;
3161 		break;
3162 	    }
3163 	    if (checklocktime(lockfile, &sleep_us, sb.st_mtime) < 0) {
3164 		ret = 1;
3165 		break;
3166 	    }
3167 	}
3168 	if (fd < 0)
3169 	    lockhistct--;
3170 	free(lnk);
3171 # else /* not HAVE_SYMLINK */
3172 	if ((fd = gettempfile(fn, 0, &tmpfile)) >= 0) {
3173 	    FILE *out = fdopen(fd, "w");
3174 	    if (out) {
3175 		fprintf(out, "%ld %s\n", (long)getpid(), getsparam("HOST"));
3176 		fclose(out);
3177 	    } else
3178 		close(fd);
3179 	    while (link(tmpfile, lockfile) < 0) {
3180 		if (errno != EEXIST) {
3181 		    ret = 2;
3182 		    break;
3183 		} else if (!keep_trying) {
3184 		    ret = 1;
3185 		    break;
3186 		} else if (lstat(lockfile, &sb) < 0) {
3187 		    if (errno == ENOENT)
3188 			continue;
3189 		    ret = 2;
3190 		} else {
3191 		    if (checklocktime(lockfile, &sleep_us, sb.st_mtime) < 0) {
3192 			ret = 1;
3193 			break;
3194 		    }
3195 		    continue;
3196 		}
3197 		lockhistct--;
3198 		break;
3199 	    }
3200 	    unlink(tmpfile);
3201 	    free(tmpfile);
3202 	}
3203 # endif /* not HAVE_SYMLINK */
3204 #else /* not HAVE_LINK */
3205 	while ((fd = open(lockfile, O_WRONLY|O_CREAT|O_EXCL, 0644)) < 0) {
3206 	    if (errno != EEXIST) {
3207 		ret = 2;
3208 		break;
3209 	    } else if (!keep_trying) {
3210 		ret = 1;
3211 		break;
3212 	    }
3213 	    if (lstat(lockfile, &sb) < 0) {
3214 		if (errno == ENOENT)
3215 		    continue;
3216 		ret = 2;
3217 		break;
3218 	    }
3219 	    if (checklocktime(lockfile, &sleep_us, sb.st_mtime) < 0) {
3220 		ret = 1;
3221 		break;
3222 	    }
3223 	}
3224 	if (fd < 0)
3225 	    lockhistct--;
3226 	else {
3227 	    FILE *out = fdopen(fd, "w");
3228 	    if (out) {
3229 		fprintf(out, "%ld %s\n", (long)mypid, getsparam("HOST"));
3230 		fclose(out);
3231 	    } else
3232 		close(fd);
3233 	}
3234 #endif /* not HAVE_LINK */
3235 	free(lockfile);
3236     }
3237 
3238     if (ct == lockhistct) {
3239 #ifdef HAVE_FCNTL_H
3240 	if (flock_fd >= 0) {
3241 	    close(flock_fd);
3242 	    flock_fd = -1;
3243 	}
3244 #endif
3245 	DPUTS(ret == 0, "BUG: return value non-zero on locking error");
3246 	return ret;
3247     }
3248     return 0;
3249 }
3250 
3251 /* Unlock the history file if this corresponds to the last nested lock
3252  * request.  If we don't have the file locked, just return.
3253  */
3254 
3255 /**/
3256 void
unlockhistfile(char * fn)3257 unlockhistfile(char *fn)
3258 {
3259     if (!fn && !(fn = getsparam("HISTFILE")))
3260 	return;
3261     if (--lockhistct) {
3262 	if (lockhistct < 0)
3263 	    lockhistct = 0;
3264     }
3265     else {
3266 	char *lockfile;
3267 	fn = unmeta(fn);
3268 	lockfile = zalloc(strlen(fn) + 5 + 1);
3269 	sprintf(lockfile, "%s.LOCK", fn);
3270 	unlink(lockfile);
3271 	free(lockfile);
3272 #ifdef HAVE_FCNTL_H
3273 	if (flock_fd >= 0) {
3274 	    close(flock_fd);
3275 	    flock_fd = -1;
3276 	}
3277 #endif
3278     }
3279 }
3280 
3281 /**/
3282 int
histfileIsLocked(void)3283 histfileIsLocked(void)
3284 {
3285     return lockhistct > 0;
3286 }
3287 
3288 /*
3289  * Get the words in the current buffer. Using the lexer.
3290  *
3291  * As far as I can make out, this is a gross hack based on a gross hack.
3292  * When analysing lines from within zle, we tweak the metafied line
3293  * positions (zlemetall and zlemetacs) directly in the lexer.  That's
3294  * bad enough, but this function appears to be designed to be called
3295  * from outside zle, pretending to be in zle and calling out, so
3296  * we set zlemetall and zlemetacs locally and copy the current zle line,
3297  * which may not even be valid at this point.
3298  *
3299  * However, I'm so confused it could simply be baking Bakewell tarts.
3300  *
3301  * list may be an existing linked list (off the heap), in which case
3302  * it will be appended to; otherwise it will be created.
3303  *
3304  * If buf is set we will take input from that string, else we will
3305  * attempt to use ZLE directly in a way they tell you not to do on all
3306  * programming courses.
3307  *
3308  * If index is non-NULL, and input is from a string in ZLE, *index
3309  * is set to the position of the end of the current editor word.
3310  *
3311  * flags is passed directly to lexflags, see lex.c, except that
3312  * we 'or' in the bit LEXFLAGS_ACTIVE to make sure the variable
3313  * is set.
3314  */
3315 
3316 /**/
3317 mod_export LinkList
bufferwords(LinkList list,char * buf,int * index,int flags)3318 bufferwords(LinkList list, char *buf, int *index, int flags)
3319 {
3320     int num = 0, cur = -1, got = 0, ne = noerrs;
3321     int owb = wb, owe = we, oadx = addedx, onc = nocomments;
3322     int ona = noaliases, ocs = zlemetacs, oll = zlemetall;
3323     int forloop = 0, rcquotes = opts[RCQUOTES];
3324     int envarray = 0;
3325     char *p, *addedspaceptr;
3326 
3327     if (!list)
3328 	list = newlinklist();
3329 
3330     /*
3331      * With RC_QUOTES, 'foo '' bar' comes back as 'foo ' bar'.  That's
3332      * not very useful.  As nothing in here requires the fully processed
3333      * string expression, we just turn the option off for this function.
3334      */
3335     opts[RCQUOTES] = 0;
3336     addedx = 0;
3337     noerrs = 1;
3338     zcontext_save();
3339     lexflags = flags | LEXFLAGS_ACTIVE;
3340     /*
3341      * Are we handling comments?
3342      */
3343     nocomments = !(flags & (LEXFLAGS_COMMENTS_KEEP|
3344 			    LEXFLAGS_COMMENTS_STRIP));
3345     if (buf) {
3346 	int l = strlen(buf);
3347 
3348 	p = (char *) zhalloc(l + 2);
3349 	memcpy(p, buf, l);
3350 	/*
3351 	 * I'm sure this space is here for a reason, but it's
3352 	 * a pain in the neck:  when we get back a string that's
3353 	 * not finished it's very hard to tell if a space at the
3354 	 * end is this one or not.  We use two tricks below to
3355 	 * work around this.
3356 	 */
3357 	addedspaceptr = p + l;
3358 	*addedspaceptr = ' ';
3359 	addedspaceptr[1] = '\0';
3360 	inpush(p, 0, NULL);
3361 	zlemetall = strlen(p) ;
3362 	zlemetacs = zlemetall + 1;
3363     } else {
3364 	int ll, cs;
3365 	char *linein;
3366 
3367 	linein = zleentry(ZLE_CMD_GET_LINE, &ll, &cs);
3368 	zlemetall = ll + 1; /* length of line plus space added below */
3369 	zlemetacs = cs;
3370 
3371 	if (!isfirstln && chline) {
3372 	    p = (char *) zhalloc(hptr - chline + ll + 2);
3373 	    memcpy(p, chline, hptr - chline);
3374 	    memcpy(p + (hptr - chline), linein, ll);
3375 	    addedspaceptr = p + (hptr - chline) + ll;
3376 	    *addedspaceptr = ' ';
3377 	    addedspaceptr[1] = '\0';
3378 	    inpush(p, 0, NULL);
3379 
3380 	    /*
3381 	     * advance line length and character position over
3382 	     * prepended string.
3383 	     */
3384 	    zlemetall += hptr - chline;
3385 	    zlemetacs += hptr - chline;
3386 	} else {
3387 	    p = (char *) zhalloc(ll + 2);
3388 	    memcpy(p, linein, ll);
3389 	    addedspaceptr = p + ll;
3390 	    *addedspaceptr = ' ';
3391 	    p[zlemetall] = '\0';
3392 	    inpush(p, 0, NULL);
3393 	}
3394 	zsfree(linein);
3395     }
3396     if (zlemetacs)
3397 	zlemetacs--;
3398     strinbeg(0);
3399     noaliases = 1;
3400     do {
3401 	if (incond)
3402 	    incond = 1 + (tok != DINBRACK && tok != INPAR &&
3403 			  tok != DBAR && tok != DAMPER &&
3404 			  tok != BANG);
3405 	ctxtlex();
3406 	if (tok == ENDINPUT || tok == LEXERR)
3407 	    break;
3408 	/*
3409 	 * After an array assignment, return to the initial
3410 	 * start-of-command state.  There could be a second ENVARRAY.
3411 	 */
3412 	if (tok == OUTPAR && envarray) {
3413 	    incmdpos = 1;
3414 	    envarray = 0;
3415 	}
3416 	if (tok == FOR) {
3417 	    /*
3418 	     * The way for (( expr1 ; expr2; expr3 )) is parsed is:
3419 	     * - a FOR tok
3420 	     * - a DINPAR with no tokstr
3421 	     * - two DINPARS with tokstr's expr1, expr2.
3422 	     * - a DOUTPAR with tokstr expr3.
3423 	     *
3424 	     * We'll decrement the variable forloop as we verify
3425 	     * the various stages.
3426 	     *
3427 	     * Don't ask me, ma'am, I'm just the programmer.
3428 	     */
3429 	    forloop = 5;
3430 	} else {
3431 	    switch (forloop) {
3432 	    case 1:
3433 		if (tok != DOUTPAR)
3434 		    forloop = 0;
3435 		break;
3436 
3437 	    case 2:
3438 	    case 3:
3439 	    case 4:
3440 		if (tok != DINPAR)
3441 		    forloop = 0;
3442 		break;
3443 
3444 	    default:
3445 		/* nothing to do */
3446 		break;
3447 	    }
3448 	}
3449 	if (tokstr) {
3450 	    switch (tok) {
3451 	    case ENVARRAY:
3452 		p = dyncat(tokstr, "=(");
3453 		envarray = 1;
3454 		break;
3455 
3456 	    case DINPAR:
3457 		if (forloop) {
3458 		    /* See above. */
3459 		    p = dyncat(tokstr, ";");
3460 		} else {
3461 		    /*
3462 		     * Mathematical expressions analysed as a single
3463 		     * word.  That's correct because it behaves like
3464 		     * double quotes.  Whitespace in the middle is
3465 		     * similarly retained, so just add the parentheses back.
3466 		     */
3467 		    p = zhtricat("((", tokstr, "))");
3468 		}
3469 		break;
3470 
3471 	    default:
3472 		p = dupstring(tokstr);
3473 		break;
3474 	    }
3475 	    if (*p) {
3476 		untokenize(p);
3477 		if (ingetptr() == addedspaceptr + 1) {
3478 		    /*
3479 		     * Whoops, we've read past the space we added, probably
3480 		     * because we were expecting a terminator but when
3481 		     * it didn't turn up we shrugged our shoulders thinking
3482 		     * it might as well be a complete string anyway.
3483 		     * So remove the space.  C.f. below for the case
3484 		     * where the missing terminator caused a lex error.
3485 		     * We use the same paranoid test.
3486 		     */
3487 		    int plen = strlen(p);
3488 		    if (plen && p[plen-1] == ' ' &&
3489 			(plen == 1 || p[plen-2] != Meta))
3490 			p[plen-1] = '\0';
3491 		}
3492 		addlinknode(list, p);
3493 		num++;
3494 	    }
3495 	} else if (buf) {
3496 	    if (IS_REDIROP(tok) && tokfd >= 0) {
3497 		char b[20];
3498 
3499 		sprintf(b, "%d%s", tokfd, tokstrings[tok]);
3500 		addlinknode(list, dupstring(b));
3501 		num++;
3502 	    } else if (tok != NEWLIN) {
3503 		addlinknode(list, dupstring(tokstrings[tok]));
3504 		num++;
3505 	    }
3506 	}
3507 	if (forloop) {
3508 	    if (forloop == 1) {
3509 		/*
3510 		 * Final "))" of for loop to match opening,
3511 		 * since we've just added the preceding element.
3512  		 */
3513 		addlinknode(list, dupstring("))"));
3514 	    }
3515 	    forloop--;
3516 	}
3517 	if (!got && !lexflags) {
3518 	    got = 1;
3519 	    cur = num - 1;
3520 	}
3521     } while (tok != ENDINPUT && tok != LEXERR && !(errflag & ERRFLAG_INT));
3522     if (buf && tok == LEXERR && tokstr && *tokstr) {
3523 	int plen;
3524 	untokenize((p = dupstring(tokstr)));
3525 	plen = strlen(p);
3526 	/*
3527 	 * Strip the space we added for lexing but which won't have
3528 	 * been swallowed by the lexer because we aborted early.
3529 	 * The test is paranoia.
3530 	 */
3531 	if (plen && p[plen-1] == ' ' && (plen == 1 || p[plen-2] != Meta))
3532 	    p[plen - 1] = '\0';
3533 	addlinknode(list, p);
3534 	num++;
3535     }
3536     if (cur < 0 && num)
3537 	cur = num - 1;
3538     noaliases = ona;
3539     strinend();
3540     inpop();
3541     errflag &= ~ERRFLAG_ERROR;
3542     nocomments = onc;
3543     noerrs = ne;
3544     zcontext_restore();
3545     zlemetacs = ocs;
3546     zlemetall = oll;
3547     wb = owb;
3548     we = owe;
3549     addedx = oadx;
3550     opts[RCQUOTES] = rcquotes;
3551 
3552     if (index)
3553 	*index = cur;
3554 
3555     return list;
3556 }
3557 
3558 /*
3559  * Split up a line into words for use in a history file.
3560  *
3561  * lineptr is the line to be split.
3562  *
3563  * *wordsp and *nwordsp are an array already allocated to hold words
3564  * and its length.  The array holds both start and end positions,
3565  * so *nwordsp actually counts twice the number of words in the
3566  * original string.  *nwordsp may be zero in which case the array
3567  * will be allocated.
3568  *
3569  * *nwordposp returns the used length of *wordsp in the same units as
3570  * *nwordsp, i.e. twice the number of words in the input line.
3571  *
3572  * If uselex is 1, attempt to do this using the lexical analyser.
3573  * This is more accurate, but slower; for reading history files it's
3574  * controlled by the option HISTLEXWORDS.  If this failed (which
3575  * indicates a bug in the shell) it falls back to whitespace-separated
3576  * strings, printing a message if in debug mode.
3577  *
3578  * If uselex is 0, just look for whitespace-separated words; the only
3579  * special handling is for a backslash-newline combination as used
3580  * by the history file format to save multiline buffers.
3581  */
3582 /**/
3583 mod_export void
histsplitwords(char * lineptr,short ** wordsp,int * nwordsp,int * nwordposp,int uselex)3584 histsplitwords(char *lineptr, short **wordsp, int *nwordsp, int *nwordposp,
3585 	       int uselex)
3586 {
3587     int nwords = *nwordsp, nwordpos = 0;
3588     short *words = *wordsp;
3589     char *start = lineptr;
3590 
3591     if (uselex) {
3592 	LinkList wordlist;
3593 	LinkNode wordnode;
3594 	int nwords_max;
3595 
3596 	wordlist = bufferwords(NULL, lineptr, NULL,
3597 			       LEXFLAGS_COMMENTS_KEEP);
3598 	if (errflag)
3599 	    return;
3600 	nwords_max = 2 * countlinknodes(wordlist);
3601 	if (nwords_max > nwords) {
3602 	    *nwordsp = nwords = nwords_max;
3603 	    *wordsp = words = (short *)zrealloc(words, nwords*sizeof(short));
3604 	}
3605 	for (wordnode = firstnode(wordlist);
3606 	     wordnode;
3607 	     incnode(wordnode)) {
3608 	    char *word = getdata(wordnode);
3609 	    char *lptr, *wptr = word;
3610 	    int loop_next = 0, skipping;
3611 
3612 	    /* Skip stuff at the start of the word */
3613 	    for (;;) {
3614 		/*
3615 		 * Not really an oddity: "\\\n" is
3616 		 * removed from input as if whitespace.
3617 		 */
3618 		if (inblank(*lineptr))
3619 		    lineptr++;
3620 		else if (lineptr[0] == '\\' && lineptr[1] == '\n') {
3621 		    /*
3622 		     * Optimisation: we handle this in the loop below,
3623 		     * too.
3624 		     */
3625 		    lineptr += 2;
3626 		} else
3627 		    break;
3628 	    }
3629 	    lptr = lineptr;
3630 	    /*
3631 	     * Skip chunks of word with possible intervening
3632 	     * backslash-newline.
3633 	     *
3634 	     * To get round C's annoying lack of ability to
3635 	     * reference the outer loop, we'll break from this
3636 	     * one with
3637 	     * loop_next = 0: carry on as normal
3638 	     * loop_next = 1: break from outer loop
3639 	     * loop_next = 2: continue round outer loop.
3640 	     */
3641 	    do {
3642 		skipping = 0;
3643 		if (strpfx(wptr, lptr)) {
3644 		    /*
3645 		     * Normal case: word from lexer matches start of
3646 		     * string from line.  Just advance over it.
3647 		     */
3648 		    int len;
3649 		    if (!strcmp(wptr, ";") && strpfx(";;", lptr)) {
3650 			/*
3651 			 * Don't get confused between a semicolon that's
3652 			 * probably really a newline and a double
3653 			 * semicolon that's terminating a case.
3654 			 */
3655 			loop_next = 2;
3656 			break;
3657 		    }
3658 		    len = strlen(wptr);
3659 		    lptr += len;
3660 		    wptr += len;
3661 		} else {
3662 		    /*
3663 		     * Didn't get to the end of the word.
3664 		     * See what's amiss.
3665 		     */
3666 		    int bad = 0;
3667 		    /*
3668 		     * Oddity 1: newlines turn into semicolons.
3669 		     */
3670 		    if (!strcmp(wptr, ";"))
3671 		    {
3672 			loop_next = 2;
3673 			break;
3674 		    }
3675 		    while (*lptr) {
3676 			if (!*wptr) {
3677 			    /*
3678 			     * End of the word before the end of the
3679 			     * line: not good.
3680 			     */
3681 			    bad = 1;
3682 			    loop_next = 1;
3683 			    break;
3684 			}
3685 			/*
3686 			 * Oddity 2: !'s turn into |'s.
3687 			 */
3688 			if (*lptr == *wptr ||
3689 			    (*lptr == '!' && *wptr == '|')) {
3690 			    lptr++;
3691 			    if (!*++wptr)
3692 				break;
3693 			} else if (lptr[0] == '\\' &&
3694 				   lptr[1] == '\n') {
3695 			    /*
3696 			     * \\\n can occur in the middle of a word;
3697 			     * wptr is already pointing at this, we
3698 			     * just need to skip over the break
3699 			     * in lptr and look at the next chunk.
3700 			     */
3701 			    lptr += 2;
3702 			    skipping = 1;
3703 			    break;
3704 			} else {
3705 			    bad = 1;
3706 			    loop_next = 1;
3707 			    break;
3708 			}
3709 		    }
3710 		    if (bad) {
3711 #ifdef DEBUG
3712 			dputs(ERRMSG("bad wordsplit reading history: "
3713 				     "%s\nat: %s\nword: %s"),
3714 			      start, lineptr, word);
3715 #endif
3716 			lineptr = start;
3717 			nwordpos = 0;
3718 			uselex = 0;
3719 			loop_next = 1;
3720 		    }
3721 		}
3722 	    } while (skipping);
3723 	    if (loop_next) {
3724 		if (loop_next == 1)
3725 		    break;
3726 		continue;
3727 	    }
3728 	    /* Record position of current word... */
3729 	    words[nwordpos++] = lineptr - start;
3730 	    words[nwordpos++] = lptr - start;
3731 
3732 	    /* ready for start of next word. */
3733 	    lineptr = lptr;
3734 	}
3735     }
3736     if (!uselex) {
3737 	do {
3738 	    for (;;) {
3739 		if (inblank(*lineptr))
3740 		    lineptr++;
3741 		else if (lineptr[0] == '\\' && lineptr[1] == '\n')
3742 		    lineptr += 2;
3743 		else
3744 		    break;
3745 	    }
3746 	    if (*lineptr) {
3747 		if (nwordpos >= nwords) {
3748 		    *nwordsp = nwords = nwords + 64;
3749 		    *wordsp = words = (short *)
3750 			zrealloc(words, nwords*sizeof(*words));
3751 		}
3752 		words[nwordpos++] = lineptr - start;
3753 		while (*lineptr && !inblank(*lineptr))
3754 		    lineptr++;
3755 		words[nwordpos++] = lineptr - start;
3756 	    }
3757 	} while (*lineptr);
3758     }
3759 
3760     *nwordposp = nwordpos;
3761 }
3762 
3763 /* Move the current history list out of the way and prepare a fresh history
3764  * list using hf for HISTFILE, hs for HISTSIZE, and shs for SAVEHIST.  If
3765  * the hf value is an empty string, HISTFILE will be unset from the new
3766  * environment; if it is NULL, HISTFILE will not be changed, not even by the
3767  * pop function (this functionality is used internally to rewrite the current
3768  * history file without affecting pointers into the environment).
3769  */
3770 
3771 /**/
3772 int
pushhiststack(char * hf,zlong hs,zlong shs,int level)3773 pushhiststack(char *hf, zlong hs, zlong shs, int level)
3774 {
3775     struct histsave *h;
3776     int curline_in_ring = (histactive & HA_ACTIVE) && hist_ring == &curline;
3777 
3778     if (histsave_stack_pos == histsave_stack_size) {
3779 	histsave_stack_size += 5;
3780 	histsave_stack = zrealloc(histsave_stack,
3781 			    histsave_stack_size * sizeof (struct histsave));
3782     }
3783 
3784     if (curline_in_ring)
3785 	unlinkcurline();
3786 
3787     h = &histsave_stack[histsave_stack_pos++];
3788 
3789     h->lasthist = lasthist;
3790     if (hf) {
3791 	if ((h->histfile = getsparam("HISTFILE")) != NULL && *h->histfile)
3792 	    h->histfile = ztrdup(h->histfile);
3793 	else
3794 	    h->histfile = "";
3795     } else
3796 	h->histfile = NULL;
3797     h->histtab = histtab;
3798     h->hist_ring = hist_ring;
3799     h->curhist = curhist;
3800     h->histlinect = histlinect;
3801     h->histsiz = histsiz;
3802     h->savehistsiz = savehistsiz;
3803     h->locallevel = level;
3804 
3805     memset(&lasthist, 0, sizeof lasthist);
3806     if (hf) {
3807 	if (*hf)
3808 	    setsparam("HISTFILE", ztrdup(hf));
3809 	else
3810 	    unsetparam("HISTFILE");
3811     }
3812     hist_ring = NULL;
3813     curhist = histlinect = 0;
3814     if (zleactive)
3815 	zleentry(ZLE_CMD_SET_HIST_LINE, curhist);
3816     histsiz = hs;
3817     savehistsiz = shs;
3818     inithist(); /* sets histtab */
3819 
3820     if (curline_in_ring)
3821 	linkcurline();
3822 
3823     return histsave_stack_pos;
3824 }
3825 
3826 
3827 /**/
3828 int
pophiststack(void)3829 pophiststack(void)
3830 {
3831     struct histsave *h;
3832     int curline_in_ring = (histactive & HA_ACTIVE) && hist_ring == &curline;
3833 
3834     if (histsave_stack_pos == 0)
3835 	return 0;
3836 
3837     if (curline_in_ring)
3838 	unlinkcurline();
3839 
3840     deletehashtable(histtab);
3841     zsfree(lasthist.text);
3842 
3843     h = &histsave_stack[--histsave_stack_pos];
3844 
3845     lasthist = h->lasthist;
3846     if (h->histfile) {
3847 	if (*h->histfile)
3848 	    setsparam("HISTFILE", h->histfile);
3849 	else
3850 	    unsetparam("HISTFILE");
3851     }
3852     histtab = h->histtab;
3853     hist_ring = h->hist_ring;
3854     curhist = h->curhist;
3855     if (zleactive)
3856 	zleentry(ZLE_CMD_SET_HIST_LINE, curhist);
3857     histlinect = h->histlinect;
3858     histsiz = h->histsiz;
3859     savehistsiz = h->savehistsiz;
3860 
3861     if (curline_in_ring)
3862 	linkcurline();
3863 
3864     return histsave_stack_pos + 1;
3865 }
3866 
3867 /* If pop_through > 0, pop all array items >= the 1-relative index value.
3868  * If pop_through <= 0, pop (-1)*pop_through levels off the stack.
3869  * If the (new) top of stack is from a higher locallevel, auto-pop until
3870  * it is not.
3871  */
3872 
3873 /**/
3874 int
saveandpophiststack(int pop_through,int writeflags)3875 saveandpophiststack(int pop_through, int writeflags)
3876 {
3877     if (pop_through <= 0) {
3878 	pop_through += histsave_stack_pos + 1;
3879 	if (pop_through <= 0)
3880 	    pop_through = 1;
3881     }
3882     while (pop_through > 1
3883      && histsave_stack[pop_through-2].locallevel > locallevel)
3884 	pop_through--;
3885     if (histsave_stack_pos < pop_through)
3886 	return 0;
3887     do {
3888 	if (!nohistsave)
3889 	    savehistfile(NULL, 1, writeflags);
3890 	pophiststack();
3891     } while (histsave_stack_pos >= pop_through);
3892     return 1;
3893 }
3894