root/src/noitedit/history.c

Revision 60aa58b81f5826158d1b04067717cc454dc1742b, 19.7 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 6 years ago)

various leaks in the console driver and our fork of libedit. tgetent() still appears to leak, but that might be an ncurses bug

  • Property mode set to 100644
Line 
1 /*      $NetBSD: history.c,v 1.17 2001/03/20 00:08:31 christos Exp $    */
2
3 /*-
4  * Copyright (c) 1992, 1993
5  *      The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Christos Zoulas of Cornell University.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *      This product includes software developed by the University of
21  *      California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  */
38
39 #include "noitedit/compat.h"
40 #if !defined(lint) && !defined(SCCSID)
41 #if 0
42 static char sccsid[] = "@(#)history.c   8.1 (Berkeley) 6/4/93";
43 #else
44 __RCSID("$NetBSD: history.c,v 1.17 2001/03/20 00:08:31 christos Exp $");
45 #endif
46 #endif /* not lint && not SCCSID */
47
48 /*
49  * hist.c: History access functions
50  */
51 #include "noitedit/sys.h"
52
53 #include <string.h>
54 #include <stdlib.h>
55 #include <stdarg.h>
56 #ifdef HAVE_VIS_H
57 #include <vis.h>
58 #endif
59 #include <sys/stat.h>
60
61 static const char hist_cookie[] = "_HiStOrY_V2_\n";
62
63 #include "noitedit/histedit.h"
64
65 typedef int (*history_gfun_t)(ptr_t, HistEvent *);
66 typedef int (*history_efun_t)(ptr_t, HistEvent *, const char *);
67 typedef void (*history_vfun_t)(ptr_t, HistEvent *);
68 typedef int (*history_sfun_t)(ptr_t, HistEvent *, const int);
69
70 struct history {
71         ptr_t h_ref;            /* Argument for history fcns     */
72         int h_ent;              /* Last entry point for history  */
73         history_gfun_t h_first; /* Get the first element         */
74         history_gfun_t h_next;  /* Get the next element          */
75         history_gfun_t h_last;  /* Get the last element          */
76         history_gfun_t h_prev;  /* Get the previous element      */
77         history_gfun_t h_curr;  /* Get the current element       */
78         history_sfun_t h_set;   /* Set the current element       */
79         history_vfun_t h_clear; /* Clear the history list        */
80         history_efun_t h_enter; /* Add an element                */
81         history_efun_t h_add;   /* Append to an element          */
82 };
83 #define HNEXT(h, ev)            (*(h)->h_next)((h)->h_ref, ev)
84 #define HFIRST(h, ev)           (*(h)->h_first)((h)->h_ref, ev)
85 #define HPREV(h, ev)            (*(h)->h_prev)((h)->h_ref, ev)
86 #define HLAST(h, ev)            (*(h)->h_last)((h)->h_ref, ev)
87 #define HCURR(h, ev)            (*(h)->h_curr)((h)->h_ref, ev)
88 #define HSET(h, ev, n)          (*(h)->h_set)((h)->h_ref, ev, n)
89 #define HCLEAR(h, ev)           (*(h)->h_clear)((h)->h_ref, ev)
90 #define HENTER(h, ev, str)      (*(h)->h_enter)((h)->h_ref, ev, str)
91 #define HADD(h, ev, str)        (*(h)->h_add)((h)->h_ref, ev, str)
92
93 #define h_malloc(a)     malloc(a)
94 #define h_realloc(a, b) realloc((a), (b))
95 #define h_free(a)       free(a)
96
97
98 private int history_setsize(History *, HistEvent *, int);
99 private int history_getsize(History *, HistEvent *);
100 private int history_set_fun(History *, History *);
101 private int history_load(History *, const char *);
102 private int history_save(History *, const char *);
103 private int history_prev_event(History *, HistEvent *, int);
104 private int history_next_event(History *, HistEvent *, int);
105 private int history_next_string(History *, HistEvent *, const char *);
106 private int history_prev_string(History *, HistEvent *, const char *);
107
108
109 /***********************************************************************/
110
111 /*
112  * Builtin- history implementation
113  */
114 typedef struct hentry_t {
115         HistEvent ev;           /* What we return                */
116         struct hentry_t *next;  /* Next entry                    */
117         struct hentry_t *prev;  /* Previous entry                */
118 }        hentry_t;
119
120 typedef struct history_t {
121         hentry_t list;          /* Fake list header element      */
122         hentry_t *cursor;       /* Current element in the list   */
123         int max;                /* Maximum number of events      */
124         int cur;                /* Current number of events      */
125         int eventid;            /* For generation of unique event id     */
126 }         history_t;
127
128 private int history_def_first(ptr_t, HistEvent *);
129 private int history_def_last(ptr_t, HistEvent *);
130 private int history_def_next(ptr_t, HistEvent *);
131 private int history_def_prev(ptr_t, HistEvent *);
132 private int history_def_curr(ptr_t, HistEvent *);
133 private int history_def_set(ptr_t, HistEvent *, const int n);
134 private int history_def_enter(ptr_t, HistEvent *, const char *);
135 private int history_def_add(ptr_t, HistEvent *, const char *);
136 private void history_def_init(ptr_t *, HistEvent *, int);
137 private void history_def_clear(ptr_t, HistEvent *);
138 private int history_def_insert(history_t *, HistEvent *, const char *);
139 private void history_def_delete(history_t *, HistEvent *, hentry_t *);
140
141 #define history_def_setsize(p, num)(void) (((history_t *) p)->max = (num))
142 #define history_def_getsize(p)  (((history_t *) p)->cur)
143
144 #define he_strerror(code)       he_errlist[code]
145 #define he_seterrev(evp, code)  {\
146                                     evp->num = code;\
147                                     evp->str = he_strerror(code);\
148                                 }
149
150 /* error messages */
151 static const char *const he_errlist[] = {
152         "OK",
153         "unknown error",
154         "malloc() failed",
155         "first event not found",
156         "last event not found",
157         "empty list",
158         "no next event",
159         "no previous event",
160         "current event is invalid",
161         "event not found",
162         "can't read history from file",
163         "can't write history",
164         "required parameter(s) not supplied",
165         "history size negative",
166         "function not allowed with other history-functions-set the default",
167         "bad parameters"
168 };
169 /* error codes */
170 #define _HE_OK                   0
171 #define _HE_UNKNOWN              1
172 #define _HE_MALLOC_FAILED        2
173 #define _HE_FIRST_NOTFOUND       3
174 #define _HE_LAST_NOTFOUND        4
175 #define _HE_EMPTY_LIST           5
176 #define _HE_END_REACHED          6
177 #define _HE_START_REACHED        7
178 #define _HE_CURR_INVALID         8
179 #define _HE_NOT_FOUND            9
180 #define _HE_HIST_READ           10
181 #define _HE_HIST_WRITE          11
182 #define _HE_PARAM_MISSING       12
183 #define _HE_SIZE_NEGATIVE       13
184 #define _HE_NOT_ALLOWED         14
185 #define _HE_BAD_PARAM           15
186
187 /* history_def_first():
188  *      Default function to return the first event in the history.
189  */
190 private int
191 history_def_first(ptr_t p, HistEvent *ev)
192 {
193         history_t *h = (history_t *) p;
194
195         h->cursor = h->list.next;
196         if (h->cursor != &h->list)
197                 *ev = h->cursor->ev;
198         else {
199                 he_seterrev(ev, _HE_FIRST_NOTFOUND);
200                 return (-1);
201         }
202
203         return (0);
204 }
205
206
207 /* history_def_last():
208  *      Default function to return the last event in the history.
209  */
210 private int
211 history_def_last(ptr_t p, HistEvent *ev)
212 {
213         history_t *h = (history_t *) p;
214
215         h->cursor = h->list.prev;
216         if (h->cursor != &h->list)
217                 *ev = h->cursor->ev;
218         else {
219                 he_seterrev(ev, _HE_LAST_NOTFOUND);
220                 return (-1);
221         }
222
223         return (0);
224 }
225
226
227 /* history_def_next():
228  *      Default function to return the next event in the history.
229  */
230 private int
231 history_def_next(ptr_t p, HistEvent *ev)
232 {
233         history_t *h = (history_t *) p;
234
235         if (h->cursor != &h->list)
236                 h->cursor = h->cursor->next;
237         else {
238                 he_seterrev(ev, _HE_EMPTY_LIST);
239                 return (-1);
240         }
241
242         if (h->cursor != &h->list)
243                 *ev = h->cursor->ev;
244         else {
245                 he_seterrev(ev, _HE_END_REACHED);
246                 return (-1);
247         }
248
249         return (0);
250 }
251
252
253 /* history_def_prev():
254  *      Default function to return the previous event in the history.
255  */
256 private int
257 history_def_prev(ptr_t p, HistEvent *ev)
258 {
259         history_t *h = (history_t *) p;
260
261         if (h->cursor != &h->list)
262                 h->cursor = h->cursor->prev;
263         else {
264                 he_seterrev(ev,
265                     (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST);
266                 return (-1);
267         }
268
269         if (h->cursor != &h->list)
270                 *ev = h->cursor->ev;
271         else {
272                 he_seterrev(ev, _HE_START_REACHED);
273                 return (-1);
274         }
275
276         return (0);
277 }
278
279
280 /* history_def_curr():
281  *      Default function to return the current event in the history.
282  */
283 private int
284 history_def_curr(ptr_t p, HistEvent *ev)
285 {
286         history_t *h = (history_t *) p;
287
288         if (h->cursor != &h->list)
289                 *ev = h->cursor->ev;
290         else {
291                 he_seterrev(ev,
292                     (h->cur > 0) ? _HE_CURR_INVALID : _HE_EMPTY_LIST);
293                 return (-1);
294         }
295
296         return (0);
297 }
298
299
300 /* history_def_set():
301  *      Default function to set the current event in the history to the
302  *      given one.
303  */
304 private int
305 history_def_set(ptr_t p, HistEvent *ev, const int n)
306 {
307         history_t *h = (history_t *) p;
308
309         if (h->cur == 0) {
310                 he_seterrev(ev, _HE_EMPTY_LIST);
311                 return (-1);
312         }
313         if (h->cursor == &h->list || h->cursor->ev.num != n) {
314                 for (h->cursor = h->list.next; h->cursor != &h->list;
315                     h->cursor = h->cursor->next)
316                         if (h->cursor->ev.num == n)
317                                 break;
318         }
319         if (h->cursor == &h->list) {
320                 he_seterrev(ev, _HE_NOT_FOUND);
321                 return (-1);
322         }
323         return (0);
324 }
325
326
327 /* history_def_add():
328  *      Append string to element
329  */
330 private int
331 history_def_add(ptr_t p, HistEvent *ev, const char *str)
332 {
333         history_t *h = (history_t *) p;
334         size_t len;
335         char *s;
336
337         if (h->cursor == &h->list)
338                 return (history_def_enter(p, ev, str));
339         len = strlen(h->cursor->ev.str) + strlen(str) + 1;
340         s = (char *) h_malloc(len);
341         if (!s) {
342                 he_seterrev(ev, _HE_MALLOC_FAILED);
343                 return (-1);
344         }
345         (void) strlcpy(s, h->cursor->ev.str, len);
346         (void) strlcat(s, str, len);
347         /* LINTED const cast */
348         h_free((ptr_t) h->cursor->ev.str);
349         h->cursor->ev.str = s;
350         *ev = h->cursor->ev;
351         return (0);
352 }
353
354
355 /* history_def_delete():
356  *      Delete element hp of the h list
357  */
358 /* ARGSUSED */
359 private void
360 history_def_delete(history_t *h, HistEvent *ev, hentry_t *hp)
361 {
362         if (hp == &h->list) {
363     abort();
364   }
365         hp->prev->next = hp->next;
366         hp->next->prev = hp->prev;
367         /* LINTED const cast */
368         h_free((ptr_t) hp->ev.str);
369         h_free(hp);
370         h->cur--;
371 }
372
373
374 /* history_def_insert():
375  *      Insert element with string str in the h list
376  */
377 private int
378 history_def_insert(history_t *h, HistEvent *ev, const char *str)
379 {
380
381         h->cursor = (hentry_t *) h_malloc(sizeof(hentry_t));
382         if (h->cursor)
383                 h->cursor->ev.str = strdup(str);
384         if (!h->cursor || !h->cursor->ev.str) {
385                 he_seterrev(ev, _HE_MALLOC_FAILED);
386                 return (-1);
387         }
388         h->cursor->ev.num = ++h->eventid;
389         h->cursor->next = h->list.next;
390         h->cursor->prev = &h->list;
391         h->list.next->prev = h->cursor;
392         h->list.next = h->cursor;
393         h->cur++;
394
395         *ev = h->cursor->ev;
396         return (0);
397 }
398
399
400 /* history_def_enter():
401  *      Default function to enter an item in the history
402  */
403 private int
404 history_def_enter(ptr_t p, HistEvent *ev, const char *str)
405 {
406         history_t *h = (history_t *) p;
407
408         if (history_def_insert(h, ev, str) == -1)
409                 return (-1);    /* error, keep error message */
410
411         /*
412          * Always keep at least one entry.
413          * This way we don't have to check for the empty list.
414          */
415         while (h->cur - 1 > h->max)
416                 history_def_delete(h, ev, h->list.prev);
417
418         return (0);
419 }
420
421
422 /* history_def_init():
423  *      Default history initialization function
424  */
425 /* ARGSUSED */
426 private void
427 history_def_init(ptr_t *p, HistEvent *ev, int n)
428 {
429         history_t *h = (history_t *) h_malloc(sizeof(history_t));
430
431         if (n <= 0)
432                 n = 0;
433         h->eventid = 0;
434         h->cur = 0;
435         h->max = n;
436         h->list.next = h->list.prev = &h->list;
437         h->list.ev.str = NULL;
438         h->list.ev.num = 0;
439         h->cursor = &h->list;
440         *p = (ptr_t) h;
441 }
442
443
444 /* history_def_clear():
445  *      Default history cleanup function
446  */
447 private void
448 history_def_clear(ptr_t p, HistEvent *ev)
449 {
450         history_t *h = (history_t *) p;
451
452         while (h->list.prev != &h->list)
453                 history_def_delete(h, ev, h->list.prev);
454         h->eventid = 0;
455         h->cur = 0;
456 }
457
458
459
460
461 /************************************************************************/
462
463 /* history_init():
464  *      Initialization function.
465  */
466 public History *
467 history_init(void)
468 {
469         History *h = (History *) h_malloc(sizeof(History));
470         HistEvent ev;
471
472         history_def_init(&h->h_ref, &ev, 0);
473         h->h_ent = -1;
474         h->h_next = history_def_next;
475         h->h_first = history_def_first;
476         h->h_last = history_def_last;
477         h->h_prev = history_def_prev;
478         h->h_curr = history_def_curr;
479         h->h_set = history_def_set;
480         h->h_clear = history_def_clear;
481         h->h_enter = history_def_enter;
482         h->h_add = history_def_add;
483
484         return (h);
485 }
486
487
488 /* history_end():
489  *      clean up history;
490  */
491 public void
492 history_end(History *h)
493 {
494         HistEvent ev;
495
496         if (h->h_next == history_def_next)
497                 history_def_clear(h->h_ref, &ev);
498   h_free(h->h_ref);
499 }
500
501
502
503 /* history_setsize():
504  *      Set history number of events
505  */
506 private int
507 history_setsize(History *h, HistEvent *ev, int num)
508 {
509
510         if (h->h_next != history_def_next) {
511                 he_seterrev(ev, _HE_NOT_ALLOWED);
512                 return (-1);
513         }
514         if (num < 0) {
515                 he_seterrev(ev, _HE_BAD_PARAM);
516                 return (-1);
517         }
518         history_def_setsize(h->h_ref, num);
519         return (0);
520 }
521
522
523 /* history_getsize():
524  *      Get number of events currently in history
525  */
526 private int
527 history_getsize(History *h, HistEvent *ev)
528 {
529         int retval = 0;
530
531         if (h->h_next != history_def_next) {
532                 he_seterrev(ev, _HE_NOT_ALLOWED);
533                 return (-1);
534         }
535         retval = history_def_getsize(h->h_ref);
536         if (retval < -1) {
537                 he_seterrev(ev, _HE_SIZE_NEGATIVE);
538                 return (-1);
539         }
540         ev->num = retval;
541         return (0);
542 }
543
544
545 /* history_set_fun():
546  *      Set history functions
547  */
548 private int
549 history_set_fun(History *h, History *nh)
550 {
551         HistEvent ev;
552
553         if (nh->h_first == NULL || nh->h_next == NULL || nh->h_last == NULL ||
554             nh->h_prev == NULL || nh->h_curr == NULL || nh->h_set == NULL ||
555             nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL ||
556             nh->h_ref == NULL) {
557                 if (h->h_next != history_def_next) {
558                         history_def_init(&h->h_ref, &ev, 0);
559                         h->h_first = history_def_first;
560                         h->h_next = history_def_next;
561                         h->h_last = history_def_last;
562                         h->h_prev = history_def_prev;
563                         h->h_curr = history_def_curr;
564                         h->h_set = history_def_set;
565                         h->h_clear = history_def_clear;
566                         h->h_enter = history_def_enter;
567                         h->h_add = history_def_add;
568                 }
569                 return (-1);
570         }
571         if (h->h_next == history_def_next)
572                 history_def_clear(h->h_ref, &ev);
573
574         h->h_ent = -1;
575         h->h_first = nh->h_first;
576         h->h_next = nh->h_next;
577         h->h_last = nh->h_last;
578         h->h_prev = nh->h_prev;
579         h->h_curr = nh->h_curr;
580         h->h_set = nh->h_set;
581         h->h_clear = nh->h_clear;
582         h->h_enter = nh->h_enter;
583         h->h_add = nh->h_add;
584
585         return (0);
586 }
587
588
589 /* history_load():
590  *      History load function
591  */
592 private int
593 history_load(History *h, const char *fname)
594 {
595         FILE *fp;
596         char *line;
597         size_t sz, max_size;
598         char *ptr;
599         int i = -1;
600         HistEvent ev;
601
602         if ((fp = fopen(fname, "r")) == NULL)
603                 return (i);
604
605         if ((line = fgetln(fp, &sz)) == NULL)
606                 goto done;
607
608         if (strncmp(line, hist_cookie, sz) != 0)
609                 goto done;
610
611         ptr = h_malloc(max_size = 1024);
612         for (i = 0; (line = fgetln(fp, &sz)) != NULL; i++) {
613                 char c = line[sz];
614
615                 if (sz != 0 && line[sz - 1] == '\n')
616                         line[--sz] = '\0';
617                 else
618                         line[sz] = '\0';
619
620                 if (max_size <= sz) {
621                         max_size = (sz + 1024) & ~1023;
622                         ptr = h_realloc(ptr, max_size);
623                 }
624                 (void) strlcpy(ptr, line, max_size);
625                 line[sz] = c;
626                 HENTER(h, &ev, ptr);
627         }
628         h_free(ptr);
629
630 done:
631         (void) fclose(fp);
632         return (i);
633 }
634
635
636 /* history_save():
637  *      History save function
638  */
639 private int
640 history_save(History *h, const char *fname)
641 {
642         FILE *fp;
643         HistEvent ev;
644         int i = 0, retval;
645         size_t len, max_size;
646         char *ptr;
647
648         if ((fp = fopen(fname, "w")) == NULL)
649                 return (-1);
650
651 #if !_MSC_VER
652         (void) fchmod(fileno(fp), S_IRUSR|S_IWUSR);
653 #endif
654         (void) fputs(hist_cookie, fp);
655         ptr = h_malloc(max_size = 1024);
656         for (retval = HLAST(h, &ev);
657             retval != -1;
658             retval = HPREV(h, &ev), i++) {
659                 len = strlen(ev.str) * 4;
660                 if (len >= max_size) {
661                         max_size = (len + 1024) & ~1023;
662                         ptr = h_realloc(ptr, max_size);
663                 }
664                 /* next line is better. strvis(ptr, ev.str, VIS_WHITE); */
665                 (void) strlcpy(ptr, ev.str, max_size);
666                 (void) fprintf(fp, "%s\n", ev.str);
667         }
668         h_free(ptr);
669         (void) fclose(fp);
670         return (i);
671 }
672
673
674 /* history_prev_event():
675  *      Find the previous event, with number given
676  */
677 private int
678 history_prev_event(History *h, HistEvent *ev, int num)
679 {
680         int retval;
681
682         for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
683                 if (ev->num == num)
684                         return (0);
685
686         he_seterrev(ev, _HE_NOT_FOUND);
687         return (-1);
688 }
689
690
691 /* history_next_event():
692  *      Find the next event, with number given
693  */
694 private int
695 history_next_event(History *h, HistEvent *ev, int num)
696 {
697         int retval;
698
699         for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
700                 if (ev->num == num)
701                         return (0);
702
703         he_seterrev(ev, _HE_NOT_FOUND);
704         return (-1);
705 }
706
707
708 /* history_prev_string():
709  *      Find the previous event beginning with string
710  */
711 private int
712 history_prev_string(History *h, HistEvent *ev, const char *str)
713 {
714         size_t len = strlen(str);
715         int retval;
716
717         for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
718                 if (strncmp(str, ev->str, len) == 0)
719                         return (0);
720
721         he_seterrev(ev, _HE_NOT_FOUND);
722         return (-1);
723 }
724
725
726 /* history_next_string():
727  *      Find the next event beginning with string
728  */
729 private int
730 history_next_string(History *h, HistEvent *ev, const char *str)
731 {
732         size_t len = strlen(str);
733         int retval;
734
735         for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
736                 if (strncmp(str, ev->str, len) == 0)
737                         return (0);
738
739         he_seterrev(ev, _HE_NOT_FOUND);
740         return (-1);
741 }
742
743
744 /* history():
745  *      User interface to history functions.
746  */
747 int
748 history(History *h, HistEvent *ev, int fun, ...)
749 {
750         va_list va;
751         const char *str;
752         int retval;
753
754         va_start(va, fun);
755
756         he_seterrev(ev, _HE_OK);
757
758         switch (fun) {
759         case H_GETSIZE:
760                 retval = history_getsize(h, ev);
761                 break;
762
763         case H_SETSIZE:
764                 retval = history_setsize(h, ev, va_arg(va, int));
765                 break;
766
767         case H_ADD:
768                 str = va_arg(va, const char *);
769                 retval = HADD(h, ev, str);
770                 break;
771
772         case H_ENTER:
773                 str = va_arg(va, const char *);
774                 if ((retval = HENTER(h, ev, str)) != -1)
775                         h->h_ent = ev->num;
776                 break;
777
778         case H_APPEND:
779                 str = va_arg(va, const char *);
780                 if ((retval = HSET(h, ev, h->h_ent)) != -1)
781                         retval = HADD(h, ev, str);
782                 break;
783
784         case H_FIRST:
785                 retval = HFIRST(h, ev);
786                 break;
787
788         case H_NEXT:
789                 retval = HNEXT(h, ev);
790                 break;
791
792         case H_LAST:
793                 retval = HLAST(h, ev);
794                 break;
795
796         case H_PREV:
797                 retval = HPREV(h, ev);
798                 break;
799
800         case H_CURR:
801                 retval = HCURR(h, ev);
802                 break;
803
804         case H_SET:
805                 retval = HSET(h, ev, va_arg(va, const int));
806                 break;
807
808         case H_CLEAR:
809                 HCLEAR(h, ev);
810                 retval = 0;
811                 break;
812
813         case H_LOAD:
814                 retval = history_load(h, va_arg(va, const char *));
815                 if (retval == -1)
816                         he_seterrev(ev, _HE_HIST_READ);
817                 break;
818
819         case H_SAVE:
820                 retval = history_save(h, va_arg(va, const char *));
821                 if (retval == -1)
822                         he_seterrev(ev, _HE_HIST_WRITE);
823                 break;
824
825         case H_PREV_EVENT:
826                 retval = history_prev_event(h, ev, va_arg(va, int));
827                 break;
828
829         case H_NEXT_EVENT:
830                 retval = history_next_event(h, ev, va_arg(va, int));
831                 break;
832
833         case H_PREV_STR:
834                 retval = history_prev_string(h, ev, va_arg(va, const char *));
835                 break;
836
837         case H_NEXT_STR:
838                 retval = history_next_string(h, ev, va_arg(va, const char *));
839                 break;
840
841         case H_FUNC:
842         {
843                 History hf;
844
845                 hf.h_ref = va_arg(va, ptr_t);
846                 h->h_ent = -1;
847                 hf.h_first = va_arg(va, history_gfun_t);
848                 hf.h_next = va_arg(va, history_gfun_t);
849                 hf.h_last = va_arg(va, history_gfun_t);
850                 hf.h_prev = va_arg(va, history_gfun_t);
851                 hf.h_curr = va_arg(va, history_gfun_t);
852                 hf.h_set = va_arg(va, history_sfun_t);
853                 hf.h_clear = va_arg(va, history_vfun_t);
854                 hf.h_enter = va_arg(va, history_efun_t);
855                 hf.h_add = va_arg(va, history_efun_t);
856
857                 if ((retval = history_set_fun(h, &hf)) == -1)
858                         he_seterrev(ev, _HE_PARAM_MISSING);
859                 break;
860         }
861
862         case H_END:
863                 history_end(h);
864                 retval = 0;
865                 break;
866
867         default:
868                 retval = -1;
869                 he_seterrev(ev, _HE_UNKNOWN);
870                 break;
871         }
872         va_end(va);
873         return (retval);
874 }
Note: See TracBrowser for help on using the browser.