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