Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[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  */
38
39 /*
40  * hist.c: History access functions
41  */
42 #include "sys.h"
43
44 #include <string.h>
45 #include <stdlib.h>
46 #if __STDC__
47 #include <stdarg.h>
48 #else
49 #include <varargs.h>
50 #endif
51
52 static const char hist_cookie[] = "_HiStOrY_V1_\n";
53
54 #include "histedit.h"
55
56 typedef const HistEvent *       (*history_gfun_t) __P((ptr_t));
57 typedef const HistEvent *       (*history_efun_t) __P((ptr_t, const char *));
58 typedef void                    (*history_vfun_t) __P((ptr_t));
59
60 struct history {
61     ptr_t          h_ref;               /* Argument for history fcns    */
62     history_gfun_t h_first;             /* Get the first element        */
63     history_gfun_t h_next;              /* Get the next element         */
64     history_gfun_t h_last;              /* Get the last element         */
65     history_gfun_t h_prev;              /* Get the previous element     */
66     history_gfun_t h_curr;              /* Get the current element      */
67     history_vfun_t h_clear;             /* Clear the history list       */
68     history_efun_t h_enter;             /* Add an element               */
69     history_efun_t h_add;               /* Append to an element         */
70 };
71
72 #define HNEXT(h)        (*(h)->h_next)((h)->h_ref)
73 #define HFIRST(h)       (*(h)->h_first)((h)->h_ref)
74 #define HPREV(h)        (*(h)->h_prev)((h)->h_ref)
75 #define HLAST(h)        (*(h)->h_last)((h)->h_ref)
76 #define HCURR(h)        (*(h)->h_curr)((h)->h_ref)
77 #define HCLEAR(h)       (*(h)->h_clear)((h)->h_ref)
78 #define HENTER(h, str)  (*(h)->h_enter)((h)->h_ref, str)
79 #define HADD(h, str)    (*(h)->h_add)((h)->h_ref, str)
80
81 #define h_malloc(a)     malloc(a)
82 #define h_free(a)       free(a)
83
84
85 private int              history_set_num        __P((History *, int));
86 private int              history_set_fun        __P((History *, History *));
87 private int              history_load           __P((History *, const char *));
88 private int              history_save           __P((History *, const char *));
89 private const HistEvent *history_prev_event     __P((History *, int));
90 private const HistEvent *history_next_event     __P((History *, int));
91 private const HistEvent *history_next_string    __P((History *, const char *));
92 private const HistEvent *history_prev_string    __P((History *, const char *));
93
94
95 /***********************************************************************/
96
97 /*
98  * Builtin- history implementation
99  */
100 typedef struct hentry_t {
101     HistEvent ev;               /* What we return               */
102     struct hentry_t *next;      /* Next entry                   */
103     struct hentry_t *prev;      /* Previous entry               */
104 } hentry_t;
105
106 typedef struct history_t {
107     hentry_t  list;             /* Fake list header element     */
108     hentry_t *cursor;           /* Current element in the list  */
109     int max;                    /* Maximum number of events     */
110     int cur;                    /* Current number of events     */
111     int eventno;                /* Current event number         */
112 } history_t;
113
114 private const HistEvent *history_def_first  __P((ptr_t));
115 private const HistEvent *history_def_last   __P((ptr_t));
116 private const HistEvent *history_def_next   __P((ptr_t));
117 private const HistEvent *history_def_prev   __P((ptr_t));
118 private const HistEvent *history_def_curr   __P((ptr_t));
119 private const HistEvent *history_def_enter  __P((ptr_t, const char *));
120 private const HistEvent *history_def_add    __P((ptr_t, const char *));
121 private void             history_def_init   __P((ptr_t *, int));
122 private void             history_def_clear  __P((ptr_t));
123 private const HistEvent *history_def_insert __P((history_t *, const char *));
124 private void             history_def_delete __P((history_t *, hentry_t *));
125
126 #define history_def_set(p, num) (void) (((history_t *) p)->max = (num))
127
128
129 /* history_def_first():
130  *      Default function to return the first event in the history.
131  */
132 private const HistEvent *
133 history_def_first(p)
134     ptr_t p;
135 {
136     history_t *h = (history_t *) p;
137     h->cursor = h->list.next;
138     if (h->cursor != &h->list)
139         return &h->cursor->ev;
140     else
141         return NULL;
142 }
143
144 /* history_def_last():
145  *      Default function to return the last event in the history.
146  */
147 private const HistEvent *
148 history_def_last(p)
149     ptr_t p;
150 {
151     history_t *h = (history_t *) p;
152     h->cursor = h->list.prev;
153     if (h->cursor != &h->list)
154         return &h->cursor->ev;
155     else
156         return NULL;
157 }
158
159 /* history_def_next():
160  *      Default function to return the next event in the history.
161  */
162 private const HistEvent *
163 history_def_next(p)
164     ptr_t p;
165 {
166     history_t *h = (history_t *) p;
167
168     if (h->cursor != &h->list)
169         h->cursor = h->cursor->next;
170     else
171         return NULL;
172
173     if (h->cursor != &h->list)
174         return &h->cursor->ev;
175     else
176         return NULL;
177 }
178
179
180 /* history_def_prev():
181  *      Default function to return the previous event in the history.
182  */
183 private const HistEvent *
184 history_def_prev(p)
185     ptr_t p;
186 {
187     history_t *h = (history_t *) p;
188
189     if (h->cursor != &h->list)
190         h->cursor = h->cursor->prev;
191     else
192         return NULL;
193
194     if (h->cursor != &h->list)
195         return &h->cursor->ev;
196     else
197         return NULL;
198 }
199
200
201 /* history_def_curr():
202  *      Default function to return the current event in the history.
203  */
204 private const HistEvent *
205 history_def_curr(p)
206     ptr_t p;
207 {
208     history_t *h = (history_t *) p;
209
210     if (h->cursor != &h->list)
211         return &h->cursor->ev;
212     else
213         return NULL;
214 }
215
216
217 /* history_def_add():
218  *      Append string to element
219  */
220 private const HistEvent *
221 history_def_add(p, str)
222     ptr_t p;
223     const char *str;
224 {
225     history_t *h = (history_t *) p;
226     size_t len;
227     char *s;
228
229     if (h->cursor == &h->list)
230         return (history_def_enter(p, str));
231     len = strlen(h->cursor->ev.str) + strlen(str) + 1;
232     s = (char *) h_malloc(len);
233     (void)strcpy(s, h->cursor->ev.str); /* XXX strcpy is safe */
234     (void)strcat(s, str);                       /* XXX strcat is safe */
235     h_free((ptr_t) h->cursor->ev.str);
236     h->cursor->ev.str = s;
237     return &h->cursor->ev;
238 }
239
240
241 /* history_def_delete():
242  *      Delete element hp of the h list
243  */
244 private void
245 history_def_delete(h, hp)
246     history_t *h;
247     hentry_t *hp;
248 {
249     if (hp == &h->list)
250         abort();
251     hp->prev->next = hp->next;
252     hp->next->prev = hp->prev;
253     h_free((ptr_t) hp->ev.str);
254     h_free(hp);
255     h->cur--;
256 }
257
258
259 /* history_def_insert():
260  *      Insert element with string str in the h list
261  */
262 private const HistEvent *
263 history_def_insert(h, str)
264     history_t *h;
265     const char *str;
266 {
267     h->cursor = (hentry_t *) h_malloc(sizeof(hentry_t));
268     h->cursor->ev.str = strdup(str);
269     h->cursor->next = h->list.next;
270     h->cursor->prev = &h->list;
271     h->list.next->prev = h->cursor;
272     h->list.next = h->cursor;
273     h->cur++;
274
275     return &h->cursor->ev;
276 }
277
278
279 /* history_def_enter():
280  *      Default function to enter an item in the history
281  */
282 private const HistEvent *
283 history_def_enter(p, str)
284     ptr_t p;
285     const char *str;
286 {
287     history_t *h = (history_t *) p;
288     const HistEvent *ev;
289
290
291     ev = history_def_insert(h, str);
292     ((HistEvent*) ev)->num = ++h->eventno;
293
294     /*
295      * Always keep at least one entry.
296      * This way we don't have to check for the empty list.
297      */
298     while (h->cur > h->max + 1)
299         history_def_delete(h, h->list.prev);
300     return ev;
301 }
302
303
304 /* history_def_init():
305  *      Default history initialization function
306  */
307 private void
308 history_def_init(p, n)
309     ptr_t *p;
310     int n;
311 {
312     history_t *h = (history_t *) h_malloc(sizeof(history_t));
313     if (n <= 0)
314         n = 0;
315     h->eventno = 0;
316     h->cur = 0;
317     h->max = n;
318     h->list.next = h->list.prev = &h->list;
319     h->list.ev.str = NULL;
320     h->list.ev.num = 0;
321     h->cursor = &h->list;
322     *p = (ptr_t) h;
323 }
324
325
326 /* history_def_clear():
327  *      Default history cleanup function
328  */
329 private void
330 history_def_clear(p)
331     ptr_t p;
332 {
333     history_t *h = (history_t *) p;
334
335     while (h->list.prev != &h->list)
336         history_def_delete(h, h->list.prev);
337     h->eventno = 0;
338     h->cur = 0;
339 }
340
341 /************************************************************************/
342
343 /* history_init():
344  *      Initialization function.
345  */
346 public History *
347 history_init()
348 {
349     History *h = (History *) h_malloc(sizeof(History));
350
351     history_def_init(&h->h_ref, 0);
352
353     h->h_next  = history_def_next;
354     h->h_first = history_def_first;
355     h->h_last  = history_def_last;
356     h->h_prev  = history_def_prev;
357     h->h_curr  = history_def_curr;
358     h->h_clear = history_def_clear;
359     h->h_enter = history_def_enter;
360     h->h_add   = history_def_add;
361
362     return h;
363 }
364
365
366 /* history_end():
367  *      clean up history;
368  */
369 public void
370 history_end(h)
371     History *h;
372 {
373     if (h->h_next == history_def_next)
374         history_def_clear(h->h_ref);
375 }
376
377
378
379 /* history_set_num():
380  *      Set history number of events
381  */
382 private int
383 history_set_num(h, num)
384     History *h;
385     int num;
386 {
387     if (h->h_next != history_def_next || num < 0)
388         return -1;
389     history_def_set(h->h_ref, num);
390     return 0;
391 }
392
393
394 /* history_set_fun():
395  *      Set history functions
396  */
397 private int
398 history_set_fun(h, nh)
399     History *h, *nh;
400 {
401     if (nh->h_first == NULL || nh->h_next == NULL ||
402         nh->h_last == NULL  || nh->h_prev == NULL || nh->h_curr == NULL ||
403         nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL ||
404         nh->h_ref == NULL) {
405         if (h->h_next != history_def_next) {
406             history_def_init(&h->h_ref, 0);
407             h->h_first = history_def_first;
408             h->h_next  = history_def_next;
409             h->h_last  = history_def_last;
410             h->h_prev  = history_def_prev;
411             h->h_curr  = history_def_curr;
412             h->h_clear = history_def_clear;
413             h->h_enter = history_def_enter;
414             h->h_add   = history_def_add;
415         }
416         return -1;
417     }
418
419     if (h->h_next == history_def_next)
420         history_def_clear(h->h_ref);
421
422     h->h_first = nh->h_first;
423     h->h_next  = nh->h_next;
424     h->h_last  = nh->h_last;
425     h->h_prev  = nh->h_prev;
426     h->h_curr  = nh->h_curr;
427     h->h_clear = nh->h_clear;
428     h->h_enter = nh->h_enter;
429     h->h_add   = nh->h_add;
430     return 0;
431 }
432
433
434 /* history_load():
435  *      History load function
436  */
437 private int
438 history_load(h, fname)
439     History *h;
440     const char *fname;
441 {
442     FILE *fp;
443     char *line;
444     size_t sz;
445     int i = -1;
446
447     if ((fp = fopen(fname, "r")) == NULL)
448         return i;
449
450     if ((line = fgetln(fp, &sz)) == NULL)
451         goto done;
452
453     if (strncmp(line, hist_cookie, sz) != 0)
454         goto done;
455         
456     for (i = 0; (line = fgetln(fp, &sz)) != NULL; i++) {
457         char c = line[sz];
458         line[sz] = '\0';
459         HENTER(h, line);
460         line[sz] = c;
461     }
462
463 done:
464     (void) fclose(fp);
465     return i;
466 }
467
468
469 /* history_save():
470  *      History save function
471  */
472 private int
473 history_save(h, fname)
474     History *h;
475     const char *fname;
476 {
477     FILE *fp;
478     const HistEvent *ev;
479     int i = 0;
480
481     if ((fp = fopen(fname, "w")) == NULL)
482         return -1;
483
484     (void) fputs(hist_cookie, fp);
485     for (ev = HLAST(h); ev != NULL; ev = HPREV(h), i++)
486         (void) fprintf(fp, "%s", ev->str);
487     (void) fclose(fp);
488     return i;
489 }
490
491
492 /* history_prev_event():
493  *      Find the previous event, with number given
494  */
495 private const HistEvent *
496 history_prev_event(h, num)
497     History *h;
498     int num;
499 {
500     const HistEvent *ev;
501     for (ev = HCURR(h); ev != NULL; ev = HPREV(h))
502         if (ev->num == num)
503             return ev;
504     return NULL;
505 }
506
507
508 /* history_next_event():
509  *      Find the next event, with number given
510  */
511 private const HistEvent *
512 history_next_event(h, num)
513     History *h;
514     int num;
515 {
516     const HistEvent *ev;
517     for (ev = HCURR(h); ev != NULL; ev = HNEXT(h))
518         if (ev->num == num)
519             return ev;
520     return NULL;
521 }
522
523
524 /* history_prev_string():
525  *      Find the previous event beginning with string
526  */
527 private const HistEvent *
528 history_prev_string(h, str)
529     History *h;
530     const char* str;
531 {
532     const HistEvent *ev;
533     size_t len = strlen(str);
534
535     for (ev = HCURR(h); ev != NULL; ev = HNEXT(h))
536         if (strncmp(str, ev->str, len) == 0)
537             return ev;
538     return NULL;
539 }
540
541
542 /* history_next_string():
543  *      Find the next event beginning with string
544  */
545 private const HistEvent *
546 history_next_string(h, str)
547     History *h;
548     const char* str;
549 {
550     const HistEvent *ev;
551     size_t len = strlen(str);
552
553     for (ev = HCURR(h); ev != NULL; ev = HPREV(h))
554         if (strncmp(str, ev->str, len) == 0)
555             return ev;
556     return NULL;
557 }
558
559
560 /* history():
561  *      User interface to history functions.
562  */
563 const HistEvent *
564 #if __STDC__
565 history(History *h, int fun, ...)
566 #else
567 history(va_alist)
568     va_dcl
569 #endif
570 {
571     va_list va;
572     const HistEvent *ev = NULL;
573     const char *str;
574     static HistEvent sev = { 0, "" };
575
576 #if __STDC__
577     va_start(va, fun);
578 #else
579     History *h;
580     int fun;
581     va_start(va);
582     h = va_arg(va, History *);
583     fun = va_arg(va, int);
584 #endif
585
586     switch (fun) {
587     case H_ADD:
588         str = va_arg(va, const char *);
589         ev = HADD(h, str);
590         break;
591
592     case H_ENTER:
593         str = va_arg(va, const char *);
594         ev = HENTER(h, str);
595         break;
596
597     case H_FIRST:
598         ev = HFIRST(h);
599         break;
600
601     case H_NEXT:
602         ev = HNEXT(h);
603         break;
604
605     case H_LAST:
606         ev = HLAST(h);
607         break;
608
609     case H_PREV:
610         ev = HPREV(h);
611         break;
612
613     case H_CURR:
614         ev = HCURR(h);
615         break;
616
617     case H_CLEAR:
618         HCLEAR(h);
619         break;
620         
621     case H_LOAD:
622         sev.num = history_load(h, va_arg(va, const char *));
623         ev = &sev;
624         break;
625         
626     case H_SAVE:
627         sev.num = history_save(h, va_arg(va, const char *));
628         ev = &sev;
629         break;
630
631     case H_PREV_EVENT:
632         ev = history_prev_event(h, va_arg(va, int));
633         break;
634
635     case H_NEXT_EVENT:
636         ev = history_next_event(h, va_arg(va, int));
637         break;
638
639     case H_PREV_STR:
640         ev = history_prev_string(h, va_arg(va, const char*));
641         break;
642
643     case H_NEXT_STR:
644         ev = history_next_string(h, va_arg(va, const char*));
645         break;
646
647     case H_EVENT:
648         if (history_set_num(h, va_arg(va, int)) == 0) {
649             sev.num = -1;
650             ev = &sev;
651         }
652         break;
653
654     case H_FUNC:
655         {
656             History hf;
657             hf.h_ref   = va_arg(va, ptr_t);
658             hf.h_first = va_arg(va, history_gfun_t);
659             hf.h_next  = va_arg(va, history_gfun_t);
660             hf.h_last  = va_arg(va, history_gfun_t);
661             hf.h_prev  = va_arg(va, history_gfun_t);
662             hf.h_curr  = va_arg(va, history_gfun_t);
663             hf.h_clear = va_arg(va, history_vfun_t);
664             hf.h_enter = va_arg(va, history_efun_t);
665             hf.h_add   = va_arg(va, history_efun_t);
666
667             if (history_set_fun(h, &hf) == 0) {
668                 sev.num = -1;
669                 ev = &sev;
670             }
671         }
672         break;
673
674     case H_END:
675         history_end(h);
676         break;
677
678     default:
679         break;
680     }
681     va_end(va);
682     return ev;
683 }