35799: with NO_EXEC, parse parameter subscript expressions
[zsh/mirror.git] / Src / hist.c
blob6725313946a35d43755d12f434874483d2c01214
1 /*
2 * hist.c - history expansion
4 * This file is part of zsh, the Z shell.
6 * Copyright (c) 1992-1997 Paul Falstad
7 * All rights reserved.
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.
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.
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.
30 #include "zsh.mdh"
31 #include "hist.pro"
33 /* Functions to call for getting/ungetting a character and for history
34 * word control. */
36 /**/
37 mod_export int (*hgetc) _((void));
39 /**/
40 void (*hungetc) _((int));
42 /**/
43 void (*hwaddc) _((int));
45 /**/
46 void (*hwbegin) _((int));
48 /**/
49 void (*hwend) _((void));
51 /**/
52 void (*addtoline) _((int));
54 /* != 0 means history substitution is turned off */
56 /**/
57 mod_export int stophist;
59 /* if != 0, we are expanding the current line */
61 /**/
62 mod_export int expanding;
64 /* these are used to modify the cursor position during expansion */
66 /**/
67 mod_export int excs, exlast;
70 * Current history event number
72 * Note on curhist: with history inactive, this points to the
73 * last line actually added to the history list. With history active,
74 * the line does not get added to the list until hend(), if at all.
75 * However, curhist is incremented to reflect the current line anyway
76 * and a temporary history entry is inserted while the user is editing.
77 * If the resulting line was not added to the list, a flag is set so
78 * that curhist will be decremented in hbegin().
80 * Note curhist is passed to zle on variable length argument list:
81 * type must match that retrieved in zle_main_entry.
84 /**/
85 mod_export zlong curhist;
87 /**/
88 struct histent curline;
90 /* current line count of allocated history entries */
92 /**/
93 zlong histlinect;
95 /* The history lines are kept in a hash, and also doubly-linked in a ring */
97 /**/
98 HashTable histtab;
99 /**/
100 mod_export Histent hist_ring;
102 /* capacity of history lists */
104 /**/
105 zlong histsiz;
107 /* desired history-file size (in lines) */
109 /**/
110 zlong savehistsiz;
112 /* if = 1, we have performed history substitution on the current line *
113 * if = 2, we have used the 'p' modifier */
115 /**/
116 int histdone;
118 /* state of the history mechanism */
120 /**/
121 int histactive;
123 /* Current setting of the associated option, but sometimes also includes
124 * the setting of the HIST_SAVE_NO_DUPS option. */
126 /**/
127 int hist_ignore_all_dups;
129 /* What flags (if any) we should skip when moving through the history */
131 /**/
132 mod_export int hist_skip_flags;
134 /* Bits of histactive variable */
135 #define HA_ACTIVE (1<<0) /* History mechanism is active */
136 #define HA_NOINC (1<<1) /* Don't store, curhist not incremented */
137 #define HA_INWORD (1<<2) /* We're inside a word, don't add
138 start and end markers */
140 /* Array of word beginnings and endings in current history line. */
142 /**/
143 short *chwords;
145 /* Max, actual position in chwords.
146 * nwords = chwordpos/2 because we record beginning and end of words.
149 /**/
150 int chwordlen, chwordpos;
152 /* the last l for s/l/r/ history substitution */
154 /**/
155 char *hsubl;
157 /* the last r for s/l/r/ history substitution */
159 /**/
160 char *hsubr;
162 /* pointer into the history line */
164 /**/
165 mod_export char *hptr;
167 /* the current history line */
169 /**/
170 mod_export char *chline;
173 * The current history line as seen by ZLE.
174 * We modify chline for use in other contexts while ZLE may
175 * still be running; ZLE should see only the top-level value.
177 * To avoid having to modify this every time we modify chline,
178 * we set it when we push the stack, and unset it when we pop
179 * the appropriate value off the stack. As it's never modified
180 * on the stack this is the only maintainance we ever do on it.
181 * In return, ZLE has to check both zle_chline and (if that's
182 * NULL) chline to get the current value.
185 /**/
186 mod_export char *zle_chline;
188 /* true if the last character returned by hgetc was an escaped bangchar *
189 * if it is set and NOBANGHIST is unset hwaddc escapes bangchars */
191 /**/
192 int qbang;
194 /* max size of histline */
196 /**/
197 int hlinesz;
199 /* default event (usually curhist-1, that is, "!!") */
201 static zlong defev;
203 /* Remember the last line in the history file so we can find it again. */
204 static struct histfile_stats {
205 char *text;
206 time_t stim, mtim;
207 off_t fpos, fsiz;
208 zlong next_write_ev;
209 } lasthist;
211 static struct histsave {
212 struct histfile_stats lasthist;
213 char *histfile;
214 HashTable histtab;
215 Histent hist_ring;
216 zlong curhist;
217 zlong histlinect;
218 zlong histsiz;
219 zlong savehistsiz;
220 int locallevel;
221 } *histsave_stack;
222 static int histsave_stack_size = 0;
223 static int histsave_stack_pos = 0;
225 static zlong histfile_linect;
227 /* save history context */
229 /**/
230 void
231 hist_context_save(struct hist_stack *hs, int toplevel)
233 if (toplevel) {
234 /* top level, make this version visible to ZLE */
235 zle_chline = chline;
236 /* ensure line stored is NULL-terminated */
237 if (hptr)
238 *hptr = '\0';
240 hs->histactive = histactive;
241 hs->histdone = histdone;
242 hs->stophist = stophist;
243 hs->hline = chline;
244 hs->hptr = hptr;
245 hs->chwords = chwords;
246 hs->chwordlen = chwordlen;
247 hs->chwordpos = chwordpos;
248 hs->hgetc = hgetc;
249 hs->hungetc = hungetc;
250 hs->hwaddc = hwaddc;
251 hs->hwbegin = hwbegin;
252 hs->hwend = hwend;
253 hs->addtoline = addtoline;
254 hs->hlinesz = hlinesz;
256 * We save and restore the command stack with history
257 * as it's visible to the user interactively, so if
258 * we're preserving history state we'll continue to
259 * show the current set of commands from input.
261 hs->cstack = cmdstack;
262 hs->csp = cmdsp;
264 stophist = 0;
265 chline = NULL;
266 hptr = NULL;
267 histactive = 0;
268 cmdstack = (unsigned char *)zalloc(CMDSTACKSZ);
269 cmdsp = 0;
272 /* restore history context */
274 /**/
275 void
276 hist_context_restore(const struct hist_stack *hs, int toplevel)
278 if (toplevel) {
279 /* Back to top level: don't need special ZLE value */
280 DPUTS(hs->hline != zle_chline, "BUG: Ouch, wrong chline for ZLE");
281 zle_chline = NULL;
283 histactive = hs->histactive;
284 histdone = hs->histdone;
285 stophist = hs->stophist;
286 chline = hs->hline;
287 hptr = hs->hptr;
288 chwords = hs->chwords;
289 chwordlen = hs->chwordlen;
290 chwordpos = hs->chwordpos;
291 hgetc = hs->hgetc;
292 hungetc = hs->hungetc;
293 hwaddc = hs->hwaddc;
294 hwbegin = hs->hwbegin;
295 hwend = hs->hwend;
296 addtoline = hs->addtoline;
297 hlinesz = hs->hlinesz;
298 if (cmdstack)
299 zfree(cmdstack, CMDSTACKSZ);
300 cmdstack = hs->cstack;
301 cmdsp = hs->csp;
305 * Mark that the current level of history is within a word whatever
306 * characters turn up, or turn that mode off. This is used for nested
307 * parsing of substitutions.
309 * The caller takes care only to turn this on or off at the start
310 * or end of recursive use of the same mode, so a single flag is
311 * good enough here.
314 /**/
315 void
316 hist_in_word(int yesno)
318 if (yesno)
319 histactive |= HA_INWORD;
320 else
321 histactive &= ~HA_INWORD;
324 /* add a character to the current history word */
326 static void
327 ihwaddc(int c)
329 /* Only if history line exists and lexing has not finished. */
330 if (chline && !(errflag || lexstop) &&
332 * If we're reading inside a word for command substitution
333 * we allow the lexer to expand aliases but don't deal
334 * with them here. Note matching code in ihungetc().
335 * TBD: it might be neater to deal with all aliases in this
336 * fashion as we never need the expansion in the history
337 * line, only in the lexer and above.
339 (inbufflags & (INP_ALIAS|INP_HIST)) != INP_ALIAS) {
340 /* Quote un-expanded bangs in the history line. */
341 if (c == bangchar && stophist < 2 && qbang)
342 /* If qbang is not set, we do not escape this bangchar as it's *
343 * not necessary (e.g. it's a bang in !=, or it is followed *
344 * by a space). Roughly speaking, qbang is zero only if the *
345 * history interpreter has already digested this bang and *
346 * found that it is not necessary to escape it. */
347 hwaddc('\\');
348 *hptr++ = c;
350 /* Resize history line if necessary */
351 if (hptr - chline >= hlinesz) {
352 int oldsiz = hlinesz;
354 chline = realloc(chline, hlinesz = oldsiz + 64);
355 hptr = chline + oldsiz;
360 /* This function adds a character to the zle input line. It is used when *
361 * zsh expands history (see doexpandhist() in zle_tricky.c). It also *
362 * calculates the new cursor position after the expansion. It is called *
363 * from hgetc() and from gettok() in lex.c for characters in comments. */
365 /**/
366 void
367 iaddtoline(int c)
369 if (!expanding || lexstop)
370 return;
371 if (qbang && c == bangchar && stophist < 2) {
372 exlast--;
373 zleentry(ZLE_CMD_ADD_TO_LINE, '\\');
375 if (excs > zlemetacs) {
376 excs += 1 + inbufct - exlast;
377 if (excs < zlemetacs)
378 /* this case could be handled better but it is *
379 * so rare that it does not worth it */
380 excs = zlemetacs;
382 exlast = inbufct;
383 zleentry(ZLE_CMD_ADD_TO_LINE, itok(c) ? ztokens[c - Pound] : c);
387 static int
388 ihgetc(void)
390 int c = ingetc();
392 qbang = 0;
393 if (!stophist && !(inbufflags & INP_ALIAS)) {
394 /* If necessary, expand history characters. */
395 c = histsubchar(c);
396 if (c < 0) {
397 /* bad expansion */
398 lexstop = 1;
399 errflag |= ERRFLAG_ERROR;
400 return ' ';
403 if ((inbufflags & INP_HIST) && !stophist) {
404 /* the current character c came from a history expansion *
405 * (inbufflags & INP_HIST) and history is not disabled *
406 * (e.g. we are not inside single quotes). In that case, \! *
407 * should be treated as ! (since this \! came from a previous *
408 * history line where \ was used to escape the bang). So if *
409 * c == '\\' we fetch one more character to see if it's a bang, *
410 * and if it is not, we unget it and reset c back to '\\' */
411 qbang = 0;
412 if (c == '\\' && !(qbang = (c = ingetc()) == bangchar))
413 safeinungetc(c), c = '\\';
414 } else if (stophist || (inbufflags & INP_ALIAS))
415 /* If the result is a bangchar which came from history or alias *
416 * expansion, we treat it as an escaped bangchar, unless history *
417 * is disabled. If stophist == 1 it only means that history is *
418 * temporarily disabled by a !" which won't appear in the *
419 * history, so we still have an escaped bang. stophist > 1 if *
420 * history is disabled with NOBANGHIST or by someone else (e.g. *
421 * when the lexer scans single quoted text). */
422 qbang = c == bangchar && (stophist < 2);
423 hwaddc(c);
424 addtoline(c);
426 return c;
429 /**/
430 static void
431 safeinungetc(int c)
433 if (lexstop)
434 lexstop = 0;
435 else
436 inungetc(c);
439 /**/
440 void
441 herrflush(void)
443 inpopalias();
445 while (!lexstop && inbufct && !strin)
446 hwaddc(ingetc());
450 * Extract :s/foo/bar/ delimiters and arguments
452 * The first character expected is the first delimiter.
453 * The arguments are stored in the hsubl and hsubr variables.
455 * subline is the part of the command line to be matched.
457 * If a ':' was found but was not followed by a 'G',
458 * *cflagp is set to 1 and the input is backed up to the
459 * character following the colon.
462 /**/
463 static int
464 getsubsargs(char *subline, int *gbalp, int *cflagp)
466 int del, follow;
467 char *ptr1, *ptr2;
469 del = ingetc();
470 ptr1 = hdynread2(del);
471 if (!ptr1)
472 return 1;
473 ptr2 = hdynread2(del);
474 if (strlen(ptr1)) {
475 zsfree(hsubl);
476 hsubl = ptr1;
477 } else if (!hsubl) { /* fail silently on this */
478 zsfree(ptr1);
479 zsfree(ptr2);
480 return 0;
482 zsfree(hsubr);
483 hsubr = ptr2;
484 follow = ingetc();
485 if (follow == ':') {
486 follow = ingetc();
487 if (follow == 'G')
488 *gbalp = 1;
489 else {
490 inungetc(follow);
491 *cflagp = 1;
493 } else
494 inungetc(follow);
495 return 0;
498 /* Get the maximum no. of words for a history entry. */
500 /**/
501 static int
502 getargc(Histent ehist)
504 return ehist->nwords ? ehist->nwords-1 : 0;
507 /**/
508 static int
509 substfailed(void)
511 herrflush();
512 zerr("substitution failed");
513 return -1;
516 /* Perform history substitution, returning the next character afterwards. */
518 /**/
519 static int
520 histsubchar(int c)
522 int farg, evset = -1, larg, argc, cflag = 0, bflag = 0;
523 zlong ev;
524 static int marg = -1;
525 static zlong mev = -1;
526 char *buf, *ptr;
527 char *sline;
528 int lexraw_mark;
529 Histent ehist;
530 size_t buflen;
533 * If accumulating raw input for use in command substitution,
534 * we don't want the history text, so mark it for later removal.
535 * It would be better to do this at a level above the history
536 * and below the lexer --- but there isn't one.
538 * Include the character we are attempting to substitute.
540 lexraw_mark = zshlex_raw_mark(-1);
542 /* look, no goto's */
543 if (isfirstch && c == hatchar) {
544 int gbal = 0;
546 /* Line begins ^foo^bar */
547 isfirstch = 0;
548 inungetc(hatchar);
549 if (!(ehist = gethist(defev))
550 || !(sline = getargs(ehist, 0, getargc(ehist))))
551 return -1;
553 if (getsubsargs(sline, &gbal, &cflag))
554 return substfailed();
555 if (!hsubl)
556 return -1;
557 if (subst(&sline, hsubl, hsubr, gbal))
558 return substfailed();
559 } else {
560 /* Line doesn't begin ^foo^bar */
561 if (c != ' ')
562 isfirstch = 0;
563 if (c == '\\') {
564 int g = ingetc();
566 if (g != bangchar)
567 safeinungetc(g);
568 else {
569 qbang = 1;
570 return bangchar;
573 if (c != bangchar)
574 return c;
575 *hptr = '\0';
576 if ((c = ingetc()) == '{') {
577 bflag = cflag = 1;
578 c = ingetc();
580 if (c == '\"') {
581 stophist = 1;
582 return ingetc();
584 if ((!cflag && inblank(c)) || c == '=' || c == '(' || lexstop) {
585 safeinungetc(c);
586 return bangchar;
588 cflag = 0;
589 ptr = buf = zhalloc(buflen = 265);
591 /* get event number */
593 queue_signals();
594 if (c == '?') {
595 for (;;) {
596 c = ingetc();
597 if (c == '?' || c == '\n' || lexstop)
598 break;
599 else {
600 *ptr++ = c;
601 if (ptr == buf + buflen) {
602 buf = hrealloc(buf, buflen, 2 * buflen);
603 ptr = buf + buflen;
604 buflen *= 2;
608 if (c != '\n' && !lexstop)
609 c = ingetc();
610 *ptr = '\0';
611 mev = ev = hconsearch(hsubl = ztrdup(buf), &marg);
612 evset = 0;
613 if (ev == -1) {
614 herrflush();
615 unqueue_signals();
616 zerr("no such event: %s", buf);
617 return -1;
619 } else {
620 zlong t0;
622 for (;;) {
623 if (inblank(c) || c == ';' || c == ':' || c == '^' ||
624 c == '$' || c == '*' || c == '%' || c == '}' ||
625 c == '\'' || c == '"' || c == '`' || lexstop)
626 break;
627 if (ptr != buf) {
628 if (c == '-')
629 break;
630 if ((idigit(buf[0]) || buf[0] == '-') && !idigit(c))
631 break;
633 *ptr++ = c;
634 if (ptr == buf + buflen) {
635 buf = hrealloc(buf, buflen, 2 * buflen);
636 ptr = buf + buflen;
637 buflen *= 2;
639 if (c == '#' || c == bangchar) {
640 c = ingetc();
641 break;
643 c = ingetc();
645 if (ptr == buf &&
646 (c == '}' || c == ';' || c == '\'' || c == '"' || c == '`')) {
647 /* Neither event nor word designator, no expansion */
648 safeinungetc(c);
649 return bangchar;
651 *ptr = 0;
652 if (!*buf) {
653 if (c != '%') {
654 if (isset(CSHJUNKIEHISTORY))
655 ev = addhistnum(curhist,-1,HIST_FOREIGN);
656 else
657 ev = defev;
658 if (c == ':' && evset == -1)
659 evset = 0;
660 else
661 evset = 1;
662 } else {
663 if (marg != -1)
664 ev = mev;
665 else
666 ev = defev;
667 evset = 0;
669 } else if ((t0 = zstrtol(buf, NULL, 10))) {
670 ev = (t0 < 0) ? addhistnum(curhist,t0,HIST_FOREIGN) : t0;
671 evset = 1;
672 } else if ((unsigned)*buf == bangchar) {
673 ev = addhistnum(curhist,-1,HIST_FOREIGN);
674 evset = 1;
675 } else if (*buf == '#') {
676 ev = curhist;
677 evset = 1;
678 } else if ((ev = hcomsearch(buf)) == -1) {
679 herrflush();
680 unqueue_signals();
681 zerr("event not found: %s", buf);
682 return -1;
683 } else
684 evset = 1;
687 /* get the event */
689 if (!(ehist = gethist(defev = ev))) {
690 unqueue_signals();
691 return -1;
693 /* extract the relevant arguments */
695 argc = getargc(ehist);
696 if (c == ':') {
697 cflag = 1;
698 c = ingetc();
699 if (c == '%' && marg != -1) {
700 if (!evset) {
701 ehist = gethist(defev = mev);
702 argc = getargc(ehist);
703 } else {
704 herrflush();
705 unqueue_signals();
706 zerr("ambiguous history reference");
707 return -1;
712 if (c == '*') {
713 farg = 1;
714 larg = argc;
715 cflag = 0;
716 } else {
717 inungetc(c);
718 larg = farg = getargspec(argc, marg, evset);
719 if (larg == -2) {
720 unqueue_signals();
721 return -1;
723 if (farg != -1)
724 cflag = 0;
725 c = ingetc();
726 if (c == '*') {
727 cflag = 0;
728 larg = argc;
729 } else if (c == '-') {
730 cflag = 0;
731 larg = getargspec(argc, marg, evset);
732 if (larg == -2) {
733 unqueue_signals();
734 return -1;
736 if (larg == -1)
737 larg = argc - 1;
738 } else
739 inungetc(c);
741 if (farg == -1)
742 farg = 0;
743 if (larg == -1)
744 larg = argc;
745 if (!(sline = getargs(ehist, farg, larg))) {
746 unqueue_signals();
747 return -1;
749 unqueue_signals();
752 /* do the modifiers */
754 for (;;) {
755 c = (cflag) ? ':' : ingetc();
756 cflag = 0;
757 if (c == ':') {
758 int gbal = 0;
760 if ((c = ingetc()) == 'g') {
761 gbal = 1;
762 c = ingetc();
763 if (c != 's' && c != '&') {
764 zerr("'s' or '&' modifier expected after 'g'");
765 return -1;
768 switch (c) {
769 case 'p':
770 histdone = HISTFLAG_DONE | HISTFLAG_NOEXEC;
771 break;
772 case 'a':
773 if (!chabspath(&sline)) {
774 herrflush();
775 zerr("modifier failed: a");
776 return -1;
778 break;
780 case 'A':
781 if (!chrealpath(&sline)) {
782 herrflush();
783 zerr("modifier failed: A");
784 return -1;
786 break;
787 case 'c':
788 if (!(sline = equalsubstr(sline, 0, 0))) {
789 herrflush();
790 zerr("modifier failed: c");
791 return -1;
793 break;
794 case 'h':
795 if (!remtpath(&sline)) {
796 herrflush();
797 zerr("modifier failed: h");
798 return -1;
800 break;
801 case 'e':
802 if (!rembutext(&sline)) {
803 herrflush();
804 zerr("modifier failed: e");
805 return -1;
807 break;
808 case 'r':
809 if (!remtext(&sline)) {
810 herrflush();
811 zerr("modifier failed: r");
812 return -1;
814 break;
815 case 't':
816 if (!remlpaths(&sline)) {
817 herrflush();
818 zerr("modifier failed: t");
819 return -1;
821 break;
822 case 's':
823 if (getsubsargs(sline, &gbal, &cflag))
824 return -1; /* fall through */
825 case '&':
826 if (hsubl && hsubr) {
827 if (subst(&sline, hsubl, hsubr, gbal))
828 return substfailed();
829 } else {
830 herrflush();
831 zerr("no previous substitution");
832 return -1;
834 break;
835 case 'q':
836 quote(&sline);
837 break;
838 case 'Q':
840 int one = noerrs, oef = errflag;
842 noerrs = 1;
843 parse_subst_string(sline);
844 noerrs = one;
845 errflag = oef | (errflag & ERRFLAG_INT);
846 remnulargs(sline);
847 untokenize(sline);
849 break;
850 case 'x':
851 quotebreak(&sline);
852 break;
853 case 'l':
854 sline = casemodify(sline, CASMOD_LOWER);
855 break;
856 case 'u':
857 sline = casemodify(sline, CASMOD_UPPER);
858 break;
859 default:
860 herrflush();
861 zerr("illegal modifier: %c", c);
862 return -1;
864 } else {
865 if (c != '}' || !bflag)
866 inungetc(c);
867 if (c != '}' && bflag) {
868 zerr("'}' expected");
869 return -1;
871 break;
875 zshlex_raw_back_to_mark(lexraw_mark);
878 * Push the expanded value onto the input stack,
879 * marking this as a history word for purposes of the alias stack.
882 lexstop = 0;
883 /* this function is called only called from hgetc and only if *
884 * !(inbufflags & INP_ALIAS). History expansion should never be *
885 * done with INP_ALIAS (to prevent recursive history expansion and *
886 * histoty expansion of aliases). Escapes are not removed here. *
887 * This is now handled in hgetc. */
888 inpush(sline, INP_HIST, NULL); /* sline from heap, don't free */
889 histdone |= HISTFLAG_DONE;
890 if (isset(HISTVERIFY))
891 histdone |= HISTFLAG_NOEXEC | HISTFLAG_RECALL;
893 /* Don't try and re-expand line. */
894 return ingetc();
897 /* unget a char and remove it from chline. It can only be used *
898 * to unget a character returned by hgetc. */
900 static void
901 ihungetc(int c)
903 int doit = 1;
905 while (!lexstop && !errflag) {
906 if (hptr[-1] != (char) c && stophist < 4 &&
907 hptr > chline + 1 && hptr[-1] == '\n' && hptr[-2] == '\\')
908 hungetc('\n'), hungetc('\\');
910 if (expanding) {
911 zlemetacs--;
912 zlemetall--;
913 exlast++;
915 if ((inbufflags & (INP_ALIAS|INP_HIST)) != INP_ALIAS) {
916 DPUTS(hptr <= chline, "BUG: hungetc attempted at buffer start");
917 hptr--;
918 DPUTS(*hptr != (char) c, "BUG: wrong character in hungetc() ");
919 qbang = (c == bangchar && stophist < 2 &&
920 hptr > chline && hptr[-1] == '\\');
921 } else {
922 /* No active bangs in aliases */
923 qbang = 0;
925 if (doit)
926 inungetc(c);
927 if (!qbang)
928 return;
929 doit = !stophist && ((inbufflags & INP_HIST) ||
930 !(inbufflags & INP_ALIAS));
931 c = '\\';
935 /* begin reading a string */
937 /**/
938 mod_export void
939 strinbeg(int dohist)
941 strin++;
942 hbegin(dohist);
943 lexinit();
945 * Also initialise some variables owned by the parser but
946 * used for communication between the parser and lexer.
948 init_parse_status();
951 /* done reading a string */
953 /**/
954 mod_export void
955 strinend(void)
957 hend(NULL);
958 DPUTS(!strin, "BUG: strinend() called without strinbeg()");
959 strin--;
960 isfirstch = 1;
961 histdone = 0;
964 /* dummy functions to use instead of hwaddc(), hwbegin(), and hwend() when
965 * they aren't needed */
967 static void
968 nohw(UNUSED(int c))
972 static void
973 nohwe(void)
977 /* these functions handle adding/removing curline to/from the hist_ring */
979 static void
980 linkcurline(void)
982 if (!hist_ring)
983 hist_ring = curline.up = curline.down = &curline;
984 else {
985 curline.up = hist_ring;
986 curline.down = hist_ring->down;
987 hist_ring->down = hist_ring->down->up = &curline;
988 hist_ring = &curline;
990 curline.histnum = ++curhist;
993 static void
994 unlinkcurline(void)
996 curline.up->down = curline.down;
997 curline.down->up = curline.up;
998 if (hist_ring == &curline) {
999 if (!histlinect)
1000 hist_ring = NULL;
1001 else
1002 hist_ring = curline.up;
1004 curhist--;
1007 /* initialize the history mechanism */
1009 /**/
1010 mod_export void
1011 hbegin(int dohist)
1013 char *hf;
1015 isfirstln = isfirstch = 1;
1016 errflag &= ~ERRFLAG_ERROR;
1017 histdone = 0;
1018 if (!dohist)
1019 stophist = 2;
1020 else if (dohist != 2)
1021 stophist = (!interact || unset(SHINSTDIN)) ? 2 : 0;
1022 else
1023 stophist = 0;
1025 * pws: We used to test for "|| (inbufflags & INP_ALIAS)"
1026 * in this test, but at this point we don't have input
1027 * set up up so this can trigger unnecessarily.
1028 * I don't see how the test at this point could ever be
1029 * useful, since we only get here when we're initialising
1030 * the history mechanism, before we've done any input.
1032 * (I also don't see any point where this function is called with
1033 * dohist=0.)
1035 if (stophist == 2) {
1036 chline = hptr = NULL;
1037 hlinesz = 0;
1038 chwords = NULL;
1039 chwordlen = 0;
1040 hgetc = ingetc;
1041 hungetc = inungetc;
1042 hwaddc = nohw;
1043 hwbegin = nohw;
1044 hwend = nohwe;
1045 addtoline = nohw;
1046 } else {
1047 chline = hptr = zshcalloc(hlinesz = 64);
1048 chwords = zalloc((chwordlen = 64) * sizeof(short));
1049 hgetc = ihgetc;
1050 hungetc = ihungetc;
1051 hwaddc = ihwaddc;
1052 hwbegin = ihwbegin;
1053 hwend = ihwend;
1054 addtoline = iaddtoline;
1055 if (!isset(BANGHIST))
1056 stophist = 4;
1058 chwordpos = 0;
1060 if (hist_ring && !hist_ring->ftim && !strin)
1061 hist_ring->ftim = time(NULL);
1062 if ((dohist == 2 || (interact && isset(SHINSTDIN))) && !strin) {
1063 histactive = HA_ACTIVE;
1064 attachtty(mypgrp);
1065 linkcurline();
1066 defev = addhistnum(curhist, -1, HIST_FOREIGN);
1067 } else
1068 histactive = HA_ACTIVE | HA_NOINC;
1070 hf = getsparam("HISTFILE");
1072 * For INCAPPENDHISTORYTIME, when interactive, save the history here
1073 * as it gives a better estimate of the times of commands.
1075 * If INCAPPENDHISTORY is also set we've already done it.
1077 * If SHAREHISTORY is also set continue to do so in the
1078 * standard place, because that's safer about reading and
1079 * rewriting history atomically.
1081 * The histsave_stack_pos test won't usually fail here.
1082 * We need to test the opposite for the hend() case because we
1083 * need to save in the history file we've switched to, but then
1084 * we pop immediately after that so the variable becomes zero.
1085 * We will already have saved the line and restored the history
1086 * so that (correctly) nothing happens here. But it shows
1087 * I thought about it.
1089 if (isset(INCAPPENDHISTORYTIME) && !isset(SHAREHISTORY) &&
1090 !isset(INCAPPENDHISTORY) &&
1091 !(histactive & HA_NOINC) && !strin && histsave_stack_pos == 0)
1092 savehistfile(hf, 0, HFILE_USE_OPTIONS | HFILE_FAST);
1095 /**/
1096 void
1097 histreduceblanks(void)
1099 int i, len, pos, needblank, spacecount = 0, trunc_ok;
1100 char *lastptr, *ptr;
1102 if (isset(HISTIGNORESPACE))
1103 while (chline[spacecount] == ' ') spacecount++;
1105 for (i = 0, len = spacecount; i < chwordpos; i += 2) {
1106 len += chwords[i+1] - chwords[i]
1107 + (i > 0 && chwords[i] > chwords[i-1]);
1109 if (chline[len] == '\0')
1110 return;
1112 /* Remember where the delimited words end */
1113 if (chwordpos)
1114 lastptr = chline + chwords[chwordpos-1];
1115 else
1116 lastptr = chline;
1118 for (i = 0, pos = spacecount; i < chwordpos; i += 2) {
1119 len = chwords[i+1] - chwords[i];
1120 needblank = (i < chwordpos-2 && chwords[i+2] > chwords[i+1]);
1121 if (pos != chwords[i]) {
1122 memmove(chline + pos, chline + chwords[i], len + needblank);
1123 chwords[i] = pos;
1124 chwords[i+1] = chwords[i] + len;
1126 pos += len + needblank;
1130 * A terminating comment isn't recorded as a word.
1131 * Only truncate the line if just whitespace remains.
1133 trunc_ok = 1;
1134 for (ptr = lastptr; *ptr; ptr++) {
1135 if (!inblank(*ptr)) {
1136 trunc_ok = 0;
1137 break;
1140 if (trunc_ok) {
1141 chline[pos] = '\0';
1142 } else {
1143 ptr = chline + pos;
1144 while ((*ptr++ = *lastptr++))
1149 /**/
1150 void
1151 histremovedups(void)
1153 Histent he, next;
1154 for (he = hist_ring; he; he = next) {
1155 next = up_histent(he);
1156 if (he->node.flags & HIST_DUP)
1157 freehistnode(&he->node);
1161 /**/
1162 mod_export zlong
1163 addhistnum(zlong hl, int n, int xflags)
1165 int dir = n < 0? -1 : n > 0? 1 : 0;
1166 Histent he = gethistent(hl, dir);
1168 if (!he)
1169 return 0;
1170 if (he->histnum != hl)
1171 n -= dir;
1172 if (n)
1173 he = movehistent(he, n, xflags);
1174 if (!he)
1175 return dir < 0? firsthist() - 1 : curhist + 1;
1176 return he->histnum;
1179 /**/
1180 mod_export Histent
1181 movehistent(Histent he, int n, int xflags)
1183 while (n < 0) {
1184 if (!(he = up_histent(he)))
1185 return NULL;
1186 if (!(he->node.flags & xflags))
1187 n++;
1189 while (n > 0) {
1190 if (!(he = down_histent(he)))
1191 return NULL;
1192 if (!(he->node.flags & xflags))
1193 n--;
1195 checkcurline(he);
1196 return he;
1199 /**/
1200 mod_export Histent
1201 up_histent(Histent he)
1203 return !he || he->up == hist_ring? NULL : he->up;
1206 /**/
1207 mod_export Histent
1208 down_histent(Histent he)
1210 return he == hist_ring? NULL : he->down;
1213 /**/
1214 mod_export Histent
1215 gethistent(zlong ev, int nearmatch)
1217 Histent he;
1219 if (!hist_ring)
1220 return NULL;
1222 if (ev - hist_ring->down->histnum < hist_ring->histnum - ev) {
1223 for (he = hist_ring->down; he->histnum < ev; he = he->down) ;
1224 if (he->histnum != ev) {
1225 if (nearmatch == 0
1226 || (nearmatch < 0 && (he = up_histent(he)) == NULL))
1227 return NULL;
1230 else {
1231 for (he = hist_ring; he->histnum > ev; he = he->up) ;
1232 if (he->histnum != ev) {
1233 if (nearmatch == 0
1234 || (nearmatch > 0 && (he = down_histent(he)) == NULL))
1235 return NULL;
1239 checkcurline(he);
1240 return he;
1243 static void
1244 putoldhistentryontop(short keep_going)
1246 static Histent next = NULL;
1247 Histent he = (keep_going || !hist_ring) ? next : hist_ring->down;
1248 if (he)
1249 next = he->down;
1250 else
1251 return;
1252 if (isset(HISTEXPIREDUPSFIRST) && !(he->node.flags & HIST_DUP)) {
1253 static zlong max_unique_ct = 0;
1254 if (!keep_going)
1255 max_unique_ct = savehistsiz;
1256 do {
1257 if (max_unique_ct-- <= 0 || he == hist_ring) {
1258 max_unique_ct = 0;
1259 he = hist_ring->down;
1260 next = hist_ring;
1261 break;
1263 he = next;
1264 next = he->down;
1265 } while (!(he->node.flags & HIST_DUP));
1267 if (he != hist_ring->down) {
1268 he->up->down = he->down;
1269 he->down->up = he->up;
1270 he->up = hist_ring;
1271 he->down = hist_ring->down;
1272 hist_ring->down = he->down->up = he;
1274 hist_ring = he;
1277 /**/
1278 Histent
1279 prepnexthistent(void)
1281 Histent he;
1282 int curline_in_ring = hist_ring == &curline;
1284 if (curline_in_ring)
1285 unlinkcurline();
1286 if (hist_ring && hist_ring->node.flags & HIST_TMPSTORE) {
1287 curhist--;
1288 freehistnode(&hist_ring->node);
1291 if (histlinect < histsiz || !hist_ring) {
1292 he = (Histent)zshcalloc(sizeof *he);
1293 if (!hist_ring)
1294 hist_ring = he->up = he->down = he;
1295 else {
1296 he->up = hist_ring;
1297 he->down = hist_ring->down;
1298 hist_ring->down = he->down->up = he;
1299 hist_ring = he;
1301 histlinect++;
1303 else {
1304 putoldhistentryontop(0);
1305 freehistdata(hist_ring, 0);
1306 he = hist_ring;
1308 he->histnum = ++curhist;
1309 if (curline_in_ring)
1310 linkcurline();
1311 return he;
1314 /* A helper function for hend() */
1316 static int
1317 should_ignore_line(Eprog prog)
1319 if (isset(HISTIGNORESPACE)) {
1320 if (*chline == ' ' || aliasspaceflag)
1321 return 1;
1324 if (!prog)
1325 return 0;
1327 if (isset(HISTNOFUNCTIONS)) {
1328 Wordcode pc = prog->prog;
1329 wordcode code = *pc;
1330 if (wc_code(code) == WC_LIST && WC_LIST_TYPE(code) & Z_SIMPLE
1331 && wc_code(pc[2]) == WC_FUNCDEF)
1332 return 1;
1335 if (isset(HISTNOSTORE)) {
1336 char *b = getjobtext(prog, NULL);
1337 int saw_builtin;
1338 if (*b == 'b' && strncmp(b,"builtin ",8) == 0) {
1339 b += 8;
1340 saw_builtin = 1;
1341 } else
1342 saw_builtin = 0;
1343 if (*b == 'h' && strncmp(b,"history",7) == 0 && (!b[7] || b[7] == ' ')
1344 && (saw_builtin || !shfunctab->getnode(shfunctab,"history")))
1345 return 1;
1346 if (*b == 'r' && (!b[1] || b[1] == ' ')
1347 && (saw_builtin || !shfunctab->getnode(shfunctab,"r")))
1348 return 1;
1349 if (*b == 'f' && b[1] == 'c' && b[2] == ' ' && b[3] == '-'
1350 && (saw_builtin || !shfunctab->getnode(shfunctab,"fc"))) {
1351 b += 3;
1352 do {
1353 if (*++b == 'l')
1354 return 1;
1355 } while (ialpha(*b));
1359 return 0;
1362 /* say we're done using the history mechanism */
1364 /**/
1365 mod_export int
1366 hend(Eprog prog)
1368 LinkList hookargs = newlinklist();
1369 int flag, hookret, stack_pos = histsave_stack_pos;
1371 * save:
1372 * 0: don't save
1373 * 1: save normally
1374 * -1: save temporarily, delete after next line
1375 * -2: save internally but mark for not writing
1377 int save = 1;
1378 char *hf;
1380 DPUTS(stophist != 2 && !(inbufflags & INP_ALIAS) && !chline,
1381 "BUG: chline is NULL in hend()");
1382 queue_signals();
1383 if (histdone & HISTFLAG_SETTY)
1384 settyinfo(&shttyinfo);
1385 if (!(histactive & HA_NOINC))
1386 unlinkcurline();
1387 if (histactive & HA_NOINC) {
1388 zfree(chline, hlinesz);
1389 zfree(chwords, chwordlen*sizeof(short));
1390 chline = hptr = NULL;
1391 chwords = NULL;
1392 histactive = 0;
1393 unqueue_signals();
1394 return 1;
1396 if (hist_ignore_all_dups != isset(HISTIGNOREALLDUPS)
1397 && (hist_ignore_all_dups = isset(HISTIGNOREALLDUPS)) != 0)
1398 histremovedups();
1400 if (hptr) {
1402 * Added the following in case the test "hptr < chline + 1"
1403 * is more than just paranoia.
1405 DPUTS(hptr < chline, "History end pointer off start of line");
1406 *hptr = '\0';
1408 addlinknode(hookargs, "zshaddhistory");
1409 addlinknode(hookargs, chline);
1410 callhookfunc("zshaddhistory", hookargs, 1, &hookret);
1411 /* For history sharing, lock history file once for both read and write */
1412 hf = getsparam("HISTFILE");
1413 if (isset(SHAREHISTORY) && !lockhistfile(hf, 0)) {
1414 readhistfile(hf, 0, HFILE_USE_OPTIONS | HFILE_FAST);
1415 curline.histnum = curhist+1;
1417 flag = histdone;
1418 histdone = 0;
1419 if (hptr < chline + 1)
1420 save = 0;
1421 else {
1422 if (hptr[-1] == '\n') {
1423 if (chline[1]) {
1424 *--hptr = '\0';
1425 } else
1426 save = 0;
1428 if (chwordpos <= 2)
1429 save = 0;
1430 else if (should_ignore_line(prog))
1431 save = -1;
1432 else if (hookret == 2)
1433 save = -2;
1434 else if (hookret)
1435 save = -1;
1437 if (flag & (HISTFLAG_DONE | HISTFLAG_RECALL)) {
1438 char *ptr;
1440 ptr = ztrdup(chline);
1441 if ((flag & (HISTFLAG_DONE | HISTFLAG_RECALL)) == HISTFLAG_DONE) {
1442 zputs(ptr, shout);
1443 fputc('\n', shout);
1444 fflush(shout);
1446 if (flag & HISTFLAG_RECALL) {
1447 zpushnode(bufstack, ptr);
1448 save = 0;
1449 } else
1450 zsfree(ptr);
1452 if (save || *chline == ' ') {
1453 Histent he;
1454 for (he = hist_ring; he && he->node.flags & HIST_FOREIGN;
1455 he = up_histent(he)) ;
1456 if (he && he->node.flags & HIST_TMPSTORE) {
1457 if (he == hist_ring)
1458 curline.histnum = curhist--;
1459 freehistnode(&he->node);
1462 if (save) {
1463 Histent he;
1464 int newflags;
1466 #ifdef DEBUG
1467 /* debugging only */
1468 if (chwordpos%2) {
1469 hwend();
1470 DPUTS(1, "BUG: uncompleted line in history");
1472 #endif
1473 /* get rid of pesky \n which we've already nulled out */
1474 if (chwordpos > 1 && !chline[chwords[chwordpos-2]]) {
1475 chwordpos -= 2;
1476 /* strip superfluous blanks, if desired */
1477 if (isset(HISTREDUCEBLANKS))
1478 histreduceblanks();
1480 if (save == -1)
1481 newflags = HIST_TMPSTORE;
1482 else if (save == -2)
1483 newflags = HIST_NOWRITE;
1484 else
1485 newflags = 0;
1486 if ((isset(HISTIGNOREDUPS) || isset(HISTIGNOREALLDUPS)) && save > 0
1487 && hist_ring && histstrcmp(chline, hist_ring->node.nam) == 0) {
1488 /* This history entry compares the same as the previous.
1489 * In case minor changes were made, we overwrite the
1490 * previous one with the current one. This also gets the
1491 * timestamp right. Perhaps, preserve the HIST_OLD flag.
1493 he = hist_ring;
1494 newflags |= he->node.flags & HIST_OLD; /* Avoid re-saving */
1495 freehistdata(he, 0);
1496 curline.histnum = curhist;
1497 } else
1498 he = prepnexthistent();
1500 he->node.nam = ztrdup(chline);
1501 he->stim = time(NULL);
1502 he->ftim = 0L;
1503 he->node.flags = newflags;
1505 if ((he->nwords = chwordpos/2)) {
1506 he->words = (short *)zalloc(chwordpos * sizeof(short));
1507 memcpy(he->words, chwords, chwordpos * sizeof(short));
1509 if (!(newflags & HIST_TMPSTORE))
1510 addhistnode(histtab, he->node.nam, he);
1512 zfree(chline, hlinesz);
1513 zfree(chwords, chwordlen*sizeof(short));
1514 chline = hptr = NULL;
1515 chwords = NULL;
1516 histactive = 0;
1518 * For normal INCAPPENDHISTORY case and reasoning, see hbegin().
1520 if (isset(SHAREHISTORY) ? histfileIsLocked() :
1521 (isset(INCAPPENDHISTORY) || (isset(INCAPPENDHISTORYTIME) &&
1522 histsave_stack_pos != 0)))
1523 savehistfile(hf, 0, HFILE_USE_OPTIONS | HFILE_FAST);
1524 unlockhistfile(hf); /* It's OK to call this even if we aren't locked */
1526 * No good reason for the user to push the history more than once, but
1527 * it's easy to be tidy...
1529 while (histsave_stack_pos > stack_pos)
1530 pophiststack();
1531 unqueue_signals();
1532 return !(flag & HISTFLAG_NOEXEC || errflag);
1535 /* begin a word */
1537 /**/
1538 void
1539 ihwbegin(int offset)
1541 if (stophist == 2 || (histactive & HA_INWORD) ||
1542 (inbufflags & (INP_ALIAS|INP_HIST)) == INP_ALIAS)
1543 return;
1544 if (chwordpos%2)
1545 chwordpos--; /* make sure we're on a word start, not end */
1546 chwords[chwordpos++] = hptr - chline + offset;
1549 /* add a word to the history List */
1551 /**/
1552 void
1553 ihwend(void)
1555 if (stophist == 2 || (histactive & HA_INWORD) ||
1556 (inbufflags & (INP_ALIAS|INP_HIST)) == INP_ALIAS)
1557 return;
1558 if (chwordpos%2 && chline) {
1559 /* end of word reached and we've already begun a word */
1560 if (hptr > chline + chwords[chwordpos-1]) {
1561 chwords[chwordpos++] = hptr - chline;
1562 if (chwordpos >= chwordlen) {
1563 chwords = (short *) realloc(chwords,
1564 (chwordlen += 32) *
1565 sizeof(short));
1567 } else {
1568 /* scrub that last word, it doesn't exist */
1569 chwordpos--;
1574 /* Go back to immediately after the last word, skipping space. */
1576 /**/
1577 void
1578 histbackword(void)
1580 if (!(chwordpos%2) && chwordpos)
1581 hptr = chline + chwords[chwordpos-1];
1584 /* Get the start and end point of the current history word */
1586 /**/
1587 static void
1588 hwget(char **startptr)
1590 int pos = chwordpos - 2;
1592 #ifdef DEBUG
1593 /* debugging only */
1594 if (!chwordpos) {
1595 /* no words available */
1596 DPUTS(1, "BUG: hwget() called with no words");
1597 *startptr = "";
1598 return;
1600 else if (chwordpos%2) {
1601 DPUTS(1, "BUG: hwget() called in middle of word");
1602 *startptr = "";
1603 return;
1605 #endif
1607 *startptr = chline + chwords[pos];
1608 chline[chwords[++pos]] = '\0';
1611 /* Replace the current history word with rep, if different */
1613 /**/
1614 void
1615 hwrep(char *rep)
1617 char *start;
1618 hwget(&start);
1620 if (!strcmp(rep, start))
1621 return;
1623 hptr = start;
1624 chwordpos = chwordpos - 2;
1625 hwbegin(0);
1626 qbang = 1;
1627 while (*rep)
1628 hwaddc(*rep++);
1629 hwend();
1632 /* Get the entire current line, deleting it in the history. */
1634 /**/
1635 mod_export char *
1636 hgetline(void)
1638 /* Currently only used by pushlineoredit().
1639 * It's necessary to prevent that from getting too pally with
1640 * the history code.
1642 char *ret;
1644 if (!chline || hptr == chline)
1645 return NULL;
1646 *hptr = '\0';
1647 ret = dupstring(chline);
1649 /* reset line */
1650 hptr = chline;
1651 chwordpos = 0;
1653 return ret;
1656 /* get an argument specification */
1658 /**/
1659 static int
1660 getargspec(int argc, int marg, int evset)
1662 int c, ret = -1;
1664 if ((c = ingetc()) == '0')
1665 return 0;
1666 if (idigit(c)) {
1667 ret = 0;
1668 while (idigit(c)) {
1669 ret = ret * 10 + c - '0';
1670 c = ingetc();
1672 inungetc(c);
1673 } else if (c == '^')
1674 ret = 1;
1675 else if (c == '$')
1676 ret = argc;
1677 else if (c == '%') {
1678 if (evset) {
1679 herrflush();
1680 zerr("Ambiguous history reference");
1681 return -2;
1683 if (marg == -1) {
1684 herrflush();
1685 zerr("%% with no previous word matched");
1686 return -2;
1688 ret = marg;
1689 } else
1690 inungetc(c);
1691 return ret;
1694 /* do ?foo? search */
1696 /**/
1697 static zlong
1698 hconsearch(char *str, int *marg)
1700 int t1 = 0;
1701 char *s;
1702 Histent he;
1704 for (he = up_histent(hist_ring); he; he = up_histent(he)) {
1705 if (he->node.flags & HIST_FOREIGN)
1706 continue;
1707 if ((s = strstr(he->node.nam, str))) {
1708 int pos = s - he->node.nam;
1709 while (t1 < he->nwords && he->words[2*t1] <= pos)
1710 t1++;
1711 *marg = t1 - 1;
1712 return he->histnum;
1715 return -1;
1718 /* do !foo search */
1720 /**/
1721 zlong
1722 hcomsearch(char *str)
1724 Histent he;
1725 int len = strlen(str);
1727 for (he = up_histent(hist_ring); he; he = up_histent(he)) {
1728 if (he->node.flags & HIST_FOREIGN)
1729 continue;
1730 if (strncmp(he->node.nam, str, len) == 0)
1731 return he->histnum;
1733 return -1;
1736 /* various utilities for : modifiers */
1738 /**/
1740 chabspath(char **junkptr)
1742 char *current, *dest;
1744 if (!**junkptr)
1745 return 1;
1747 if (**junkptr != '/') {
1748 *junkptr = zhtricat(metafy(zgetcwd(), -1, META_HEAPDUP), "/", *junkptr);
1751 current = *junkptr;
1752 dest = *junkptr;
1754 #ifdef HAVE_SUPERROOT
1755 while (*current == '/' && current[1] == '.' && current[2] == '.' &&
1756 (!current[3] || current[3] == '/')) {
1757 *dest++ = '/';
1758 *dest++ = '.';
1759 *dest++ = '.';
1760 current += 3;
1762 #endif
1764 for (;;) {
1765 if (*current == '/') {
1766 #ifdef __CYGWIN__
1767 if (current == *junkptr && current[1] == '/')
1768 *dest++ = *current++;
1769 #endif
1770 *dest++ = *current++;
1771 while (*current == '/')
1772 current++;
1773 } else if (!*current) {
1774 while (dest > *junkptr + 1 && dest[-1] == '/')
1775 dest--;
1776 *dest = '\0';
1777 break;
1778 } else if (current[0] == '.' && current[1] == '.' &&
1779 (!current[2] || current[2] == '/')) {
1780 if (current == *junkptr || dest == *junkptr) {
1781 *dest++ = '.';
1782 *dest++ = '.';
1783 current += 2;
1784 } else if (dest > *junkptr + 2 &&
1785 !strncmp(dest - 3, "../", 3)) {
1786 *dest++ = '.';
1787 *dest++ = '.';
1788 current += 2;
1789 } else if (dest > *junkptr + 1) {
1790 *dest = '\0';
1791 for (dest--;
1792 dest > *junkptr + 1 && dest[-1] != '/';
1793 dest--);
1794 if (dest[-1] != '/')
1795 dest--;
1796 current += 2;
1797 if (*current == '/')
1798 current++;
1799 } else if (dest == *junkptr + 1) {
1800 /* This might break with Cygwin's leading double slashes? */
1801 current += 2;
1802 } else {
1803 return 0;
1805 } else if (current[0] == '.' && (current[1] == '/' || !current[1])) {
1806 while (*++current == '/');
1807 } else {
1808 while (*current != '/' && *current != '\0')
1809 if ((*dest++ = *current++) == Meta)
1810 *dest++ = *current++;
1813 return 1;
1816 /**/
1818 chrealpath(char **junkptr)
1820 char *str;
1821 #ifdef HAVE_REALPATH
1822 # ifdef REALPATH_ACCEPTS_NULL
1823 char *lastpos, *nonreal, *real;
1824 # else
1825 char *lastpos, *nonreal, pathbuf[PATH_MAX];
1826 char *real = pathbuf;
1827 # endif
1828 #endif
1830 if (!**junkptr)
1831 return 1;
1833 /* Notice that this means ..'s are applied before symlinks are resolved! */
1834 if (!chabspath(junkptr))
1835 return 0;
1837 #ifndef HAVE_REALPATH
1838 return 1;
1839 #else
1841 * Notice that this means you cannot pass relative paths into this
1842 * function!
1844 if (**junkptr != '/')
1845 return 0;
1847 unmetafy(*junkptr, NULL);
1849 lastpos = strend(*junkptr);
1850 nonreal = lastpos + 1;
1852 while (!
1853 #ifdef REALPATH_ACCEPTS_NULL
1854 /* realpath() with a NULL second argument uses malloc() to get
1855 * memory so we don't need to worry about overflowing PATH_MAX */
1856 (real = realpath(*junkptr, NULL))
1857 #else
1858 realpath(*junkptr, real)
1859 #endif
1861 if (errno == EINVAL || errno == ENOMEM)
1862 return 0;
1864 if (nonreal == *junkptr) {
1865 #ifndef REALPATH_ACCEPTS_NULL
1866 real = NULL;
1867 #endif
1868 break;
1871 while (*nonreal != '/' && nonreal >= *junkptr)
1872 nonreal--;
1873 *nonreal = '\0';
1876 str = nonreal;
1877 while (str <= lastpos) {
1878 if (*str == '\0')
1879 *str = '/';
1880 str++;
1883 if (real) {
1884 *junkptr = metafy(str = bicat(real, nonreal), -1, META_HEAPDUP);
1885 zsfree(str);
1886 #ifdef REALPATH_ACCEPTS_NULL
1887 free(real);
1888 #endif
1889 } else {
1890 *junkptr = metafy(nonreal, lastpos - nonreal + 1, META_HEAPDUP);
1892 #endif
1894 return 1;
1897 /**/
1899 remtpath(char **junkptr)
1901 char *str = strend(*junkptr);
1903 /* ignore trailing slashes */
1904 while (str >= *junkptr && IS_DIRSEP(*str))
1905 --str;
1906 /* skip filename */
1907 while (str >= *junkptr && !IS_DIRSEP(*str))
1908 --str;
1909 if (str < *junkptr) {
1910 if (IS_DIRSEP(**junkptr))
1911 *junkptr = dupstring ("/");
1912 else
1913 *junkptr = dupstring (".");
1915 return 0;
1917 /* repeated slashes are considered like a single slash */
1918 while (str > *junkptr && IS_DIRSEP(str[-1]))
1919 --str;
1920 /* never erase the root slash */
1921 if (str == *junkptr) {
1922 ++str;
1923 /* Leading doubled slashes (`//') have a special meaning on cygwin
1924 and some old flavor of UNIX, so we do not assimilate them to
1925 a single slash. However a greater number is ok to squeeze. */
1926 if (IS_DIRSEP(*str) && !IS_DIRSEP(str[1]))
1927 ++str;
1929 *str = '\0';
1930 return 1;
1933 /**/
1935 remtext(char **junkptr)
1937 char *str;
1939 for (str = strend(*junkptr); str >= *junkptr && !IS_DIRSEP(*str); --str)
1940 if (*str == '.') {
1941 *str = '\0';
1942 return 1;
1944 return 0;
1947 /**/
1949 rembutext(char **junkptr)
1951 char *str;
1953 for (str = strend(*junkptr); str >= *junkptr && !IS_DIRSEP(*str); --str)
1954 if (*str == '.') {
1955 *junkptr = dupstring(str + 1); /* .xx or xx? */
1956 return 1;
1958 /* no extension */
1959 *junkptr = dupstring ("");
1960 return 0;
1963 /**/
1964 mod_export int
1965 remlpaths(char **junkptr)
1967 char *str = strend(*junkptr);
1969 if (IS_DIRSEP(*str)) {
1970 /* remove trailing slashes */
1971 while (str >= *junkptr && IS_DIRSEP(*str))
1972 --str;
1973 str[1] = '\0';
1975 for (; str >= *junkptr; --str)
1976 if (IS_DIRSEP(*str)) {
1977 *str = '\0';
1978 *junkptr = dupstring(str + 1);
1979 return 1;
1981 return 0;
1985 * Return modified version of str from the heap with modification
1986 * according to one of the CASMOD_* types defined in zsh.h; CASMOD_NONE
1987 * is not handled, for obvious reasons.
1990 /**/
1991 char *
1992 casemodify(char *str, int how)
1994 char *str2 = zhalloc(2 * strlen(str) + 1);
1995 char *ptr2 = str2;
1996 int nextupper = 1;
1998 #ifdef MULTIBYTE_SUPPORT
1999 if (isset(MULTIBYTE)) {
2000 VARARR(char, mbstr, MB_CUR_MAX);
2001 mbstate_t ps;
2003 mb_charinit();
2004 memset(&ps, 0, sizeof(ps));
2005 while (*str) {
2006 wint_t wc;
2007 int len = mb_metacharlenconv(str, &wc), mod = 0, len2;
2009 * wc is set to WEOF if the start of str couldn't be
2010 * converted. Presumably WEOF doesn't match iswlower(), but
2011 * better be safe.
2013 if (wc == WEOF) {
2014 while (len--)
2015 *ptr2++ = *str++;
2016 /* not alphanumeric */
2017 nextupper = 1;
2018 continue;
2020 switch (how) {
2021 case CASMOD_LOWER:
2022 if (iswupper(wc)) {
2023 wc = towlower(wc);
2024 mod = 1;
2026 break;
2028 case CASMOD_UPPER:
2029 if (iswlower(wc)) {
2030 wc = towupper(wc);
2031 mod = 1;
2033 break;
2035 case CASMOD_CAPS:
2036 default: /* shuts up compiler */
2037 if (IS_COMBINING(wc))
2038 break;
2039 if (!iswalnum(wc))
2040 nextupper = 1;
2041 else if (nextupper) {
2042 if (iswlower(wc)) {
2043 wc = towupper(wc);
2044 mod = 1;
2046 nextupper = 0;
2047 } else if (iswupper(wc)) {
2048 wc = towlower(wc);
2049 mod = 1;
2051 break;
2053 if (mod && (len2 = wcrtomb(mbstr, wc, &ps)) > 0) {
2054 char *mbptr;
2056 for (mbptr = mbstr; mbptr < mbstr + len2; mbptr++) {
2057 if (imeta(STOUC(*mbptr))) {
2058 *ptr2++ = Meta;
2059 *ptr2++ = *mbptr ^ 32;
2060 } else
2061 *ptr2++ = *mbptr;
2063 str += len;
2064 } else {
2065 while (len--)
2066 *ptr2++ = *str++;
2070 else
2071 #endif
2072 while (*str) {
2073 int c;
2074 if (*str == Meta) {
2075 c = str[1] ^ 32;
2076 str += 2;
2077 } else
2078 c = *str++;
2079 switch (how) {
2080 case CASMOD_LOWER:
2081 if (isupper(c))
2082 c = tolower(c);
2083 break;
2085 case CASMOD_UPPER:
2086 if (islower(c))
2087 c = toupper(c);
2088 break;
2090 case CASMOD_CAPS:
2091 default: /* shuts up compiler */
2092 if (!ialnum(c))
2093 nextupper = 1;
2094 else if (nextupper) {
2095 if (islower(c))
2096 c = toupper(c);
2097 nextupper = 0;
2098 } else if (isupper(c))
2099 c = tolower(c);
2100 break;
2102 if (imeta(c)) {
2103 *ptr2++ = Meta;
2104 *ptr2++ = c ^ 32;
2105 } else
2106 *ptr2++ = c;
2108 *ptr2 = '\0';
2109 return str2;
2114 * Substitute "in" for "out" in "*strptr" and update "*strptr".
2115 * If "gbal", do global substitution.
2117 * This returns a result from the heap. There seems to have
2118 * been some confusion on this point.
2121 /**/
2123 subst(char **strptr, char *in, char *out, int gbal)
2125 char *str = *strptr, *substcut, *sptr;
2126 int off, inlen, outlen;
2128 if (!*in)
2129 in = str, gbal = 0;
2131 if (isset(HISTSUBSTPATTERN)) {
2132 int fl = SUB_LONG|SUB_REST|SUB_RETFAIL;
2133 char *oldin = in;
2134 if (gbal)
2135 fl |= SUB_GLOBAL;
2136 if (*in == '#' || *in == Pound) {
2137 /* anchor at head, flag needed if SUB_END is also set */
2138 fl |= SUB_START;
2139 in++;
2141 if (*in == '%') {
2142 /* anchor at tail */
2143 in++;
2144 fl |= SUB_END;
2146 if (in == oldin) {
2147 /* no anchor, substring match */
2148 fl |= SUB_SUBSTR;
2150 if (in == str)
2151 in = dupstring(in);
2152 if (parse_subst_string(in) || errflag)
2153 return 1;
2154 if (parse_subst_string(out) || errflag)
2155 return 1;
2156 singsub(&in);
2157 if (getmatch(strptr, in, fl, 1, out))
2158 return 0;
2159 } else {
2160 if ((substcut = (char *)strstr(str, in))) {
2161 inlen = strlen(in);
2162 sptr = convamps(out, in, inlen);
2163 outlen = strlen(sptr);
2165 do {
2166 *substcut = '\0';
2167 off = substcut - *strptr + outlen;
2168 substcut += inlen;
2169 *strptr = zhtricat(*strptr, sptr, substcut);
2170 str = (char *)*strptr + off;
2171 } while (gbal && (substcut = (char *)strstr(str, in)));
2173 return 0;
2177 return 1;
2180 /**/
2181 static char *
2182 convamps(char *out, char *in, int inlen)
2184 char *ptr, *ret, *pp;
2185 int slen, sdup = 0;
2187 for (ptr = out, slen = 0; *ptr; ptr++, slen++)
2188 if (*ptr == '\\')
2189 ptr++, sdup = 1;
2190 else if (*ptr == '&')
2191 slen += inlen - 1, sdup = 1;
2192 if (!sdup)
2193 return out;
2194 ret = pp = (char *) zhalloc(slen + 1);
2195 for (ptr = out; *ptr; ptr++)
2196 if (*ptr == '\\')
2197 *pp++ = *++ptr;
2198 else if (*ptr == '&') {
2199 strcpy(pp, in);
2200 pp += inlen;
2201 } else
2202 *pp++ = *ptr;
2203 *pp = '\0';
2204 return ret;
2207 /**/
2208 mod_export void
2209 checkcurline(Histent he)
2211 if (he->histnum == curhist && (histactive & HA_ACTIVE)) {
2212 curline.node.nam = chline;
2213 curline.nwords = chwordpos/2;
2214 curline.words = chwords;
2218 /**/
2219 mod_export Histent
2220 quietgethist(int ev)
2222 return gethistent(ev, GETHIST_EXACT);
2225 /**/
2226 static Histent
2227 gethist(int ev)
2229 Histent ret;
2231 ret = quietgethist(ev);
2232 if (!ret) {
2233 herrflush();
2234 zerr("no such event: %d", ev);
2236 return ret;
2239 /**/
2240 static char *
2241 getargs(Histent elist, int arg1, int arg2)
2243 short *words = elist->words;
2244 int pos1, nwords = elist->nwords;
2246 if (arg2 < arg1 || arg1 >= nwords || arg2 >= nwords) {
2247 /* remember, argN is indexed from 0, nwords is total no. of words */
2248 herrflush();
2249 zerr("no such word in event");
2250 return NULL;
2253 pos1 = words[2*arg1];
2254 return dupstrpfx(elist->node.nam + pos1, words[2*arg2+1] - pos1);
2257 /**/
2258 static int
2259 quote(char **tr)
2261 char *ptr, *rptr, **str = tr;
2262 int len = 3;
2263 int inquotes = 0;
2265 for (ptr = *str; *ptr; ptr++, len++)
2266 if (*ptr == '\'') {
2267 len += 3;
2268 if (!inquotes)
2269 inquotes = 1;
2270 else
2271 inquotes = 0;
2272 } else if (inblank(*ptr) && !inquotes && ptr[-1] != '\\')
2273 len += 2;
2274 ptr = *str;
2275 *str = rptr = (char *) zhalloc(len);
2276 *rptr++ = '\'';
2277 for (; *ptr; ptr++)
2278 if (*ptr == '\'') {
2279 if (!inquotes)
2280 inquotes = 1;
2281 else
2282 inquotes = 0;
2283 *rptr++ = '\'';
2284 *rptr++ = '\\';
2285 *rptr++ = '\'';
2286 *rptr++ = '\'';
2287 } else if (inblank(*ptr) && !inquotes && ptr[-1] != '\\') {
2288 *rptr++ = '\'';
2289 *rptr++ = *ptr;
2290 *rptr++ = '\'';
2291 } else
2292 *rptr++ = *ptr;
2293 *rptr++ = '\'';
2294 *rptr++ = 0;
2295 return 0;
2298 /**/
2299 static int
2300 quotebreak(char **tr)
2302 char *ptr, *rptr, **str = tr;
2303 int len = 3;
2305 for (ptr = *str; *ptr; ptr++, len++)
2306 if (*ptr == '\'')
2307 len += 3;
2308 else if (inblank(*ptr))
2309 len += 2;
2310 ptr = *str;
2311 *str = rptr = (char *) zhalloc(len);
2312 *rptr++ = '\'';
2313 for (; *ptr;)
2314 if (*ptr == '\'') {
2315 *rptr++ = '\'';
2316 *rptr++ = '\\';
2317 *rptr++ = '\'';
2318 *rptr++ = '\'';
2319 ptr++;
2320 } else if (inblank(*ptr)) {
2321 *rptr++ = '\'';
2322 *rptr++ = *ptr++;
2323 *rptr++ = '\'';
2324 } else
2325 *rptr++ = *ptr++;
2326 *rptr++ = '\'';
2327 *rptr++ = '\0';
2328 return 0;
2331 /* read an arbitrary amount of data into a buffer until stop is found */
2333 #if 0 /**/
2334 char *
2335 hdynread(int stop)
2337 int bsiz = 256, ct = 0, c;
2338 char *buf = (char *)zalloc(bsiz), *ptr;
2340 ptr = buf;
2341 while ((c = ingetc()) != stop && c != '\n' && !lexstop) {
2342 if (c == '\\')
2343 c = ingetc();
2344 *ptr++ = c;
2345 if (++ct == bsiz) {
2346 buf = realloc(buf, bsiz *= 2);
2347 ptr = buf + ct;
2350 *ptr = 0;
2351 if (c == '\n') {
2352 inungetc('\n');
2353 zerr("delimiter expected");
2354 zfree(buf, bsiz);
2355 return NULL;
2357 return buf;
2359 #endif
2361 /**/
2362 static char *
2363 hdynread2(int stop)
2365 int bsiz = 256, ct = 0, c;
2366 char *buf = (char *)zalloc(bsiz), *ptr;
2368 ptr = buf;
2369 while ((c = ingetc()) != stop && c != '\n' && !lexstop) {
2370 if (c == '\\')
2371 c = ingetc();
2372 *ptr++ = c;
2373 if (++ct == bsiz) {
2374 buf = realloc(buf, bsiz *= 2);
2375 ptr = buf + ct;
2378 *ptr = 0;
2379 if (c == '\n')
2380 inungetc('\n');
2381 return buf;
2384 /**/
2385 void
2386 inithist(void)
2388 createhisttable();
2391 /**/
2392 void
2393 resizehistents(void)
2395 if (histlinect > histsiz) {
2396 /* The reason we don't just call freehistnode(hist_ring->down) is
2397 * so that we can honor the HISTEXPIREDUPSFIRST setting. */
2398 putoldhistentryontop(0);
2399 freehistnode(&hist_ring->node);
2400 while (histlinect > histsiz) {
2401 putoldhistentryontop(1);
2402 freehistnode(&hist_ring->node);
2407 static int
2408 readhistline(int start, char **bufp, int *bufsiz, FILE *in)
2410 char *buf = *bufp;
2411 if (fgets(buf + start, *bufsiz - start, in)) {
2412 int len = start + strlen(buf + start);
2413 if (len == start)
2414 return -1;
2415 if (buf[len - 1] != '\n') {
2416 if (!feof(in)) {
2417 if (len < (*bufsiz) - 1)
2418 return -1;
2419 *bufp = zrealloc(buf, 2 * (*bufsiz));
2420 *bufsiz = 2 * (*bufsiz);
2421 return readhistline(len, bufp, bufsiz, in);
2424 else {
2425 buf[len - 1] = '\0';
2426 if (len > 1 && buf[len - 2] == '\\') {
2427 buf[--len - 1] = '\n';
2428 if (!feof(in))
2429 return readhistline(len, bufp, bufsiz, in);
2432 return len;
2434 return 0;
2437 /**/
2438 void
2439 readhistfile(char *fn, int err, int readflags)
2441 char *buf, *start = NULL;
2442 FILE *in;
2443 Histent he;
2444 time_t stim, ftim, tim = time(NULL);
2445 off_t fpos;
2446 short *words;
2447 struct stat sb;
2448 int nwordpos, nwords, bufsiz;
2449 int searching, newflags, l, ret, uselex;
2451 if (!fn && !(fn = getsparam("HISTFILE")))
2452 return;
2453 if (stat(unmeta(fn), &sb) < 0 ||
2454 sb.st_size == 0)
2455 return;
2456 if (readflags & HFILE_FAST) {
2457 if ((lasthist.fsiz == sb.st_size && lasthist.mtim == sb.st_mtime)
2458 || lockhistfile(fn, 0))
2459 return;
2460 lasthist.fsiz = sb.st_size;
2461 lasthist.mtim = sb.st_mtime;
2462 } else if ((ret = lockhistfile(fn, 1))) {
2463 if (ret == 2) {
2464 zwarn("locking failed for %s: %e: reading anyway", fn, errno);
2465 } else {
2466 zerr("locking failed for %s: %e", fn, errno);
2467 return;
2470 if ((in = fopen(unmeta(fn), "r"))) {
2471 nwords = 64;
2472 words = (short *)zalloc(nwords*sizeof(short));
2473 bufsiz = 1024;
2474 buf = zalloc(bufsiz);
2476 pushheap();
2477 if (readflags & HFILE_FAST && lasthist.text) {
2478 if (lasthist.fpos < lasthist.fsiz) {
2479 fseek(in, lasthist.fpos, 0);
2480 searching = 1;
2482 else {
2483 histfile_linect = 0;
2484 searching = -1;
2486 } else
2487 searching = 0;
2489 newflags = HIST_OLD | HIST_READ;
2490 if (readflags & HFILE_FAST)
2491 newflags |= HIST_FOREIGN;
2492 if (readflags & HFILE_SKIPOLD
2493 || (hist_ignore_all_dups && newflags & hist_skip_flags))
2494 newflags |= HIST_MAKEUNIQUE;
2495 while (fpos = ftell(in), (l = readhistline(0, &buf, &bufsiz, in))) {
2496 char *pt;
2497 int remeta = 0;
2499 if (l < 0) {
2500 zerr("corrupt history file %s", fn);
2501 break;
2505 * Handle the special case that we're reading from an
2506 * old shell with fewer meta characters, so we need to
2507 * metafy some more. (It's not clear why the history
2508 * file is metafied at all; some would say this is plain
2509 * stupid. But we're stuck with it now without some
2510 * hairy workarounds for compatibility).
2512 * This is rare so doesn't need to be that efficient; just
2513 * allocate space off the heap.
2515 for (pt = buf; *pt; pt++) {
2516 if (*pt == Meta && pt[1])
2517 pt++;
2518 else if (imeta(*pt)) {
2519 remeta = 1;
2520 break;
2523 if (remeta) {
2524 unmetafy(buf, &remeta);
2525 pt = metafy(buf, remeta, META_USEHEAP);
2526 } else {
2527 pt = buf;
2530 if (*pt == ':') {
2531 pt++;
2532 stim = zstrtol(pt, NULL, 0);
2533 for (; *pt != ':' && *pt; pt++);
2534 if (*pt) {
2535 pt++;
2536 ftim = zstrtol(pt, NULL, 0);
2537 for (; *pt != ';' && *pt; pt++);
2538 if (*pt)
2539 pt++;
2540 } else
2541 ftim = stim;
2542 } else {
2543 if (*pt == '\\' && pt[1] == ':')
2544 pt++;
2545 stim = ftim = 0;
2548 if (searching) {
2549 if (searching > 0) {
2550 if (stim == lasthist.stim
2551 && histstrcmp(pt, lasthist.text) == 0)
2552 searching = 0;
2553 else {
2554 fseek(in, 0, 0);
2555 histfile_linect = 0;
2556 searching = -1;
2558 continue;
2560 else if (stim < lasthist.stim) {
2561 histfile_linect++;
2562 continue;
2564 searching = 0;
2567 if (readflags & HFILE_USE_OPTIONS) {
2568 histfile_linect++;
2569 lasthist.fpos = fpos;
2570 lasthist.stim = stim;
2573 he = prepnexthistent();
2574 he->node.nam = ztrdup(pt);
2575 he->node.flags = newflags;
2576 if ((he->stim = stim) == 0)
2577 he->stim = he->ftim = tim;
2578 else if (ftim < stim)
2579 he->ftim = stim + ftim;
2580 else
2581 he->ftim = ftim;
2584 * Divide up the words.
2586 start = pt;
2587 uselex = isset(HISTLEXWORDS) && !(readflags & HFILE_FAST);
2588 histsplitwords(pt, &words, &nwords, &nwordpos, uselex);
2590 he->nwords = nwordpos/2;
2591 if (he->nwords) {
2592 he->words = (short *)zalloc(nwordpos*sizeof(short));
2593 memcpy(he->words, words, nwordpos*sizeof(short));
2594 } else
2595 he->words = (short *)NULL;
2596 addhistnode(histtab, he->node.nam, he);
2597 if (he->node.flags & HIST_DUP) {
2598 freehistnode(&he->node);
2599 curhist--;
2602 * Do this last out of paranoia in case use of
2603 * heap is disguised...
2605 if (uselex || remeta)
2606 freeheap();
2607 if (errflag & ERRFLAG_INT)
2608 break;
2610 if (start && readflags & HFILE_USE_OPTIONS) {
2611 zsfree(lasthist.text);
2612 lasthist.text = ztrdup(start);
2614 zfree(words, nwords*sizeof(short));
2615 zfree(buf, bufsiz);
2617 popheap();
2618 fclose(in);
2619 } else if (err)
2620 zerr("can't read history file %s", fn);
2622 unlockhistfile(fn);
2624 if (zleactive)
2625 zleentry(ZLE_CMD_SET_HIST_LINE, curhist);
2628 #ifdef HAVE_FCNTL_H
2629 static int flock_fd = -1;
2632 * Lock file using fcntl(). Return 0 on success, 1 on failure of
2633 * locking mechanism, 2 on permanent failure (e.g. permission).
2636 static int
2637 flockhistfile(char *fn, int keep_trying)
2639 struct flock lck;
2640 long sleep_us = 0x10000; /* about 67 ms */
2641 time_t end_time;
2643 if (flock_fd >= 0)
2644 return 0; /* already locked */
2646 if ((flock_fd = open(unmeta(fn), O_RDWR | O_NOCTTY)) < 0)
2647 return errno == ENOENT ? 0 : 2; /* "successfully" locked missing file */
2649 lck.l_type = F_WRLCK;
2650 lck.l_whence = SEEK_SET;
2651 lck.l_start = 0;
2652 lck.l_len = 0; /* lock the whole file */
2655 * Timeout is ten seconds.
2657 end_time = time(NULL) + (time_t)10;
2658 while (fcntl(flock_fd, F_SETLKW, &lck) == -1) {
2659 if (!keep_trying || time(NULL) >= end_time ||
2661 * Randomise wait to minimise clashes with shells exiting at
2662 * the same time.
2664 !zsleep_random(sleep_us, end_time)) {
2665 close(flock_fd);
2666 flock_fd = -1;
2667 return 1;
2669 sleep_us <<= 1;
2672 return 0;
2674 #endif
2676 /**/
2677 void
2678 savehistfile(char *fn, int err, int writeflags)
2680 char *t, *tmpfile, *start = NULL;
2681 FILE *out;
2682 Histent he;
2683 zlong xcurhist = curhist - !!(histactive & HA_ACTIVE);
2684 int extended_history = isset(EXTENDEDHISTORY);
2685 int ret;
2687 if (!interact || savehistsiz <= 0 || !hist_ring
2688 || (!fn && !(fn = getsparam("HISTFILE"))))
2689 return;
2690 if (writeflags & HFILE_FAST) {
2691 he = gethistent(lasthist.next_write_ev, GETHIST_DOWNWARD);
2692 while (he && he->node.flags & HIST_OLD) {
2693 lasthist.next_write_ev = he->histnum + 1;
2694 he = down_histent(he);
2696 if (!he || lockhistfile(fn, 0))
2697 return;
2698 if (histfile_linect > savehistsiz + savehistsiz / 5)
2699 writeflags &= ~HFILE_FAST;
2701 else {
2702 if (lockhistfile(fn, 1)) {
2703 zerr("locking failed for %s: %e", fn, errno);
2704 return;
2706 he = hist_ring->down;
2708 if (writeflags & HFILE_USE_OPTIONS) {
2709 if (isset(APPENDHISTORY) || isset(INCAPPENDHISTORY)
2710 || isset(INCAPPENDHISTORYTIME) || isset(SHAREHISTORY))
2711 writeflags |= HFILE_APPEND | HFILE_SKIPOLD;
2712 else
2713 histfile_linect = 0;
2714 if (isset(HISTSAVENODUPS))
2715 writeflags |= HFILE_SKIPDUPS;
2716 if (isset(SHAREHISTORY))
2717 extended_history = 1;
2719 errno = 0;
2720 if (writeflags & HFILE_APPEND) {
2721 int fd = open(unmeta(fn), O_CREAT | O_WRONLY | O_APPEND | O_NOCTTY, 0600);
2722 tmpfile = NULL;
2723 out = fd >= 0 ? fdopen(fd, "a") : NULL;
2724 } else if (!isset(HISTSAVEBYCOPY)) {
2725 int fd = open(unmeta(fn), O_CREAT | O_WRONLY | O_TRUNC | O_NOCTTY, 0600);
2726 tmpfile = NULL;
2727 out = fd >= 0 ? fdopen(fd, "w") : NULL;
2728 } else {
2729 tmpfile = bicat(unmeta(fn), ".new");
2730 if (unlink(tmpfile) < 0 && errno != ENOENT)
2731 out = NULL;
2732 else {
2733 struct stat sb;
2734 int old_exists = stat(unmeta(fn), &sb) == 0;
2735 uid_t euid = geteuid();
2737 if (old_exists
2738 #if defined HAVE_FCHMOD && defined HAVE_FCHOWN
2739 && euid
2740 #endif
2741 && sb.st_uid != euid) {
2742 free(tmpfile);
2743 tmpfile = NULL;
2744 if (err) {
2745 if (isset(APPENDHISTORY) || isset(INCAPPENDHISTORY)
2746 || isset(INCAPPENDHISTORYTIME) || isset(SHAREHISTORY))
2747 zerr("rewriting %s would change its ownership -- skipped", fn);
2748 else
2749 zerr("rewriting %s would change its ownership -- history not saved", fn);
2750 err = 0; /* Don't report a generic error below. */
2752 out = NULL;
2753 } else {
2754 int fd = open(tmpfile, O_CREAT | O_WRONLY | O_EXCL, 0600);
2755 if (fd >=0) {
2756 out = fdopen(fd, "w");
2757 if (!out)
2758 close(fd);
2759 } else
2760 out = NULL;
2763 #ifdef HAVE_FCHMOD
2764 if (old_exists && out) {
2765 #ifdef HAVE_FCHOWN
2766 if (fchown(fileno(out), sb.st_uid, sb.st_gid) < 0) {} /* IGNORE FAILURE */
2767 #endif
2768 if (fchmod(fileno(out), sb.st_mode) < 0) {} /* IGNORE FAILURE */
2770 #endif
2773 if (out) {
2774 char *history_ignore;
2775 Patprog histpat = NULL;
2777 pushheap();
2779 if ((history_ignore = getsparam("HISTORY_IGNORE")) != NULL) {
2780 tokenize(history_ignore = dupstring(history_ignore));
2781 remnulargs(history_ignore);
2782 histpat = patcompile(history_ignore, 0, NULL);
2785 ret = 0;
2786 for (; he && he->histnum <= xcurhist; he = down_histent(he)) {
2787 int count_backslashes = 0;
2789 if ((writeflags & HFILE_SKIPDUPS && he->node.flags & HIST_DUP)
2790 || (writeflags & HFILE_SKIPFOREIGN && he->node.flags & HIST_FOREIGN)
2791 || he->node.flags & HIST_TMPSTORE)
2792 continue;
2793 if (histpat &&
2794 pattry(histpat, metafy(he->node.nam, -1, META_HEAPDUP))) {
2795 continue;
2797 if (writeflags & HFILE_SKIPOLD) {
2798 if (he->node.flags & (HIST_OLD|HIST_NOWRITE))
2799 continue;
2800 he->node.flags |= HIST_OLD;
2801 if (writeflags & HFILE_USE_OPTIONS)
2802 lasthist.next_write_ev = he->histnum + 1;
2804 if (writeflags & HFILE_USE_OPTIONS) {
2805 lasthist.fpos = ftell(out);
2806 lasthist.stim = he->stim;
2807 histfile_linect++;
2809 t = start = he->node.nam;
2810 if (extended_history) {
2811 ret = fprintf(out, ": %ld:%ld;", (long)he->stim,
2812 he->ftim? (long)(he->ftim - he->stim) : 0L);
2813 } else if (*t == ':')
2814 ret = fputc('\\', out);
2816 for (; ret >= 0 && *t; t++) {
2817 if (*t == '\n')
2818 if ((ret = fputc('\\', out)) < 0)
2819 break;
2820 if (*t == '\\')
2821 count_backslashes++;
2822 else
2823 count_backslashes = 0;
2824 if ((ret = fputc(*t, out)) < 0)
2825 break;
2827 if (ret < 0)
2828 break;
2829 if (count_backslashes && (count_backslashes % 2 == 0))
2830 if ((ret = fputc(' ', out)) < 0)
2831 break;
2832 if (ret < 0 || (ret = fputc('\n', out)) < 0)
2833 break;
2835 if (ret >= 0 && start && writeflags & HFILE_USE_OPTIONS) {
2836 struct stat sb;
2837 if ((ret = fflush(out)) >= 0) {
2838 if (fstat(fileno(out), &sb) == 0) {
2839 lasthist.fsiz = sb.st_size;
2840 lasthist.mtim = sb.st_mtime;
2842 zsfree(lasthist.text);
2843 lasthist.text = ztrdup(start);
2846 if (fclose(out) < 0 && ret >= 0)
2847 ret = -1;
2848 if (ret >= 0) {
2849 if (tmpfile) {
2850 if (rename(tmpfile, unmeta(fn)) < 0) {
2851 zerr("can't rename %s.new to $HISTFILE", fn);
2852 ret = -1;
2853 err = 0;
2854 #ifdef HAVE_FCNTL_H
2855 } else {
2856 /* We renamed over the locked HISTFILE, so close fd.
2857 * If we do more writing, we'll get a lock then. */
2858 if (flock_fd >= 0) {
2859 close(flock_fd);
2860 flock_fd = -1;
2862 #endif
2866 if (ret >= 0 && writeflags & HFILE_SKIPOLD
2867 && !(writeflags & (HFILE_FAST | HFILE_NO_REWRITE))) {
2868 int remember_histactive = histactive;
2870 /* Zeroing histactive avoids unnecessary munging of curline. */
2871 histactive = 0;
2872 /* The NULL leaves HISTFILE alone, preserving fn's value. */
2873 pushhiststack(NULL, savehistsiz, savehistsiz, -1);
2875 hist_ignore_all_dups |= isset(HISTSAVENODUPS);
2876 readhistfile(fn, err, 0);
2877 hist_ignore_all_dups = isset(HISTIGNOREALLDUPS);
2878 if (histlinect)
2879 savehistfile(fn, err, 0);
2881 pophiststack();
2882 histactive = remember_histactive;
2886 popheap();
2887 } else
2888 ret = -1;
2890 if (ret < 0 && err) {
2891 if (tmpfile)
2892 zerr("failed to write history file %s.new: %e", fn, errno);
2893 else
2894 zerr("failed to write history file %s: %e", fn, errno);
2896 if (tmpfile)
2897 free(tmpfile);
2899 unlockhistfile(fn);
2902 static int lockhistct;
2904 static int
2905 checklocktime(char *lockfile, long *sleep_usp, time_t then)
2907 time_t now = time(NULL);
2909 if (now + 10 < then) {
2910 /* File is more than 10 seconds in the future? */
2911 errno = EEXIST;
2912 return -1;
2915 if (now - then < 10) {
2917 * To give the effect of a gradually increasing backoff,
2918 * we'll sleep a period based on the time we've spent so far.
2920 DPUTS(now < then, "time flowing backwards through history");
2922 * Randomise to minimise clashes with shells exiting at the same
2923 * time.
2925 (void)zsleep_random(*sleep_usp, then + 10);
2926 *sleep_usp <<= 1;
2927 } else
2928 unlink(lockfile);
2930 return 0;
2934 * Lock history file. Return 0 on success, 1 on failure to lock this
2935 * time, 2 on permanent failure (e.g. permission).
2938 /**/
2940 lockhistfile(char *fn, int keep_trying)
2942 int ct = lockhistct;
2943 int ret = 0;
2944 long sleep_us = 0x10000; /* about 67 ms */
2946 if (!fn && !(fn = getsparam("HISTFILE")))
2947 return 1;
2949 if (!lockhistct++) {
2950 struct stat sb;
2951 int fd;
2952 char *lockfile;
2953 #ifdef HAVE_LINK
2954 # ifdef HAVE_SYMLINK
2955 char pidbuf[32], *lnk;
2956 # else
2957 char *tmpfile;
2958 # endif
2959 #endif
2961 #ifdef HAVE_FCNTL_H
2962 if (isset(HISTFCNTLLOCK))
2963 return flockhistfile(fn, keep_trying);
2964 #endif
2966 lockfile = bicat(unmeta(fn), ".LOCK");
2967 /* NOTE: only use symlink locking on a link()-having host in order to
2968 * avoid a change from open()-based locking to symlink()-based. */
2969 #ifdef HAVE_LINK
2970 # ifdef HAVE_SYMLINK
2971 sprintf(pidbuf, "/pid-%ld/host-", (long)mypid);
2972 lnk = getsparam("HOST");
2973 lnk = bicat(pidbuf, lnk ? lnk : "");
2974 /* We'll abuse fd as our success flag. */
2975 while ((fd = symlink(lnk, lockfile)) < 0) {
2976 if (errno != EEXIST) {
2977 ret = 2;
2978 break;
2979 } else if (!keep_trying) {
2980 ret = 1;
2981 break;
2983 if (lstat(lockfile, &sb) < 0) {
2984 if (errno == ENOENT)
2985 continue;
2986 break;
2988 if (checklocktime(lockfile, &sleep_us, sb.st_mtime) < 0) {
2989 ret = 1;
2990 break;
2993 if (fd < 0)
2994 lockhistct--;
2995 free(lnk);
2996 # else /* not HAVE_SYMLINK */
2997 if ((fd = gettempfile(fn, 0, &tmpfile)) >= 0) {
2998 FILE *out = fdopen(fd, "w");
2999 if (out) {
3000 fprintf(out, "%ld %s\n", (long)getpid(), getsparam("HOST"));
3001 fclose(out);
3002 } else
3003 close(fd);
3004 while (link(tmpfile, lockfile) < 0) {
3005 if (errno != EEXIST) {
3006 ret = 2;
3007 break;
3008 } else if (!keep_trying) {
3009 ret = 1;
3010 break;
3011 } else if (lstat(lockfile, &sb) < 0) {
3012 if (errno == ENOENT)
3013 continue;
3014 ret = 2;
3015 } else {
3016 if (checklocktime(lockfile, &sleep_us, sb.st_mtime) < 0) {
3017 ret = 1;
3018 break;
3020 continue;
3022 lockhistct--;
3023 break;
3025 unlink(tmpfile);
3026 free(tmpfile);
3028 # endif /* not HAVE_SYMLINK */
3029 #else /* not HAVE_LINK */
3030 while ((fd = open(lockfile, O_WRONLY|O_CREAT|O_EXCL, 0644)) < 0) {
3031 if (errno != EEXIST) {
3032 ret = 2;
3033 break;
3034 } else if (!keep_trying) {
3035 ret = 1;
3036 break;
3038 if (lstat(lockfile, &sb) < 0) {
3039 if (errno == ENOENT)
3040 continue;
3041 ret = 2;
3042 break;
3044 if (checklocktime(lockfile, &sleep_us, sb.st_mtime) < 0) {
3045 ret = 1;
3046 break;
3049 if (fd < 0)
3050 lockhistct--;
3051 else {
3052 FILE *out = fdopen(fd, "w");
3053 if (out) {
3054 fprintf(out, "%ld %s\n", (long)mypid, getsparam("HOST"));
3055 fclose(out);
3056 } else
3057 close(fd);
3059 #endif /* not HAVE_LINK */
3060 free(lockfile);
3063 if (ct == lockhistct) {
3064 #ifdef HAVE_FCNTL_H
3065 if (flock_fd >= 0) {
3066 close(flock_fd);
3067 flock_fd = -1;
3069 #endif
3070 DPUTS(ret == 0, "BUG: return value non-zero on locking error");
3071 return ret;
3073 return 0;
3076 /* Unlock the history file if this corresponds to the last nested lock
3077 * request. If we don't have the file locked, just return.
3080 /**/
3081 void
3082 unlockhistfile(char *fn)
3084 if (!fn && !(fn = getsparam("HISTFILE")))
3085 return;
3086 if (--lockhistct) {
3087 if (lockhistct < 0)
3088 lockhistct = 0;
3090 else {
3091 char *lockfile;
3092 fn = unmeta(fn);
3093 lockfile = zalloc(strlen(fn) + 5 + 1);
3094 sprintf(lockfile, "%s.LOCK", fn);
3095 unlink(lockfile);
3096 free(lockfile);
3097 #ifdef HAVE_FCNTL_H
3098 if (flock_fd >= 0) {
3099 close(flock_fd);
3100 flock_fd = -1;
3102 #endif
3106 /**/
3108 histfileIsLocked(void)
3110 return lockhistct > 0;
3114 * Get the words in the current buffer. Using the lexer.
3116 * As far as I can make out, this is a gross hack based on a gross hack.
3117 * When analysing lines from within zle, we tweak the metafied line
3118 * positions (zlemetall and zlemetacs) directly in the lexer. That's
3119 * bad enough, but this function appears to be designed to be called
3120 * from outside zle, pretending to be in zle and calling out, so
3121 * we set zlemetall and zlemetacs locally and copy the current zle line,
3122 * which may not even be valid at this point.
3124 * However, I'm so confused it could simply be baking Bakewell tarts.
3126 * list may be an existing linked list (off the heap), in which case
3127 * it will be appended to; otherwise it will be created.
3129 * If buf is set we will take input from that string, else we will
3130 * attempt to use ZLE directly in a way they tell you not to do on all
3131 * programming courses.
3133 * If index is non-NULL, and input is from a string in ZLE, *index
3134 * is set to the position of the end of the current editor word.
3136 * flags is passed directly to lexflags, see lex.c, except that
3137 * we 'or' in the bit LEXFLAGS_ACTIVE to make sure the variable
3138 * is set.
3141 /**/
3142 mod_export LinkList
3143 bufferwords(LinkList list, char *buf, int *index, int flags)
3145 int num = 0, cur = -1, got = 0, ne = noerrs;
3146 int owb = wb, owe = we, oadx = addedx, onc = nocomments;
3147 int ona = noaliases, ocs = zlemetacs, oll = zlemetall;
3148 int forloop = 0, rcquotes = opts[RCQUOTES];
3149 char *p, *addedspaceptr;
3151 if (!list)
3152 list = newlinklist();
3155 * With RC_QUOTES, 'foo '' bar' comes back as 'foo ' bar'. That's
3156 * not very useful. As nothing in here requires the fully processed
3157 * string expression, we just turn the option off for this function.
3159 opts[RCQUOTES] = 0;
3160 addedx = 0;
3161 noerrs = 1;
3162 zcontext_save();
3163 lexflags = flags | LEXFLAGS_ACTIVE;
3165 * Are we handling comments?
3167 nocomments = !(flags & (LEXFLAGS_COMMENTS_KEEP|
3168 LEXFLAGS_COMMENTS_STRIP));
3169 if (buf) {
3170 int l = strlen(buf);
3172 p = (char *) zhalloc(l + 2);
3173 memcpy(p, buf, l);
3175 * I'm sure this space is here for a reason, but it's
3176 * a pain in the neck: when we get back a string that's
3177 * not finished it's very hard to tell if a space at the
3178 * end is this one or not. We use two tricks below to
3179 * work around this.
3181 addedspaceptr = p + l;
3182 *addedspaceptr = ' ';
3183 addedspaceptr[1] = '\0';
3184 inpush(p, 0, NULL);
3185 zlemetall = strlen(p) ;
3186 zlemetacs = zlemetall + 1;
3187 } else {
3188 int ll, cs;
3189 char *linein;
3191 linein = zleentry(ZLE_CMD_GET_LINE, &ll, &cs);
3192 zlemetall = ll + 1; /* length of line plus space added below */
3193 zlemetacs = cs;
3195 if (!isfirstln && chline) {
3196 p = (char *) zhalloc(hptr - chline + ll + 2);
3197 memcpy(p, chline, hptr - chline);
3198 memcpy(p + (hptr - chline), linein, ll);
3199 addedspaceptr = p + (hptr - chline) + ll;
3200 *addedspaceptr = ' ';
3201 addedspaceptr[1] = '\0';
3202 inpush(p, 0, NULL);
3205 * advance line length and character position over
3206 * prepended string.
3208 zlemetall += hptr - chline;
3209 zlemetacs += hptr - chline;
3210 } else {
3211 p = (char *) zhalloc(ll + 2);
3212 memcpy(p, linein, ll);
3213 addedspaceptr = p + ll;
3214 *addedspaceptr = ' ';
3215 p[zlemetall] = '\0';
3216 inpush(p, 0, NULL);
3218 zsfree(linein);
3220 if (zlemetacs)
3221 zlemetacs--;
3222 strinbeg(0);
3223 noaliases = 1;
3224 do {
3225 if (incond)
3226 incond = 1 + (tok != DINBRACK && tok != INPAR &&
3227 tok != DBAR && tok != DAMPER &&
3228 tok != BANG);
3229 ctxtlex();
3230 if (tok == ENDINPUT || tok == LEXERR)
3231 break;
3232 if (tok == FOR) {
3234 * The way for (( expr1 ; expr2; expr3 )) is parsed is:
3235 * - a FOR tok
3236 * - a DINPAR with no tokstr
3237 * - two DINPARS with tokstr's expr1, expr2.
3238 * - a DOUTPAR with tokstr expr3.
3240 * We'll decrement the variable forloop as we verify
3241 * the various stages.
3243 * Don't ask me, ma'am, I'm just the programmer.
3245 forloop = 5;
3246 } else {
3247 switch (forloop) {
3248 case 1:
3249 if (tok != DOUTPAR)
3250 forloop = 0;
3251 break;
3253 case 2:
3254 case 3:
3255 case 4:
3256 if (tok != DINPAR)
3257 forloop = 0;
3258 break;
3260 default:
3261 /* nothing to do */
3262 break;
3265 if (tokstr) {
3266 switch (tok) {
3267 case ENVARRAY:
3268 p = dyncat(tokstr, "=(");
3269 break;
3271 case DINPAR:
3272 if (forloop) {
3273 /* See above. */
3274 p = dyncat(tokstr, ";");
3275 } else {
3277 * Mathematical expressions analysed as a single
3278 * word. That's correct because it behaves like
3279 * double quotes. Whitespace in the middle is
3280 * similarly retained, so just add the parentheses back.
3282 p = zhtricat("((", tokstr, "))");
3284 break;
3286 default:
3287 p = dupstring(tokstr);
3288 break;
3290 if (*p) {
3291 untokenize(p);
3292 if (ingetptr() == addedspaceptr + 1) {
3294 * Whoops, we've read past the space we added, probably
3295 * because we were expecting a terminator but when
3296 * it didn't turn up we shrugged our shoulders thinking
3297 * it might as well be a complete string anyway.
3298 * So remove the space. C.f. below for the case
3299 * where the missing terminator caused a lex error.
3300 * We use the same paranoid test.
3302 int plen = strlen(p);
3303 if (plen && p[plen-1] == ' ' &&
3304 (plen == 1 || p[plen-2] != Meta))
3305 p[plen-1] = '\0';
3307 addlinknode(list, p);
3308 num++;
3310 } else if (buf) {
3311 if (IS_REDIROP(tok) && tokfd >= 0) {
3312 char b[20];
3314 sprintf(b, "%d%s", tokfd, tokstrings[tok]);
3315 addlinknode(list, dupstring(b));
3316 num++;
3317 } else if (tok != NEWLIN) {
3318 addlinknode(list, dupstring(tokstrings[tok]));
3319 num++;
3322 if (forloop) {
3323 if (forloop == 1) {
3325 * Final "))" of for loop to match opening,
3326 * since we've just added the preceding element.
3328 addlinknode(list, dupstring("))"));
3330 forloop--;
3332 if (!got && !lexflags) {
3333 got = 1;
3334 cur = num - 1;
3336 } while (tok != ENDINPUT && tok != LEXERR && !(errflag & ERRFLAG_INT));
3337 if (buf && tok == LEXERR && tokstr && *tokstr) {
3338 int plen;
3339 untokenize((p = dupstring(tokstr)));
3340 plen = strlen(p);
3342 * Strip the space we added for lexing but which won't have
3343 * been swallowed by the lexer because we aborted early.
3344 * The test is paranoia.
3346 if (plen && p[plen-1] == ' ' && (plen == 1 || p[plen-2] != Meta))
3347 p[plen - 1] = '\0';
3348 addlinknode(list, p);
3349 num++;
3351 if (cur < 0 && num)
3352 cur = num - 1;
3353 noaliases = ona;
3354 strinend();
3355 inpop();
3356 errflag &= ~ERRFLAG_ERROR;
3357 nocomments = onc;
3358 noerrs = ne;
3359 zcontext_restore();
3360 zlemetacs = ocs;
3361 zlemetall = oll;
3362 wb = owb;
3363 we = owe;
3364 addedx = oadx;
3365 opts[RCQUOTES] = rcquotes;
3367 if (index)
3368 *index = cur;
3370 return list;
3374 * Split up a line into words for use in a history file.
3376 * lineptr is the line to be split.
3378 * *wordsp and *nwordsp are an array already allocated to hold words
3379 * and its length. The array holds both start and end positions,
3380 * so *nwordsp actually counts twice the number of words in the
3381 * original string. *nwordsp may be zero in which case the array
3382 * will be allocated.
3384 * *nwordposp returns the used length of *wordsp in the same units as
3385 * *nwordsp, i.e. twice the number of words in the input line.
3387 * If uselex is 1, attempt to do this using the lexical analyser.
3388 * This is more accurate, but slower; for reading history files it's
3389 * controlled by the option HISTLEXWORDS. If this failed (which
3390 * indicates a bug in the shell) it falls back to whitespace-separated
3391 * strings, printing a message if in debug mode.
3393 * If uselex is 0, just look for whitespace-separated words; the only
3394 * special handling is for a backslash-newline combination as used
3395 * by the history file format to save multiline buffers.
3397 /**/
3398 mod_export void
3399 histsplitwords(char *lineptr, short **wordsp, int *nwordsp, int *nwordposp,
3400 int uselex)
3402 int nwords = *nwordsp, nwordpos = 0;
3403 short *words = *wordsp;
3404 char *start = lineptr;
3406 if (uselex) {
3407 LinkList wordlist;
3408 LinkNode wordnode;
3409 int nwords_max;
3411 wordlist = bufferwords(NULL, lineptr, NULL,
3412 LEXFLAGS_COMMENTS_KEEP);
3413 if (errflag)
3414 return;
3415 nwords_max = 2 * countlinknodes(wordlist);
3416 if (nwords_max > nwords) {
3417 *nwordsp = nwords = nwords_max;
3418 *wordsp = words = (short *)zrealloc(words, nwords*sizeof(short));
3420 for (wordnode = firstnode(wordlist);
3421 wordnode;
3422 incnode(wordnode)) {
3423 char *word = getdata(wordnode);
3424 char *lptr, *wptr = word;
3425 int loop_next = 0, skipping;
3427 /* Skip stuff at the start of the word */
3428 for (;;) {
3430 * Not really an oddity: "\\\n" is
3431 * removed from input as if whitespace.
3433 if (inblank(*lineptr))
3434 lineptr++;
3435 else if (lineptr[0] == '\\' && lineptr[1] == '\n') {
3437 * Optimisation: we handle this in the loop below,
3438 * too.
3440 lineptr += 2;
3441 } else
3442 break;
3444 lptr = lineptr;
3446 * Skip chunks of word with possible intervening
3447 * backslash-newline.
3449 * To get round C's annoying lack of ability to
3450 * reference the outer loop, we'll break from this
3451 * one with
3452 * loop_next = 0: carry on as normal
3453 * loop_next = 1: break from outer loop
3454 * loop_next = 2: continue round outer loop.
3456 do {
3457 skipping = 0;
3458 if (strpfx(wptr, lptr)) {
3460 * Normal case: word from lexer matches start of
3461 * string from line. Just advance over it.
3463 int len;
3464 if (!strcmp(wptr, ";") && strpfx(";;", lptr)) {
3466 * Don't get confused between a semicolon that's
3467 * probably really a newline and a double
3468 * semicolon that's terminating a case.
3470 loop_next = 2;
3471 break;
3473 len = strlen(wptr);
3474 lptr += len;
3475 wptr += len;
3476 } else {
3478 * Didn't get to the end of the word.
3479 * See what's amiss.
3481 int bad = 0;
3483 * Oddity 1: newlines turn into semicolons.
3485 if (!strcmp(wptr, ";"))
3487 loop_next = 2;
3488 break;
3490 while (*lptr) {
3491 if (!*wptr) {
3493 * End of the word before the end of the
3494 * line: not good.
3496 bad = 1;
3497 loop_next = 1;
3498 break;
3501 * Oddity 2: !'s turn into |'s.
3503 if (*lptr == *wptr ||
3504 (*lptr == '!' && *wptr == '|')) {
3505 lptr++;
3506 if (!*++wptr)
3507 break;
3508 } else if (lptr[0] == '\\' &&
3509 lptr[1] == '\n') {
3511 * \\\n can occur in the middle of a word;
3512 * wptr is already pointing at this, we
3513 * just need to skip over the break
3514 * in lptr and look at the next chunk.
3516 lptr += 2;
3517 skipping = 1;
3518 break;
3519 } else {
3520 bad = 1;
3521 loop_next = 1;
3522 break;
3525 if (bad) {
3526 #ifdef DEBUG
3527 dputs(ERRMSG("bad wordsplit reading history: "
3528 "%s\nat: %s\nword: %s"),
3529 start, lineptr, word);
3530 #endif
3531 lineptr = start;
3532 nwordpos = 0;
3533 uselex = 0;
3534 loop_next = 1;
3537 } while (skipping);
3538 if (loop_next) {
3539 if (loop_next == 1)
3540 break;
3541 continue;
3543 /* Record position of current word... */
3544 words[nwordpos++] = lineptr - start;
3545 words[nwordpos++] = lptr - start;
3547 /* ready for start of next word. */
3548 lineptr = lptr;
3551 if (!uselex) {
3552 do {
3553 for (;;) {
3554 if (inblank(*lineptr))
3555 lineptr++;
3556 else if (lineptr[0] == '\\' && lineptr[1] == '\n')
3557 lineptr += 2;
3558 else
3559 break;
3561 if (*lineptr) {
3562 if (nwordpos >= nwords) {
3563 *nwordsp = nwords = nwords + 64;
3564 *wordsp = words = (short *)
3565 zrealloc(words, nwords*sizeof(*words));
3567 words[nwordpos++] = lineptr - start;
3568 while (*lineptr && !inblank(*lineptr))
3569 lineptr++;
3570 words[nwordpos++] = lineptr - start;
3572 } while (*lineptr);
3575 *nwordposp = nwordpos;
3578 /* Move the current history list out of the way and prepare a fresh history
3579 * list using hf for HISTFILE, hs for HISTSIZE, and shs for SAVEHIST. If
3580 * the hf value is an empty string, HISTFILE will be unset from the new
3581 * environment; if it is NULL, HISTFILE will not be changed, not even by the
3582 * pop function (this functionality is used internally to rewrite the current
3583 * history file without affecting pointers into the environment).
3586 /**/
3588 pushhiststack(char *hf, zlong hs, zlong shs, int level)
3590 struct histsave *h;
3591 int curline_in_ring = (histactive & HA_ACTIVE) && hist_ring == &curline;
3593 if (histsave_stack_pos == histsave_stack_size) {
3594 histsave_stack_size += 5;
3595 histsave_stack = zrealloc(histsave_stack,
3596 histsave_stack_size * sizeof (struct histsave));
3599 if (curline_in_ring)
3600 unlinkcurline();
3602 h = &histsave_stack[histsave_stack_pos++];
3604 h->lasthist = lasthist;
3605 if (hf) {
3606 if ((h->histfile = getsparam("HISTFILE")) != NULL && *h->histfile)
3607 h->histfile = ztrdup(h->histfile);
3608 else
3609 h->histfile = "";
3610 } else
3611 h->histfile = NULL;
3612 h->histtab = histtab;
3613 h->hist_ring = hist_ring;
3614 h->curhist = curhist;
3615 h->histlinect = histlinect;
3616 h->histsiz = histsiz;
3617 h->savehistsiz = savehistsiz;
3618 h->locallevel = level;
3620 memset(&lasthist, 0, sizeof lasthist);
3621 if (hf) {
3622 if (*hf)
3623 setsparam("HISTFILE", ztrdup(hf));
3624 else
3625 unsetparam("HISTFILE");
3627 hist_ring = NULL;
3628 curhist = histlinect = 0;
3629 if (zleactive)
3630 zleentry(ZLE_CMD_SET_HIST_LINE, curhist);
3631 histsiz = hs;
3632 savehistsiz = shs;
3633 inithist(); /* sets histtab */
3635 if (curline_in_ring)
3636 linkcurline();
3638 return histsave_stack_pos;
3642 /**/
3644 pophiststack(void)
3646 struct histsave *h;
3647 int curline_in_ring = (histactive & HA_ACTIVE) && hist_ring == &curline;
3649 if (histsave_stack_pos == 0)
3650 return 0;
3652 if (curline_in_ring)
3653 unlinkcurline();
3655 deletehashtable(histtab);
3656 zsfree(lasthist.text);
3658 h = &histsave_stack[--histsave_stack_pos];
3660 lasthist = h->lasthist;
3661 if (h->histfile) {
3662 if (*h->histfile)
3663 setsparam("HISTFILE", h->histfile);
3664 else
3665 unsetparam("HISTFILE");
3667 histtab = h->histtab;
3668 hist_ring = h->hist_ring;
3669 curhist = h->curhist;
3670 if (zleactive)
3671 zleentry(ZLE_CMD_SET_HIST_LINE, curhist);
3672 histlinect = h->histlinect;
3673 histsiz = h->histsiz;
3674 savehistsiz = h->savehistsiz;
3676 if (curline_in_ring)
3677 linkcurline();
3679 return histsave_stack_pos + 1;
3682 /* If pop_through > 0, pop all array items >= the 1-relative index value.
3683 * If pop_through <= 0, pop (-1)*pop_through levels off the stack.
3684 * If the (new) top of stack is from a higher locallevel, auto-pop until
3685 * it is not.
3688 /**/
3690 saveandpophiststack(int pop_through, int writeflags)
3692 if (pop_through <= 0) {
3693 pop_through += histsave_stack_pos + 1;
3694 if (pop_through <= 0)
3695 pop_through = 1;
3697 while (pop_through > 1
3698 && histsave_stack[pop_through-2].locallevel > locallevel)
3699 pop_through--;
3700 if (histsave_stack_pos < pop_through)
3701 return 0;
3702 do {
3703 if (!nohistsave)
3704 savehistfile(NULL, 1, writeflags);
3705 pophiststack();
3706 } while (histsave_stack_pos >= pop_through);
3707 return 1;