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