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