history.c revision 1.11 1 /* $NetBSD: history.c,v 1.11 1998/12/12 19:52:51 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 <sys/cdefs.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.11 1998/12/12 19:52:51 christos Exp $");
45 #endif
46 #endif /* not lint && not SCCSID */
47
48 /*
49 * hist.c: History access functions
50 */
51 #include "sys.h"
52
53 #include <string.h>
54 #include <stdlib.h>
55 #ifdef __STDC__
56 #include <stdarg.h>
57 #else
58 #include <varargs.h>
59 #endif
60
61 static const char hist_cookie[] = "_HiStOrY_V1_\n";
62
63 #include "histedit.h"
64
65 typedef int (*history_gfun_t) __P((ptr_t, HistEvent *));
66 typedef int (*history_efun_t) __P((ptr_t, HistEvent *, const char *));
67 typedef void (*history_vfun_t) __P((ptr_t, HistEvent *));
68 typedef int (*history_sfun_t) __P((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
84 #define HNEXT(h, ev) (*(h)->h_next)((h)->h_ref, ev)
85 #define HFIRST(h, ev) (*(h)->h_first)((h)->h_ref, ev)
86 #define HPREV(h, ev) (*(h)->h_prev)((h)->h_ref, ev)
87 #define HLAST(h, ev) (*(h)->h_last)((h)->h_ref, ev)
88 #define HCURR(h, ev) (*(h)->h_curr)((h)->h_ref, ev)
89 #define HSET(h, ev, n) (*(h)->h_set)((h)->h_ref, ev, n)
90 #define HCLEAR(h, ev) (*(h)->h_clear)((h)->h_ref, ev)
91 #define HENTER(h, ev, str) (*(h)->h_enter)((h)->h_ref, ev, str)
92 #define HADD(h, ev, str) (*(h)->h_add)((h)->h_ref, ev, str)
93
94 #define h_malloc(a) malloc(a)
95 #define h_free(a) free(a)
96
97
98 private int history_set_num __P((History *, HistEvent *, int));
99 private int history_get_size __P((History *, HistEvent *));
100 private int history_set_fun __P((History *, History *));
101 private int history_load __P((History *, const char *));
102 private int history_save __P((History *, const char *));
103 private int history_prev_event __P((History *, HistEvent *, int));
104 private int history_next_event __P((History *, HistEvent *, int));
105 private int history_next_string __P((History *, HistEvent *, const char *));
106 private int history_prev_string __P((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 __P((ptr_t, HistEvent *));
129 private int history_def_last __P((ptr_t, HistEvent *));
130 private int history_def_next __P((ptr_t, HistEvent *));
131 private int history_def_prev __P((ptr_t, HistEvent *));
132 private int history_def_curr __P((ptr_t, HistEvent *));
133 private int history_def_set __P((ptr_t, HistEvent *, const int n));
134 private int history_def_enter __P((ptr_t, HistEvent *, const char *));
135 private int history_def_add __P((ptr_t, HistEvent *, const char *));
136 private void history_def_init __P((ptr_t *, HistEvent *, int));
137 private void history_def_clear __P((ptr_t, HistEvent *));
138 private int history_def_insert __P((history_t *, HistEvent *,const char *));
139 private void history_def_delete __P((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
170 /* error codes */
171 #define _HE_OK 0
172 #define _HE_UNKNOWN 1
173 #define _HE_MALLOC_FAILED 2
174 #define _HE_FIRST_NOTFOUND 3
175 #define _HE_LAST_NOTFOUND 4
176 #define _HE_EMPTY_LIST 5
177 #define _HE_END_REACHED 6
178 #define _HE_START_REACHED 7
179 #define _HE_CURR_INVALID 8
180 #define _HE_NOT_FOUND 9
181 #define _HE_HIST_READ 10
182 #define _HE_HIST_WRITE 11
183 #define _HE_PARAM_MISSING 12
184 #define _HE_SIZE_NEGATIVE 13
185 #define _HE_NOT_ALLOWED 14
186 #define _HE_BAD_PARAM 15
187
188 /* history_def_first():
189 * Default function to return the first event in the history.
190 */
191 private int
192 history_def_first(p, ev)
193 ptr_t p;
194 HistEvent *ev;
195 {
196 history_t *h = (history_t *) p;
197
198 h->cursor = h->list.next;
199 if (h->cursor != &h->list)
200 *ev = h->cursor->ev;
201 else {
202 he_seterrev(ev, _HE_FIRST_NOTFOUND);
203 return -1;
204 }
205
206 return 0;
207 }
208
209
210 /* history_def_last():
211 * Default function to return the last event in the history.
212 */
213 private int
214 history_def_last(p, ev)
215 ptr_t p;
216 HistEvent *ev;
217 {
218 history_t *h = (history_t *) p;
219
220 h->cursor = h->list.prev;
221 if (h->cursor != &h->list)
222 *ev = h->cursor->ev;
223 else {
224 he_seterrev(ev, _HE_LAST_NOTFOUND);
225 return -1;
226 }
227
228 return 0;
229 }
230
231
232 /* history_def_next():
233 * Default function to return the next event in the history.
234 */
235 private int
236 history_def_next(p, ev)
237 ptr_t p;
238 HistEvent *ev;
239 {
240 history_t *h = (history_t *) p;
241
242 if (h->cursor != &h->list)
243 h->cursor = h->cursor->next;
244 else {
245 he_seterrev(ev, _HE_EMPTY_LIST);
246 return -1;
247 }
248
249 if (h->cursor != &h->list)
250 *ev = h->cursor->ev;
251 else {
252 he_seterrev(ev, _HE_END_REACHED);
253 return -1;
254 }
255
256 return 0;
257 }
258
259
260 /* history_def_prev():
261 * Default function to return the previous event in the history.
262 */
263 private int
264 history_def_prev(p, ev)
265 ptr_t p;
266 HistEvent *ev;
267 {
268 history_t *h = (history_t *) p;
269
270 if (h->cursor != &h->list)
271 h->cursor = h->cursor->prev;
272 else {
273 he_seterrev(ev, (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST);
274 return -1;
275 }
276
277 if (h->cursor != &h->list)
278 *ev = h->cursor->ev;
279 else {
280 he_seterrev(ev, _HE_START_REACHED);
281 return -1;
282 }
283
284 return 0;
285 }
286
287
288 /* history_def_curr():
289 * Default function to return the current event in the history.
290 */
291 private int
292 history_def_curr(p, ev)
293 ptr_t p;
294 HistEvent *ev;
295 {
296 history_t *h = (history_t *) p;
297
298 if (h->cursor != &h->list)
299 *ev = h->cursor->ev;
300 else {
301 he_seterrev(ev, (h->cur > 0) ? _HE_CURR_INVALID : _HE_EMPTY_LIST);
302 return -1;
303 }
304
305 return 0;
306 }
307
308
309 /* history_def_set():
310 * Default function to set the current event in the history to the
311 * given one.
312 */
313 private int
314 history_def_set(p, ev, n)
315 ptr_t p;
316 HistEvent *ev;
317 int n;
318 {
319 history_t *h = (history_t *) p;
320
321 if (h->cur == 0) {
322 he_seterrev(ev, _HE_EMPTY_LIST);
323 return -1;
324 }
325
326 if (h->cursor == &h->list || h->cursor->ev.num != n) {
327 for (h->cursor = h->list.next; h->cursor != &h->list;
328 h->cursor = h->cursor->next)
329 if (h->cursor->ev.num == n)
330 break;
331 }
332
333 if (h->cursor == &h->list) {
334 he_seterrev(ev, _HE_NOT_FOUND);
335 return -1;
336 }
337
338 return 0;
339 }
340
341
342 /* history_def_add():
343 * Append string to element
344 */
345 private int
346 history_def_add(p, ev, str)
347 ptr_t p;
348 HistEvent *ev;
349 const char *str;
350 {
351 history_t *h = (history_t *) p;
352 size_t len;
353 char *s;
354
355 if (h->cursor == &h->list)
356 return (history_def_enter(p, ev, str));
357 len = strlen(h->cursor->ev.str) + strlen(str) + 1;
358 s = (char *) h_malloc(len);
359 if (!s) {
360 he_seterrev(ev, _HE_MALLOC_FAILED);
361 return -1;
362 }
363 (void)strcpy(s, h->cursor->ev.str); /* XXX strcpy is safe */
364 (void)strcat(s, str); /* XXX strcat is safe */
365 /* LINTED const cast */
366 h_free((ptr_t) h->cursor->ev.str);
367 h->cursor->ev.str = s;
368 *ev = h->cursor->ev;
369 return 0;
370 }
371
372
373 /* history_def_delete():
374 * Delete element hp of the h list
375 */
376 /* ARGSUSED */
377 private void
378 history_def_delete(h, ev, hp)
379 history_t *h;
380 HistEvent *ev;
381 hentry_t *hp;
382 {
383 if (hp == &h->list)
384 abort();
385 hp->prev->next = hp->next;
386 hp->next->prev = hp->prev;
387 /* LINTED const cast */
388 h_free((ptr_t) hp->ev.str);
389 h_free(hp);
390 h->cur--;
391 }
392
393
394 /* history_def_insert():
395 * Insert element with string str in the h list
396 */
397 private int
398 history_def_insert(h, ev, str)
399 history_t *h;
400 HistEvent *ev;
401 const char *str;
402 {
403 h->cursor = (hentry_t *) h_malloc(sizeof(hentry_t));
404 if (h->cursor)
405 h->cursor->ev.str = strdup(str);
406 if (!h->cursor || !h->cursor->ev.str) {
407 he_seterrev(ev, _HE_MALLOC_FAILED);
408 return -1;
409 }
410 h->cursor->ev.num = ++h->eventid;
411 h->cursor->next = h->list.next;
412 h->cursor->prev = &h->list;
413 h->list.next->prev = h->cursor;
414 h->list.next = h->cursor;
415 h->cur++;
416
417 *ev = h->cursor->ev;
418 return 0;
419 }
420
421
422 /* history_def_enter():
423 * Default function to enter an item in the history
424 */
425 private int
426 history_def_enter(p, ev, str)
427 ptr_t p;
428 HistEvent *ev;
429 const char *str;
430 {
431 history_t *h = (history_t *) p;
432
433 if (history_def_insert(h, ev, str) == -1)
434 return -1; /* error, keep error message */
435
436 /*
437 * Always keep at least one entry.
438 * This way we don't have to check for the empty list.
439 */
440 while (h->cur - 1 > h->max)
441 history_def_delete(h, ev, h->list.prev);
442
443 return 0;
444 }
445
446
447 /* history_def_init():
448 * Default history initialization function
449 */
450 /* ARGSUSED */
451 private void
452 history_def_init(p, ev, n)
453 ptr_t *p;
454 HistEvent *ev;
455 int n;
456 {
457 history_t *h = (history_t *) h_malloc(sizeof(history_t));
458 if (n <= 0)
459 n = 0;
460 h->eventid = 0;
461 h->cur = 0;
462 h->max = n;
463 h->list.next = h->list.prev = &h->list;
464 h->list.ev.str = NULL;
465 h->list.ev.num = 0;
466 h->cursor = &h->list;
467 *p = (ptr_t) h;
468 }
469
470
471 /* history_def_clear():
472 * Default history cleanup function
473 */
474 private void
475 history_def_clear(p, ev)
476 ptr_t p;
477 HistEvent *ev;
478 {
479 history_t *h = (history_t *) p;
480
481 while (h->list.prev != &h->list)
482 history_def_delete(h, ev, h->list.prev);
483 h->eventid = 0;
484 h->cur = 0;
485 }
486
487
488
489
490 /************************************************************************/
491
492 /* history_init():
493 * Initialization function.
494 */
495 public History *
496 history_init()
497 {
498 History *h = (History *) h_malloc(sizeof(History));
499 HistEvent ev;
500
501 history_def_init(&h->h_ref, &ev, 0);
502 h->h_ent = -1;
503 h->h_next = history_def_next;
504 h->h_first = history_def_first;
505 h->h_last = history_def_last;
506 h->h_prev = history_def_prev;
507 h->h_curr = history_def_curr;
508 h->h_set = history_def_set;
509 h->h_clear = history_def_clear;
510 h->h_enter = history_def_enter;
511 h->h_add = history_def_add;
512
513 return h;
514 }
515
516
517 /* history_end():
518 * clean up history;
519 */
520 public void
521 history_end(h)
522 History *h;
523 {
524 HistEvent ev;
525 if (h->h_next == history_def_next)
526 history_def_clear(h->h_ref, &ev);
527 }
528
529
530
531 /* history_set_num():
532 * Set history number of events
533 */
534 private int
535 history_set_num(h, ev, num)
536 History *h;
537 HistEvent *ev;
538 int num;
539 {
540 if (h->h_next != history_def_next) {
541 he_seterrev(ev, _HE_NOT_ALLOWED);
542 return -1;
543 }
544
545 if (num < 0) {
546 he_seterrev(ev, _HE_BAD_PARAM);
547 return -1;
548 }
549
550 history_def_setsize(h->h_ref, num);
551 return 0;
552 }
553
554 /* history_get_size():
555 * Get number of events currently in history
556 */
557 private int
558 history_get_size(h, ev)
559 History *h;
560 HistEvent *ev;
561 {
562 int retval=0;
563
564 if (h->h_next != history_def_next) {
565 he_seterrev(ev, _HE_NOT_ALLOWED);
566 return -1;
567 }
568 retval = history_def_getsize(h->h_ref);
569 if (retval < -1) {
570 he_seterrev(ev, _HE_SIZE_NEGATIVE);
571 return -1;
572 }
573
574 ev->num = retval;
575 return 0;
576 }
577
578 /* history_set_fun():
579 * Set history functions
580 */
581 private int
582 history_set_fun(h, nh)
583 History *h;
584 History *nh;
585 {
586 HistEvent ev;
587
588 if (nh->h_first == NULL || nh->h_next == NULL || nh->h_last == NULL ||
589 nh->h_prev == NULL || nh->h_curr == NULL || nh->h_set == NULL ||
590 nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL ||
591 nh->h_ref == NULL) {
592 if (h->h_next != history_def_next) {
593 history_def_init(&h->h_ref, &ev, 0);
594 h->h_first = history_def_first;
595 h->h_next = history_def_next;
596 h->h_last = history_def_last;
597 h->h_prev = history_def_prev;
598 h->h_curr = history_def_curr;
599 h->h_set = history_def_set;
600 h->h_clear = history_def_clear;
601 h->h_enter = history_def_enter;
602 h->h_add = history_def_add;
603 }
604 return -1;
605 }
606
607 if (h->h_next == history_def_next)
608 history_def_clear(h->h_ref, &ev);
609
610 h->h_ent = -1;
611 h->h_first = nh->h_first;
612 h->h_next = nh->h_next;
613 h->h_last = nh->h_last;
614 h->h_prev = nh->h_prev;
615 h->h_curr = nh->h_curr;
616 h->h_set = nh->h_set;
617 h->h_clear = nh->h_clear;
618 h->h_enter = nh->h_enter;
619 h->h_add = nh->h_add;
620
621 return 0;
622 }
623
624
625 /* history_load():
626 * History load function
627 */
628 private int
629 history_load(h, fname)
630 History *h;
631 const char *fname;
632 {
633 FILE *fp;
634 char *line;
635 size_t sz;
636 int i = -1;
637 HistEvent ev;
638
639 if ((fp = fopen(fname, "r")) == NULL)
640 return i;
641
642 if ((line = fgetln(fp, &sz)) == NULL)
643 goto done;
644
645 if (strncmp(line, hist_cookie, sz) != 0)
646 goto done;
647
648 for (i = 0; (line = fgetln(fp, &sz)) != NULL; i++) {
649 char c = line[sz];
650 line[sz] = '\0';
651 HENTER(h, &ev, line);
652 line[sz] = c;
653 }
654
655 done:
656 (void) fclose(fp);
657 return i;
658 }
659
660
661 /* history_save():
662 * History save function
663 */
664 private int
665 history_save(h, fname)
666 History *h;
667 const char *fname;
668 {
669 FILE *fp;
670 HistEvent ev;
671 int i = 0, retval;
672
673 if ((fp = fopen(fname, "w")) == NULL)
674 return -1;
675
676 (void) fputs(hist_cookie, fp);
677 for (retval = HLAST(h, &ev); retval != -1; retval = HPREV(h, &ev), i++)
678 (void) fprintf(fp, "%s", ev.str);
679 (void) fclose(fp);
680 return i;
681 }
682
683
684 /* history_prev_event():
685 * Find the previous event, with number given
686 */
687 private int
688 history_prev_event(h, ev, num)
689 History *h;
690 HistEvent *ev;
691 int num;
692 {
693 int retval;
694 for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
695 if (ev->num == num)
696 return 0;
697
698 he_seterrev(ev, _HE_NOT_FOUND);
699 return -1;
700 }
701
702
703 /* history_next_event():
704 * Find the next event, with number given
705 */
706 private int
707 history_next_event(h, ev, num)
708 History *h;
709 HistEvent *ev;
710 int num;
711 {
712 int retval;
713 for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
714 if (ev->num == num)
715 return 0;
716
717 he_seterrev(ev, _HE_NOT_FOUND);
718 return -1;
719 }
720
721
722 /* history_prev_string():
723 * Find the previous event beginning with string
724 */
725 private int
726 history_prev_string(h, ev, str)
727 History *h;
728 HistEvent *ev;
729 const char* str;
730 {
731 size_t len = strlen(str);
732 int retval;
733
734 for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
735 if (strncmp(str, ev->str, len) == 0)
736 return 0;
737
738 he_seterrev(ev, _HE_NOT_FOUND);
739 return -1;
740 }
741
742
743
744
745 /* history_next_string():
746 * Find the next event beginning with string
747 */
748 private int
749 history_next_string(h, ev, str)
750 History *h;
751 HistEvent *ev;
752 const char* str;
753 {
754 size_t len = strlen(str);
755 int retval;
756
757 for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
758 if (strncmp(str, ev->str, len) == 0)
759 return 0;
760
761 he_seterrev(ev, _HE_NOT_FOUND);
762 return -1;
763 }
764
765
766 /* history():
767 * User interface to history functions.
768 */
769 int
770 #ifdef __STDC__
771 history(History *h, HistEvent *ev, int fun, ...)
772 #else
773 history(va_alist)
774 va_dcl
775 #endif
776 {
777 va_list va;
778 const char *str;
779 int retval;
780
781 #ifdef __STDC__
782 va_start(va, fun);
783 #else
784 History *h;
785 HistEvent *ev;
786 int fun;
787 va_start(va);
788 h = va_arg(va, History *);
789 ev = va_arg(va, HistEvent *);
790 fun = va_arg(va, int);
791 #endif
792
793 he_seterrev(ev, _HE_OK);
794
795 switch (fun) {
796 case H_GETSIZE:
797 retval = history_get_size(h, ev);
798 break;
799
800 case H_SETSIZE:
801 retval = history_set_num(h, ev, va_arg(va, int));
802 break;
803
804 case H_ADD:
805 str = va_arg(va, const char *);
806 retval = HADD(h, ev, str);
807 break;
808
809 case H_ENTER:
810 str = va_arg(va, const char *);
811 if ((retval = HENTER(h, ev, str)) != -1)
812 h->h_ent = ev->num;
813 break;
814
815 case H_APPEND:
816 str = va_arg(va, const char *);
817 if ((retval = HSET(h, ev, h->h_ent)) != -1)
818 retval = HADD(h, ev, str);
819 break;
820
821 case H_FIRST:
822 retval = HFIRST(h, ev);
823 break;
824
825 case H_NEXT:
826 retval = HNEXT(h, ev);
827 break;
828
829 case H_LAST:
830 retval = HLAST(h, ev);
831 break;
832
833 case H_PREV:
834 retval = HPREV(h, ev);
835 break;
836
837 case H_CURR:
838 retval = HCURR(h, ev);
839 break;
840
841 case H_SET:
842 retval = HSET(h, ev, va_arg(va, const int));
843 break;
844
845 case H_CLEAR:
846 HCLEAR(h, ev);
847 retval = 0;
848 break;
849
850 case H_LOAD:
851 retval = history_load(h, va_arg(va, const char *));
852 if (retval == -1)
853 he_seterrev(ev, _HE_HIST_READ);
854 break;
855
856 case H_SAVE:
857 retval = history_save(h, va_arg(va, const char *));
858 if (retval == -1)
859 he_seterrev(ev, _HE_HIST_WRITE);
860 break;
861
862 case H_PREV_EVENT:
863 retval = history_prev_event(h, ev, va_arg(va, int));
864 break;
865
866 case H_NEXT_EVENT:
867 retval = history_next_event(h, ev, va_arg(va, int));
868 break;
869
870 case H_PREV_STR:
871 retval = history_prev_string(h, ev, va_arg(va, const char*));
872 break;
873
874 case H_NEXT_STR:
875 retval = history_next_string(h, ev, va_arg(va, const char*));
876 break;
877
878 case H_FUNC:
879 {
880 History hf;
881
882 hf.h_ref = va_arg(va, ptr_t);
883 h->h_ent = -1;
884 hf.h_first = va_arg(va, history_gfun_t);
885 hf.h_next = va_arg(va, history_gfun_t);
886 hf.h_last = va_arg(va, history_gfun_t);
887 hf.h_prev = va_arg(va, history_gfun_t);
888 hf.h_curr = va_arg(va, history_gfun_t);
889 hf.h_set = va_arg(va, history_sfun_t);
890 hf.h_clear = va_arg(va, history_vfun_t);
891 hf.h_enter = va_arg(va, history_efun_t);
892 hf.h_add = va_arg(va, history_efun_t);
893
894 if ((retval = history_set_fun(h, &hf)) == -1)
895 he_seterrev(ev, _HE_PARAM_MISSING);
896 }
897 break;
898
899 case H_END:
900 history_end(h);
901 retval = 0;
902 break;
903
904 default:
905 retval = -1;
906 he_seterrev(ev, _HE_UNKNOWN);
907 break;
908 }
909 va_end(va);
910 return retval;
911 }
912