history.c revision 84260
1/*-
2 * Copyright (c) 1992, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Christos Zoulas of Cornell University.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 *	$NetBSD: history.c,v 1.16 2000/09/04 22:06:30 lukem Exp $
37 */
38
39#include <sys/cdefs.h>
40__FBSDID("$FreeBSD: head/lib/libedit/history.c 84260 2001-10-01 08:41:27Z obrien $");
41#if !defined(lint) && !defined(SCCSID)
42static char sccsid[] = "@(#)history.c	8.1 (Berkeley) 6/4/93";
43#endif /* not lint && not SCCSID */
44#include <sys/cdefs.h>
45__FBSDID("$FreeBSD: head/lib/libedit/history.c 84260 2001-10-01 08:41:27Z obrien $");
46
47/*
48 * hist.c: History access functions
49 */
50#include "sys.h"
51
52#include <string.h>
53#include <stdlib.h>
54#include <stdarg.h>
55#include <vis.h>
56#include <sys/stat.h>
57
58static const char hist_cookie[] = "_HiStOrY_V2_\n";
59
60#include "histedit.h"
61
62typedef int (*history_gfun_t)(ptr_t, HistEvent *);
63typedef int (*history_efun_t)(ptr_t, HistEvent *, const char *);
64typedef void (*history_vfun_t)(ptr_t, HistEvent *);
65typedef int (*history_sfun_t)(ptr_t, HistEvent *, const int);
66
67struct history {
68	ptr_t h_ref;		/* Argument for history fcns	 */
69	int h_ent;		/* Last entry point for history	 */
70	history_gfun_t h_first;	/* Get the first element	 */
71	history_gfun_t h_next;	/* Get the next element		 */
72	history_gfun_t h_last;	/* Get the last element		 */
73	history_gfun_t h_prev;	/* Get the previous element	 */
74	history_gfun_t h_curr;	/* Get the current element	 */
75	history_sfun_t h_set;	/* Set 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#define	HNEXT(h, ev)		(*(h)->h_next)((h)->h_ref, ev)
81#define	HFIRST(h, ev)		(*(h)->h_first)((h)->h_ref, ev)
82#define	HPREV(h, ev)		(*(h)->h_prev)((h)->h_ref, ev)
83#define	HLAST(h, ev)		(*(h)->h_last)((h)->h_ref, ev)
84#define	HCURR(h, ev)		(*(h)->h_curr)((h)->h_ref, ev)
85#define	HSET(h, ev, n)		(*(h)->h_set)((h)->h_ref, ev, n)
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_realloc(a, b)	realloc((a), (b))
92#define	h_free(a)	free(a)
93
94
95private int history_setsize(History *, HistEvent *, int);
96private int history_getsize(History *, HistEvent *);
97private int history_set_fun(History *, History *);
98private int history_load(History *, const char *);
99private int history_save(History *, const char *);
100private int history_prev_event(History *, HistEvent *, int);
101private int history_next_event(History *, HistEvent *, int);
102private int history_next_string(History *, HistEvent *, const char *);
103private int history_prev_string(History *, HistEvent *, const char *);
104
105
106/***********************************************************************/
107
108/*
109 * Builtin- history implementation
110 */
111typedef struct hentry_t {
112	HistEvent ev;		/* What we return		 */
113	struct hentry_t *next;	/* Next entry			 */
114	struct hentry_t *prev;	/* Previous entry		 */
115}        hentry_t;
116
117typedef struct history_t {
118	hentry_t list;		/* Fake list header element	 */
119	hentry_t *cursor;	/* Current element in the list	 */
120	int max;		/* Maximum number of events	 */
121	int cur;		/* Current number of events	 */
122	int eventid;		/* For generation of unique event id	 */
123}         history_t;
124
125private int history_def_first(ptr_t, HistEvent *);
126private int history_def_last(ptr_t, HistEvent *);
127private int history_def_next(ptr_t, HistEvent *);
128private int history_def_prev(ptr_t, HistEvent *);
129private int history_def_curr(ptr_t, HistEvent *);
130private int history_def_set(ptr_t, HistEvent *, const int n);
131private int history_def_enter(ptr_t, HistEvent *, const char *);
132private int history_def_add(ptr_t, HistEvent *, const char *);
133private void history_def_init(ptr_t *, HistEvent *, int);
134private void history_def_clear(ptr_t, HistEvent *);
135private int history_def_insert(history_t *, HistEvent *, const char *);
136private void history_def_delete(history_t *, HistEvent *, hentry_t *);
137
138#define	history_def_setsize(p, num)(void) (((history_t *) p)->max = (num))
139#define	history_def_getsize(p)  (((history_t *) p)->cur)
140
141#define	he_strerror(code)	he_errlist[code]
142#define	he_seterrev(evp, code)	{\
143				    evp->num = code;\
144				    evp->str = he_strerror(code);\
145				}
146
147/* error messages */
148static const char *const he_errlist[] = {
149	"OK",
150	"unknown error",
151	"malloc() failed",
152	"first event not found",
153	"last event not found",
154	"empty list",
155	"no next event",
156	"no previous event",
157	"current event is invalid",
158	"event not found",
159	"can't read history from file",
160	"can't write history",
161	"required parameter(s) not supplied",
162	"history size negative",
163	"function not allowed with other history-functions-set the default",
164	"bad parameters"
165};
166/* error codes */
167#define	_HE_OK                   0
168#define	_HE_UNKNOWN		 1
169#define	_HE_MALLOC_FAILED        2
170#define	_HE_FIRST_NOTFOUND       3
171#define	_HE_LAST_NOTFOUND        4
172#define	_HE_EMPTY_LIST           5
173#define	_HE_END_REACHED          6
174#define	_HE_START_REACHED	 7
175#define	_HE_CURR_INVALID	 8
176#define	_HE_NOT_FOUND		 9
177#define	_HE_HIST_READ		10
178#define	_HE_HIST_WRITE		11
179#define	_HE_PARAM_MISSING	12
180#define	_HE_SIZE_NEGATIVE	13
181#define	_HE_NOT_ALLOWED		14
182#define	_HE_BAD_PARAM		15
183
184/* history_def_first():
185 *	Default function to return the first event in the history.
186 */
187private int
188history_def_first(ptr_t p, 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
204/* history_def_last():
205 *	Default function to return the last event in the history.
206 */
207private int
208history_def_last(ptr_t p, HistEvent *ev)
209{
210	history_t *h = (history_t *) p;
211
212	h->cursor = h->list.prev;
213	if (h->cursor != &h->list)
214		*ev = h->cursor->ev;
215	else {
216		he_seterrev(ev, _HE_LAST_NOTFOUND);
217		return (-1);
218	}
219
220	return (0);
221}
222
223
224/* history_def_next():
225 *	Default function to return the next event in the history.
226 */
227private int
228history_def_next(ptr_t p, HistEvent *ev)
229{
230	history_t *h = (history_t *) p;
231
232	if (h->cursor != &h->list)
233		h->cursor = h->cursor->next;
234	else {
235		he_seterrev(ev, _HE_EMPTY_LIST);
236		return (-1);
237	}
238
239	if (h->cursor != &h->list)
240		*ev = h->cursor->ev;
241	else {
242		he_seterrev(ev, _HE_END_REACHED);
243		return (-1);
244	}
245
246	return (0);
247}
248
249
250/* history_def_prev():
251 *	Default function to return the previous event in the history.
252 */
253private int
254history_def_prev(ptr_t p, HistEvent *ev)
255{
256	history_t *h = (history_t *) p;
257
258	if (h->cursor != &h->list)
259		h->cursor = h->cursor->prev;
260	else {
261		he_seterrev(ev,
262		    (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST);
263		return (-1);
264	}
265
266	if (h->cursor != &h->list)
267		*ev = h->cursor->ev;
268	else {
269		he_seterrev(ev, _HE_START_REACHED);
270		return (-1);
271	}
272
273	return (0);
274}
275
276
277/* history_def_curr():
278 *	Default function to return the current event in the history.
279 */
280private int
281history_def_curr(ptr_t p, HistEvent *ev)
282{
283	history_t *h = (history_t *) p;
284
285	if (h->cursor != &h->list)
286		*ev = h->cursor->ev;
287	else {
288		he_seterrev(ev,
289		    (h->cur > 0) ? _HE_CURR_INVALID : _HE_EMPTY_LIST);
290		return (-1);
291	}
292
293	return (0);
294}
295
296
297/* history_def_set():
298 *	Default function to set the current event in the history to the
299 *	given one.
300 */
301private int
302history_def_set(ptr_t p, HistEvent *ev, const int n)
303{
304	history_t *h = (history_t *) p;
305
306	if (h->cur == 0) {
307		he_seterrev(ev, _HE_EMPTY_LIST);
308		return (-1);
309	}
310	if (h->cursor == &h->list || h->cursor->ev.num != n) {
311		for (h->cursor = h->list.next; h->cursor != &h->list;
312		    h->cursor = h->cursor->next)
313			if (h->cursor->ev.num == n)
314				break;
315	}
316	if (h->cursor == &h->list) {
317		he_seterrev(ev, _HE_NOT_FOUND);
318		return (-1);
319	}
320	return (0);
321}
322
323
324/* history_def_add():
325 *	Append string to element
326 */
327private int
328history_def_add(ptr_t p, HistEvent *ev, const char *str)
329{
330	history_t *h = (history_t *) p;
331	size_t len;
332	char *s;
333
334	if (h->cursor == &h->list)
335		return (history_def_enter(p, ev, str));
336	len = strlen(h->cursor->ev.str) + strlen(str) + 1;
337	s = (char *) h_malloc(len);
338	if (!s) {
339		he_seterrev(ev, _HE_MALLOC_FAILED);
340		return (-1);
341	}
342	(void) strlcpy(s, h->cursor->ev.str, len);
343	(void) strlcat(s, str, len);
344	/* LINTED const cast */
345	h_free((ptr_t) h->cursor->ev.str);
346	h->cursor->ev.str = s;
347	*ev = h->cursor->ev;
348	return (0);
349}
350
351
352/* history_def_delete():
353 *	Delete element hp of the h list
354 */
355/* ARGSUSED */
356private void
357history_def_delete(history_t *h, HistEvent *ev, hentry_t *hp)
358{
359
360	if (hp == &h->list)
361		abort();
362	hp->prev->next = hp->next;
363	hp->next->prev = hp->prev;
364	/* LINTED const cast */
365	h_free((ptr_t) hp->ev.str);
366	h_free(hp);
367	h->cur--;
368}
369
370
371/* history_def_insert():
372 *	Insert element with string str in the h list
373 */
374private int
375history_def_insert(history_t *h, HistEvent *ev, const char *str)
376{
377
378	h->cursor = (hentry_t *) h_malloc(sizeof(hentry_t));
379	if (h->cursor)
380		h->cursor->ev.str = strdup(str);
381	if (!h->cursor || !h->cursor->ev.str) {
382		he_seterrev(ev, _HE_MALLOC_FAILED);
383		return (-1);
384	}
385	h->cursor->ev.num = ++h->eventid;
386	h->cursor->next = h->list.next;
387	h->cursor->prev = &h->list;
388	h->list.next->prev = h->cursor;
389	h->list.next = h->cursor;
390	h->cur++;
391
392	*ev = h->cursor->ev;
393	return (0);
394}
395
396
397/* history_def_enter():
398 *	Default function to enter an item in the history
399 */
400private int
401history_def_enter(ptr_t p, HistEvent *ev, const char *str)
402{
403	history_t *h = (history_t *) p;
404
405	if (history_def_insert(h, ev, str) == -1)
406		return (-1);	/* error, keep error message */
407
408	/*
409         * Always keep at least one entry.
410         * This way we don't have to check for the empty list.
411         */
412	while (h->cur - 1 > h->max)
413		history_def_delete(h, ev, h->list.prev);
414
415	return (0);
416}
417
418
419/* history_def_init():
420 *	Default history initialization function
421 */
422/* ARGSUSED */
423private void
424history_def_init(ptr_t *p, HistEvent *ev, int n)
425{
426	history_t *h = (history_t *) h_malloc(sizeof(history_t));
427
428	if (n <= 0)
429		n = 0;
430	h->eventid = 0;
431	h->cur = 0;
432	h->max = n;
433	h->list.next = h->list.prev = &h->list;
434	h->list.ev.str = NULL;
435	h->list.ev.num = 0;
436	h->cursor = &h->list;
437	*p = (ptr_t) h;
438}
439
440
441/* history_def_clear():
442 *	Default history cleanup function
443 */
444private void
445history_def_clear(ptr_t p, HistEvent *ev)
446{
447	history_t *h = (history_t *) p;
448
449	while (h->list.prev != &h->list)
450		history_def_delete(h, ev, h->list.prev);
451	h->eventid = 0;
452	h->cur = 0;
453}
454
455
456
457
458/************************************************************************/
459
460/* history_init():
461 *	Initialization function.
462 */
463public History *
464history_init(void)
465{
466	History *h = (History *) h_malloc(sizeof(History));
467	HistEvent ev;
468
469	history_def_init(&h->h_ref, &ev, 0);
470	h->h_ent = -1;
471	h->h_next = history_def_next;
472	h->h_first = history_def_first;
473	h->h_last = history_def_last;
474	h->h_prev = history_def_prev;
475	h->h_curr = history_def_curr;
476	h->h_set = history_def_set;
477	h->h_clear = history_def_clear;
478	h->h_enter = history_def_enter;
479	h->h_add = history_def_add;
480
481	return (h);
482}
483
484
485/* history_end():
486 *	clean up history;
487 */
488public void
489history_end(History *h)
490{
491	HistEvent ev;
492
493	if (h->h_next == history_def_next)
494		history_def_clear(h->h_ref, &ev);
495}
496
497
498
499/* history_setsize():
500 *	Set history number of events
501 */
502private int
503history_setsize(History *h, HistEvent *ev, int num)
504{
505
506	if (h->h_next != history_def_next) {
507		he_seterrev(ev, _HE_NOT_ALLOWED);
508		return (-1);
509	}
510	if (num < 0) {
511		he_seterrev(ev, _HE_BAD_PARAM);
512		return (-1);
513	}
514	history_def_setsize(h->h_ref, num);
515	return (0);
516}
517
518
519/* history_getsize():
520 *      Get number of events currently in history
521 */
522private int
523history_getsize(History *h, HistEvent *ev)
524{
525	int retval = 0;
526
527	if (h->h_next != history_def_next) {
528		he_seterrev(ev, _HE_NOT_ALLOWED);
529		return (-1);
530	}
531	retval = history_def_getsize(h->h_ref);
532	if (retval < -1) {
533		he_seterrev(ev, _HE_SIZE_NEGATIVE);
534		return (-1);
535	}
536	ev->num = retval;
537	return (0);
538}
539
540
541/* history_set_fun():
542 *	Set history functions
543 */
544private int
545history_set_fun(History *h, History *nh)
546{
547	HistEvent ev;
548
549	if (nh->h_first == NULL || nh->h_next == NULL || nh->h_last == NULL ||
550	    nh->h_prev == NULL || nh->h_curr == NULL || nh->h_set == NULL ||
551	    nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL ||
552	    nh->h_ref == NULL) {
553		if (h->h_next != history_def_next) {
554			history_def_init(&h->h_ref, &ev, 0);
555			h->h_first = history_def_first;
556			h->h_next = history_def_next;
557			h->h_last = history_def_last;
558			h->h_prev = history_def_prev;
559			h->h_curr = history_def_curr;
560			h->h_set = history_def_set;
561			h->h_clear = history_def_clear;
562			h->h_enter = history_def_enter;
563			h->h_add = history_def_add;
564		}
565		return (-1);
566	}
567	if (h->h_next == history_def_next)
568		history_def_clear(h->h_ref, &ev);
569
570	h->h_ent = -1;
571	h->h_first = nh->h_first;
572	h->h_next = nh->h_next;
573	h->h_last = nh->h_last;
574	h->h_prev = nh->h_prev;
575	h->h_curr = nh->h_curr;
576	h->h_set = nh->h_set;
577	h->h_clear = nh->h_clear;
578	h->h_enter = nh->h_enter;
579	h->h_add = nh->h_add;
580
581	return (0);
582}
583
584
585/* history_load():
586 *	History load function
587 */
588private int
589history_load(History *h, const char *fname)
590{
591	FILE *fp;
592	char *line;
593	size_t sz, max_size;
594	char *ptr;
595	int i = -1;
596	HistEvent ev;
597
598	if ((fp = fopen(fname, "r")) == NULL)
599		return (i);
600
601	if ((line = fgetln(fp, &sz)) == NULL)
602		goto done;
603
604	if (strncmp(line, hist_cookie, sz) != 0)
605		goto done;
606
607	ptr = h_malloc(max_size = 1024);
608	for (i = 0; (line = fgetln(fp, &sz)) != NULL; i++) {
609		char c = line[sz];
610
611		if (sz != 0 && line[sz - 1] == '\n')
612			line[--sz] = '\0';
613		else
614			line[sz] = '\0';
615
616		if (max_size < sz) {
617			max_size = (sz + 1023) & ~1023;
618			ptr = h_realloc(ptr, max_size);
619		}
620		(void) strunvis(ptr, line);
621		line[sz] = c;
622		HENTER(h, &ev, ptr);
623	}
624	h_free(ptr);
625
626done:
627	(void) fclose(fp);
628	return (i);
629}
630
631
632/* history_save():
633 *	History save function
634 */
635private int
636history_save(History *h, const char *fname)
637{
638	FILE *fp;
639	HistEvent ev;
640	int i = 0, retval;
641	size_t len, max_size;
642	char *ptr;
643
644	if ((fp = fopen(fname, "w")) == NULL)
645		return (-1);
646
647	(void) fchmod(fileno(fp), S_IRUSR|S_IWUSR);
648	(void) fputs(hist_cookie, fp);
649	ptr = h_malloc(max_size = 1024);
650	for (retval = HLAST(h, &ev);
651	    retval != -1;
652	    retval = HPREV(h, &ev), i++) {
653		len = strlen(ev.str) * 4;
654		if (len >= max_size) {
655			max_size = (len + 1023) & 1023;
656			ptr = h_realloc(ptr, max_size);
657		}
658		(void) strvis(ptr, ev.str, VIS_WHITE);
659		(void) fprintf(fp, "%s\n", ev.str);
660	}
661	h_free(ptr);
662	(void) fclose(fp);
663	return (i);
664}
665
666
667/* history_prev_event():
668 *	Find the previous event, with number given
669 */
670private int
671history_prev_event(History *h, HistEvent *ev, int num)
672{
673	int retval;
674
675	for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
676		if (ev->num == num)
677			return (0);
678
679	he_seterrev(ev, _HE_NOT_FOUND);
680	return (-1);
681}
682
683
684/* history_next_event():
685 *	Find the next event, with number given
686 */
687private int
688history_next_event(History *h, HistEvent *ev, int num)
689{
690	int retval;
691
692	for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
693		if (ev->num == num)
694			return (0);
695
696	he_seterrev(ev, _HE_NOT_FOUND);
697	return (-1);
698}
699
700
701/* history_prev_string():
702 *	Find the previous event beginning with string
703 */
704private int
705history_prev_string(History *h, HistEvent *ev, const char *str)
706{
707	size_t len = strlen(str);
708	int retval;
709
710	for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
711		if (strncmp(str, ev->str, len) == 0)
712			return (0);
713
714	he_seterrev(ev, _HE_NOT_FOUND);
715	return (-1);
716}
717
718
719/* history_next_string():
720 *	Find the next event beginning with string
721 */
722private int
723history_next_string(History *h, HistEvent *ev, const char *str)
724{
725	size_t len = strlen(str);
726	int retval;
727
728	for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
729		if (strncmp(str, ev->str, len) == 0)
730			return (0);
731
732	he_seterrev(ev, _HE_NOT_FOUND);
733	return (-1);
734}
735
736
737/* history():
738 *	User interface to history functions.
739 */
740int
741history(History *h, HistEvent *ev, int fun, ...)
742{
743	va_list va;
744	const char *str;
745	int retval;
746
747	va_start(va, fun);
748
749	he_seterrev(ev, _HE_OK);
750
751	switch (fun) {
752	case H_GETSIZE:
753		retval = history_getsize(h, ev);
754		break;
755
756	case H_SETSIZE:
757		retval = history_setsize(h, ev, va_arg(va, int));
758		break;
759
760	case H_ADD:
761		str = va_arg(va, const char *);
762		retval = HADD(h, ev, str);
763		break;
764
765	case H_ENTER:
766		str = va_arg(va, const char *);
767		if ((retval = HENTER(h, ev, str)) != -1)
768			h->h_ent = ev->num;
769		break;
770
771	case H_APPEND:
772		str = va_arg(va, const char *);
773		if ((retval = HSET(h, ev, h->h_ent)) != -1)
774			retval = HADD(h, ev, str);
775		break;
776
777	case H_FIRST:
778		retval = HFIRST(h, ev);
779		break;
780
781	case H_NEXT:
782		retval = HNEXT(h, ev);
783		break;
784
785	case H_LAST:
786		retval = HLAST(h, ev);
787		break;
788
789	case H_PREV:
790		retval = HPREV(h, ev);
791		break;
792
793	case H_CURR:
794		retval = HCURR(h, ev);
795		break;
796
797	case H_SET:
798		retval = HSET(h, ev, va_arg(va, const int));
799		break;
800
801	case H_CLEAR:
802		HCLEAR(h, ev);
803		retval = 0;
804		break;
805
806	case H_LOAD:
807		retval = history_load(h, va_arg(va, const char *));
808		if (retval == -1)
809			he_seterrev(ev, _HE_HIST_READ);
810		break;
811
812	case H_SAVE:
813		retval = history_save(h, va_arg(va, const char *));
814		if (retval == -1)
815			he_seterrev(ev, _HE_HIST_WRITE);
816		break;
817
818	case H_PREV_EVENT:
819		retval = history_prev_event(h, ev, va_arg(va, int));
820		break;
821
822	case H_NEXT_EVENT:
823		retval = history_next_event(h, ev, va_arg(va, int));
824		break;
825
826	case H_PREV_STR:
827		retval = history_prev_string(h, ev, va_arg(va, const char *));
828		break;
829
830	case H_NEXT_STR:
831		retval = history_next_string(h, ev, va_arg(va, const char *));
832		break;
833
834	case H_FUNC:
835	{
836		History hf;
837
838		hf.h_ref = va_arg(va, ptr_t);
839		h->h_ent = -1;
840		hf.h_first = va_arg(va, history_gfun_t);
841		hf.h_next = va_arg(va, history_gfun_t);
842		hf.h_last = va_arg(va, history_gfun_t);
843		hf.h_prev = va_arg(va, history_gfun_t);
844		hf.h_curr = va_arg(va, history_gfun_t);
845		hf.h_set = va_arg(va, history_sfun_t);
846		hf.h_clear = va_arg(va, history_vfun_t);
847		hf.h_enter = va_arg(va, history_efun_t);
848		hf.h_add = va_arg(va, history_efun_t);
849
850		if ((retval = history_set_fun(h, &hf)) == -1)
851			he_seterrev(ev, _HE_PARAM_MISSING);
852		break;
853	}
854
855	case H_END:
856		history_end(h);
857		retval = 0;
858		break;
859
860	default:
861		retval = -1;
862		he_seterrev(ev, _HE_UNKNOWN);
863		break;
864	}
865	va_end(va);
866	return (retval);
867}
868