home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Unix / Shells / zsh / Source / src / hist.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-07  |  26.5 KB  |  1,398 lines

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