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