ccf09fb3eaa34404ccbd9d31bb2c3abab2e51b9a
[dragonfly.git] / lib / libedit / history.c
1 /*-
2  * Copyright (c) 1992, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Christos Zoulas of Cornell University.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by the University of
19  *      California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  * @(#)history.c        8.1 (Berkeley) 6/4/93
37  * $DragonFly: src/lib/libedit/history.c,v 1.5 2004/07/27 11:22:34 asmodai Exp $
38  */
39
40 /*
41  * hist.c: History access functions
42  */
43 #include "sys.h"
44
45 #include <string.h>
46 #include <stdlib.h>
47 #include <stdarg.h>
48
49 static const char hist_cookie[] = "_HiStOrY_V1_\n";
50
51 #include "histedit.h"
52
53 typedef const HistEvent *       (*history_gfun_t) (ptr_t);
54 typedef const HistEvent *       (*history_efun_t) (ptr_t, const char *);
55 typedef void                    (*history_vfun_t) (ptr_t);
56
57 struct history {
58     ptr_t          h_ref;               /* Argument for history fcns    */
59     history_gfun_t h_first;             /* Get the first element        */
60     history_gfun_t h_next;              /* Get the next element         */
61     history_gfun_t h_last;              /* Get the last element         */
62     history_gfun_t h_prev;              /* Get the previous element     */
63     history_gfun_t h_curr;              /* Get the current element      */
64     history_vfun_t h_clear;             /* Clear the history list       */
65     history_efun_t h_enter;             /* Add an element               */
66     history_efun_t h_add;               /* Append to an element         */
67 };
68
69 #define HNEXT(h)        (*(h)->h_next)((h)->h_ref)
70 #define HFIRST(h)       (*(h)->h_first)((h)->h_ref)
71 #define HPREV(h)        (*(h)->h_prev)((h)->h_ref)
72 #define HLAST(h)        (*(h)->h_last)((h)->h_ref)
73 #define HCURR(h)        (*(h)->h_curr)((h)->h_ref)
74 #define HCLEAR(h)       (*(h)->h_clear)((h)->h_ref)
75 #define HENTER(h, str)  (*(h)->h_enter)((h)->h_ref, str)
76 #define HADD(h, str)    (*(h)->h_add)((h)->h_ref, str)
77
78 #define h_malloc(a)     malloc(a)
79 #define h_free(a)       free(a)
80
81
82 private int              history_set_num        (History *, int);
83 private int              history_set_fun        (History *, History *);
84 private int              history_load           (History *, const char *);
85 private int              history_save           (History *, const char *);
86 private const HistEvent *history_prev_event     (History *, int);
87 private const HistEvent *history_next_event     (History *, int);
88 private const HistEvent *history_next_string    (History *, const char *);
89 private const HistEvent *history_prev_string    (History *, const char *);
90
91
92 /***********************************************************************/
93
94 /*
95  * Builtin- history implementation
96  */
97 typedef struct hentry_t {
98     HistEvent ev;               /* What we return               */
99     struct hentry_t *next;      /* Next entry                   */
100     struct hentry_t *prev;      /* Previous entry               */
101 } hentry_t;
102
103 typedef struct history_t {
104     hentry_t  list;             /* Fake list header element     */
105     hentry_t *cursor;           /* Current element in the list  */
106     int max;                    /* Maximum number of events     */
107     int cur;                    /* Current number of events     */
108     int eventno;                /* Current event number         */
109 } history_t;
110
111 private const HistEvent *history_def_first  (ptr_t);
112 private const HistEvent *history_def_last   (ptr_t);
113 private const HistEvent *history_def_next   (ptr_t);
114 private const HistEvent *history_def_prev   (ptr_t);
115 private const HistEvent *history_def_curr   (ptr_t);
116 private const HistEvent *history_def_enter  (ptr_t, const char *);
117 private const HistEvent *history_def_add    (ptr_t, const char *);
118 private void             history_def_init   (ptr_t *, int);
119 private void             history_def_clear  (ptr_t);
120 private const HistEvent *history_def_insert (history_t *, const char *);
121 private void             history_def_delete (history_t *, hentry_t *);
122
123 #define history_def_set(p, num) (void) (((history_t *) p)->max = (num))
124
125
126 /* history_def_first():
127  *      Default function to return the first event in the history.
128  */
129 private const HistEvent *
130 history_def_first(p)
131     ptr_t p;
132 {
133     history_t *h = (history_t *) p;
134     h->cursor = h->list.next;
135     if (h->cursor != &h->list)
136         return &h->cursor->ev;
137     else
138         return NULL;
139 }
140
141 /* history_def_last():
142  *      Default function to return the last event in the history.
143  */
144 private const HistEvent *
145 history_def_last(p)
146     ptr_t p;
147 {
148     history_t *h = (history_t *) p;
149     h->cursor = h->list.prev;
150     if (h->cursor != &h->list)
151         return &h->cursor->ev;
152     else
153         return NULL;
154 }
155
156 /* history_def_next():
157  *      Default function to return the next event in the history.
158  */
159 private const HistEvent *
160 history_def_next(p)
161     ptr_t p;
162 {
163     history_t *h = (history_t *) p;
164
165     if (h->cursor != &h->list)
166         h->cursor = h->cursor->next;
167     else
168         return NULL;
169
170     if (h->cursor != &h->list)
171         return &h->cursor->ev;
172     else
173         return NULL;
174 }
175
176
177 /* history_def_prev():
178  *      Default function to return the previous event in the history.
179  */
180 private const HistEvent *
181 history_def_prev(p)
182     ptr_t p;
183 {
184     history_t *h = (history_t *) p;
185
186     if (h->cursor != &h->list)
187         h->cursor = h->cursor->prev;
188     else
189         return NULL;
190
191     if (h->cursor != &h->list)
192         return &h->cursor->ev;
193     else
194         return NULL;
195 }
196
197
198 /* history_def_curr():
199  *      Default function to return the current event in the history.
200  */
201 private const HistEvent *
202 history_def_curr(p)
203     ptr_t p;
204 {
205     history_t *h = (history_t *) p;
206
207     if (h->cursor != &h->list)
208         return &h->cursor->ev;
209     else
210         return NULL;
211 }
212
213
214 /* history_def_add():
215  *      Append string to element
216  */
217 private const HistEvent *
218 history_def_add(p, str)
219     ptr_t p;
220     const char *str;
221 {
222     history_t *h = (history_t *) p;
223     size_t len;
224     char *s;
225
226     if (h->cursor == &h->list)
227         return (history_def_enter(p, str));
228     len = strlen(h->cursor->ev.str) + strlen(str) + 1;
229     s = (char *) h_malloc(len);
230     (void)strcpy(s, h->cursor->ev.str); /* XXX strcpy is safe */
231     (void)strcat(s, str);                       /* XXX strcat is safe */
232     h_free((ptr_t) h->cursor->ev.str);
233     h->cursor->ev.str = s;
234     return &h->cursor->ev;
235 }
236
237
238 /* history_def_delete():
239  *      Delete element hp of the h list
240  */
241 private void
242 history_def_delete(h, hp)
243     history_t *h;
244     hentry_t *hp;
245 {
246     if (hp == &h->list)
247         abort();
248     hp->prev->next = hp->next;
249     hp->next->prev = hp->prev;
250     h_free((ptr_t) hp->ev.str);
251     h_free(hp);
252     h->cur--;
253 }
254
255
256 /* history_def_insert():
257  *      Insert element with string str in the h list
258  */
259 private const HistEvent *
260 history_def_insert(h, str)
261     history_t *h;
262     const char *str;
263 {
264     h->cursor = (hentry_t *) h_malloc(sizeof(hentry_t));
265     h->cursor->ev.str = strdup(str);
266     h->cursor->next = h->list.next;
267     h->cursor->prev = &h->list;
268     h->list.next->prev = h->cursor;
269     h->list.next = h->cursor;
270     h->cur++;
271
272     return &h->cursor->ev;
273 }
274
275
276 /* history_def_enter():
277  *      Default function to enter an item in the history
278  */
279 private const HistEvent *
280 history_def_enter(p, str)
281     ptr_t p;
282     const char *str;
283 {
284     history_t *h = (history_t *) p;
285     const HistEvent *ev;
286
287
288     ev = history_def_insert(h, str);
289     ((HistEvent*) ev)->num = ++h->eventno;
290
291     /*
292      * Always keep at least one entry.
293      * This way we don't have to check for the empty list.
294      */
295     while (h->cur > h->max + 1)
296         history_def_delete(h, h->list.prev);
297     return ev;
298 }
299
300
301 /* history_def_init():
302  *      Default history initialization function
303  */
304 private void
305 history_def_init(p, n)
306     ptr_t *p;
307     int n;
308 {
309     history_t *h = (history_t *) h_malloc(sizeof(history_t));
310     if (n <= 0)
311         n = 0;
312     h->eventno = 0;
313     h->cur = 0;
314     h->max = n;
315     h->list.next = h->list.prev = &h->list;
316     h->list.ev.str = NULL;
317     h->list.ev.num = 0;
318     h->cursor = &h->list;
319     *p = (ptr_t) h;
320 }
321
322
323 /* history_def_clear():
324  *      Default history cleanup function
325  */
326 private void
327 history_def_clear(p)
328     ptr_t p;
329 {
330     history_t *h = (history_t *) p;
331
332     while (h->list.prev != &h->list)
333         history_def_delete(h, h->list.prev);
334     h->eventno = 0;
335     h->cur = 0;
336 }
337
338 /************************************************************************/
339
340 /* history_init():
341  *      Initialization function.
342  */
343 public History *
344 history_init()
345 {
346     History *h = (History *) h_malloc(sizeof(History));
347
348     history_def_init(&h->h_ref, 0);
349
350     h->h_next  = history_def_next;
351     h->h_first = history_def_first;
352     h->h_last  = history_def_last;
353     h->h_prev  = history_def_prev;
354     h->h_curr  = history_def_curr;
355     h->h_clear = history_def_clear;
356     h->h_enter = history_def_enter;
357     h->h_add   = history_def_add;
358
359     return h;
360 }
361
362
363 /* history_end():
364  *      clean up history;
365  */
366 public void
367 history_end(h)
368     History *h;
369 {
370     if (h->h_next == history_def_next)
371         history_def_clear(h->h_ref);
372 }
373
374
375
376 /* history_set_num():
377  *      Set history number of events
378  */
379 private int
380 history_set_num(h, num)
381     History *h;
382     int num;
383 {
384     if (h->h_next != history_def_next || num < 0)
385         return -1;
386     history_def_set(h->h_ref, num);
387     return 0;
388 }
389
390
391 /* history_set_fun():
392  *      Set history functions
393  */
394 private int
395 history_set_fun(h, nh)
396     History *h, *nh;
397 {
398     if (nh->h_first == NULL || nh->h_next == NULL ||
399         nh->h_last == NULL  || nh->h_prev == NULL || nh->h_curr == NULL ||
400         nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL ||
401         nh->h_ref == NULL) {
402         if (h->h_next != history_def_next) {
403             history_def_init(&h->h_ref, 0);
404             h->h_first = history_def_first;
405             h->h_next  = history_def_next;
406             h->h_last  = history_def_last;
407             h->h_prev  = history_def_prev;
408             h->h_curr  = history_def_curr;
409             h->h_clear = history_def_clear;
410             h->h_enter = history_def_enter;
411             h->h_add   = history_def_add;
412         }
413         return -1;
414     }
415
416     if (h->h_next == history_def_next)
417         history_def_clear(h->h_ref);
418
419     h->h_first = nh->h_first;
420     h->h_next  = nh->h_next;
421     h->h_last  = nh->h_last;
422     h->h_prev  = nh->h_prev;
423     h->h_curr  = nh->h_curr;
424     h->h_clear = nh->h_clear;
425     h->h_enter = nh->h_enter;
426     h->h_add   = nh->h_add;
427     return 0;
428 }
429
430
431 /* history_load():
432  *      History load function
433  */
434 private int
435 history_load(h, fname)
436     History *h;
437     const char *fname;
438 {
439     FILE *fp;
440     char *line;
441     size_t sz;
442     int i = -1;
443
444     if ((fp = fopen(fname, "r")) == NULL)
445         return i;
446
447     if ((line = fgetln(fp, &sz)) == NULL)
448         goto done;
449
450     if (strncmp(line, hist_cookie, sz) != 0)
451         goto done;
452         
453     for (i = 0; (line = fgetln(fp, &sz)) != NULL; i++) {
454         char c = line[sz];
455         line[sz] = '\0';
456         HENTER(h, line);
457         line[sz] = c;
458     }
459
460 done:
461     (void) fclose(fp);
462     return i;
463 }
464
465
466 /* history_save():
467  *      History save function
468  */
469 private int
470 history_save(h, fname)
471     History *h;
472     const char *fname;
473 {
474     FILE *fp;
475     const HistEvent *ev;
476     int i = 0;
477
478     if ((fp = fopen(fname, "w")) == NULL)
479         return -1;
480
481     (void) fputs(hist_cookie, fp);
482     for (ev = HLAST(h); ev != NULL; ev = HPREV(h), i++)
483         (void) fprintf(fp, "%s", ev->str);
484     (void) fclose(fp);
485     return i;
486 }
487
488
489 /* history_prev_event():
490  *      Find the previous event, with number given
491  */
492 private const HistEvent *
493 history_prev_event(h, num)
494     History *h;
495     int num;
496 {
497     const HistEvent *ev;
498     for (ev = HCURR(h); ev != NULL; ev = HPREV(h))
499         if (ev->num == num)
500             return ev;
501     return NULL;
502 }
503
504
505 /* history_next_event():
506  *      Find the next event, with number given
507  */
508 private const HistEvent *
509 history_next_event(h, num)
510     History *h;
511     int num;
512 {
513     const HistEvent *ev;
514     for (ev = HCURR(h); ev != NULL; ev = HNEXT(h))
515         if (ev->num == num)
516             return ev;
517     return NULL;
518 }
519
520
521 /* history_prev_string():
522  *      Find the previous event beginning with string
523  */
524 private const HistEvent *
525 history_prev_string(h, str)
526     History *h;
527     const char* str;
528 {
529     const HistEvent *ev;
530     size_t len = strlen(str);
531
532     for (ev = HCURR(h); ev != NULL; ev = HNEXT(h))
533         if (strncmp(str, ev->str, len) == 0)
534             return ev;
535     return NULL;
536 }
537
538
539 /* history_next_string():
540  *      Find the next event beginning with string
541  */
542 private const HistEvent *
543 history_next_string(h, str)
544     History *h;
545     const char* str;
546 {
547     const HistEvent *ev;
548     size_t len = strlen(str);
549
550     for (ev = HCURR(h); ev != NULL; ev = HPREV(h))
551         if (strncmp(str, ev->str, len) == 0)
552             return ev;
553     return NULL;
554 }
555
556
557 /* history():
558  *      User interface to history functions.
559  */
560 const HistEvent *
561 history(History *h, int fun, ...)
562 {
563     va_list va;
564     const HistEvent *ev = NULL;
565     const char *str;
566     static HistEvent sev = { 0, "" };
567
568     va_start(va, fun);
569
570     switch (fun) {
571     case H_ADD:
572         str = va_arg(va, const char *);
573         ev = HADD(h, str);
574         break;
575
576     case H_ENTER:
577         str = va_arg(va, const char *);
578         ev = HENTER(h, str);
579         break;
580
581     case H_FIRST:
582         ev = HFIRST(h);
583         break;
584
585     case H_NEXT:
586         ev = HNEXT(h);
587         break;
588
589     case H_LAST:
590         ev = HLAST(h);
591         break;
592
593     case H_PREV:
594         ev = HPREV(h);
595         break;
596
597     case H_CURR:
598         ev = HCURR(h);
599         break;
600
601     case H_CLEAR:
602         HCLEAR(h);
603         break;
604         
605     case H_LOAD:
606         sev.num = history_load(h, va_arg(va, const char *));
607         ev = &sev;
608         break;
609         
610     case H_SAVE:
611         sev.num = history_save(h, va_arg(va, const char *));
612         ev = &sev;
613         break;
614
615     case H_PREV_EVENT:
616         ev = history_prev_event(h, va_arg(va, int));
617         break;
618
619     case H_NEXT_EVENT:
620         ev = history_next_event(h, va_arg(va, int));
621         break;
622
623     case H_PREV_STR:
624         ev = history_prev_string(h, va_arg(va, const char*));
625         break;
626
627     case H_NEXT_STR:
628         ev = history_next_string(h, va_arg(va, const char*));
629         break;
630
631     case H_EVENT:
632         if (history_set_num(h, va_arg(va, int)) == 0) {
633             sev.num = -1;
634             ev = &sev;
635         }
636         break;
637
638     case H_FUNC:
639         {
640             History hf;
641             hf.h_ref   = va_arg(va, ptr_t);
642             hf.h_first = va_arg(va, history_gfun_t);
643             hf.h_next  = va_arg(va, history_gfun_t);
644             hf.h_last  = va_arg(va, history_gfun_t);
645             hf.h_prev  = va_arg(va, history_gfun_t);
646             hf.h_curr  = va_arg(va, history_gfun_t);
647             hf.h_clear = va_arg(va, history_vfun_t);
648             hf.h_enter = va_arg(va, history_efun_t);
649             hf.h_add   = va_arg(va, history_efun_t);
650
651             if (history_set_fun(h, &hf) == 0) {
652                 sev.num = -1;
653                 ev = &sev;
654             }
655         }
656         break;
657
658     case H_END:
659         history_end(h);
660         break;
661
662     default:
663         break;
664     }
665     va_end(va);
666     return ev;
667 }