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