home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / gnu / pdksh-src.lha / src / amiga / pdksh / sh / history.c < prev    next >
C/C++ Source or Header  |  1993-12-01  |  8KB  |  427 lines

  1. /*
  2.  * command history
  3.  *
  4.  * only implements in-memory history.
  5.  */
  6.  
  7. #ifndef lint
  8. static char *RCSid = "$Id: history.c,v 1.2 1992/04/25 08:33:28 sjg Exp $";
  9. #endif
  10.  
  11. #include "stdh.h"
  12. #include <errno.h>
  13. #include <setjmp.h>
  14. #include "sh.h"
  15.  
  16. char   *histrpl();
  17. char  **current;
  18. int    curpos;
  19.  
  20. static FILE *hist_fh = NULL;
  21. static FILE *hist_open ARGS((char *mode));
  22. #ifndef HISTFILE
  23. # define HISTFILE ".pdksh_hist"
  24. #endif
  25.  
  26.   
  27. c_fc(wp)
  28.     register char **wp;
  29. {
  30.     register char *id;
  31.     FILE *f;
  32.     struct temp *tf;
  33.     register char **hp;
  34.     char **hbeg, **hend;
  35.     char *p, *cmd = NULL;
  36.     int lflag = 0, nflag = 0, sflag = 0, rflag = 0, gflag = 0;
  37.     int done = 0;
  38.     void histbackup();
  39.  
  40.     for (wp++; (id = *wp) != NULL && *id++ == '-' && !done; wp++)
  41.         while (*id && !done) {
  42.             switch (*id++) {
  43.               case 'l':
  44.                 lflag++;
  45.                 break;
  46.               case 'n':
  47.                 nflag++;
  48.                 break;
  49.               case 'r':
  50.                 rflag++;
  51.                 break;
  52.               case 'g':
  53.                 gflag++;
  54.                 break;
  55.               case 'e':
  56.                 if (++wp && (p = *wp)) {
  57.                     if (p[0] == '-' && !p[1]) {
  58.                         sflag++;
  59.                     } else {
  60.                         cmd = alloc((size_t)(strlen(p)+4),ATEMP);
  61.                         strcpy(cmd, p);
  62.                         strcat(cmd, " $_");
  63.                     }
  64.                 } else
  65.                     errorf("argument expected\n");
  66.                 id = "";
  67.                 break;
  68.               default:
  69.                 wp--;
  70.                 done++;
  71.                 break;
  72.             }
  73.         }
  74.  
  75.     if (sflag) {
  76.         char *pat = NULL, *rep = NULL;
  77.  
  78.         hp = histptr - 1;
  79.         while ((id = *wp++) != NULL) {
  80.             /* todo: multiple substitutions */
  81.             if ((p = strchr(id, '=')) != NULL) {
  82.                 pat = id;
  83.                 rep = p;
  84.                 *rep++ = '\0';
  85.             } else
  86.                 hp = histget(id);
  87.         }
  88.  
  89.         if (hp == NULL || hp < history)
  90.             errorf("cannot find history\n");
  91.         if (pat == NULL)
  92.             strcpy(line, *hp);
  93.         else
  94.             histrpl(*hp, pat, rep, gflag);
  95.         histbackup();
  96.         histsave(line); 
  97.         histpush--; 
  98.         line[0] = '\0';
  99.         return 0;
  100.     }
  101.  
  102.     if (*wp != NULL) {
  103.         hbeg = histget(*wp++); /* first */
  104.         if (*wp != NULL)
  105.             hend = histget(*wp++); /* last */
  106.         else if (lflag)
  107.             hend = histptr;
  108.         else
  109.             hend = hbeg;
  110.     } else {
  111.         if (lflag)
  112.             hbeg = histptr - 16, hend = histptr;
  113.         else
  114.             hbeg = hend = histptr - 1;
  115.         if (hbeg < history)
  116.             hbeg = history;
  117.     }
  118.     if (hbeg == NULL || hend == NULL)
  119.         errorf("can't find history\n");
  120.  
  121.     if (lflag)
  122.         f = stdout;
  123.     else {
  124.         nflag++;
  125.         tf = maketemp(ATEMP);
  126.         tf->next = e.temps; e.temps = tf;
  127.         f = fopen(tf->name, "w");
  128.         if (f == NULL)
  129.             errorf("cannot create temp file %s", tf->name);
  130.         setvbuf(f, (char *)NULL, _IOFBF, BUFSIZ);
  131.     }
  132.  
  133.     for (hp = (rflag ? hend : hbeg); rflag ? (hp >= hbeg) : (hp <= hend);
  134.           rflag ? hp-- : hp++) {
  135.         if (!nflag)
  136.             fprintf(f, "%3d: ", source->line - (int)(histptr-hp));
  137.         fprintf(f, "%s\n", *hp);
  138.     }
  139.  
  140.     if (lflag)
  141.         return 0;
  142.     else
  143.         fclose(f);
  144.  
  145.     setstr(local("_"), tf->name);
  146.     if (cmd) {
  147.         command(cmd); /* edit temp file */
  148.         afree(cmd, ATEMP);
  149.     } else
  150.         command("${FCEDIT:-/bin/ed} $_");
  151.  
  152.     f = fopen(tf->name, "r");
  153.     if (f == NULL)
  154.         errorf("cannot open temp file %s\n", tf->name);
  155.     setvbuf(f, (char *)NULL, _IOFBF, BUFSIZ);
  156.     /* we push the editted lines onto the history list */
  157.     while (fgets(line, sizeof(line), f) != NULL) {
  158.         histsave(line); 
  159.         histpush--; 
  160.     }
  161.     line[0] = '\0';
  162.     fclose(f);
  163.  
  164.     return 0;
  165. }
  166.  
  167. /******************************/
  168. /* Back up over last histsave */
  169. /******************************/
  170. void
  171. histbackup()
  172. {
  173.     static int last_line = -1;
  174.  
  175.     if (histptr > history && last_line != source->line) { 
  176.         source->line--;
  177.         afree((void*)*histptr, APERM);
  178.         histptr--;
  179.         last_line = source->line;
  180.     }
  181. }
  182.  
  183. /*
  184.  * save command in history
  185.  */
  186. void
  187. histsave(cmd)
  188.     char *cmd;
  189. {
  190.     register char **hp = histptr;
  191.     char *cp;
  192.  
  193.     if (++hp >= history + HISTORY) { /* remove oldest command */
  194.         afree((void*)*history, APERM);
  195.         for (hp = history; hp < history + HISTORY - 1; hp++)
  196.             hp[0] = hp[1];
  197.     }
  198.     *hp = strsave(cmd, APERM);
  199.     if ((cp = strchr(*hp, '\n')) != NULL)
  200.         *cp = '\0';
  201.     histptr = hp;
  202. }
  203.  
  204. /*
  205.  * get pointer to history given pattern
  206.  * pattern is a number or string
  207.  */
  208. char **
  209. histget(str)
  210.     char *str;
  211. {
  212.     register char **hp = NULL;
  213.  
  214.     if (*str == '-')
  215.         hp = histptr + getn(str);
  216.     else
  217.     if (digit(*str))
  218.         hp = histptr + (getn(str) - source->line);
  219.     else 
  220.     if (*str == '?') {    /* unanchored match */
  221.         for (hp = histptr-1; hp >= history; hp--)
  222.             if (strstr(*hp, str+1) != NULL)
  223.                 break;
  224.     } else {        /* anchored match */
  225.         for (hp = histptr; hp >= history; hp--)
  226.             if (strncmp(*hp, str, strlen(str)) == 0)
  227.                 break;
  228.     }
  229.  
  230.     return (history <= hp && hp <= histptr) ? hp : NULL;
  231. }
  232.  
  233. char *
  234. histrpl(s, pat, rep, global)
  235.     char *s;
  236.     char *pat, *rep;
  237.     int global;
  238. {
  239.     char *s1, *p, *last = NULL;
  240.     int len = strlen(pat);
  241.  
  242.     if (strlen(s) - strlen(pat) + strlen(rep) >= LINE)
  243.         errorf("substitution too long\n");
  244.     line[0] = '\0';
  245.     p = line;
  246.     while (s1 = strstr(s, pat)) {
  247.         strncpy(p, s, s1 - s);        /* first part */
  248.         strcpy(p + (s1 - s), rep);    /* replacement */
  249.         s = s1 + len;
  250.         last = s1;
  251.         p = strchr(p, 0);
  252.         if (!global)
  253.             s = "";
  254.     }
  255.     if (last)
  256.         strcpy(p, last + len);        /* last part */
  257.     else
  258.         errorf("substitution failed\n");
  259.     return line;
  260. }
  261.  
  262. /*
  263.  * 92-04-25 <sjg@zen>
  264.  * A simple history file implementation.
  265.  * At present we only save the history when we exit.
  266.  * This can cause problems when there are multiple shells are 
  267.  * running under the same user-id.  The last shell to exit gets 
  268.  * to save its history.
  269.  */
  270. void
  271. hist_init(s)
  272.   Source *s;
  273. {
  274.   static int once = 0;
  275.   FILE *fh;
  276.   
  277.   if (once++)
  278.     return;
  279.  
  280.   if (fh = hist_open("r"))
  281.   {
  282.     while (fgets(line, sizeof(line), fh) != NULL)
  283.     {
  284.       histsave(line); 
  285.       s->line++;
  286.     }
  287.     line[0] = '\0';
  288.     fclose(fh);
  289. #if 0    /* this might be a good idea? */
  290.     hist_fh = hist_open("a");
  291. #endif
  292.   }
  293.   
  294. }
  295.  
  296.  
  297. /*
  298.  * save our history.
  299.  * We check that we do not have more than we are allowed.
  300.  * If the history file is read-only we do nothing.
  301.  * Handy for having all shells start with a useful history set.
  302.  */
  303.  
  304. void
  305. hist_finish()
  306. {
  307.   static int once = 0;
  308.   FILE *fh;
  309.   register int i, mx;
  310.   register char **hp, *mode = "w";
  311.   
  312.   if (once++)
  313.     return;
  314.   if ((mx = atoi(strval(global("HISTSIZE")))) > HISTORY || mx <= 0)
  315.     mx = HISTORY;
  316.   /* check how many we have */
  317.   i = histptr - history;
  318.   if (i >= mx)
  319.   {
  320.     hp = &histptr[-mx];
  321.   }
  322.   else
  323.   {
  324.     hp = history;
  325.   }
  326.   if (fh = hist_open(mode))
  327.   {
  328.     for (i = 0; i < mx && hp[i]; i++)
  329.       fprintf(fh, "%s\n", hp[i]);
  330.     fclose(fh);
  331.   }
  332. }
  333.  
  334.  
  335. /*
  336.  * simply grab the nominated history file.
  337.  */
  338. static FILE *
  339. hist_open(mode)
  340.   char *mode;
  341. {
  342.   register char *rcp;
  343.   FILE *fh;
  344.   char name[128];
  345.   
  346.   if ((rcp = strval(global("HISTFILE"))) == NULL || *rcp == '\0')
  347.   {
  348.     (void) sprintf(name, "%s/%s", strval(global("HOME")), HISTFILE);
  349.     rcp = name;
  350.   }
  351.   return fopen(rcp, mode);
  352. }
  353.  
  354.  
  355.  
  356. /*
  357.  * Return the current position.
  358.  */
  359. char **
  360. histpos()
  361. {
  362.     return current;
  363. }
  364.  
  365. int
  366. histN()
  367. {
  368.     return curpos;
  369. }
  370.  
  371. int
  372. histnum(n)
  373. {
  374.     int    last = histptr - history;
  375.  
  376.     if (n < 0 || n >= last) {
  377.         current = histptr;
  378.         curpos = last;
  379.         return last;
  380.     }  else {
  381.         current = &history[n];
  382.         curpos = n;
  383.         return n;
  384.     }
  385. }
  386.  
  387. /*
  388.  * This will become unecessary if histget is modified to allow
  389.  * searching from positions other than the end, and in either 
  390.  * direction.
  391.  */
  392. char *
  393. findhist(start, fwd, str)
  394.     int    start;
  395.     int    fwd;
  396.     char     *str;
  397. {
  398.     int     pos = start;
  399.     char     *line, *last;
  400.  
  401.     /* XXX check that we are valid after this */
  402.     if (fwd)
  403.         pos++;
  404.     else
  405.         pos--;
  406.     histnum(pos);
  407.     line = *histpos();
  408.     do {
  409.         last = line;
  410.         if (strstr(line, str) != 0) {
  411.             /* keep position current */
  412.             return (line);
  413.         }
  414.         if (fwd)
  415.             pos++;
  416.         else
  417.             pos--;
  418.         histnum(pos);
  419.         line = *histpos();
  420.     } while (line && *line && line != last && pos>0);
  421.  
  422.     histnum(start);
  423.     if (pos <= 0)
  424.         return (char*)-1; /* TODO */
  425.     return NULL;
  426. }
  427.