386BSD 0.1 development
[unix-history] / usr / othersrc / public / zsh-2.2 / src / hist.c
CommitLineData
dbf02a84
WJ
1/*
2 *
3 * hist.c - history expansion
4 *
5 * This file is part of zsh, the Z shell.
6 *
7 * This software is Copyright 1992 by Paul Falstad
8 *
9 * Permission is hereby granted to copy, reproduce, redistribute or otherwise
10 * use this software as long as: there is no monetary profit gained
11 * specifically from the use or reproduction of this software, it is not
12 * sold, rented, traded or otherwise marketed, and this copyright notice is
13 * included prominently in any copy made.
14 *
15 * The author make no claims as to the fitness or correctness of this software
16 * for any use whatsoever, and it is provided as is. Any use of this software
17 * is at the user's own risk.
18 *
19 */
20
21#include "zsh.h"
22
23#define HEAPSIZE 4096
24
25struct hp {
26 Hp next;
27 char *pool,*ptr;
28 int free,histno;
29};
30
31static Hp hp_lit, hp_lex;
32static Histent curhistent;
33
34static int lastc;
35
36/* add a character to the current history word */
37
38void hwaddc(c) /**/
39int c;
40{
41 if (hlastw && hline && (!(errflag || lexstop) || c == HISTSPACE)) {
42 if (c == '!' && unset(NOBANGHIST)) hwaddc('\\');
43 *hptr++ = c;
44 if (hptr-hline >= hlinesz) {
45 int ll,flag = 0,oldsiz = hlinesz;
46
47 ll = hptr-hlastw;
48 if (curhistent->lex == hline) flag = 1;
49 hline = hp_realloc(&hp_lex,hline,oldsiz,hlinesz = oldsiz+16);
50 if (flag) curhistent->lex = hline;
51 hptr = hline+oldsiz;
52 hlastw = hptr-ll;
53 }
54 }
55}
56
57#define habort() { errflag = lexstop = 1; return ' '; }
58
59/* get a character after performing history substitution */
60
61int hgetc() /**/
62{
63int c,ev,farg,larg,argc,marg = -1,cflag = 0,bflag = 0;
64char buf[256],*ptr;
65char *sline,*eline;
66
67tailrec:
68 c = hgetch();
69 if (stophist || alstackind)
70 {
71 hwaddc(c);
72 return c;
73 }
74 if (isfirstch && c == hatchar)
75 {
76 isfirstch = 0;
77 hungetch(hatchar);
78 hungets(":s");
79 c = bangchar;
80 goto hatskip;
81 }
82 if (c != ' ')
83 isfirstch = 0;
84 if (c == '\\') {
85 int g = hgetch();
86
87 if (g != bangchar)
88 hungetch(g);
89 else {
90 hwaddc(bangchar);
91 return bangchar;
92 }
93 }
94 if (c != bangchar)
95 {
96 hwaddc(c);
97 return c;
98 }
99hatskip:
100 *hptr = '\0';
101 if ((c = hgetch()) == '{')
102 {
103 bflag = cflag = 1;
104 c = hgetch();
105 }
106 if (c == '\"')
107 {
108 stophist = 1;
109 goto tailrec;
110 }
111 if (!cflag && inblank(c) || c == '=' || c == '(' || lexstop)
112 {
113 if (lexstop)
114 lexstop = 0;
115 else
116 hungetch(c);
117 hwaddc(bangchar);
118 return bangchar;
119 }
120 cflag = 0;
121 ptr = buf;
122
123 /* get event number */
124
125 if (c == '?')
126 {
127 for(;;)
128 {
129 c = hgetch();
130 if (c == '?' || c == '\n' || lexstop)
131 break;
132 else
133 *ptr++ = c;
134 }
135 if (c != '\n' && !lexstop)
136 c = hgetch();
137 *ptr = '\0';
138 ev = hconsearch(hsubl = ztrdup(buf),&marg);
139 if (ev == -1)
140 {
141 herrflush();
142 zerr("no such event: %s",buf,0);
143 habort();
144 }
145 }
146 else
147 {
148 int t0;
149
150 for (;;)
151 {
152 if (inblank(c) || c == ';' || c == ':' || c == '^' || c == '$' ||
153 c == '*' || c == '%' || c == '}' || lexstop)
154 break;
155 if (ptr != buf) {
156 if (c == '-') break;
157 if ((idigit(buf[0]) || buf[0] == '-') && !idigit(c)) break;
158 }
159 *ptr++ = c;
160 if (c == '#' || c == bangchar)
161 {
162 c = hgetch();
163 break;
164 }
165 c = hgetch();
166 }
167 *ptr = 0;
168 if (!*buf)
169 ev = defev;
170 else if (t0 = atoi(buf))
171 ev = (t0 < 0) ? curhist+t0 : t0;
172 else if (*buf == bangchar)
173 ev = curhist-1;
174 else if (*buf == '#')
175 ev = curhist;
176 else if ((ev = hcomsearch(buf)) == -1)
177 {
178 zerr("event not found: %s",buf,0);
179 while (c != '\n' && !lexstop)
180 c = hgetch();
181 habort();
182 }
183 }
184
185 /* get the event */
186
187 if (!(eline = getevent(defev = ev)))
188 habort();
189
190 /* extract the relevant arguments */
191
192 argc = getargc(eline);
193 if (c == ':')
194 {
195 cflag = 1;
196 c = hgetch();
197 }
198 if (c == '*')
199 {
200 farg = 1;
201 larg = argc;
202 cflag = 0;
203 }
204 else
205 {
206 hungetch(c);
207 larg = farg = getargspec(argc,marg);
208 if (larg == -2)
209 habort();
210 if (farg != -1)
211 cflag = 0;
212 c = hgetch();
213 if (c == '*')
214 {
215 cflag = 0;
216 larg = argc;
217 }
218 else if (c == '-')
219 {
220 cflag = 0;
221 larg = getargspec(argc,marg);
222 if (larg == -2)
223 habort();
224 if (larg == -1)
225 larg = argc-1;
226 }
227 else
228 hungetch(c);
229 }
230 if (farg == -1)
231 farg = 0;
232 if (larg == -1)
233 larg = argc;
234 if (!(sline = getargs(eline,farg,larg)))
235 habort();
236
237 /* do the modifiers */
238
239 for(;;)
240 {
241 c = (cflag) ? ':' : hgetch();
242 cflag = 0;
243 if (c == ':')
244 {
245 int gbal = 0;
246
247 if ((c = hgetch()) == 'g')
248 {
249 gbal = 1;
250 c = hgetch();
251 }
252 switch(c)
253 {
254 case 'p':
255 histdone = HISTFLAG_DONE|HISTFLAG_NOEXEC;
256 break;
257 case 'h':
258 if (!remtpath(&sline))
259 {
260 herrflush();
261 zerr("modifier failed: h",NULL,0);
262 habort();
263 }
264 break;
265 case 'e':
266 if (!rembutext(&sline))
267 {
268 herrflush();
269 zerr("modifier failed: e",NULL,0);
270 habort();
271 }
272 break;
273 case 'r':
274 if (!remtext(&sline))
275 {
276 herrflush();
277 zerr("modifier failed: r",NULL,0);
278 habort();
279 }
280 break;
281 case 't':
282 if (!remlpaths(&sline))
283 {
284 herrflush();
285 zerr("modifier failed: t",NULL,0);
286 habort();
287 }
288 break;
289 case 's':
290 {
291 int del;
292 char *ptr1,*ptr2;
293
294 del = hgetch();
295 ptr1 = hdynread2(del);
296 if (!ptr1)
297 habort();
298 ptr2 = hdynread2(del);
299 if (strlen(ptr1))
300 {
301 if (hsubl)
302 free(hsubl);
303 hsubl = ptr1;
304 }
305 if (hsubr)
306 free(hsubr);
307 hsubr = ptr2;
308 }
309 case '&':
310 if (hsubl && hsubr)
311 subst(&sline,hsubl,hsubr,gbal);
312 else
313 {
314 herrflush();
315 zerr("no previous substitution with &",NULL,0);
316 habort();
317 }
318 break;
319 case 'q':
320 quote(&sline);
321 break;
322 case 'x':
323 quotebreak(&sline);
324 break;
325 case 'l':
326 downcase(&sline);
327 break;
328 case 'u':
329 upcase(&sline);
330 break;
331 default:
332 herrflush();
333 zerr("illegal modifier: %c",NULL,c);
334 habort();
335 break;
336 }
337 }
338 else
339 {
340 if (c != '}' || !bflag)
341 hungetch(c);
342 if (c != '}' && bflag)
343 {
344 zerr("'}' expected",NULL,0);
345 habort();
346 }
347 break;
348 }
349 }
350
351 /* stuff the resulting string in the input queue and start over */
352
353 lexstop = 0;
354 if (alstackind != MAXAL)
355 {
356 hungets(HISTMARK);
357 alstack[alstackind++] = NULL;
358 }
359 for (ptr = sline; *ptr; ptr++) {
360 if (ptr[0] == '\\' && ptr[1] == '!') chuck(ptr);
361 }
362 hungets(sline);
363 histdone |= HISTFLAG_DONE;
364 if (isset(HISTVERIFY)) histdone |= HISTFLAG_NOEXEC|HISTFLAG_RECALL;
365 goto tailrec;
366}
367
368/* reset the alias stack for lexrestore () */
369
370void clearalstack() /**/
371{
372Alias ix;
373
374 while (alstackind)
375 {
376 ix = alstack[--alstackind];
377 ix->inuse = 0;
378 }
379}
380
381/* get a character without history expansion */
382
383int hgetch() /**/
384{
385unsigned char *line,*pmpt,*pmpt2 = NULL;
386int plen;
387
388start:
389 if (inbufct)
390 {
391 inbufct--;
392 if ((lastc = *inbufptr++) == ALPOP)
393 {
394 Alias ix;
395 char *t;
396
397 if (!alstackind)
398 {
399 zerr("alias stack underflow",NULL,0);
400 errflag = lexstop = 1;
401 return lastc = ' ';
402 }
403 ix = alstack[--alstackind];
404 if (ix)
405 {
406 ix->inuse = 0;
407 t = ix->text;
408 if (*t && t[strlen(t)-1] == ' ')
409 alstat = ALSTAT_MORE;
410 else
411 alstat = ALSTAT_JUNK;
412 }
413 goto start;
414 }
415 if (itok(lastc))
416 goto start;
417 return lastc;
418 }
419 if (strin || errflag)
420 {
421 lexstop = 1;
422 return lastc = ' ';
423 }
424 if (interact && isset(SHINSTDIN))
425 if (!isfirstln)
426 pmpt = (unsigned char *)putprompt(prompt2,&plen);
427 else
428 {
429 int foo;
430
431 pmpt = (unsigned char *)putprompt(prompt,&plen);
432 pmpt2 = (unsigned char *)((rprompt) ? putprompt(rprompt,&foo) : NULL);
433 }
434 if (!(interact && isset(SHINSTDIN) && SHTTY != -1 && isset(USEZLE))) {
435 char *lbuf;
436 if (interact && isset(SHINSTDIN))
437 write(2,pmpt,strlen((char *) pmpt));
438 line = (unsigned char *)fgets(lbuf = zalloc(256),256,bshin);
439 if (!line) free(lbuf);
440 } else
441 line = zleread(pmpt,pmpt2,plen);
442 if (!line) {
443 lexstop = 1;
444 return lastc = ' ';
445 }
446 if (errflag) {
447 free(line);
448 lexstop = errflag = 1;
449 return lastc = ' ';
450 }
451 if (interact && isset(SHINSTDIN)) {
452 char *s = curhistent->lit;
453 curhistent->lit = hp_concat(s,(char*)line);
454 }
455 if (isfirstln) spaceflag = *line == ' ';
456 if (isset(VERBOSE)) {
457 fputs((char *) line,stderr);
458 fflush(stderr);
459 }
460 if (*line && line[strlen((char *) line)-1] == '\n')
461 {
462 lineno++;
463 if (interact && isset(SUNKEYBOARDHACK) && isset(SHINSTDIN) &&
464 SHTTY != -1 && *line && line[1] &&
465 line[strlen((char *) line)-2] == '`')
466 {
467 int ct;
468 unsigned char *ptr;
469
470 for (ct = 0, ptr = line; *ptr; ptr++)
471 if (*ptr == '`')
472 ct++;
473 if (ct & 1)
474 {
475 ptr[-2] = '\n';
476 ptr[-1] = '\0';
477 }
478 }
479 }
480 isfirstch = 1;
481 hungets((char*)line);
482 free(line);
483 goto start;
484}
485
486/* Read one line of at most n-1 chars from the input queue */
487
488char *hgets(buf, n) /**/
489char *buf;int n;
490{
491int l;
492
493 for (l = 0; l < n-1; l++)
494 if ((buf[l] = hgetch()) == '\n' || lexstop)
495 break;
496 buf[l+(lexstop?0:1)] = 0;
497
498 return (!lexstop || l) ? buf : NULL;
499}
500
501/* put a string in the input queue */
502
503void hungets(str) /**/
504char *str;
505{
506int slen = strlen(str);
507
508/* shrink inbuf if it gets too big */
509
510 if (!inbufct && inbufsz > 65536)
511 {
512 free(inbuf);
513 inbuf = zalloc(inbufsz = 256);
514 inbufptr = inbuf+inbufsz;
515 inbufct = 0;
516 }
517 if (slen+inbufct > inbufsz)
518 {
519 char *x;
520
521 while (slen+inbufct > inbufsz)
522 inbufsz *= 4;
523 x = zalloc(inbufsz);
524 memcpy(x+inbufsz-inbufct,inbufptr,inbufct);
525 inbufptr = x+inbufsz-inbufct;
526 free(inbuf);
527 inbuf = x;
528 }
529 memcpy(inbufptr -= slen,str,slen);
530 inbufct += slen;
531}
532
533/* unget a char and remove it from hline */
534
535void hungetc(c) /**/
536int c;
537{
538 if (lexstop)
539 return;
540 if (hlastw) {
541 if (hlastw == hptr)
542 zerr("hungetc attempted at buffer start",NULL,0);
543 else {
544 hptr--;
545 if (*hptr == '!' && unset(NOBANGHIST)) hptr--;
546 }
547 }
548 hungetch(c);
549}
550
551void hungetch(c) /**/
552int c;
553{
554 if (lexstop)
555 return;
556 if (inbufct == inbufsz)
557 {
558 hungets(" ");
559 *inbufptr = c;
560 }
561 else
562 {
563 *--inbufptr = c;
564 inbufct++;
565 }
566}
567
568/* begin reading a string */
569
570void strinbeg() /**/
571{
572 strin = 1;
573 hbegin();
574 lexinit();
575}
576
577/* done reading a string */
578
579void strinend() /**/
580{
581 strin = 0;
582 isfirstch = 1;
583 histdone = 0;
584 hend();
585}
586
587/* stuff a whole file into the input queue and print it */
588
589int stuff(fn) /**/
590char *fn;
591{
592FILE *in;
593char *buf;
594int len;
595
596 if (!(in = fopen(fn,"r")))
597 {
598 zerr("can't open %s",fn,0);
599 return 1;
600 }
601 fseek(in,0,2);
602 len = ftell(in);
603 fseek(in,0,0);
604 buf = alloc(len+1);
605 if (!(fread(buf,len,1,in)))
606 {
607 zerr("read error on %s",fn,0);
608 fclose(in);
609 free(buf);
610 return 1;
611 }
612 fclose(in);
613 buf[len] = '\0';
614 fwrite(buf,len,1,stdout);
615 hungets(buf);
616 return 0;
617}
618
619/* flush input queue */
620
621void hflush() /**/
622{
623 inbufptr += inbufct;
624 inbufct = 0;
625}
626
627/* initialize the history mechanism */
628
629void hbegin() /**/
630{
631 isfirstln = isfirstch = 1;
632 histremmed = errflag = histdone = spaceflag = 0;
633 stophist = isset(NOBANGHIST) || unset(SHINSTDIN);
634 lithist = isset(HISTLIT);
635 hline = hptr = hp_alloc(&hp_lex,hlinesz = 16);
636 curhistent = gethistent(curhist);
637 if (!curhistent->ftim) curhistent->ftim = time(NULL);
638 if (interact && isset(SHINSTDIN) && !strin) {
639 inittty();
640 defev = curhist++;
641 if (curhist-histsiz >= 0) gethistent(curhist-histsiz)->lex = NULL;
642 if (curhist-lithistsiz >= 0) gethistent(curhist-lithistsiz)->lit = NULL;
643 curhistent = gethistent(curhist);
644 hp_purge(hp_lex,curhist-histsiz);
645 hp_purge(hp_lit,curhist-lithistsiz);
646 curhistent->lex = hline;
647 *(curhistent->lit = hp_alloc(&hp_lit,1)) = '\0';
648 } else
649 histremmed = 1;
650}
651
652void inittty() /**/
653{
654 attachtty(mypgrp);
655}
656
657/* say we're done using the history mechanism */
658
659int hend() /**/
660{
661int flag,save = 1;
662Histent he;
663
664 if (!hline)
665 return 1;
666 if (!interact || strin || unset(SHINSTDIN)) {
667 hp_free(hp_lex,hline,hlinesz);
668 return 1;
669 }
670 flag = histdone;
671 histdone = 0;
672 if (hptr < hline+2)
673 save = 0;
674 else {
675 char *s,*t;
676
677 s = curhistent->lit;
678 if (*s && *(t = s+strlen(s)-1) == HISTSPACE) *t = '\0';
679 hptr[-1] = '\0';
680 if (hptr[-2] == '\n')
681 if (hline[1]) {
682 if (hptr[-3] == HISTSPACE) hptr[-3] = '\0';
683 } else save = 0;
684 he = gethistent(curhist-1);
685 if (!strcmp(hline,"\n") ||
686 (isset(HISTIGNOREDUPS) && he->lex && !strcmp(he->lex,hline)) ||
687 (isset(HISTIGNORESPACE) && spaceflag))
688 save = 0;
689 }
690 if (flag & (HISTFLAG_DONE|HISTFLAG_RECALL)) {
691 char *ptr,*p;
692 p = ptr = ztrdup(hline);
693 for (;*p;p++) if (*p == HISTSPACE) *p = ' ';
694 if ((flag & (HISTFLAG_DONE|HISTFLAG_RECALL)) == HISTFLAG_DONE) {
695 fprintf(stderr,"%s\n",ptr);
696 fflush(stderr);
697 }
698 if (flag & HISTFLAG_RECALL) {
699 permalloc();
700 pushnode(bufstack,ptr);
701 lastalloc();
702 save = 0;
703 } else free(ptr);
704 }
705 curhistent->stim = time(NULL);
706 curhistent->ftim = 0L;
707 if (!save) remhist();
708 if (hline && !curhistent->lex) hp_free(hp_lex,hline,hlinesz);
709 hline = NULL;
710 return !(flag & HISTFLAG_NOEXEC || errflag);
711}
712
713/* remove the current line from the history List */
714
715void remhist() /**/
716{
717 if (!histremmed) { histremmed = 1; curhist--; }
718}
719
720/* begin a word */
721
722void hwbegin() /**/
723{
724 hlastw = hptr;
725}
726
727/* add a word to the history List */
728
729char *hwadd() /**/
730{
731char *ret = hlastw;
732
733 if (hlastw && hline)
734 {
735 hwaddc(HISTSPACE);
736 if (alstackind || strin)
737 if (!(alstackind == 1 && !alstack[0]))
738 hptr = hlastw;
739 }
740 if (alstat == ALSTAT_JUNK)
741 alstat = 0;
742 return ret;
743}
744
745/* get an argument specification */
746
747int getargspec(argc,marg) /**/
748int argc;int marg;
749{
750int c,ret = -1;
751
752 if ((c = hgetch()) == '0')
753 return 0;
754 if (idigit(c))
755 {
756 ret = 0;
757 while (idigit(c))
758 {
759 ret = ret*10+c-'0';
760 c = hgetch();
761 }
762 hungetch(c);
763 }
764 else if (c == '^')
765 ret = 1;
766 else if (c == '$')
767 ret = argc;
768 else if (c == '%')
769 {
770 if (marg == -1)
771 {
772 herrflush();
773 zerr("%% with no previous word matched",NULL,0);
774 return -2;
775 }
776 ret = marg;
777 }
778 else
779 hungetch(c);
780 return ret;
781}
782
783/* do ?foo? search */
784
785int hconsearch(str,marg) /**/
786char *str;int *marg;
787{
788int t0,t1 = 0;
789char *s,*hs;
790
791 for (t0 = curhist-1; hs = quietgetevent(t0); t0--)
792 if (s = ztrstr(hs,str)) {
793 while (s != hs) if (*s-- == HISTSPACE) t1++;
794 *marg = t1;
795 return t0;
796 }
797 return -1;
798}
799
800/* do !foo search */
801
802int hcomsearch(str) /**/
803char *str;
804{
805int t0;
806char *hs;
807
808 for (t0 = curhist-1; hs = quietgetevent(t0); t0--)
809 if (!strncmp(hs,str,strlen(str))) return t0;
810 return -1;
811}
812
813/* various utilities for : modifiers */
814
815int remtpath(junkptr) /**/
816char **junkptr;
817{
818char *str = *junkptr,*cut;
819
820 if (cut = strrchr(str,'/')) {
821 if (str != cut) *cut = '\0';
822 else str[1] = '\0';
823 return 1;
824 }
825 return 0;
826}
827
828int remtext(junkptr) /**/
829char **junkptr;
830{
831char *str = *junkptr,*cut;
832
833 if ((cut = strrchr(str,'.')) && cut != str)
834 {
835 *cut = '\0';
836 return 1;
837 }
838 return 0;
839}
840
841int rembutext(junkptr) /**/
842char **junkptr;
843{
844char *str = *junkptr,*cut;
845
846 if ((cut = strrchr(str,'.')) && cut != str)
847 {
848 *junkptr = strdup(cut+1); /* .xx or xx? */
849 return 1;
850 }
851 return 0;
852}
853
854int remlpaths(junkptr) /**/
855char **junkptr;
856{
857char *str = *junkptr,*cut;
858
859 if (cut = strrchr(str,'/'))
860 {
861 *cut = '\0';
862 *junkptr = strdup(cut+1);
863 return 1;
864 }
865 return 0;
866}
867
868int makeuppercase(junkptr) /**/
869char **junkptr;
870{
871char *str = *junkptr;
872
873 for (; *str; str++)
874 *str = tuupper(*str);
875 return 1;
876}
877
878int makelowercase(junkptr) /**/
879char **junkptr;
880{
881char *str = *junkptr;
882
883 for (; *str; str++)
884 *str = tulower(*str);
885 return 1;
886}
887
888void subst(strptr,in,out,gbal) /**/
889char **strptr;char *in;char *out;int gbal;
890{
891char *str = *strptr,*cut,*sptr;
892int off;
893
894 while (cut = (char *) ztrstr(str,in)) {
895 *cut = '\0';
896 sptr = convamps(out,in);
897 off = cut-*strptr+strlen(sptr);
898 cut += strlen(in);
899 *strptr = tricat(*strptr,sptr,cut);
900 if (gbal) {
901 str = (char *) *strptr+off;
902 continue;
903 }
904 break;
905 }
906}
907
908char *convamps(out,in) /**/
909char *out;char *in;
910{
911char *ptr,*ret,*pp;
912int slen,inlen = strlen(in);
913
914 for (ptr = out, slen = 0; *ptr; ptr++,slen++)
915 if (*ptr == '\\')
916 ptr++;
917 else if (*ptr == '&')
918 slen += inlen-1;
919 ret = pp = alloc(slen+1);
920 for (ptr = out; *ptr; ptr++)
921 if (*ptr == '\\')
922 *pp++ = *++ptr;
923 else if (*ptr == '&')
924 {
925 strcpy(pp,in);
926 pp += inlen;
927 }
928 else
929 *pp++ = *ptr;
930 *pp = '\0';
931 return ret;
932}
933
934char *makehstr(s) /**/
935char *s;
936{
937char *t;
938
939 t = s = strdup(s);
940 for (; *t; t++)
941 if (*t == HISTSPACE)
942 *t = ' ';
943 return s;
944}
945
946char *quietgetevent(ev) /**/
947int ev;
948{
949Histent ent;
950
951 if (ev < firsthist()) return NULL;
952 ent = gethistent(ev);
953 return (lithist) ? ent->lit : ent->lex;
954}
955
956char *getevent(ev) /**/
957int ev;
958{
959char *ret;
960
961 ret = quietgetevent(ev);
962 if (!ret) {
963 herrflush();
964 zerr("no such event: %d",NULL,ev);
965 }
966 return ret;
967}
968
969int getargc(list) /**/
970char *list;
971{
972int argc = 0;
973
974 for (; *list; list++) if (*list == HISTSPACE) argc++;
975 return argc;
976}
977
978char *getargs(elist,arg1,arg2) /**/
979char *elist;int arg1;int arg2;
980{
981char *ret = elist,*retn;
982int acnt = arg2-arg1+1;
983
984 while (arg1--)
985 while (*ret && *ret++ != HISTSPACE);
986 if (!*ret)
987 {
988 herrflush();
989 zerr("no such word in event",NULL,0);
990 return NULL;
991 }
992 retn = ret = strdup(ret);
993 while (acnt > 0)
994 {
995 while (*ret && *ret != HISTSPACE)
996 ret++;
997 if (*ret == HISTSPACE)
998 *ret = ' ';
999 else
1000 break;
1001 acnt--;
1002 }
1003 if (acnt > 1 && !*ret)
1004 {
1005 herrflush();
1006 zerr("no such word in event",NULL,0);
1007 return NULL;
1008 }
1009 *ret = '\0';
1010 return retn;
1011}
1012
1013void upcase(x) /**/
1014char **x;
1015{
1016char *pp = *(char **) x;
1017
1018 for (; *pp; pp++)
1019 *pp = tuupper(*pp);
1020}
1021
1022void downcase(x) /**/
1023char **x;
1024{
1025char *pp = *(char **) x;
1026
1027 for (; *pp; pp++)
1028 *pp = tulower(*pp);
1029}
1030
1031int quote(tr) /**/
1032char **tr;
1033{
1034char *ptr,*rptr,**str = (char **) tr;
1035int len = 3;
1036
1037 for (ptr = *str; *ptr; ptr++,len++)
1038 if (*ptr == '\'') len += 3;
1039 ptr = *str;
1040 *str = rptr = alloc(len);
1041 *rptr++ = '\'';
1042 for (; *ptr; ptr++)
1043 if (*ptr == '\'') {
1044 *rptr++ = '\''; *rptr++ = '\\'; *rptr++ = '\''; *rptr++ = '\'';
1045 } else
1046 *rptr++ = *ptr;
1047 *rptr++ = '\'';
1048 *rptr++ = 0;
1049 str[1] = NULL;
1050 return 0;
1051}
1052
1053int quotebreak(tr) /**/
1054char **tr;
1055{
1056char *ptr,*rptr,**str = (char **) tr;
1057int len = 3;
1058
1059 for (ptr = *str; *ptr; ptr++,len++)
1060 if (*ptr == '\'')
1061 len += 3;
1062 else if (inblank(*ptr))
1063 len += 2;
1064 ptr = *str;
1065 *str = rptr = alloc(len);
1066 *rptr++ = '\'';
1067 for (; *ptr; )
1068 if (*ptr == '\'') {
1069 *rptr++ = '\''; *rptr++ = '\\'; *rptr++ = '\''; *rptr++ = '\'';
1070 ptr++;
1071 } else if (inblank(*ptr)) {
1072 *rptr++ = '\''; *rptr++ = *ptr++; *rptr++ = '\'';
1073 } else
1074 *rptr++ = *ptr++;
1075 *rptr++ = '\'';
1076 *rptr++ = '\0';
1077 return 0;
1078}
1079
1080void herrflush() /**/
1081{
1082 if (strin)
1083 hflush();
1084 else while (lastc != '\n' && !lexstop)
1085 hgetch();
1086}
1087
1088/* read an arbitrary amount of data into a buffer until stop is found */
1089
1090char *hdynread(stop) /**/
1091int stop;
1092{
1093int bsiz = 256,ct = 0,c;
1094char *buf = zalloc(bsiz),*ptr;
1095
1096 ptr = buf;
1097 while ((c = hgetch()) != stop && c != '\n' && !lexstop)
1098 {
1099 if (c == '\\')
1100 c = hgetch();
1101 *ptr++ = c;
1102 if (++ct == bsiz)
1103 {
1104 buf = realloc(buf,bsiz *= 2);
1105 ptr = buf+ct;
1106 }
1107 }
1108 *ptr = 0;
1109 if (c == '\n')
1110 {
1111 hungetch('\n');
1112 zerr("delimiter expected",NULL,0);
1113 free(buf);
1114 return NULL;
1115 }
1116 return buf;
1117}
1118
1119char *hdynread2(stop) /**/
1120int stop;
1121{
1122int bsiz = 256,ct = 0,c;
1123char *buf = zalloc(bsiz),*ptr;
1124
1125 ptr = buf;
1126 while ((c = hgetch()) != stop && c != '\n' && !lexstop)
1127 {
1128 if (c == '\n')
1129 {
1130 hungetch(c);
1131 break;
1132 }
1133 if (c == '\\')
1134 c = hgetch();
1135 *ptr++ = c;
1136 if (++ct == bsiz)
1137 {
1138 buf = realloc(buf,bsiz *= 2);
1139 ptr = buf+ct;
1140 }
1141 }
1142 *ptr = 0;
1143 if (c == '\n')
1144 hungetch('\n');
1145 return buf;
1146}
1147
1148void inithist() /**/
1149{
1150 hp_lit = zalloc(sizeof *hp_lit);
1151 hp_lit->next = NULL;
1152 hp_lit->ptr = hp_lit->pool = zalloc(HEAPSIZE);
1153 hp_lit->free = HEAPSIZE;
1154 hp_lex = zalloc(sizeof *hp_lex);
1155 hp_lex->next = NULL;
1156 hp_lex->ptr = hp_lex->pool = zalloc(HEAPSIZE);
1157 hp_lex->free = HEAPSIZE;
1158 histentct = (lithistsiz > histsiz) ? lithistsiz : histsiz;
1159 histentarr = zcalloc(histentct*sizeof *histentarr);
1160}
1161
1162void resizehistents() /**/
1163{
1164int newentct,t0,t1,firstlit,firstlex;
1165Histent newarr;
1166
1167 newentct = (lithistsiz > histsiz) ? lithistsiz : histsiz;
1168 newarr = zcalloc(newentct*sizeof *newarr);
1169 firstlex = curhist-histsiz+1;
1170 firstlit = curhist-lithistsiz+1;
1171 t0 = firsthist();
1172 if (t0 < curhist-newentct) t0 = curhist-newentct;
1173 t1 = t0 % newentct;
1174 for (; t0 <= curhist; t0++) {
1175 newarr[t1] = *gethistent(t0);
1176 if (t0 < firstlex) newarr[t1].lex = NULL;
1177 if (t0 < firstlit) newarr[t1].lit = NULL;
1178 t1++; if (t1 == newentct) t1 = 0;
1179 }
1180 free(histentarr);
1181 histentarr = newarr;
1182 histentct = newentct;
1183}
1184
1185char *hp_alloc(hp,siz) /**/
1186Hp *hp; int siz;
1187{
1188char *ret;
1189Hp h = *hp;
1190
1191 if (h->free >= siz) {
1192 ret = h->ptr;
1193 h->ptr += siz;
1194 h->free -= siz;
1195 return ret;
1196 }
1197#ifdef MEMDEBUG
1198 fprintf(stderr,"new heap (siz = %d, curhist = %d)\n",siz,curhist);
1199#endif
1200 permalloc();
1201 h = zalloc(sizeof *h);
1202 h->next = *hp;
1203 h->free = (siz > HEAPSIZE) ? siz : HEAPSIZE;
1204 h->ptr = h->pool = zalloc(h->free);
1205 h->histno = curhist;
1206 *hp = h;
1207 heapalloc();
1208 return hp_alloc(hp,siz);
1209}
1210
1211char *hp_realloc(hp,ptr,oldsiz,newsiz) /**/
1212Hp *hp; char *ptr; int oldsiz; int newsiz;
1213{
1214Hp h = *hp;
1215int delta = newsiz-oldsiz;
1216char *ret;
1217
1218 if (h->ptr-oldsiz == ptr && h->free >= delta) {
1219 h->free -= delta;
1220 h->ptr += delta;
1221 return ptr;
1222 }
1223#ifdef MEMDEBUG
1224 fprintf(stderr,"realloc copy\n");
1225#endif
1226 memcpy(ret = hp_alloc(hp,newsiz),ptr,oldsiz);
1227 return ret;
1228}
1229
1230void hp_free(h,ptr,siz) /**/
1231Hp h; char *ptr; int siz;
1232{
1233 if (h->ptr-siz == ptr) {
1234 h->free += siz;
1235 h->ptr -= siz;
1236 }
1237}
1238
1239char *hp_concat(old,new) /**/
1240char *old; char *new;
1241{
1242int oldlen,newlen;
1243
1244 oldlen = strlen(old); newlen = strlen(new);
1245 old = hp_realloc(&hp_lit,old,oldlen+1,oldlen+newlen+1);
1246 strcpy(old+oldlen,new);
1247 return old;
1248}
1249
1250void hp_purge(h,lim) /**/
1251Hp h; int lim;
1252{
1253Hp hlast;
1254
1255 if (!h->next) return;
1256 while (h->next) { hlast = h; h = h->next; }
1257 if (h->histno <= lim || h->histno == 0) {
1258#ifdef MEMDEBUG
1259 fprintf(stderr,"purging %d\n",lim);
1260#endif
1261 free(h->pool);
1262 free(h);
1263 hlast->next = NULL;
1264 }
1265}
1266
1267void readhistfile(s,err) /**/
1268char *s;int err;
1269{
1270char buf[1024];
1271FILE *in;
1272Histent ent;
1273time_t tim = time(NULL);
1274
1275 if (!s) return;
1276 if (in = fopen(s,"r")) {
1277 while (fgets(buf,1024,in)) {
1278 int l = strlen(buf);
1279 char *pt = buf;
1280
1281 while (l && buf[l-1] == '\n') {
1282 buf[l-1] = '\0';
1283 if (l > 1 && buf[l-2] == '\\') {
1284 buf[l-2] = '\n';
1285 fgets(buf+l-1,1024-(l-1),in);
1286 l = strlen(buf);
1287 } else break;
1288 }
1289 for (;*pt;pt++) if (*pt == ' ') *pt = HISTSPACE;
1290
1291 ent = gethistent(++curhist);
1292 ent->lex = hp_alloc(&hp_lex,strlen(buf)+1);
1293 strcpy(ent->lex,buf);
1294 ent->lit = hp_alloc(&hp_lit,strlen(buf)+1);
1295 strcpy(ent->lit,buf);
1296 ent->ftim = ent->stim = tim;
1297 }
1298 fclose(in);
1299 } else if (err)
1300 zerr("can't read history file",s,0);
1301}
1302
1303void savehistfile(s,err,app) /**/
1304char *s;int err;int app;
1305{
1306char *t;
1307FILE *out;
1308int ev,flag;
1309
1310 if (!s || !interact) return;
1311 ev = curhist-savehist+1;
1312 flag = (app) ? O_APPEND : O_TRUNC;
1313 if (ev < firsthist()) ev = firsthist();
1314 if (out = fdopen(open(s,O_CREAT|O_WRONLY|flag,0600),"w")) {
1315 for (; ev <= curhist; ev++) {
1316 t = quietgetevent(ev);
1317 for (; *t; t++)
1318 if (*t == HISTSPACE) fputc(' ',out);
1319 else {
1320 if (*t == '\n') fputc('\\',out);
1321 fputc(*t,out);
1322 }
1323 fputc('\n',out);
1324 }
1325 fclose(out);
1326 } else if (err) zerr("can't write history file: %s",s,0);
1327}
1328
1329int firsthist() /**/
1330{
1331int ev;
1332Histent ent;
1333
1334 ev = curhist-histentct+1;
1335 if (ev < 1) ev = 1;
1336 do {
1337 ent = gethistent(ev);
1338 if ((lithist) ? ent->lit : ent->lex) break;
1339 ev++;
1340 } while (ev < curhist);
1341 return ev;
1342}
1343