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