Missed commit of ChangeLog for 52977 / da733f5d
[zsh/mirror.git] / Src / hist.c
blob1a00c30edc4621f3c7287ab79741a1afdf196b72
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 (*hwabort) (void);
51 /**/
52 void (*hwend) (void);
54 /**/
55 void (*addtoline) (int);
57 /* != 0 means history substitution is turned off */
59 /**/
60 mod_export int stophist;
62 /* if != 0, we are expanding the current line */
64 /**/
65 mod_export int expanding;
67 /* these are used to modify the cursor position during expansion */
69 /**/
70 mod_export int excs, exlast;
73 * Current history event number
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().
83 * Note curhist is passed to zle on variable length argument list:
84 * type must match that retrieved in zle_main_entry.
87 /**/
88 mod_export zlong curhist;
90 /**/
91 struct histent curline;
93 /* current line count of allocated history entries */
95 /**/
96 zlong histlinect;
98 /* The history lines are kept in a hash, and also doubly-linked in a ring */
100 /**/
101 HashTable histtab;
102 /**/
103 mod_export Histent hist_ring;
105 /* capacity of history lists */
107 /**/
108 zlong histsiz;
110 /* desired history-file size (in lines) */
112 /**/
113 zlong savehistsiz;
115 /* if = 1, we have performed history substitution on the current line *
116 * if = 2, we have used the 'p' modifier */
118 /**/
119 int histdone;
121 /* state of the history mechanism */
123 /**/
124 int histactive;
126 /* Current setting of the associated option, but sometimes also includes
127 * the setting of the HIST_SAVE_NO_DUPS option. */
129 /**/
130 int hist_ignore_all_dups;
132 /* What flags (if any) we should skip when moving through the history */
134 /**/
135 mod_export int hist_skip_flags;
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 */
144 /* Array of word beginnings and endings in current history line. */
146 /**/
147 short *chwords;
149 /* Max, actual position in chwords.
150 * nwords = chwordpos/2 because we record beginning and end of words.
153 /**/
154 int chwordlen, chwordpos;
156 /* the last l for s/l/r/ history substitution */
158 /**/
159 char *hsubl;
161 /* the last r for s/l/r/ history substitution */
163 /**/
164 char *hsubr;
166 /* state of histsubstpattern at last substitution */
168 /**/
169 int hsubpatopt;
171 /* pointer into the history line */
173 /**/
174 mod_export char *hptr;
176 /* the current history line */
178 /**/
179 mod_export char *chline;
182 * The current history line as seen by ZLE.
183 * We modify chline for use in other contexts while ZLE may
184 * still be running; ZLE should see only the top-level value.
186 * To avoid having to modify this every time we modify chline,
187 * we set it when we push the stack, and unset it when we pop
188 * the appropriate value off the stack. As it's never modified
189 * on the stack this is the only maintenance we ever do on it.
190 * In return, ZLE has to check both zle_chline and (if that's
191 * NULL) chline to get the current value.
194 /**/
195 mod_export char *zle_chline;
197 /* true if the last character returned by hgetc was an escaped bangchar *
198 * if it is set and NOBANGHIST is unset hwaddc escapes bangchars */
200 /**/
201 int qbang;
203 /* max size of histline */
205 /**/
206 int hlinesz;
208 /* default event (usually curhist-1, that is, "!!") */
210 static zlong defev;
213 * Flag that we stopped reading line when we got to a comment,
214 * but we want to keep it in the histofy even if there were no words
215 * (i.e. the comment was the entire line).
217 static int hist_keep_comment;
219 /* Remember the last line in the history file so we can find it again. */
220 static struct histfile_stats {
221 char *text;
222 time_t stim, mtim;
223 off_t fpos, fsiz;
224 int interrupted;
225 zlong next_write_ev;
226 } lasthist;
228 static struct histsave {
229 struct histfile_stats lasthist;
230 char *histfile;
231 HashTable histtab;
232 Histent hist_ring;
233 zlong curhist;
234 zlong histlinect;
235 zlong histsiz;
236 zlong savehistsiz;
237 int locallevel;
238 } *histsave_stack;
239 static int histsave_stack_size = 0;
240 static int histsave_stack_pos = 0;
242 static zlong histfile_linect;
244 /* save history context */
246 /**/
247 void
248 hist_context_save(struct hist_stack *hs, int toplevel)
250 if (toplevel) {
251 /* top level, make this version visible to ZLE */
252 zle_chline = chline;
253 /* ensure line stored is NULL-terminated */
254 if (hptr)
255 *hptr = '\0';
257 hs->histactive = histactive;
258 hs->histdone = histdone;
259 hs->stophist = stophist;
260 hs->hline = chline;
261 hs->hptr = hptr;
262 hs->chwords = chwords;
263 hs->chwordlen = chwordlen;
264 hs->chwordpos = chwordpos;
265 hs->hgetc = hgetc;
266 hs->hungetc = hungetc;
267 hs->hwaddc = hwaddc;
268 hs->hwbegin = hwbegin;
269 hs->hwabort = hwabort;
270 hs->hwend = hwend;
271 hs->addtoline = addtoline;
272 hs->hlinesz = hlinesz;
273 hs->defev = defev;
274 hs->hist_keep_comment = hist_keep_comment;
276 * We save and restore the command stack with history
277 * as it's visible to the user interactively, so if
278 * we're preserving history state we'll continue to
279 * show the current set of commands from input.
281 hs->cstack = cmdstack;
282 hs->csp = cmdsp;
284 stophist = 0;
285 chline = NULL;
286 hptr = NULL;
287 histactive = 0;
288 cmdstack = (unsigned char *)zalloc(CMDSTACKSZ);
289 cmdsp = 0;
292 /* restore history context */
294 /**/
295 void
296 hist_context_restore(const struct hist_stack *hs, int toplevel)
298 if (toplevel) {
299 /* Back to top level: don't need special ZLE value */
300 DPUTS(hs->hline != zle_chline, "BUG: Ouch, wrong chline for ZLE");
301 zle_chline = NULL;
303 histactive = hs->histactive;
304 histdone = hs->histdone;
305 stophist = hs->stophist;
306 chline = hs->hline;
307 hptr = hs->hptr;
308 chwords = hs->chwords;
309 chwordlen = hs->chwordlen;
310 chwordpos = hs->chwordpos;
311 hgetc = hs->hgetc;
312 hungetc = hs->hungetc;
313 hwaddc = hs->hwaddc;
314 hwbegin = hs->hwbegin;
315 hwabort = hs->hwabort;
316 hwend = hs->hwend;
317 addtoline = hs->addtoline;
318 hlinesz = hs->hlinesz;
319 defev = hs->defev;
320 hist_keep_comment = hs->hist_keep_comment;
321 if (cmdstack)
322 zfree(cmdstack, CMDSTACKSZ);
323 cmdstack = hs->cstack;
324 cmdsp = hs->csp;
328 * Mark that the current level of history is within a word whatever
329 * characters turn up, or turn that mode off. This is used for nested
330 * parsing of substitutions.
332 * The caller takes care only to turn this on or off at the start
333 * or end of recursive use of the same mode, so a single flag is
334 * good enough here.
337 /**/
338 void
339 hist_in_word(int yesno)
341 if (yesno)
342 histactive |= HA_INWORD;
343 else
344 histactive &= ~HA_INWORD;
347 /**/
349 hist_is_in_word(void)
351 return (histactive & HA_INWORD) ? 1 : 0;
354 /* add a character to the current history word */
356 static void
357 ihwaddc(int c)
359 /* Only if history line exists and lexing has not finished. */
360 if (chline && !(errflag || lexstop) &&
362 * If we're reading inside a word for command substitution
363 * we allow the lexer to expand aliases but don't deal
364 * with them here. Note matching code in ihungetc().
365 * TBD: it might be neater to deal with all aliases in this
366 * fashion as we never need the expansion in the history
367 * line, only in the lexer and above.
369 (inbufflags & (INP_ALIAS|INP_HIST)) != INP_ALIAS) {
370 /* Quote un-expanded bangs in the history line. */
371 if (c == bangchar && stophist < 2 && qbang)
372 /* If qbang is not set, we do not escape this bangchar as it's *
373 * not necessary (e.g. it's a bang in !=, or it is followed *
374 * by a space). Roughly speaking, qbang is zero only if the *
375 * history interpreter has already digested this bang and *
376 * found that it is not necessary to escape it. */
377 hwaddc('\\');
378 *hptr++ = c;
380 /* Resize history line if necessary */
381 if (hptr - chline >= hlinesz) {
382 int oldsiz = hlinesz;
384 chline = realloc(chline, hlinesz = oldsiz + 64);
385 hptr = chline + oldsiz;
390 /* This function adds a character to the zle input line. It is used when *
391 * zsh expands history (see doexpandhist() in zle_tricky.c). It also *
392 * calculates the new cursor position after the expansion. It is called *
393 * from hgetc() and from gettok() in lex.c for characters in comments. */
395 /**/
396 void
397 iaddtoline(int c)
399 if (!expanding || lexstop)
400 return;
401 if (qbang && c == bangchar && stophist < 2) {
402 exlast--;
403 zleentry(ZLE_CMD_ADD_TO_LINE, '\\');
405 if (excs > zlemetacs) {
406 excs += 1 + inbufct - exlast;
407 if (excs < zlemetacs)
408 /* this case could be handled better but it is *
409 * so rare that it does not worth it */
410 excs = zlemetacs;
412 exlast = inbufct;
413 zleentry(ZLE_CMD_ADD_TO_LINE, itok(c) ? ztokens[c - Pound] : c);
417 static int
418 ihgetc(void)
420 int c = ingetc();
422 if (exit_pending)
424 lexstop = 1;
425 errflag |= ERRFLAG_ERROR;
426 return ' ';
428 qbang = 0;
429 if (!stophist && !(inbufflags & INP_ALIAS)) {
430 /* If necessary, expand history characters. */
431 c = histsubchar(c);
432 if (c < 0) {
433 /* bad expansion */
434 lexstop = 1;
435 errflag |= ERRFLAG_ERROR;
436 return ' ';
439 if ((inbufflags & INP_HIST) && !stophist) {
440 /* the current character c came from a history expansion *
441 * (inbufflags & INP_HIST) and history is not disabled *
442 * (e.g. we are not inside single quotes). In that case, \! *
443 * should be treated as ! (since this \! came from a previous *
444 * history line where \ was used to escape the bang). So if *
445 * c == '\\' we fetch one more character to see if it's a bang, *
446 * and if it is not, we unget it and reset c back to '\\' */
447 qbang = 0;
448 if (c == '\\' && !(qbang = (c = ingetc()) == bangchar))
449 safeinungetc(c), c = '\\';
450 } else if (stophist || (inbufflags & INP_ALIAS))
451 /* If the result is a bangchar which came from history or alias *
452 * expansion, we treat it as an escaped bangchar, unless history *
453 * is disabled. If stophist == 1 it only means that history is *
454 * temporarily disabled by a !" which won't appear in the *
455 * history, so we still have an escaped bang. stophist > 1 if *
456 * history is disabled with NOBANGHIST or by someone else (e.g. *
457 * when the lexer scans single quoted text). */
458 qbang = c == bangchar && (stophist < 2);
459 hwaddc(c);
460 addtoline(c);
462 return c;
465 /**/
466 static void
467 safeinungetc(int c)
469 if (lexstop)
470 lexstop = 0;
471 else
472 inungetc(c);
475 /**/
476 void
477 herrflush(void)
479 inpopalias();
481 if (lexstop)
482 return;
484 * The lex_add_raw test is needed if we are parsing a command
485 * substitution when expanding history for ZLE: strin is set but we
486 * need to finish off the input because the string we are reading is
487 * going to be used directly in the line that goes to ZLE.
489 * Note that this is a side effect --- this is not the usual reason
490 * for testing lex_add_raw which is to add the text to a different
491 * buffer used when we are actually parsing the command substitution
492 * (nothing to do with ZLE). Sorry.
494 while (inbufct && (!strin || lex_add_raw)) {
495 int c = ingetc();
496 if (!lexstop) {
497 hwaddc(c);
498 addtoline(c);
504 * Extract :s/foo/bar/ delimiters and arguments
506 * The first character expected is the first delimiter.
507 * The arguments are stored in the hsubl and hsubr variables.
509 * subline is the part of the command line to be matched.
511 * If a ':' was found but was not followed by a 'G',
512 * *cflagp is set to 1 and the input is backed up to the
513 * character following the colon.
516 /**/
517 static int
518 getsubsargs(UNUSED(char *subline), int *gbalp, int *cflagp)
520 int del, follow;
521 char *ptr1, *ptr2;
523 del = ingetc();
524 ptr1 = hdynread2(del);
525 if (!ptr1)
526 return 1;
527 ptr2 = hdynread2(del);
528 if (strlen(ptr1)) {
529 zsfree(hsubl);
530 hsubl = ptr1;
531 } else if (!hsubl) { /* fail silently on this */
532 zsfree(ptr1);
533 zsfree(ptr2);
534 return 0;
536 zsfree(hsubr);
537 hsubr = ptr2;
538 follow = ingetc();
539 if (follow == ':') {
540 follow = ingetc();
541 if (follow == 'G')
542 *gbalp = 1;
543 else {
544 inungetc(follow);
545 *cflagp = 1;
547 } else
548 inungetc(follow);
549 return 0;
552 /* Get the maximum no. of words for a history entry. */
554 /**/
555 static int
556 getargc(Histent ehist)
558 return ehist->nwords ? ehist->nwords-1 : 0;
561 /**/
562 static int
563 substfailed(void)
565 herrflush();
566 zerr("substitution failed");
567 return -1;
571 * Return a count given by decimal digits after a modifier.
573 static int
574 digitcount(void)
576 int c = ingetc(), count;
578 if (idigit(c)) {
579 count = 0;
580 do {
581 count = 10 * count + (c - '0');
582 c = ingetc();
583 } while (idigit(c));
585 else
586 count = 0;
587 inungetc(c);
588 return count;
591 /* Perform history substitution, returning the next character afterwards. */
593 /**/
594 static int
595 histsubchar(int c)
597 int farg, evset = -1, larg, argc, cflag = 0, bflag = 0;
598 zlong ev;
599 static int marg = -1;
600 static zlong mev = -1;
601 char *buf, *ptr;
602 char *sline;
603 int lexraw_mark;
604 Histent ehist;
605 size_t buflen;
608 * If accumulating raw input for use in command substitution,
609 * we don't want the history text, so mark it for later removal.
610 * It would be better to do this at a level above the history
611 * and below the lexer --- but there isn't one.
613 * Include the character we are attempting to substitute.
615 lexraw_mark = zshlex_raw_mark(-1);
617 /* look, no goto's */
618 if (isfirstch && c == hatchar) {
619 int gbal = 0;
621 /* Line begins ^foo^bar */
622 isfirstch = 0;
623 inungetc(hatchar);
624 if (!(ehist = gethist(defev))
625 || !(sline = getargs(ehist, 0, getargc(ehist))))
626 return -1;
628 if (getsubsargs(sline, &gbal, &cflag))
629 return substfailed();
630 if (!hsubl)
631 return -1;
632 if (subst(&sline, hsubl, hsubr, gbal, 0))
633 return substfailed();
634 } else {
635 /* Line doesn't begin ^foo^bar */
636 if (c != ' ')
637 isfirstch = 0;
638 if (c == '\\') {
639 int g = ingetc();
641 if (g != bangchar)
642 safeinungetc(g);
643 else {
644 qbang = 1;
645 return bangchar;
648 if (c != bangchar)
649 return c;
650 *hptr = '\0';
651 if ((c = ingetc()) == '{') {
652 bflag = cflag = 1;
653 c = ingetc();
655 if (c == '\"') {
656 stophist = 1;
657 return ingetc();
659 if ((!cflag && inblank(c)) || c == '=' || c == '(' || lexstop) {
660 safeinungetc(c);
661 return bangchar;
663 cflag = 0;
664 ptr = buf = zhalloc(buflen = 265);
666 /* get event number */
668 queue_signals();
669 if (c == '?') {
670 for (;;) {
671 c = ingetc();
672 if (c == '?' || c == '\n' || lexstop)
673 break;
674 else {
675 *ptr++ = c;
676 if (ptr == buf + buflen) {
677 buf = hrealloc(buf, buflen, 2 * buflen);
678 ptr = buf + buflen;
679 buflen *= 2;
683 if (c != '\n' && !lexstop)
684 c = ingetc();
685 *ptr = '\0';
686 mev = ev = hconsearch(hsubl = ztrdup(buf), &marg);
687 evset = 0;
688 if (ev == -1) {
689 herrflush();
690 unqueue_signals();
691 zerr("no such event: %s", buf);
692 return -1;
694 } else {
695 zlong t0;
697 for (;;) {
698 if (inblank(c) || c == ';' || c == ':' || c == '^' ||
699 c == '$' || c == '*' || c == '%' || c == '}' ||
700 c == '\'' || c == '"' || c == '`' || lexstop)
701 break;
702 if (ptr != buf) {
703 if (c == '-')
704 break;
705 if ((idigit(buf[0]) || buf[0] == '-') && !idigit(c))
706 break;
708 *ptr++ = c;
709 if (ptr == buf + buflen) {
710 buf = hrealloc(buf, buflen, 2 * buflen);
711 ptr = buf + buflen;
712 buflen *= 2;
714 if (c == '#' || c == bangchar) {
715 c = ingetc();
716 break;
718 c = ingetc();
720 if (ptr == buf &&
721 (c == '}' || c == ';' || c == '\'' || c == '"' || c == '`')) {
722 /* Neither event nor word designator, no expansion */
723 safeinungetc(c);
724 unqueue_signals();
725 return bangchar;
727 *ptr = 0;
728 if (!*buf) {
729 if (c != '%') {
730 if (isset(CSHJUNKIEHISTORY))
731 ev = addhistnum(curhist,-1,HIST_FOREIGN);
732 else
733 ev = defev;
734 if (c == ':' && evset == -1)
735 evset = 0;
736 else
737 evset = 1;
738 } else {
739 if (marg != -1)
740 ev = mev;
741 else
742 ev = defev;
743 evset = 0;
745 } else if ((t0 = zstrtol(buf, NULL, 10))) {
746 ev = (t0 < 0) ? addhistnum(curhist,t0,HIST_FOREIGN) : t0;
747 evset = 1;
748 } else if ((unsigned)*buf == bangchar) {
749 ev = addhistnum(curhist,-1,HIST_FOREIGN);
750 evset = 1;
751 } else if (*buf == '#') {
752 ev = curhist;
753 evset = 1;
754 } else if ((ev = hcomsearch(buf)) == -1) {
755 herrflush();
756 unqueue_signals();
757 zerr("event not found: %s", buf);
758 return -1;
759 } else
760 evset = 1;
763 /* get the event */
765 if (!(ehist = gethist(defev = ev))) {
766 unqueue_signals();
767 return -1;
769 /* extract the relevant arguments */
771 argc = getargc(ehist);
772 if (c == ':') {
773 cflag = 1;
774 c = ingetc();
775 if (c == '%' && marg != -1) {
776 if (!evset) {
777 ehist = gethist(defev = mev);
778 argc = getargc(ehist);
779 } else {
780 herrflush();
781 unqueue_signals();
782 zerr("ambiguous history reference");
783 return -1;
788 if (c == '*') {
789 farg = 1;
790 larg = argc;
791 cflag = 0;
792 } else {
793 inungetc(c);
794 larg = farg = getargspec(argc, marg, evset);
795 if (larg == -2) {
796 unqueue_signals();
797 return -1;
799 if (farg != -1)
800 cflag = 0;
801 c = ingetc();
802 if (c == '*') {
803 cflag = 0;
804 larg = argc;
805 } else if (c == '-') {
806 cflag = 0;
807 larg = getargspec(argc, marg, evset);
808 if (larg == -2) {
809 unqueue_signals();
810 return -1;
812 if (larg == -1)
813 larg = argc - 1;
814 } else
815 inungetc(c);
817 if (farg == -1)
818 farg = 0;
819 if (larg == -1)
820 larg = argc;
821 if (!(sline = getargs(ehist, farg, larg))) {
822 unqueue_signals();
823 return -1;
825 unqueue_signals();
828 /* do the modifiers */
830 for (;;) {
831 c = (cflag) ? ':' : ingetc();
832 cflag = 0;
833 if (c == ':') {
834 int gbal = 0;
836 if ((c = ingetc()) == 'g') {
837 gbal = 1;
838 c = ingetc();
839 if (c != 's' && c != 'S' && c != '&') {
840 zerr("'s' or '&' modifier expected after 'g'");
841 return -1;
844 switch (c) {
845 case 'p':
846 histdone = HISTFLAG_DONE | HISTFLAG_NOEXEC;
847 break;
848 case 'a':
849 if (!chabspath(&sline)) {
850 herrflush();
851 zerr("modifier failed: a");
852 return -1;
854 break;
856 case 'A':
857 if (!chrealpath(&sline, 'A', 1)) {
858 herrflush();
859 zerr("modifier failed: A");
860 return -1;
862 break;
863 case 'c':
864 if (!(sline = equalsubstr(sline, 0, 0))) {
865 herrflush();
866 zerr("modifier failed: c");
867 return -1;
869 break;
870 case 'h':
871 if (!remtpath(&sline, digitcount())) {
872 herrflush();
873 zerr("modifier failed: h");
874 return -1;
876 break;
877 case 'e':
878 if (!rembutext(&sline)) {
879 herrflush();
880 zerr("modifier failed: e");
881 return -1;
883 break;
884 case 'r':
885 if (!remtext(&sline)) {
886 herrflush();
887 zerr("modifier failed: r");
888 return -1;
890 break;
891 case 't':
892 if (!remlpaths(&sline, digitcount())) {
893 herrflush();
894 zerr("modifier failed: t");
895 return -1;
897 break;
898 case 's':
899 case 'S':
900 hsubpatopt = (c == 'S');
901 if (getsubsargs(sline, &gbal, &cflag))
902 return -1; /* fall through */
903 case '&':
904 if (hsubl && hsubr) {
905 if (subst(&sline, hsubl, hsubr, gbal, hsubpatopt))
906 return substfailed();
907 } else {
908 herrflush();
909 zerr("no previous substitution");
910 return -1;
912 break;
913 case 'q':
914 quote(&sline);
915 break;
916 case 'Q':
918 int one = noerrs, oef = errflag;
920 noerrs = 1;
921 parse_subst_string(sline);
922 noerrs = one;
923 errflag = oef | (errflag & ERRFLAG_INT);
924 remnulargs(sline);
925 untokenize(sline);
927 break;
928 case 'x':
929 quotebreak(&sline);
930 break;
931 case 'l':
932 sline = casemodify(sline, CASMOD_LOWER);
933 break;
934 case 'u':
935 sline = casemodify(sline, CASMOD_UPPER);
936 break;
937 case 'P':
938 if (*sline != '/') {
939 char *here = zgetcwd();
940 if (here[strlen(here)-1] != '/')
941 sline = zhtricat(metafy(here, -1, META_HEAPDUP), "/", sline);
942 else
943 sline = dyncat(here, sline);
945 sline = xsymlink(sline, 1);
946 break;
947 default:
948 herrflush();
949 zerr("illegal modifier: %c", c);
950 return -1;
952 } else {
953 if (c != '}' || !bflag)
954 inungetc(c);
955 if (c != '}' && bflag) {
956 zerr("'}' expected");
957 return -1;
959 break;
963 zshlex_raw_back_to_mark(lexraw_mark);
966 * Push the expanded value onto the input stack,
967 * marking this as a history word for purposes of the alias stack.
970 lexstop = 0;
971 /* this function is called only called from hgetc and only if *
972 * !(inbufflags & INP_ALIAS). History expansion should never be *
973 * done with INP_ALIAS (to prevent recursive history expansion and *
974 * histoty expansion of aliases). Escapes are not removed here. *
975 * This is now handled in hgetc. */
976 inpush(sline, INP_HIST, NULL); /* sline from heap, don't free */
977 histdone |= HISTFLAG_DONE;
978 if (isset(HISTVERIFY))
979 histdone |= HISTFLAG_NOEXEC | HISTFLAG_RECALL;
981 /* Don't try and re-expand line. */
982 return ingetc();
985 /* unget a char and remove it from chline. It can only be used *
986 * to unget a character returned by hgetc. */
988 static void
989 ihungetc(int c)
991 int doit = 1;
993 while (!lexstop && !errflag) {
994 if (hptr[-1] != (char) c && stophist < 4 &&
995 hptr > chline + 1 && hptr[-1] == '\n' && hptr[-2] == '\\' &&
996 !(histactive & HA_UNGET) &&
997 (inbufflags & (INP_ALIAS|INP_HIST)) != INP_ALIAS) {
998 histactive |= HA_UNGET;
999 hungetc('\n');
1000 hungetc('\\');
1001 histactive &= ~HA_UNGET;
1004 if (expanding) {
1005 zlemetacs--;
1006 zlemetall--;
1007 exlast++;
1009 if ((inbufflags & (INP_ALIAS|INP_HIST)) != INP_ALIAS) {
1010 DPUTS(hptr <= chline, "BUG: hungetc attempted at buffer start");
1011 hptr--;
1012 DPUTS(*hptr != (char) c, "BUG: wrong character in hungetc() ");
1013 qbang = (c == bangchar && stophist < 2 &&
1014 hptr > chline && hptr[-1] == '\\');
1015 } else {
1016 /* No active bangs in aliases */
1017 qbang = 0;
1019 if (doit)
1020 inungetc(c);
1021 if (!qbang)
1022 return;
1023 doit = !stophist && ((inbufflags & INP_HIST) ||
1024 !(inbufflags & INP_ALIAS));
1025 c = '\\';
1029 /* begin reading a string */
1031 /**/
1032 mod_export void
1033 strinbeg(int dohist)
1035 strin++;
1036 hbegin(dohist);
1037 lexinit();
1039 * Also initialise some variables owned by the parser but
1040 * used for communication between the parser and lexer.
1042 init_parse_status();
1045 /* done reading a string */
1047 /**/
1048 mod_export void
1049 strinend(void)
1051 hend(NULL);
1052 DPUTS(!strin, "BUG: strinend() called without strinbeg()");
1053 strin--;
1054 isfirstch = 1;
1055 histdone = 0;
1058 /* dummy functions to use instead of hwaddc(), hwbegin(), and hwend() when
1059 * they aren't needed */
1061 static void
1062 nohw(UNUSED(int c))
1066 static void
1067 nohwabort(void)
1071 static void
1072 nohwe(void)
1076 /* these functions handle adding/removing curline to/from the hist_ring */
1078 static void
1079 linkcurline(void)
1081 if (!hist_ring)
1082 hist_ring = curline.up = curline.down = &curline;
1083 else {
1084 curline.up = hist_ring;
1085 curline.down = hist_ring->down;
1086 hist_ring->down = hist_ring->down->up = &curline;
1087 hist_ring = &curline;
1089 curline.histnum = ++curhist;
1092 static void
1093 unlinkcurline(void)
1095 curline.up->down = curline.down;
1096 curline.down->up = curline.up;
1097 if (hist_ring == &curline) {
1098 if (!histlinect)
1099 hist_ring = NULL;
1100 else
1101 hist_ring = curline.up;
1103 curhist--;
1106 /* initialize the history mechanism */
1108 /**/
1109 mod_export void
1110 hbegin(int dohist)
1112 char *hf;
1114 isfirstln = isfirstch = 1;
1115 errflag &= ~ERRFLAG_ERROR;
1116 histdone = 0;
1117 if (!dohist)
1118 stophist = 2;
1119 else if (dohist != 2)
1120 stophist = (!interact || unset(SHINSTDIN)) ? 2 : 0;
1121 else
1122 stophist = 0;
1124 * pws: We used to test for "|| (inbufflags & INP_ALIAS)"
1125 * in this test, but at this point we don't have input
1126 * set up so this can trigger unnecessarily.
1127 * I don't see how the test at this point could ever be
1128 * useful, since we only get here when we're initialising
1129 * the history mechanism, before we've done any input.
1131 * (I also don't see any point where this function is called with
1132 * dohist=0.)
1134 if (stophist == 2) {
1135 chline = hptr = NULL;
1136 hlinesz = 0;
1137 chwords = NULL;
1138 chwordlen = 0;
1139 hgetc = ingetc;
1140 hungetc = inungetc;
1141 hwaddc = nohw;
1142 hwbegin = nohw;
1143 hwabort = nohwabort;
1144 hwend = nohwe;
1145 addtoline = nohw;
1146 } else {
1147 chline = hptr = zshcalloc(hlinesz = 64);
1148 chwords = zalloc((chwordlen = 64) * sizeof(short));
1149 hgetc = ihgetc;
1150 hungetc = ihungetc;
1151 hwaddc = ihwaddc;
1152 hwbegin = ihwbegin;
1153 hwabort = ihwabort;
1154 hwend = ihwend;
1155 addtoline = iaddtoline;
1156 if (!isset(BANGHIST))
1157 stophist = 4;
1159 chwordpos = 0;
1161 if (hist_ring && !hist_ring->ftim && !strin)
1162 hist_ring->ftim = time(NULL);
1163 if ((dohist == 2 || (interact && isset(SHINSTDIN))) && !strin) {
1164 histactive = HA_ACTIVE;
1165 attachtty(mypgrp);
1166 linkcurline();
1167 defev = addhistnum(curhist, -1, HIST_FOREIGN);
1168 } else
1169 histactive = HA_ACTIVE | HA_NOINC;
1172 * For INCAPPENDHISTORYTIME, when interactive, save the history here
1173 * as it gives a better estimate of the times of commands.
1175 * If INCAPPENDHISTORY is also set we've already done it.
1177 * If SHAREHISTORY is also set continue to do so in the
1178 * standard place, because that's safer about reading and
1179 * rewriting history atomically.
1181 * The histsave_stack_pos test won't usually fail here.
1182 * We need to test the opposite for the hend() case because we
1183 * need to save in the history file we've switched to, but then
1184 * we pop immediately after that so the variable becomes zero.
1185 * We will already have saved the line and restored the history
1186 * so that (correctly) nothing happens here. But it shows
1187 * I thought about it.
1189 if (isset(INCAPPENDHISTORYTIME) && !isset(SHAREHISTORY) &&
1190 !isset(INCAPPENDHISTORY) &&
1191 !(histactive & HA_NOINC) && !strin && histsave_stack_pos == 0) {
1192 hf = getsparam("HISTFILE");
1193 savehistfile(hf, 0, HFILE_USE_OPTIONS | HFILE_FAST);
1197 /**/
1198 void
1199 histreduceblanks(void)
1201 int i, len, pos, needblank, spacecount = 0, trunc_ok;
1202 char *lastptr, *ptr;
1204 if (isset(HISTIGNORESPACE))
1205 while (chline[spacecount] == ' ') spacecount++;
1207 for (i = 0, len = spacecount; i < chwordpos; i += 2) {
1208 len += chwords[i+1] - chwords[i]
1209 + (i > 0 && chwords[i] > chwords[i-1]);
1211 if (chline[len] == '\0')
1212 return;
1214 /* Remember where the delimited words end */
1215 if (chwordpos)
1216 lastptr = chline + chwords[chwordpos-1];
1217 else
1218 lastptr = chline;
1220 for (i = 0, pos = spacecount; i < chwordpos; i += 2) {
1221 len = chwords[i+1] - chwords[i];
1222 needblank = (i < chwordpos-2 && chwords[i+2] > chwords[i+1]);
1223 if (pos != chwords[i]) {
1224 memmove(chline + pos, chline + chwords[i], len + needblank);
1225 chwords[i] = pos;
1226 chwords[i+1] = chwords[i] + len;
1228 pos += len + needblank;
1232 * A terminating comment isn't recorded as a word.
1233 * Only truncate the line if just whitespace remains.
1235 trunc_ok = 1;
1236 for (ptr = lastptr; *ptr; ptr++) {
1237 if (!inblank(*ptr)) {
1238 trunc_ok = 0;
1239 break;
1242 if (trunc_ok) {
1243 chline[pos] = '\0';
1244 } else {
1245 ptr = chline + pos;
1246 if (ptr < lastptr)
1247 while ((*ptr++ = *lastptr++))
1252 /**/
1253 void
1254 histremovedups(void)
1256 Histent he, next;
1257 for (he = hist_ring; he; he = next) {
1258 next = up_histent(he);
1259 if (he->node.flags & HIST_DUP)
1260 freehistnode(&he->node);
1264 /**/
1265 mod_export zlong
1266 addhistnum(zlong hl, int n, int xflags)
1268 int dir = n < 0? -1 : n > 0? 1 : 0;
1269 Histent he = gethistent(hl, dir);
1271 if (!he)
1272 return 0;
1273 if (he->histnum != hl)
1274 n -= dir;
1275 if (n)
1276 he = movehistent(he, n, xflags);
1277 if (!he)
1278 return dir < 0? firsthist() - 1 : curhist + 1;
1279 return he->histnum;
1282 /**/
1283 mod_export Histent
1284 movehistent(Histent he, int n, int xflags)
1286 while (n < 0) {
1287 if (!(he = up_histent(he)))
1288 return NULL;
1289 if (!(he->node.flags & xflags))
1290 n++;
1292 while (n > 0) {
1293 if (!(he = down_histent(he)))
1294 return NULL;
1295 if (!(he->node.flags & xflags))
1296 n--;
1298 checkcurline(he);
1299 return he;
1302 /**/
1303 mod_export Histent
1304 up_histent(Histent he)
1306 return !he || he->up == hist_ring? NULL : he->up;
1309 /**/
1310 mod_export Histent
1311 down_histent(Histent he)
1313 return he == hist_ring? NULL : he->down;
1316 /**/
1317 mod_export Histent
1318 gethistent(zlong ev, int nearmatch)
1320 Histent he;
1322 if (!hist_ring)
1323 return NULL;
1325 if (ev - hist_ring->down->histnum < hist_ring->histnum - ev) {
1326 for (he = hist_ring->down; he->histnum < ev; he = he->down) ;
1327 if (he->histnum != ev) {
1328 if (nearmatch == 0
1329 || (nearmatch < 0 && (he = up_histent(he)) == NULL))
1330 return NULL;
1333 else {
1334 for (he = hist_ring; he->histnum > ev; he = he->up) ;
1335 if (he->histnum != ev) {
1336 if (nearmatch == 0
1337 || (nearmatch > 0 && (he = down_histent(he)) == NULL))
1338 return NULL;
1342 checkcurline(he);
1343 return he;
1346 static void
1347 putoldhistentryontop(short keep_going)
1349 static Histent next = NULL;
1350 Histent he = (keep_going || !hist_ring) ? next : hist_ring->down;
1351 if (he)
1352 next = he->down;
1353 else
1354 return;
1355 if (isset(HISTEXPIREDUPSFIRST) && !(he->node.flags & HIST_DUP)) {
1356 static zlong max_unique_ct = 0;
1357 if (!keep_going)
1358 max_unique_ct = savehistsiz;
1359 do {
1360 if (max_unique_ct-- <= 0 || he == hist_ring) {
1361 max_unique_ct = 0;
1362 if (hist_ring)
1363 he = hist_ring->down;
1364 next = hist_ring;
1365 break;
1367 he = next;
1368 next = he->down;
1369 } while (!(he->node.flags & HIST_DUP));
1371 /* Is it really possible for hist_ring to be NULL here? */
1372 if (he && (!hist_ring || he != hist_ring->down)) {
1373 he->up->down = he->down;
1374 he->down->up = he->up;
1375 he->up = hist_ring;
1376 if (hist_ring) {
1377 he->down = hist_ring->down;
1378 hist_ring->down = he;
1380 he->down->up = he;
1382 hist_ring = he;
1385 /**/
1386 Histent
1387 prepnexthistent(void)
1389 Histent he;
1390 int curline_in_ring = hist_ring == &curline;
1392 if (curline_in_ring)
1393 unlinkcurline();
1394 if (hist_ring && hist_ring->node.flags & HIST_TMPSTORE) {
1395 curhist--;
1396 freehistnode(&hist_ring->node);
1399 if (histlinect < histsiz || !hist_ring) {
1400 he = (Histent)zshcalloc(sizeof *he);
1401 if (!hist_ring)
1402 hist_ring = he->up = he->down = he;
1403 else {
1404 he->up = hist_ring;
1405 he->down = hist_ring->down;
1406 hist_ring->down = he->down->up = he;
1407 hist_ring = he;
1409 histlinect++;
1411 else {
1412 putoldhistentryontop(0);
1413 freehistdata(hist_ring, 0);
1414 he = hist_ring;
1416 he->histnum = ++curhist;
1417 if (curline_in_ring)
1418 linkcurline();
1419 return he;
1422 /* A helper function for hend() */
1424 static int
1425 should_ignore_line(Eprog prog)
1427 if (isset(HISTIGNORESPACE)) {
1428 if (*chline == ' ' || aliasspaceflag)
1429 return 1;
1432 if (!prog)
1433 return 0;
1435 if (isset(HISTNOFUNCTIONS)) {
1436 Wordcode pc = prog->prog;
1437 wordcode code = *pc;
1438 if (wc_code(code) == WC_LIST && WC_LIST_TYPE(code) & Z_SIMPLE
1439 && wc_code(pc[2]) == WC_FUNCDEF)
1440 return 1;
1443 if (isset(HISTNOSTORE)) {
1444 char *b = getjobtext(prog, NULL);
1445 int saw_builtin;
1446 if (*b == 'b' && strncmp(b,"builtin ",8) == 0) {
1447 b += 8;
1448 saw_builtin = 1;
1449 } else
1450 saw_builtin = 0;
1451 if (*b == 'h' && strncmp(b,"history",7) == 0 && (!b[7] || b[7] == ' ')
1452 && (saw_builtin || !shfunctab->getnode(shfunctab,"history")))
1453 return 1;
1454 if (*b == 'r' && (!b[1] || b[1] == ' ')
1455 && (saw_builtin || !shfunctab->getnode(shfunctab,"r")))
1456 return 1;
1457 if (*b == 'f' && b[1] == 'c' && b[2] == ' ' && b[3] == '-'
1458 && (saw_builtin || !shfunctab->getnode(shfunctab,"fc"))) {
1459 b += 3;
1460 do {
1461 if (*++b == 'l')
1462 return 1;
1463 } while (ialpha(*b));
1467 return 0;
1470 /* say we're done using the history mechanism */
1472 /**/
1473 mod_export int
1474 hend(Eprog prog)
1476 int flag, hookret = 0, stack_pos = histsave_stack_pos;
1478 * save:
1479 * 0: don't save
1480 * 1: save normally
1481 * -1: save temporarily, delete after next line
1482 * -2: save internally but mark for not writing
1484 int save = 1;
1485 char *hf;
1487 DPUTS(stophist != 2 && !(inbufflags & INP_ALIAS) && !chline,
1488 "BUG: chline is NULL in hend()");
1489 queue_signals();
1490 if (histdone & HISTFLAG_SETTY)
1491 settyinfo(&shttyinfo);
1492 if (!(histactive & HA_NOINC))
1493 unlinkcurline();
1494 if (histactive & HA_NOINC) {
1495 zfree(chline, hlinesz);
1496 zfree(chwords, chwordlen*sizeof(short));
1497 chline = hptr = NULL;
1498 chwords = NULL;
1499 histactive = 0;
1500 unqueue_signals();
1501 return 1;
1503 if (hist_ignore_all_dups != isset(HISTIGNOREALLDUPS)
1504 && (hist_ignore_all_dups = isset(HISTIGNOREALLDUPS)) != 0)
1505 histremovedups();
1507 if (hptr) {
1509 * Added the following in case the test "hptr < chline + 1"
1510 * is more than just paranoia.
1512 DPUTS(hptr < chline, "History end pointer off start of line");
1513 *hptr = '\0';
1515 if (*chline) {
1516 LinkList hookargs = newlinklist();
1517 int save_errflag = errflag;
1518 errflag = 0;
1520 addlinknode(hookargs, "zshaddhistory");
1521 addlinknode(hookargs, chline);
1522 callhookfunc("zshaddhistory", hookargs, 1, &hookret);
1524 errflag &= ~ERRFLAG_ERROR;
1525 errflag |= save_errflag;
1527 /* For history sharing, lock history file once for both read and write */
1528 hf = getsparam("HISTFILE");
1529 if (isset(SHAREHISTORY) && !lockhistfile(hf, 0)) {
1530 readhistfile(hf, 0, HFILE_USE_OPTIONS | HFILE_FAST);
1531 curline.histnum = curhist+1;
1533 flag = histdone;
1534 histdone = 0;
1535 if (hptr < chline + 1)
1536 save = 0;
1537 else {
1538 if (hptr[-1] == '\n') {
1539 if (chline[1]) {
1540 *--hptr = '\0';
1541 } else
1542 save = 0;
1544 if (chwordpos <= 2 && !hist_keep_comment)
1545 save = 0;
1546 else if (should_ignore_line(prog))
1547 save = -1;
1548 else if (hookret == 2)
1549 save = -2;
1550 else if (hookret)
1551 save = -1;
1553 if (flag & (HISTFLAG_DONE | HISTFLAG_RECALL)) {
1554 char *ptr;
1556 ptr = ztrdup(chline);
1557 if ((flag & (HISTFLAG_DONE | HISTFLAG_RECALL)) == HISTFLAG_DONE) {
1558 zputs(ptr, shout);
1559 fputc('\n', shout);
1560 fflush(shout);
1562 if (flag & HISTFLAG_RECALL) {
1563 zpushnode(bufstack, ptr);
1564 save = 0;
1565 } else
1566 zsfree(ptr);
1568 if (save || *chline == ' ') {
1569 Histent he;
1570 for (he = hist_ring; he && he->node.flags & HIST_FOREIGN;
1571 he = up_histent(he)) ;
1572 if (he && he->node.flags & HIST_TMPSTORE) {
1573 if (he == hist_ring)
1574 curline.histnum = curhist--;
1575 freehistnode(&he->node);
1578 if (save) {
1579 Histent he;
1580 int newflags;
1582 #ifdef DEBUG
1583 /* debugging only */
1584 if (chwordpos%2) {
1585 hwend();
1586 DPUTS(1, "BUG: uncompleted line in history");
1588 #endif
1589 /* get rid of pesky \n which we've already nulled out */
1590 if (chwordpos > 1 && !chline[chwords[chwordpos-2]]) {
1591 chwordpos -= 2;
1592 /* strip superfluous blanks, if desired */
1593 if (isset(HISTREDUCEBLANKS))
1594 histreduceblanks();
1596 if (save == -1)
1597 newflags = HIST_TMPSTORE;
1598 else if (save == -2)
1599 newflags = HIST_NOWRITE;
1600 else
1601 newflags = 0;
1602 if ((isset(HISTIGNOREDUPS) || isset(HISTIGNOREALLDUPS)) && save > 0
1603 && hist_ring && histstrcmp(chline, hist_ring->node.nam) == 0) {
1604 /* This history entry compares the same as the previous.
1605 * In case minor changes were made, we overwrite the
1606 * previous one with the current one. This also gets the
1607 * timestamp right. Perhaps, preserve the HIST_OLD flag.
1609 he = hist_ring;
1610 newflags |= he->node.flags & HIST_OLD; /* Avoid re-saving */
1611 freehistdata(he, 0);
1612 curline.histnum = curhist;
1613 } else
1614 he = prepnexthistent();
1616 he->node.nam = ztrdup(chline);
1617 he->stim = time(NULL);
1618 he->ftim = 0L;
1619 he->node.flags = newflags;
1621 if ((he->nwords = chwordpos/2)) {
1622 he->words = (short *)zalloc(chwordpos * sizeof(short));
1623 memcpy(he->words, chwords, chwordpos * sizeof(short));
1625 if (!(newflags & HIST_TMPSTORE))
1626 addhistnode(histtab, he->node.nam, he);
1628 zfree(chline, hlinesz);
1629 zfree(chwords, chwordlen*sizeof(short));
1630 chline = hptr = NULL;
1631 chwords = NULL;
1632 histactive = 0;
1634 * For normal INCAPPENDHISTORY case and reasoning, see hbegin().
1636 if (isset(SHAREHISTORY) ? histfileIsLocked() :
1637 (isset(INCAPPENDHISTORY) || (isset(INCAPPENDHISTORYTIME) &&
1638 histsave_stack_pos != 0)))
1639 savehistfile(hf, 0, HFILE_USE_OPTIONS | HFILE_FAST);
1640 unlockhistfile(hf); /* It's OK to call this even if we aren't locked */
1642 * No good reason for the user to push the history more than once, but
1643 * it's easy to be tidy...
1645 while (histsave_stack_pos > stack_pos)
1646 pophiststack();
1647 hist_keep_comment = 0;
1648 unqueue_signals();
1649 return !(flag & HISTFLAG_NOEXEC || errflag);
1652 /* begin a word */
1654 /**/
1655 void
1656 ihwbegin(int offset)
1658 int pos = hptr - chline + offset;
1659 if (stophist == 2 || (histactive & HA_INWORD) ||
1660 (inbufflags & (INP_ALIAS|INP_HIST)) == INP_ALIAS)
1661 return;
1662 if (chwordpos%2)
1663 chwordpos--; /* make sure we're on a word start, not end */
1664 DPUTS1(pos < 0, "History word position < 0 in %s",
1665 dupstrpfx(chline, hptr-chline));
1666 if (pos < 0)
1667 pos = 0;
1668 chwords[chwordpos++] = pos;
1671 /* Abort current history word, not needed */
1673 /**/
1674 void
1675 ihwabort(void)
1677 if (chwordpos%2)
1678 chwordpos--;
1679 hist_keep_comment = 1;
1682 /* add a word to the history List */
1684 /**/
1685 void
1686 ihwend(void)
1688 if (stophist == 2 || (histactive & HA_INWORD) ||
1689 (inbufflags & (INP_ALIAS|INP_HIST)) == INP_ALIAS)
1690 return;
1691 if (chwordpos%2 && chline) {
1692 /* end of word reached and we've already begun a word */
1693 if (hptr > chline + chwords[chwordpos-1]) {
1694 chwords[chwordpos++] = hptr - chline;
1695 if (chwordpos >= chwordlen) {
1696 chwords = (short *) realloc(chwords,
1697 (chwordlen += 32) *
1698 sizeof(short));
1700 } else {
1701 /* scrub that last word, it doesn't exist */
1702 chwordpos--;
1707 /* Go back to immediately after the last word, skipping space. */
1709 /**/
1710 void
1711 histbackword(void)
1713 if (!(chwordpos%2) && chwordpos)
1714 hptr = chline + chwords[chwordpos-1];
1717 /* Get the start and end point of the current history word */
1719 /**/
1720 static void
1721 hwget(char **startptr)
1723 int pos = chwordpos - 2;
1725 #ifdef DEBUG
1726 /* debugging only */
1727 if (!chwordpos) {
1728 /* no words available */
1729 DPUTS(1, "BUG: hwget() called with no words");
1730 *startptr = "";
1731 return;
1733 else if (chwordpos%2) {
1734 DPUTS(1, "BUG: hwget() called in middle of word");
1735 *startptr = "";
1736 return;
1738 #endif
1740 *startptr = chline + chwords[pos];
1741 chline[chwords[++pos]] = '\0';
1744 /* Replace the current history word with rep, if different */
1746 /**/
1747 void
1748 hwrep(char *rep)
1750 char *start;
1751 hwget(&start);
1753 if (!strcmp(rep, start))
1754 return;
1756 hptr = start;
1757 chwordpos = chwordpos - 2;
1758 hwbegin(0);
1759 qbang = 1;
1760 while (*rep)
1761 hwaddc(*rep++);
1762 hwend();
1765 /* Get the entire current line, deleting it in the history. */
1767 /**/
1768 mod_export char *
1769 hgetline(void)
1771 /* Currently only used by pushlineoredit().
1772 * It's necessary to prevent that from getting too pally with
1773 * the history code.
1775 char *ret;
1777 if (!chline || hptr == chline)
1778 return NULL;
1779 *hptr = '\0';
1780 ret = dupstring(chline);
1782 /* reset line */
1783 hptr = chline;
1784 chwordpos = 0;
1786 return ret;
1789 /* get an argument specification */
1791 /**/
1792 static int
1793 getargspec(int argc, int marg, int evset)
1795 int c, ret = -1;
1797 if ((c = ingetc()) == '0')
1798 return 0;
1799 if (idigit(c)) {
1800 ret = 0;
1801 while (idigit(c)) {
1802 ret = ret * 10 + c - '0';
1803 c = ingetc();
1805 inungetc(c);
1806 } else if (c == '^')
1807 ret = 1;
1808 else if (c == '$')
1809 ret = argc;
1810 else if (c == '%') {
1811 if (evset) {
1812 herrflush();
1813 zerr("Ambiguous history reference");
1814 return -2;
1816 if (marg == -1) {
1817 herrflush();
1818 zerr("%% with no previous word matched");
1819 return -2;
1821 ret = marg;
1822 } else
1823 inungetc(c);
1824 return ret;
1827 /* do ?foo? search */
1829 /**/
1830 static zlong
1831 hconsearch(char *str, int *marg)
1833 int t1 = 0;
1834 char *s;
1835 Histent he;
1837 for (he = up_histent(hist_ring); he; he = up_histent(he)) {
1838 if (he->node.flags & HIST_FOREIGN)
1839 continue;
1840 if ((s = strstr(he->node.nam, str))) {
1841 int pos = s - he->node.nam;
1842 while (t1 < he->nwords && he->words[2*t1] <= pos)
1843 t1++;
1844 *marg = t1 - 1;
1845 return he->histnum;
1848 return -1;
1851 /* do !foo search */
1853 /**/
1854 zlong
1855 hcomsearch(char *str)
1857 Histent he;
1858 int len = strlen(str);
1860 for (he = up_histent(hist_ring); he; he = up_histent(he)) {
1861 if (he->node.flags & HIST_FOREIGN)
1862 continue;
1863 if (strncmp(he->node.nam, str, len) == 0)
1864 return he->histnum;
1866 return -1;
1869 /* various utilities for : modifiers */
1871 /**/
1873 chabspath(char **junkptr)
1875 char *current, *dest;
1877 if (!**junkptr)
1878 return 1;
1880 if (**junkptr != '/') {
1881 char *here = zgetcwd();
1882 if (here[strlen(here)-1] != '/')
1883 *junkptr = zhtricat(metafy(here, -1, META_HEAPDUP), "/", *junkptr);
1884 else
1885 *junkptr = dyncat(here, *junkptr);
1888 current = *junkptr;
1889 dest = *junkptr;
1891 #ifdef HAVE_SUPERROOT
1892 while (*current == '/' && current[1] == '.' && current[2] == '.' &&
1893 (!current[3] || current[3] == '/')) {
1894 *dest++ = '/';
1895 *dest++ = '.';
1896 *dest++ = '.';
1897 current += 3;
1899 #endif
1901 for (;;) {
1902 if (*current == '/') {
1903 #ifdef __CYGWIN__
1904 if (current == *junkptr && current[1] == '/')
1905 *dest++ = *current++;
1906 #endif
1907 *dest++ = *current++;
1908 while (*current == '/')
1909 current++;
1910 } else if (!*current) {
1911 while (dest > *junkptr + 1 && dest[-1] == '/')
1912 dest--;
1913 *dest = '\0';
1914 break;
1915 } else if (current[0] == '.' && current[1] == '.' &&
1916 (!current[2] || current[2] == '/')) {
1917 if (current == *junkptr || dest == *junkptr) {
1918 *dest++ = '.';
1919 *dest++ = '.';
1920 current += 2;
1921 } else if (dest > *junkptr + 2 &&
1922 !strncmp(dest - 3, "../", 3)) {
1923 *dest++ = '.';
1924 *dest++ = '.';
1925 current += 2;
1926 } else if (dest > *junkptr + 1) {
1927 *dest = '\0';
1928 for (dest--;
1929 dest > *junkptr + 1 && dest[-1] != '/';
1930 dest--);
1931 if (dest[-1] != '/')
1932 dest--;
1933 current += 2;
1934 if (*current == '/')
1935 current++;
1936 } else if (dest == *junkptr + 1) {
1937 /* This might break with Cygwin's leading double slashes? */
1938 current += 2;
1939 } else {
1940 return 0;
1942 } else if (current[0] == '.' && (current[1] == '/' || !current[1])) {
1943 while (*++current == '/');
1944 } else {
1945 while (*current != '/' && *current != '\0')
1946 if ((*dest++ = *current++) == Meta)
1947 *dest++ = *current++;
1950 return 1;
1954 * Resolve symlinks in junkptr.
1956 * If mode is 'A', resolve dot-dot before symlinks. Else, mode should be 'P'.
1957 * Refer to the documentation of the :A and :P modifiers for details.
1959 * use_heap is 1 if the result is to be allocated on the heap, 0 otherwise.
1961 * Return 0 for error, non-zero for success.
1964 /**/
1966 chrealpath(char **junkptr, char mode, int use_heap)
1968 char *str;
1969 #ifdef HAVE_REALPATH
1970 # ifdef REALPATH_ACCEPTS_NULL
1971 char *lastpos, *nonreal, *real;
1972 # else
1973 char *lastpos, *nonreal, pathbuf[PATH_MAX+1];
1974 char *real = pathbuf;
1975 # endif
1976 #endif
1978 DPUTS1(mode != 'A' && mode != 'P', "chrealpath: mode='%c' is invalid", mode);
1980 if (!**junkptr)
1981 return 1;
1983 if (mode == 'A')
1984 if (!chabspath(junkptr))
1985 return 0;
1987 #ifndef HAVE_REALPATH
1988 return 1;
1989 #else
1991 * Notice that this means you cannot pass relative paths into this
1992 * function!
1994 if (**junkptr != '/')
1995 return 0;
1997 unmetafy(*junkptr, NULL);
1999 lastpos = strend(*junkptr);
2000 nonreal = lastpos + 1;
2002 while (!
2003 #ifdef REALPATH_ACCEPTS_NULL
2004 /* realpath() with a NULL second argument uses malloc() to get
2005 * memory so we don't need to worry about overflowing PATH_MAX */
2006 (real = realpath(*junkptr, NULL))
2007 #else
2008 realpath(*junkptr, real)
2009 #endif
2011 if (errno == EINVAL || errno == ENOMEM)
2012 return 0;
2014 if (nonreal == *junkptr) {
2015 #ifndef REALPATH_ACCEPTS_NULL
2016 real = NULL;
2017 #endif
2018 break;
2021 while (*nonreal != '/' && nonreal >= *junkptr)
2022 nonreal--;
2023 *nonreal = '\0';
2026 str = nonreal;
2027 while (str <= lastpos) {
2028 if (*str == '\0')
2029 *str = '/';
2030 str++;
2033 use_heap = (use_heap ? META_HEAPDUP : META_DUP);
2034 if (real) {
2035 *junkptr = metafy(str = bicat(real, nonreal), -1, use_heap);
2036 zsfree(str);
2037 #ifdef REALPATH_ACCEPTS_NULL
2038 free(real);
2039 #endif
2040 } else {
2041 *junkptr = metafy(nonreal, lastpos - nonreal + 1, use_heap);
2043 #endif
2045 return 1;
2048 /**/
2050 remtpath(char **junkptr, int count)
2052 char *str = strend(*junkptr);
2054 /* ignore trailing slashes */
2055 while (str >= *junkptr && IS_DIRSEP(*str))
2056 --str;
2057 if (!count) {
2058 /* skip filename */
2059 while (str >= *junkptr && !IS_DIRSEP(*str))
2060 --str;
2062 if (str < *junkptr) {
2063 if (IS_DIRSEP(**junkptr))
2064 *junkptr = dupstring ("/");
2065 else
2066 *junkptr = dupstring (".");
2068 return 0;
2071 if (count)
2074 * Return this many components, so start from the front.
2075 * Leading slash counts as one component, consistent with
2076 * behaviour of repeated applications of :h.
2078 char *strp = *junkptr;
2079 while (strp < str) {
2080 if (IS_DIRSEP(*strp)) {
2081 if (--count <= 0) {
2082 if (strp == *junkptr)
2083 ++strp;
2084 *strp = '\0';
2085 return 1;
2087 /* Count consecutive separators as one */
2088 while (IS_DIRSEP(strp[1]))
2089 ++strp;
2091 ++strp;
2094 /* Full string needed */
2095 return 1;
2098 /* repeated slashes are considered like a single slash */
2099 while (str > *junkptr && IS_DIRSEP(str[-1]))
2100 --str;
2101 /* never erase the root slash */
2102 if (str == *junkptr) {
2103 ++str;
2104 /* Leading doubled slashes (`//') have a special meaning on cygwin
2105 and some old flavor of UNIX, so we do not assimilate them to
2106 a single slash. However a greater number is ok to squeeze. */
2107 if (IS_DIRSEP(*str) && !IS_DIRSEP(str[1]))
2108 ++str;
2110 *str = '\0';
2111 return 1;
2114 /**/
2116 remtext(char **junkptr)
2118 char *str;
2120 for (str = strend(*junkptr); str >= *junkptr && !IS_DIRSEP(*str); --str)
2121 if (*str == '.') {
2122 *str = '\0';
2123 return 1;
2125 return 0;
2128 /**/
2130 rembutext(char **junkptr)
2132 char *str;
2134 for (str = strend(*junkptr); str >= *junkptr && !IS_DIRSEP(*str); --str)
2135 if (*str == '.') {
2136 *junkptr = dupstring(str + 1); /* .xx or xx? */
2137 return 1;
2139 /* no extension */
2140 *junkptr = dupstring ("");
2141 return 0;
2144 /**/
2145 mod_export int
2146 remlpaths(char **junkptr, int count)
2148 char *str = strend(*junkptr);
2150 if (IS_DIRSEP(*str)) {
2151 /* remove trailing slashes */
2152 while (str >= *junkptr && IS_DIRSEP(*str))
2153 --str;
2154 str[1] = '\0';
2156 for (;;) {
2157 for (; str >= *junkptr; --str) {
2158 if (IS_DIRSEP(*str)) {
2159 if (--count > 0) {
2160 if (str > *junkptr) {
2161 --str;
2162 break;
2163 } else {
2164 /* Whole string needed */
2165 return 1;
2168 *str = '\0';
2169 *junkptr = dupstring(str + 1);
2170 return 1;
2173 /* Count consecutive separators as 1 */
2174 while (str >= *junkptr && IS_DIRSEP(*str))
2175 --str;
2176 if (str <= *junkptr)
2177 break;
2179 return 0;
2183 * Return modified version of str from the heap with modification
2184 * according to one of the CASMOD_* types defined in zsh.h; CASMOD_NONE
2185 * is not handled, for obvious reasons.
2188 /**/
2189 char *
2190 casemodify(char *str, int how)
2192 char *str2 = zhalloc(2 * strlen(str) + 1);
2193 char *ptr2 = str2;
2194 int nextupper = 1;
2196 #ifdef MULTIBYTE_SUPPORT
2197 if (isset(MULTIBYTE)) {
2198 VARARR(char, mbstr, MB_CUR_MAX);
2199 mbstate_t ps;
2201 mb_charinit();
2202 memset(&ps, 0, sizeof(ps));
2203 while (*str) {
2204 wint_t wc;
2205 int len = mb_metacharlenconv(str, &wc), mod = 0, len2;
2207 * wc is set to WEOF if the start of str couldn't be
2208 * converted. Presumably WEOF doesn't match iswlower(), but
2209 * better be safe.
2211 if (wc == WEOF) {
2212 while (len--)
2213 *ptr2++ = *str++;
2214 /* not alphanumeric */
2215 nextupper = 1;
2216 continue;
2218 switch (how) {
2219 case CASMOD_LOWER:
2220 if (iswupper(wc)) {
2221 wc = towlower(wc);
2222 mod = 1;
2224 break;
2226 case CASMOD_UPPER:
2227 if (iswlower(wc)) {
2228 wc = towupper(wc);
2229 mod = 1;
2231 break;
2233 case CASMOD_CAPS:
2234 default: /* shuts up compiler */
2235 if (IS_COMBINING(wc))
2236 break;
2237 if (!iswalnum(wc))
2238 nextupper = 1;
2239 else if (nextupper) {
2240 if (iswlower(wc)) {
2241 wc = towupper(wc);
2242 mod = 1;
2244 nextupper = 0;
2245 } else if (iswupper(wc)) {
2246 wc = towlower(wc);
2247 mod = 1;
2249 break;
2251 if (mod && (len2 = wcrtomb(mbstr, wc, &ps)) > 0) {
2252 char *mbptr;
2254 for (mbptr = mbstr; mbptr < mbstr + len2; mbptr++) {
2255 if (imeta((unsigned char) *mbptr)) {
2256 *ptr2++ = Meta;
2257 *ptr2++ = *mbptr ^ 32;
2258 } else
2259 *ptr2++ = *mbptr;
2261 str += len;
2262 } else {
2263 while (len--)
2264 *ptr2++ = *str++;
2268 else
2269 #endif
2270 while (*str) {
2271 int c;
2272 int mod = 0;
2273 if (*str == Meta) {
2274 c = (unsigned char) (str[1] ^ 32);
2275 str += 2;
2276 } else
2277 c = (unsigned char) *str++;
2278 switch (how) {
2279 case CASMOD_LOWER:
2280 if (isupper(c)) {
2281 c = tolower(c);
2282 mod = 1;
2284 break;
2286 case CASMOD_UPPER:
2287 if (islower(c)) {
2288 c = toupper(c);
2289 mod = 1;
2291 break;
2293 case CASMOD_CAPS:
2294 default: /* shuts up compiler */
2295 if (!ialnum(c))
2296 nextupper = 1;
2297 else if (nextupper) {
2298 if (islower(c)) {
2299 c = toupper(c);
2300 mod = 1;
2302 nextupper = 0;
2303 } else if (isupper(c)) {
2304 c = tolower(c);
2305 mod = 1;
2307 break;
2309 if (mod && imeta(c)) {
2310 *ptr2++ = Meta;
2311 *ptr2++ = c ^ 32;
2312 } else
2313 *ptr2++ = c;
2315 *ptr2 = '\0';
2316 return str2;
2321 * Substitute "in" for "out" in "*strptr" and update "*strptr".
2322 * If "gbal", do global substitution.
2324 * This returns a result from the heap. There seems to have
2325 * been some confusion on this point.
2328 /**/
2330 subst(char **strptr, char *in, char *out, int gbal, int forcepat)
2332 char *str = *strptr, *substcut, *sptr;
2333 int off, inlen, outlen;
2335 if (!*in)
2336 in = str, gbal = 0;
2338 if (isset(HISTSUBSTPATTERN) || forcepat) {
2339 int fl = SUB_LONG|SUB_REST|SUB_RETFAIL;
2340 char *oldin = in;
2341 if (gbal)
2342 fl |= SUB_GLOBAL;
2343 if (*in == '#' || *in == Pound) {
2344 /* anchor at head, flag needed if SUB_END is also set */
2345 fl |= SUB_START;
2346 in++;
2348 if (*in == '%') {
2349 /* anchor at tail */
2350 in++;
2351 fl |= SUB_END;
2353 if (in == oldin) {
2354 /* no anchor, substring match */
2355 fl |= SUB_SUBSTR;
2357 if (in == str)
2358 in = dupstring(in);
2359 if (parse_subst_string(in) || errflag)
2360 return 1;
2361 if (parse_subst_string(out) || errflag)
2362 return 1;
2363 singsub(&in);
2364 if (getmatch(strptr, in, fl, 1, out))
2365 return 0;
2366 } else {
2367 if ((substcut = (char *)strstr(str, in))) {
2368 inlen = strlen(in);
2369 sptr = convamps(out, in, inlen);
2370 outlen = strlen(sptr);
2372 do {
2373 *substcut = '\0';
2374 off = substcut - *strptr + outlen;
2375 substcut += inlen;
2376 *strptr = zhtricat(*strptr, sptr, substcut);
2377 str = (char *)*strptr + off;
2378 } while (gbal && (substcut = (char *)strstr(str, in)));
2380 return 0;
2384 return 1;
2387 /**/
2388 static char *
2389 convamps(char *out, char *in, int inlen)
2391 char *ptr, *ret, *pp;
2392 int slen, sdup = 0;
2394 for (ptr = out, slen = 0; *ptr; ptr++, slen++)
2395 if (*ptr == '\\')
2396 ptr++, sdup = 1;
2397 else if (*ptr == '&')
2398 slen += inlen - 1, sdup = 1;
2399 if (!sdup)
2400 return out;
2401 ret = pp = (char *) zhalloc(slen + 1);
2402 for (ptr = out; *ptr; ptr++)
2403 if (*ptr == '\\')
2404 *pp++ = *++ptr;
2405 else if (*ptr == '&') {
2406 strcpy(pp, in);
2407 pp += inlen;
2408 } else
2409 *pp++ = *ptr;
2410 *pp = '\0';
2411 return ret;
2414 /**/
2415 mod_export void
2416 checkcurline(Histent he)
2418 if (he->histnum == curhist && (histactive & HA_ACTIVE)) {
2419 curline.node.nam = chline;
2420 curline.nwords = chwordpos/2;
2421 curline.words = chwords;
2425 /**/
2426 mod_export Histent
2427 quietgethist(int ev)
2429 return gethistent(ev, GETHIST_EXACT);
2432 /**/
2433 static Histent
2434 gethist(int ev)
2436 Histent ret;
2438 ret = quietgethist(ev);
2439 if (!ret) {
2440 herrflush();
2441 zerr("no such event: %d", ev);
2443 return ret;
2446 /**/
2447 static char *
2448 getargs(Histent elist, int arg1, int arg2)
2450 short *words = elist->words;
2451 int pos1, pos2, nwords = elist->nwords;
2453 if (arg2 < arg1 || arg1 >= nwords || arg2 >= nwords) {
2454 /* remember, argN is indexed from 0, nwords is total no. of words */
2455 herrflush();
2456 zerr("no such word in event");
2457 return NULL;
2460 /* optimization for accessing entire history event */
2461 if (arg1 == 0 && arg2 == nwords - 1)
2462 return dupstring(elist->node.nam);
2464 pos1 = words[2*arg1];
2465 pos2 = words[2*arg2+1];
2467 /* a word has to be at least one character long, so if the position
2468 * of a word is less than its index, we've overflowed our signed
2469 * short integer word range and the recorded position is garbage. */
2470 if (pos1 < 0 || pos1 < arg1 || pos2 < 0 || pos2 < arg2) {
2471 herrflush();
2472 zerr("history event too long, can't index requested words");
2473 return NULL;
2475 return dupstrpfx(elist->node.nam + pos1, pos2 - pos1);
2478 /**/
2479 static int
2480 quote(char **tr)
2482 char *ptr, *rptr, **str = tr;
2483 int len = 3;
2484 int inquotes = 0;
2486 for (ptr = *str; *ptr; ptr++, len++)
2487 if (*ptr == '\'') {
2488 len += 3;
2489 if (!inquotes)
2490 inquotes = 1;
2491 else
2492 inquotes = 0;
2493 } else if (inblank(*ptr) && !inquotes && ptr[-1] != '\\')
2494 len += 2;
2495 ptr = *str;
2496 *str = rptr = (char *) zhalloc(len);
2497 *rptr++ = '\'';
2498 for (; *ptr; ptr++)
2499 if (*ptr == '\'') {
2500 if (!inquotes)
2501 inquotes = 1;
2502 else
2503 inquotes = 0;
2504 *rptr++ = '\'';
2505 *rptr++ = '\\';
2506 *rptr++ = '\'';
2507 *rptr++ = '\'';
2508 } else if (inblank(*ptr) && !inquotes && ptr[-1] != '\\') {
2509 *rptr++ = '\'';
2510 *rptr++ = *ptr;
2511 *rptr++ = '\'';
2512 } else
2513 *rptr++ = *ptr;
2514 *rptr++ = '\'';
2515 *rptr++ = 0;
2516 return 0;
2519 /**/
2520 static int
2521 quotebreak(char **tr)
2523 char *ptr, *rptr, **str = tr;
2524 int len = 3;
2526 for (ptr = *str; *ptr; ptr++, len++)
2527 if (*ptr == '\'')
2528 len += 3;
2529 else if (inblank(*ptr))
2530 len += 2;
2531 ptr = *str;
2532 *str = rptr = (char *) zhalloc(len);
2533 *rptr++ = '\'';
2534 for (; *ptr;)
2535 if (*ptr == '\'') {
2536 *rptr++ = '\'';
2537 *rptr++ = '\\';
2538 *rptr++ = '\'';
2539 *rptr++ = '\'';
2540 ptr++;
2541 } else if (inblank(*ptr)) {
2542 *rptr++ = '\'';
2543 *rptr++ = *ptr++;
2544 *rptr++ = '\'';
2545 } else
2546 *rptr++ = *ptr++;
2547 *rptr++ = '\'';
2548 *rptr++ = '\0';
2549 return 0;
2552 /* read an arbitrary amount of data into a buffer until stop is found */
2554 #if 0 /**/
2555 char *
2556 hdynread(int stop)
2558 int bsiz = 256, ct = 0, c;
2559 char *buf = (char *)zalloc(bsiz), *ptr;
2561 ptr = buf;
2562 while ((c = ingetc()) != stop && c != '\n' && !lexstop) {
2563 if (c == '\\')
2564 c = ingetc();
2565 *ptr++ = c;
2566 if (++ct == bsiz) {
2567 buf = realloc(buf, bsiz *= 2);
2568 ptr = buf + ct;
2571 *ptr = 0;
2572 if (c == '\n') {
2573 inungetc('\n');
2574 zerr("delimiter expected");
2575 zfree(buf, bsiz);
2576 return NULL;
2578 return buf;
2580 #endif
2582 /**/
2583 static char *
2584 hdynread2(int stop)
2586 int bsiz = 256, ct = 0, c;
2587 char *buf = (char *)zalloc(bsiz), *ptr;
2589 ptr = buf;
2590 while ((c = ingetc()) != stop && c != '\n' && !lexstop) {
2591 if (c == '\\')
2592 c = ingetc();
2593 *ptr++ = c;
2594 if (++ct == bsiz) {
2595 buf = realloc(buf, bsiz *= 2);
2596 ptr = buf + ct;
2599 *ptr = 0;
2600 if (c == '\n')
2601 inungetc('\n');
2602 return buf;
2605 /**/
2606 void
2607 inithist(void)
2609 createhisttable();
2612 /**/
2613 void
2614 resizehistents(void)
2616 if (histlinect > histsiz) {
2617 /* The reason we don't just call freehistnode(hist_ring->down) is
2618 * so that we can honor the HISTEXPIREDUPSFIRST setting. */
2619 putoldhistentryontop(0);
2620 freehistnode(&hist_ring->node);
2621 while (histlinect > histsiz) {
2622 putoldhistentryontop(1);
2623 freehistnode(&hist_ring->node);
2628 static int
2629 readhistline(int start, char **bufp, int *bufsiz, FILE *in, int *readbytes)
2631 char *buf = *bufp;
2632 if (fgets(buf + start, *bufsiz - start, in)) {
2633 int len = strlen(buf + start);
2634 *readbytes += len;
2635 len += start;
2636 if (len == start)
2637 return -1;
2638 if (buf[len - 1] != '\n') {
2639 if (!feof(in)) {
2640 if (len < (*bufsiz) - 1)
2641 return -1;
2642 *bufp = zrealloc(buf, 2 * (*bufsiz));
2643 *bufsiz = 2 * (*bufsiz);
2644 return readhistline(len, bufp, bufsiz, in, readbytes);
2647 else {
2648 int spc;
2649 buf[len - 1] = '\0';
2650 if (len > 1 && buf[len - 2] == '\\') {
2651 buf[--len - 1] = '\n';
2652 if (!feof(in))
2653 return readhistline(len, bufp, bufsiz, in, readbytes);
2656 spc = len - 2;
2657 while (spc >= 0 && buf[spc] == ' ')
2658 spc--;
2659 if (spc != len - 2 && buf[spc] == '\\')
2660 buf[--len - 1] = '\0';
2662 return len;
2664 return 0;
2667 /**/
2668 void
2669 readhistfile(char *fn, int err, int readflags)
2671 char *buf, *start = NULL;
2672 FILE *in;
2673 Histent he;
2674 time_t stim, ftim, tim = time(NULL);
2675 off_t fpos;
2676 short *words;
2677 struct stat sb;
2678 int nwordpos, nwords, bufsiz;
2679 int searching, newflags, l, ret, uselex, readbytes;
2681 if (!fn && !(fn = getsparam("HISTFILE")))
2682 return;
2683 if (stat(unmeta(fn), &sb) < 0 ||
2684 sb.st_size == 0)
2685 return;
2686 if (readflags & HFILE_FAST) {
2687 if (!lasthist.interrupted &&
2688 ((lasthist.fsiz == sb.st_size && lasthist.mtim == sb.st_mtime)
2689 || lockhistfile(fn, 0)))
2690 return;
2691 lasthist.fsiz = sb.st_size;
2692 lasthist.mtim = sb.st_mtime;
2693 lasthist.interrupted = 0;
2694 } else if ((ret = lockhistfile(fn, 1))) {
2695 if (ret == 2) {
2696 zwarn("locking failed for %s: %e: reading anyway", fn, errno);
2697 } else {
2698 zerr("locking failed for %s: %e", fn, errno);
2699 return;
2702 if ((in = fopen(unmeta(fn), "r"))) {
2703 nwords = 64;
2704 words = (short *)zalloc(nwords*sizeof(short));
2705 bufsiz = 1024;
2706 buf = zalloc(bufsiz);
2708 pushheap();
2709 if (readflags & HFILE_FAST && lasthist.text) {
2710 if (lasthist.fpos < lasthist.fsiz) {
2711 fseek(in, lasthist.fpos, SEEK_SET);
2712 searching = 1;
2714 else {
2715 histfile_linect = 0;
2716 searching = -1;
2718 } else
2719 searching = 0;
2721 fpos = ftell(in);
2722 readbytes = 0;
2723 newflags = HIST_OLD | HIST_READ;
2724 if (readflags & HFILE_FAST)
2725 newflags |= HIST_FOREIGN;
2726 if (readflags & HFILE_SKIPOLD
2727 || (hist_ignore_all_dups && newflags & hist_skip_flags))
2728 newflags |= HIST_MAKEUNIQUE;
2729 while (fpos += readbytes, readbytes = 0, (l = readhistline(0, &buf, &bufsiz, in, &readbytes))) {
2730 char *pt;
2731 int remeta = 0;
2733 if (l < 0) {
2734 zerr("corrupt history file %s", fn);
2735 break;
2739 * Handle the special case that we're reading from an
2740 * old shell with fewer meta characters, so we need to
2741 * metafy some more. (It's not clear why the history
2742 * file is metafied at all; some would say this is plain
2743 * stupid. But we're stuck with it now without some
2744 * hairy workarounds for compatibility).
2746 * This is rare so doesn't need to be that efficient; just
2747 * allocate space off the heap.
2749 for (pt = buf; *pt; pt++) {
2750 if (*pt == Meta && pt[1])
2751 pt++;
2752 else if (imeta(*pt)) {
2753 remeta = 1;
2754 break;
2757 if (remeta) {
2758 unmetafy(buf, &remeta);
2759 pt = metafy(buf, remeta, META_USEHEAP);
2760 } else {
2761 pt = buf;
2764 if (*pt == ':') {
2765 pt++;
2766 stim = zstrtol(pt, NULL, 0);
2767 for (; *pt != ':' && *pt; pt++);
2768 if (*pt) {
2769 pt++;
2770 ftim = zstrtol(pt, NULL, 0);
2771 for (; *pt != ';' && *pt; pt++);
2772 if (*pt)
2773 pt++;
2774 } else
2775 ftim = stim;
2776 } else {
2777 if (*pt == '\\' && pt[1] == ':')
2778 pt++;
2779 stim = ftim = 0;
2782 if (searching) {
2783 if (searching > 0) {
2784 if (stim == lasthist.stim
2785 && histstrcmp(pt, lasthist.text) == 0)
2786 searching = 0;
2787 else {
2788 fseek(in, 0, SEEK_SET);
2789 histfile_linect = 0;
2790 searching = -1;
2792 continue;
2794 else if (stim < lasthist.stim) {
2795 histfile_linect++;
2796 continue;
2798 searching = 0;
2801 if (readflags & HFILE_USE_OPTIONS) {
2802 histfile_linect++;
2803 lasthist.fpos = fpos;
2804 lasthist.stim = stim;
2807 he = prepnexthistent();
2808 he->node.nam = ztrdup(pt);
2809 he->node.flags = newflags;
2810 if ((he->stim = stim) == 0)
2811 he->stim = he->ftim = tim;
2812 else if (ftim < stim)
2813 he->ftim = stim + ftim;
2814 else
2815 he->ftim = ftim;
2818 * Divide up the words.
2820 start = pt;
2821 uselex = isset(HISTLEXWORDS) && !(readflags & HFILE_FAST);
2822 histsplitwords(pt, &words, &nwords, &nwordpos, uselex);
2824 he->nwords = nwordpos/2;
2825 if (he->nwords) {
2826 he->words = (short *)zalloc(nwordpos*sizeof(short));
2827 memcpy(he->words, words, nwordpos*sizeof(short));
2828 } else
2829 he->words = (short *)NULL;
2830 addhistnode(histtab, he->node.nam, he);
2831 if (he->node.flags & HIST_DUP) {
2832 freehistnode(&he->node);
2833 curhist--;
2836 * Do this last out of paranoia in case use of
2837 * heap is disguised...
2839 if (uselex || remeta)
2840 freeheap();
2841 if (errflag & ERRFLAG_INT) {
2842 /* Can't assume fast read next time if interrupted. */
2843 lasthist.interrupted = 1;
2844 break;
2847 if (start && readflags & HFILE_USE_OPTIONS) {
2848 zsfree(lasthist.text);
2849 lasthist.text = ztrdup(start);
2851 zfree(words, nwords*sizeof(short));
2852 zfree(buf, bufsiz);
2854 popheap();
2855 fclose(in);
2856 } else if (err)
2857 zerr("can't read history file %s", fn);
2859 unlockhistfile(fn);
2861 if (zleactive)
2862 zleentry(ZLE_CMD_SET_HIST_LINE, curhist);
2865 #ifdef HAVE_FCNTL_H
2866 static int flock_fd = -1;
2869 * Lock file using fcntl(). Return 0 on success, 1 on failure of
2870 * locking mechanism, 2 on permanent failure (e.g. permission).
2873 static int
2874 flockhistfile(char *fn, int keep_trying)
2876 struct flock lck;
2877 long sleep_us = 0x10000; /* about 67 ms */
2878 time_t end_time;
2880 if (flock_fd >= 0)
2881 return 0; /* already locked */
2883 if ((flock_fd = open(unmeta(fn), O_RDWR | O_NOCTTY)) < 0)
2884 return errno == ENOENT ? 0 : 2; /* "successfully" locked missing file */
2886 lck.l_type = F_WRLCK;
2887 lck.l_whence = SEEK_SET;
2888 lck.l_start = 0;
2889 lck.l_len = 0; /* lock the whole file */
2892 * Timeout is ten seconds.
2894 end_time = time(NULL) + (time_t)10;
2895 while (fcntl(flock_fd, F_SETLKW, &lck) == -1) {
2896 if (!keep_trying || time(NULL) >= end_time ||
2898 * Randomise wait to minimise clashes with shells exiting at
2899 * the same time.
2901 !zsleep_random(sleep_us, end_time)) {
2902 close(flock_fd);
2903 flock_fd = -1;
2904 return 1;
2906 sleep_us <<= 1;
2909 return 0;
2911 #endif
2913 /**/
2914 void
2915 savehistfile(char *fn, int err, int writeflags)
2917 char *t, *tmpfile, *start = NULL;
2918 FILE *out;
2919 Histent he;
2920 zlong xcurhist = curhist - !!(histactive & HA_ACTIVE);
2921 int extended_history = isset(EXTENDEDHISTORY);
2922 int ret;
2924 if (!interact || savehistsiz <= 0 || !hist_ring
2925 || (!fn && !(fn = getsparam("HISTFILE"))))
2926 return;
2927 if (writeflags & HFILE_FAST) {
2928 he = gethistent(lasthist.next_write_ev, GETHIST_DOWNWARD);
2929 while (he && he->node.flags & HIST_OLD) {
2930 lasthist.next_write_ev = he->histnum + 1;
2931 he = down_histent(he);
2933 if (!he || lockhistfile(fn, 0))
2934 return;
2935 if (histfile_linect > savehistsiz + savehistsiz / 5)
2936 writeflags &= ~HFILE_FAST;
2938 else {
2939 if (lockhistfile(fn, 1)) {
2940 zerr("locking failed for %s: %e", fn, errno);
2941 return;
2943 he = hist_ring->down;
2945 if (writeflags & HFILE_USE_OPTIONS) {
2946 if (isset(APPENDHISTORY) || isset(INCAPPENDHISTORY)
2947 || isset(INCAPPENDHISTORYTIME) || isset(SHAREHISTORY))
2948 writeflags |= HFILE_APPEND | HFILE_SKIPOLD;
2949 else
2950 histfile_linect = 0;
2951 if (isset(HISTSAVENODUPS))
2952 writeflags |= HFILE_SKIPDUPS;
2953 if (isset(SHAREHISTORY))
2954 extended_history = 1;
2956 errno = 0;
2957 if (writeflags & HFILE_APPEND) {
2958 int fd = open(unmeta(fn), O_CREAT | O_WRONLY | O_APPEND | O_NOCTTY, 0600);
2959 tmpfile = NULL;
2960 out = fd >= 0 ? fdopen(fd, "a") : NULL;
2961 } else if (!isset(HISTSAVEBYCOPY)) {
2962 int fd = open(unmeta(fn), O_CREAT | O_WRONLY | O_TRUNC | O_NOCTTY, 0600);
2963 tmpfile = NULL;
2964 out = fd >= 0 ? fdopen(fd, "w") : NULL;
2965 } else {
2966 tmpfile = bicat(unmeta(fn), ".new");
2967 if (unlink(tmpfile) < 0 && errno != ENOENT)
2968 out = NULL;
2969 else {
2970 struct stat sb;
2971 int old_exists = stat(unmeta(fn), &sb) == 0;
2972 uid_t euid = geteuid();
2974 if (old_exists
2975 #if defined HAVE_FCHMOD && defined HAVE_FCHOWN
2976 && euid
2977 #endif
2978 && sb.st_uid != euid) {
2979 free(tmpfile);
2980 tmpfile = NULL;
2981 if (err) {
2982 if (isset(APPENDHISTORY) || isset(INCAPPENDHISTORY)
2983 || isset(INCAPPENDHISTORYTIME) || isset(SHAREHISTORY))
2984 zerr("rewriting %s would change its ownership -- skipped", fn);
2985 else
2986 zerr("rewriting %s would change its ownership -- history not saved", fn);
2987 err = 0; /* Don't report a generic error below. */
2989 out = NULL;
2990 } else {
2991 int fd = open(tmpfile, O_CREAT | O_WRONLY | O_EXCL, 0600);
2992 if (fd >=0) {
2993 out = fdopen(fd, "w");
2994 if (!out)
2995 close(fd);
2996 } else
2997 out = NULL;
3000 #ifdef HAVE_FCHMOD
3001 if (old_exists && out) {
3002 #ifdef HAVE_FCHOWN
3003 if (fchown(fileno(out), sb.st_uid, sb.st_gid) < 0) {} /* IGNORE FAILURE */
3004 #endif
3005 if (fchmod(fileno(out), sb.st_mode) < 0) {} /* IGNORE FAILURE */
3007 #endif
3010 if (out) {
3011 char *history_ignore;
3012 Patprog histpat = NULL;
3014 pushheap();
3016 if ((history_ignore = getsparam("HISTORY_IGNORE")) != NULL) {
3017 tokenize(history_ignore = dupstring(history_ignore));
3018 remnulargs(history_ignore);
3019 histpat = patcompile(history_ignore, 0, NULL);
3022 ret = 0;
3023 for (; he && he->histnum <= xcurhist; he = down_histent(he)) {
3024 int end_backslashes = 0;
3026 if ((writeflags & HFILE_SKIPDUPS && he->node.flags & HIST_DUP)
3027 || (writeflags & HFILE_SKIPFOREIGN && he->node.flags & HIST_FOREIGN)
3028 || he->node.flags & HIST_TMPSTORE)
3029 continue;
3030 if (histpat &&
3031 pattry(histpat, metafy(he->node.nam, -1, META_HEAPDUP))) {
3032 continue;
3034 if (writeflags & HFILE_SKIPOLD) {
3035 if (he->node.flags & (HIST_OLD|HIST_NOWRITE))
3036 continue;
3037 he->node.flags |= HIST_OLD;
3038 if (writeflags & HFILE_USE_OPTIONS)
3039 lasthist.next_write_ev = he->histnum + 1;
3041 if (writeflags & HFILE_USE_OPTIONS) {
3042 lasthist.fpos = ftell(out);
3043 lasthist.stim = he->stim;
3044 histfile_linect++;
3046 t = start = he->node.nam;
3047 if (extended_history) {
3048 ret = fprintf(out, ": %ld:%ld;", (long)he->stim,
3049 he->ftim? (long)(he->ftim - he->stim) : 0L);
3050 } else if (*t == ':')
3051 ret = fputc('\\', out);
3053 for (; ret >= 0 && *t; t++) {
3054 if (*t == '\n')
3055 if ((ret = fputc('\\', out)) < 0)
3056 break;
3057 end_backslashes = (*t == '\\' || (end_backslashes && *t == ' '));
3058 if ((ret = fputc(*t, out)) < 0)
3059 break;
3061 if (ret < 0)
3062 break;
3063 if (end_backslashes)
3064 ret = fputc(' ', out);
3065 if (ret < 0 || (ret = fputc('\n', out)) < 0)
3066 break;
3068 if (ret >= 0 && start && writeflags & HFILE_USE_OPTIONS) {
3069 struct stat sb;
3070 if ((ret = fflush(out)) >= 0) {
3071 if (fstat(fileno(out), &sb) == 0) {
3072 lasthist.fsiz = sb.st_size;
3073 lasthist.mtim = sb.st_mtime;
3075 zsfree(lasthist.text);
3076 lasthist.text = ztrdup(start);
3079 if (fclose(out) < 0 && ret >= 0)
3080 ret = -1;
3081 if (ret >= 0) {
3082 if (tmpfile) {
3083 if (rename(tmpfile, unmeta(fn)) < 0) {
3084 zerr("can't rename %s.new to $HISTFILE", fn);
3085 ret = -1;
3086 err = 0;
3087 #ifdef HAVE_FCNTL_H
3088 } else {
3089 /* We renamed over the locked HISTFILE, so close fd.
3090 * If we do more writing, we'll get a lock then. */
3091 if (flock_fd >= 0) {
3092 close(flock_fd);
3093 flock_fd = -1;
3095 #endif
3099 if (ret >= 0 && writeflags & HFILE_SKIPOLD
3100 && !(writeflags & (HFILE_FAST | HFILE_NO_REWRITE))) {
3101 int remember_histactive = histactive;
3103 /* Zeroing histactive avoids unnecessary munging of curline. */
3104 histactive = 0;
3105 /* The NULL leaves HISTFILE alone, preserving fn's value. */
3106 pushhiststack(NULL, savehistsiz, savehistsiz, -1);
3108 hist_ignore_all_dups |= isset(HISTSAVENODUPS);
3109 readhistfile(fn, err, 0);
3110 hist_ignore_all_dups = isset(HISTIGNOREALLDUPS);
3111 if (histlinect)
3112 savehistfile(fn, err, 0);
3114 pophiststack();
3115 histactive = remember_histactive;
3119 popheap();
3120 } else
3121 ret = -1;
3123 if (ret < 0 && err) {
3124 if (tmpfile)
3125 zerr("failed to write history file %s.new: %e", fn, errno);
3126 else
3127 zerr("failed to write history file %s: %e", fn, errno);
3129 if (tmpfile)
3130 free(tmpfile);
3132 unlockhistfile(fn);
3135 static int lockhistct;
3137 static int
3138 checklocktime(char *lockfile, long *sleep_usp, time_t then)
3140 time_t now = time(NULL);
3142 if (now + 10 < then) {
3143 /* File is more than 10 seconds in the future? */
3144 errno = EEXIST;
3145 return -1;
3148 if (now - then < 10) {
3150 * To give the effect of a gradually increasing backoff,
3151 * we'll sleep a period based on the time we've spent so far.
3153 DPUTS(now < then, "time flowing backwards through history");
3155 * Randomise to minimise clashes with shells exiting at the same
3156 * time.
3158 (void)zsleep_random(*sleep_usp, then + 10);
3159 *sleep_usp <<= 1;
3160 } else
3161 unlink(lockfile);
3163 return 0;
3167 * Lock history file. Return 0 on success, 1 on failure to lock this
3168 * time, 2 on permanent failure (e.g. permission).
3171 /**/
3173 lockhistfile(char *fn, int keep_trying)
3175 int ct = lockhistct;
3176 int ret = 0;
3177 long sleep_us = 0x10000; /* about 67 ms */
3179 if (!fn && !(fn = getsparam("HISTFILE")))
3180 return 1;
3182 if (!lockhistct++) {
3183 struct stat sb;
3184 int fd;
3185 char *lockfile;
3186 #ifdef HAVE_LINK
3187 # ifdef HAVE_SYMLINK
3188 char pidbuf[32], *lnk;
3189 # else
3190 char *tmpfile;
3191 # endif
3192 #endif
3194 #ifdef HAVE_FCNTL_H
3195 if (isset(HISTFCNTLLOCK))
3196 return flockhistfile(fn, keep_trying);
3197 #endif
3199 lockfile = bicat(unmeta(fn), ".LOCK");
3200 /* NOTE: only use symlink locking on a link()-having host in order to
3201 * avoid a change from open()-based locking to symlink()-based. */
3202 #ifdef HAVE_LINK
3203 # ifdef HAVE_SYMLINK
3204 sprintf(pidbuf, "/pid-%ld/host-", (long)mypid);
3205 lnk = getsparam("HOST");
3206 lnk = bicat(pidbuf, lnk ? lnk : "");
3207 /* We'll abuse fd as our success flag. */
3208 while ((fd = symlink(lnk, lockfile)) < 0) {
3209 if (errno != EEXIST) {
3210 ret = 2;
3211 break;
3212 } else if (!keep_trying) {
3213 ret = 1;
3214 break;
3216 if (lstat(lockfile, &sb) < 0) {
3217 if (errno == ENOENT)
3218 continue;
3219 break;
3221 if (checklocktime(lockfile, &sleep_us, sb.st_mtime) < 0) {
3222 ret = 1;
3223 break;
3226 if (fd < 0)
3227 lockhistct--;
3228 free(lnk);
3229 # else /* not HAVE_SYMLINK */
3230 if ((fd = gettempfile(fn, 0, &tmpfile)) >= 0) {
3231 FILE *out = fdopen(fd, "w");
3232 if (out) {
3233 fprintf(out, "%ld %s\n", (long)getpid(), getsparam("HOST"));
3234 fclose(out);
3235 } else
3236 close(fd);
3237 while (link(tmpfile, lockfile) < 0) {
3238 if (errno != EEXIST) {
3239 ret = 2;
3240 break;
3241 } else if (!keep_trying) {
3242 ret = 1;
3243 break;
3244 } else if (lstat(lockfile, &sb) < 0) {
3245 if (errno == ENOENT)
3246 continue;
3247 ret = 2;
3248 } else {
3249 if (checklocktime(lockfile, &sleep_us, sb.st_mtime) < 0) {
3250 ret = 1;
3251 break;
3253 continue;
3255 lockhistct--;
3256 break;
3258 unlink(tmpfile);
3259 free(tmpfile);
3261 # endif /* not HAVE_SYMLINK */
3262 #else /* not HAVE_LINK */
3263 while ((fd = open(lockfile, O_WRONLY|O_CREAT|O_EXCL, 0644)) < 0) {
3264 if (errno != EEXIST) {
3265 ret = 2;
3266 break;
3267 } else if (!keep_trying) {
3268 ret = 1;
3269 break;
3271 if (lstat(lockfile, &sb) < 0) {
3272 if (errno == ENOENT)
3273 continue;
3274 ret = 2;
3275 break;
3277 if (checklocktime(lockfile, &sleep_us, sb.st_mtime) < 0) {
3278 ret = 1;
3279 break;
3282 if (fd < 0)
3283 lockhistct--;
3284 else {
3285 FILE *out = fdopen(fd, "w");
3286 if (out) {
3287 fprintf(out, "%ld %s\n", (long)mypid, getsparam("HOST"));
3288 fclose(out);
3289 } else
3290 close(fd);
3292 #endif /* not HAVE_LINK */
3293 free(lockfile);
3296 if (ct == lockhistct) {
3297 #ifdef HAVE_FCNTL_H
3298 if (flock_fd >= 0) {
3299 close(flock_fd);
3300 flock_fd = -1;
3302 #endif
3303 DPUTS(ret == 0, "BUG: return value non-zero on locking error");
3304 return ret;
3306 return 0;
3309 /* Unlock the history file if this corresponds to the last nested lock
3310 * request. If we don't have the file locked, just return.
3313 /**/
3314 void
3315 unlockhistfile(char *fn)
3317 if (!fn && !(fn = getsparam("HISTFILE")))
3318 return;
3319 if (--lockhistct) {
3320 if (lockhistct < 0)
3321 lockhistct = 0;
3323 else {
3324 char *lockfile;
3325 fn = unmeta(fn);
3326 lockfile = zalloc(strlen(fn) + 5 + 1);
3327 sprintf(lockfile, "%s.LOCK", fn);
3328 unlink(lockfile);
3329 free(lockfile);
3330 #ifdef HAVE_FCNTL_H
3331 if (flock_fd >= 0) {
3332 close(flock_fd);
3333 flock_fd = -1;
3335 #endif
3339 /**/
3341 histfileIsLocked(void)
3343 return lockhistct > 0;
3347 * Get the words in the current buffer. Using the lexer.
3349 * As far as I can make out, this is a gross hack based on a gross hack.
3350 * When analysing lines from within zle, we tweak the metafied line
3351 * positions (zlemetall and zlemetacs) directly in the lexer. That's
3352 * bad enough, but this function appears to be designed to be called
3353 * from outside zle, pretending to be in zle and calling out, so
3354 * we set zlemetall and zlemetacs locally and copy the current zle line,
3355 * which may not even be valid at this point.
3357 * However, I'm so confused it could simply be baking Bakewell tarts.
3359 * list may be an existing linked list (off the heap), in which case
3360 * it will be appended to; otherwise it will be created.
3362 * If buf is set we will take input from that string, else we will
3363 * attempt to use ZLE directly in a way they tell you not to do on all
3364 * programming courses.
3366 * If index is non-NULL, and input is from a string in ZLE, *index
3367 * is set to the position of the end of the current editor word.
3369 * flags is passed directly to lexflags, see lex.c, except that
3370 * we 'or' in the bit LEXFLAGS_ACTIVE to make sure the variable
3371 * is set.
3374 /**/
3375 mod_export LinkList
3376 bufferwords(LinkList list, char *buf, int *index, int flags)
3378 int num = 0, cur = -1, got = 0, ne = noerrs;
3379 int owb = wb, owe = we, oadx = addedx, onc = nocomments;
3380 int ona = noaliases, ocs = zlemetacs, oll = zlemetall;
3381 int forloop = 0, rcquotes = opts[RCQUOTES];
3382 int envarray = 0;
3383 char *p, *addedspaceptr;
3385 if (!list)
3386 list = newlinklist();
3389 * With RC_QUOTES, 'foo '' bar' comes back as 'foo ' bar'. That's
3390 * not very useful. As nothing in here requires the fully processed
3391 * string expression, we just turn the option off for this function.
3393 opts[RCQUOTES] = 0;
3394 addedx = 0;
3395 noerrs = 1;
3396 zcontext_save();
3397 lexflags = flags | LEXFLAGS_ACTIVE;
3399 * Are we handling comments?
3401 nocomments = !(flags & (LEXFLAGS_COMMENTS_KEEP|
3402 LEXFLAGS_COMMENTS_STRIP));
3403 if (buf) {
3404 int l = strlen(buf);
3406 p = (char *) zhalloc(l + 2);
3407 memcpy(p, buf, l);
3409 * I'm sure this space is here for a reason, but it's
3410 * a pain in the neck: when we get back a string that's
3411 * not finished it's very hard to tell if a space at the
3412 * end is this one or not. We use two tricks below to
3413 * work around this.
3415 addedspaceptr = p + l;
3416 *addedspaceptr = ' ';
3417 addedspaceptr[1] = '\0';
3418 inpush(p, 0, NULL);
3419 zlemetall = strlen(p) ;
3420 zlemetacs = zlemetall + 1;
3421 } else {
3422 int ll, cs;
3423 char *linein;
3425 linein = zleentry(ZLE_CMD_GET_LINE, &ll, &cs);
3426 zlemetall = ll + 1; /* length of line plus space added below */
3427 zlemetacs = cs;
3429 if (!isfirstln && chline) {
3430 p = (char *) zhalloc(hptr - chline + ll + 2);
3431 memcpy(p, chline, hptr - chline);
3432 memcpy(p + (hptr - chline), linein, ll);
3433 addedspaceptr = p + (hptr - chline) + ll;
3434 *addedspaceptr = ' ';
3435 addedspaceptr[1] = '\0';
3436 inpush(p, 0, NULL);
3439 * advance line length and character position over
3440 * prepended string.
3442 zlemetall += hptr - chline;
3443 zlemetacs += hptr - chline;
3444 } else {
3445 p = (char *) zhalloc(ll + 2);
3446 memcpy(p, linein, ll);
3447 addedspaceptr = p + ll;
3448 *addedspaceptr = ' ';
3449 p[zlemetall] = '\0';
3450 inpush(p, 0, NULL);
3452 zsfree(linein);
3454 if (zlemetacs)
3455 zlemetacs--;
3456 strinbeg(0);
3457 noaliases = 1;
3458 do {
3459 if (incond)
3460 incond = 1 + (tok != DINBRACK && tok != INPAR &&
3461 tok != DBAR && tok != DAMPER &&
3462 tok != BANG);
3463 ctxtlex();
3464 if (tok == ENDINPUT || tok == LEXERR)
3465 break;
3467 * After an array assignment, return to the initial
3468 * start-of-command state. There could be a second ENVARRAY.
3470 if (tok == OUTPAR && envarray) {
3471 incmdpos = 1;
3472 envarray = 0;
3474 if (tok == FOR) {
3476 * The way for (( expr1 ; expr2; expr3 )) is parsed is:
3477 * - a FOR tok
3478 * - a DINPAR with no tokstr
3479 * - two DINPARS with tokstr's expr1, expr2.
3480 * - a DOUTPAR with tokstr expr3.
3482 * We'll decrement the variable forloop as we verify
3483 * the various stages.
3485 * Don't ask me, ma'am, I'm just the programmer.
3487 forloop = 5;
3488 } else {
3489 switch (forloop) {
3490 case 1:
3491 if (tok != DOUTPAR)
3492 forloop = 0;
3493 break;
3495 case 2:
3496 case 3:
3497 case 4:
3498 if (tok != DINPAR)
3499 forloop = 0;
3500 break;
3502 default:
3503 /* nothing to do */
3504 break;
3507 if (tokstr) {
3508 switch (tok) {
3509 case ENVARRAY:
3510 p = dyncat(tokstr, "=(");
3511 envarray = 1;
3512 break;
3514 case DINPAR:
3515 if (forloop) {
3516 /* See above. */
3517 p = dyncat(tokstr, ";");
3518 } else {
3520 * Mathematical expressions analysed as a single
3521 * word. That's correct because it behaves like
3522 * double quotes. Whitespace in the middle is
3523 * similarly retained, so just add the parentheses back.
3525 p = zhtricat("((", tokstr, "))");
3527 break;
3529 default:
3530 p = dupstring(tokstr);
3531 break;
3533 if (*p) {
3534 untokenize(p);
3535 if (ingetptr() == addedspaceptr + 1) {
3537 * Whoops, we've read past the space we added, probably
3538 * because we were expecting a terminator but when
3539 * it didn't turn up we shrugged our shoulders thinking
3540 * it might as well be a complete string anyway.
3541 * So remove the space. C.f. below for the case
3542 * where the missing terminator caused a lex error.
3543 * We use the same paranoid test.
3545 int plen = strlen(p);
3546 if (plen && p[plen-1] == ' ' &&
3547 (plen == 1 || p[plen-2] != Meta))
3548 p[plen-1] = '\0';
3550 addlinknode(list, p);
3551 num++;
3553 } else if (buf) {
3554 if (IS_REDIROP(tok) && tokfd >= 0) {
3555 char b[20];
3557 sprintf(b, "%d%s", tokfd, tokstrings[tok]);
3558 addlinknode(list, dupstring(b));
3559 num++;
3560 } else if (tok != NEWLIN) {
3561 addlinknode(list, dupstring(tokstrings[tok]));
3562 num++;
3565 if (forloop) {
3566 if (forloop == 1) {
3568 * Final "))" of for loop to match opening,
3569 * since we've just added the preceding element.
3571 addlinknode(list, dupstring("))"));
3573 forloop--;
3575 if (!got && !lexflags) {
3576 got = 1;
3577 cur = num - 1;
3579 } while (tok != ENDINPUT && tok != LEXERR && !(errflag & ERRFLAG_INT));
3580 if (buf && tok == LEXERR && tokstr && *tokstr) {
3581 int plen;
3582 untokenize((p = dupstring(tokstr)));
3583 plen = strlen(p);
3585 * Strip the space we added for lexing but which won't have
3586 * been swallowed by the lexer because we aborted early.
3587 * The test is paranoia.
3589 if (plen && p[plen-1] == ' ' && (plen == 1 || p[plen-2] != Meta))
3590 p[plen - 1] = '\0';
3591 addlinknode(list, p);
3592 num++;
3594 if (cur < 0 && num)
3595 cur = num - 1;
3596 noaliases = ona;
3597 strinend();
3598 inpop();
3599 errflag &= ~ERRFLAG_ERROR;
3600 nocomments = onc;
3601 noerrs = ne;
3602 zcontext_restore();
3603 zlemetacs = ocs;
3604 zlemetall = oll;
3605 wb = owb;
3606 we = owe;
3607 addedx = oadx;
3608 opts[RCQUOTES] = rcquotes;
3610 if (index)
3611 *index = cur;
3613 return list;
3617 * Split up a line into words for use in a history file.
3619 * lineptr is the line to be split.
3621 * *wordsp and *nwordsp are an array already allocated to hold words
3622 * and its length. The array holds both start and end positions,
3623 * so *nwordsp actually counts twice the number of words in the
3624 * original string. *nwordsp may be zero in which case the array
3625 * will be allocated.
3627 * *nwordposp returns the used length of *wordsp in the same units as
3628 * *nwordsp, i.e. twice the number of words in the input line.
3630 * If uselex is 1, attempt to do this using the lexical analyser.
3631 * This is more accurate, but slower; for reading history files it's
3632 * controlled by the option HISTLEXWORDS. If this failed (which
3633 * indicates a bug in the shell) it falls back to whitespace-separated
3634 * strings, printing a message if in debug mode.
3636 * If uselex is 0, just look for whitespace-separated words; the only
3637 * special handling is for a backslash-newline combination as used
3638 * by the history file format to save multiline buffers.
3640 /**/
3641 mod_export void
3642 histsplitwords(char *lineptr, short **wordsp, int *nwordsp, int *nwordposp,
3643 int uselex)
3645 int nwords = *nwordsp, nwordpos = 0;
3646 short *words = *wordsp;
3647 char *start = lineptr;
3649 if (uselex) {
3650 LinkList wordlist;
3651 LinkNode wordnode;
3652 int nwords_max;
3654 wordlist = bufferwords(NULL, lineptr, NULL,
3655 LEXFLAGS_COMMENTS_KEEP);
3656 if (errflag)
3657 return;
3658 nwords_max = 2 * countlinknodes(wordlist);
3659 if (nwords_max > nwords) {
3660 *nwordsp = nwords = nwords_max;
3661 *wordsp = words = (short *)zrealloc(words, nwords*sizeof(short));
3663 for (wordnode = firstnode(wordlist);
3664 wordnode;
3665 incnode(wordnode)) {
3666 char *word = getdata(wordnode);
3667 char *lptr, *wptr = word;
3668 int loop_next = 0, skipping;
3670 /* Skip stuff at the start of the word */
3671 for (;;) {
3673 * Not really an oddity: "\\\n" is
3674 * removed from input as if whitespace.
3676 if (inblank(*lineptr))
3677 lineptr++;
3678 else if (lineptr[0] == '\\' && lineptr[1] == '\n') {
3680 * Optimisation: we handle this in the loop below,
3681 * too.
3683 lineptr += 2;
3684 } else
3685 break;
3687 lptr = lineptr;
3689 * Skip chunks of word with possible intervening
3690 * backslash-newline.
3692 * To get round C's annoying lack of ability to
3693 * reference the outer loop, we'll break from this
3694 * one with
3695 * loop_next = 0: carry on as normal
3696 * loop_next = 1: break from outer loop
3697 * loop_next = 2: continue round outer loop.
3699 do {
3700 skipping = 0;
3701 if (strpfx(wptr, lptr)) {
3703 * Normal case: word from lexer matches start of
3704 * string from line. Just advance over it.
3706 int len;
3707 if (!strcmp(wptr, ";") && strpfx(";;", lptr)) {
3709 * Don't get confused between a semicolon that's
3710 * probably really a newline and a double
3711 * semicolon that's terminating a case.
3713 loop_next = 2;
3714 break;
3716 len = strlen(wptr);
3717 lptr += len;
3718 wptr += len;
3719 } else {
3721 * Didn't get to the end of the word.
3722 * See what's amiss.
3724 int bad = 0;
3726 * Oddity 1: newlines turn into semicolons.
3728 if (!strcmp(wptr, ";"))
3730 loop_next = 2;
3731 break;
3733 while (*lptr) {
3734 if (!*wptr) {
3736 * End of the word before the end of the
3737 * line: not good.
3739 bad = 1;
3740 loop_next = 1;
3741 break;
3744 * Oddity 2: !'s turn into |'s.
3746 if (*lptr == *wptr ||
3747 (*lptr == '!' && *wptr == '|')) {
3748 lptr++;
3749 if (!*++wptr)
3750 break;
3751 } else if (lptr[0] == '\\' &&
3752 lptr[1] == '\n') {
3754 * \\\n can occur in the middle of a word;
3755 * wptr is already pointing at this, we
3756 * just need to skip over the break
3757 * in lptr and look at the next chunk.
3759 lptr += 2;
3760 skipping = 1;
3761 break;
3762 } else {
3763 bad = 1;
3764 loop_next = 1;
3765 break;
3768 if (bad) {
3769 #ifdef DEBUG
3770 dputs(ERRMSG("bad wordsplit reading history: "
3771 "%s\nat: %s\nword: %s"),
3772 start, lineptr, word);
3773 #endif
3774 lineptr = start;
3775 nwordpos = 0;
3776 uselex = 0;
3777 loop_next = 1;
3780 } while (skipping);
3781 if (loop_next) {
3782 if (loop_next == 1)
3783 break;
3784 continue;
3786 /* Record position of current word... */
3787 words[nwordpos++] = lineptr - start;
3788 words[nwordpos++] = lptr - start;
3790 /* ready for start of next word. */
3791 lineptr = lptr;
3794 if (!uselex) {
3795 do {
3796 for (;;) {
3797 if (inblank(*lineptr))
3798 lineptr++;
3799 else if (lineptr[0] == '\\' && lineptr[1] == '\n')
3800 lineptr += 2;
3801 else
3802 break;
3804 if (*lineptr) {
3805 if (nwordpos >= nwords) {
3806 *nwordsp = nwords = nwords + 64;
3807 *wordsp = words = (short *)
3808 zrealloc(words, nwords*sizeof(*words));
3810 words[nwordpos++] = lineptr - start;
3811 while (*lineptr) {
3812 if (*lineptr == Meta && lineptr[1])
3813 lineptr += 2;
3814 else if (!inblank(*lineptr))
3815 lineptr++;
3816 else
3817 break;
3819 words[nwordpos++] = lineptr - start;
3821 } while (*lineptr);
3824 *nwordposp = nwordpos;
3827 /* Move the current history list out of the way and prepare a fresh history
3828 * list using hf for HISTFILE, hs for HISTSIZE, and shs for SAVEHIST. If
3829 * the hf value is an empty string, HISTFILE will be unset from the new
3830 * environment; if it is NULL, HISTFILE will not be changed, not even by the
3831 * pop function (this functionality is used internally to rewrite the current
3832 * history file without affecting pointers into the environment).
3835 /**/
3837 pushhiststack(char *hf, zlong hs, zlong shs, int level)
3839 struct histsave *h;
3840 int curline_in_ring = (histactive & HA_ACTIVE) && hist_ring == &curline;
3842 if (histsave_stack_pos == histsave_stack_size) {
3843 histsave_stack_size += 5;
3844 histsave_stack = zrealloc(histsave_stack,
3845 histsave_stack_size * sizeof (struct histsave));
3848 if (curline_in_ring)
3849 unlinkcurline();
3851 h = &histsave_stack[histsave_stack_pos++];
3853 h->lasthist = lasthist;
3854 if (hf) {
3855 if ((h->histfile = getsparam("HISTFILE")) != NULL && *h->histfile)
3856 h->histfile = ztrdup(h->histfile);
3857 else
3858 h->histfile = "";
3859 } else
3860 h->histfile = NULL;
3861 h->histtab = histtab;
3862 h->hist_ring = hist_ring;
3863 h->curhist = curhist;
3864 h->histlinect = histlinect;
3865 h->histsiz = histsiz;
3866 h->savehistsiz = savehistsiz;
3867 h->locallevel = level;
3869 memset(&lasthist, 0, sizeof lasthist);
3870 if (hf) {
3871 if (*hf)
3872 setsparam("HISTFILE", ztrdup(hf));
3873 else
3874 unsetparam("HISTFILE");
3876 hist_ring = NULL;
3877 curhist = histlinect = 0;
3878 if (zleactive)
3879 zleentry(ZLE_CMD_SET_HIST_LINE, curhist);
3880 histsiz = hs;
3881 savehistsiz = shs;
3882 inithist(); /* sets histtab */
3884 if (curline_in_ring)
3885 linkcurline();
3887 return histsave_stack_pos;
3891 /**/
3893 pophiststack(void)
3895 struct histsave *h;
3896 int curline_in_ring = (histactive & HA_ACTIVE) && hist_ring == &curline;
3898 if (histsave_stack_pos == 0)
3899 return 0;
3901 if (curline_in_ring)
3902 unlinkcurline();
3904 deletehashtable(histtab);
3905 zsfree(lasthist.text);
3907 h = &histsave_stack[--histsave_stack_pos];
3909 lasthist = h->lasthist;
3910 if (h->histfile) {
3911 if (*h->histfile)
3912 setsparam("HISTFILE", h->histfile);
3913 else
3914 unsetparam("HISTFILE");
3916 histtab = h->histtab;
3917 hist_ring = h->hist_ring;
3918 curhist = h->curhist;
3919 if (zleactive)
3920 zleentry(ZLE_CMD_SET_HIST_LINE, curhist);
3921 histlinect = h->histlinect;
3922 histsiz = h->histsiz;
3923 savehistsiz = h->savehistsiz;
3925 if (curline_in_ring)
3926 linkcurline();
3928 return histsave_stack_pos + 1;
3931 /* If pop_through > 0, pop all array items >= the 1-relative index value.
3932 * If pop_through <= 0, pop (-1)*pop_through levels off the stack.
3933 * If the (new) top of stack is from a higher locallevel, auto-pop until
3934 * it is not.
3937 /**/
3939 saveandpophiststack(int pop_through, int writeflags)
3941 if (pop_through <= 0) {
3942 pop_through += histsave_stack_pos + 1;
3943 if (pop_through <= 0)
3944 pop_through = 1;
3946 while (pop_through > 1
3947 && histsave_stack[pop_through-2].locallevel > locallevel)
3948 pop_through--;
3949 if (histsave_stack_pos < pop_through)
3950 return 0;
3951 do {
3952 if (!nohistsave)
3953 savehistfile(NULL, 1, writeflags);
3954 pophiststack();
3955 } while (histsave_stack_pos >= pop_through);
3956 return 1;