11573Srgrimes/*-
21573Srgrimes * Copyright (c) 1992, 1993
31573Srgrimes *	The Regents of the University of California.  All rights reserved.
41573Srgrimes *
51573Srgrimes * This code is derived from software contributed to Berkeley by
61573Srgrimes * Christos Zoulas of Cornell University.
71573Srgrimes *
81573Srgrimes * Redistribution and use in source and binary forms, with or without
91573Srgrimes * modification, are permitted provided that the following conditions
101573Srgrimes * are met:
111573Srgrimes * 1. Redistributions of source code must retain the above copyright
121573Srgrimes *    notice, this list of conditions and the following disclaimer.
131573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141573Srgrimes *    notice, this list of conditions and the following disclaimer in the
151573Srgrimes *    documentation and/or other materials provided with the distribution.
16148834Sstefanf * 3. Neither the name of the University nor the names of its contributors
171573Srgrimes *    may be used to endorse or promote products derived from this software
181573Srgrimes *    without specific prior written permission.
191573Srgrimes *
201573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
211573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231573Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
241573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301573Srgrimes * SUCH DAMAGE.
3184260Sobrien *
32237448Spfg *	$NetBSD: history.c,v 1.34 2009/09/07 21:24:33 christos Exp $
331573Srgrimes */
341573Srgrimes
351573Srgrimes#if !defined(lint) && !defined(SCCSID)
361573Srgrimesstatic char sccsid[] = "@(#)history.c	8.1 (Berkeley) 6/4/93";
371573Srgrimes#endif /* not lint && not SCCSID */
3884260Sobrien#include <sys/cdefs.h>
3984260Sobrien__FBSDID("$FreeBSD$");
401573Srgrimes
411573Srgrimes/*
421573Srgrimes * hist.c: History access functions
431573Srgrimes */
441573Srgrimes#include "sys.h"
451573Srgrimes
461573Srgrimes#include <string.h>
471573Srgrimes#include <stdlib.h>
481573Srgrimes#include <stdarg.h>
4984260Sobrien#include <vis.h>
5084260Sobrien#include <sys/stat.h>
511573Srgrimes
5284260Sobrienstatic const char hist_cookie[] = "_HiStOrY_V2_\n";
5326926Smsmith
541573Srgrimes#include "histedit.h"
551573Srgrimes
5684260Sobrientypedef int (*history_gfun_t)(ptr_t, HistEvent *);
5784260Sobrientypedef int (*history_efun_t)(ptr_t, HistEvent *, const char *);
5884260Sobrientypedef void (*history_vfun_t)(ptr_t, HistEvent *);
5984260Sobrientypedef int (*history_sfun_t)(ptr_t, HistEvent *, const int);
601573Srgrimes
611573Srgrimesstruct history {
6284260Sobrien	ptr_t h_ref;		/* Argument for history fcns	 */
6384260Sobrien	int h_ent;		/* Last entry point for history	 */
6484260Sobrien	history_gfun_t h_first;	/* Get the first element	 */
6584260Sobrien	history_gfun_t h_next;	/* Get the next element		 */
6684260Sobrien	history_gfun_t h_last;	/* Get the last element		 */
6784260Sobrien	history_gfun_t h_prev;	/* Get the previous element	 */
6884260Sobrien	history_gfun_t h_curr;	/* Get the current element	 */
6984260Sobrien	history_sfun_t h_set;	/* Set the current element	 */
70148834Sstefanf	history_sfun_t h_del;	/* Set the given element	 */
7184260Sobrien	history_vfun_t h_clear;	/* Clear the history list	 */
7284260Sobrien	history_efun_t h_enter;	/* Add an element		 */
7384260Sobrien	history_efun_t h_add;	/* Append to an element		 */
741573Srgrimes};
75148834Sstefanf
7684260Sobrien#define	HNEXT(h, ev)		(*(h)->h_next)((h)->h_ref, ev)
7784260Sobrien#define	HFIRST(h, ev)		(*(h)->h_first)((h)->h_ref, ev)
7884260Sobrien#define	HPREV(h, ev)		(*(h)->h_prev)((h)->h_ref, ev)
7984260Sobrien#define	HLAST(h, ev)		(*(h)->h_last)((h)->h_ref, ev)
8084260Sobrien#define	HCURR(h, ev)		(*(h)->h_curr)((h)->h_ref, ev)
8184260Sobrien#define	HSET(h, ev, n)		(*(h)->h_set)((h)->h_ref, ev, n)
8284260Sobrien#define	HCLEAR(h, ev)		(*(h)->h_clear)((h)->h_ref, ev)
8384260Sobrien#define	HENTER(h, ev, str)	(*(h)->h_enter)((h)->h_ref, ev, str)
8484260Sobrien#define	HADD(h, ev, str)	(*(h)->h_add)((h)->h_ref, ev, str)
85148834Sstefanf#define	HDEL(h, ev, n)		(*(h)->h_del)((h)->h_ref, ev, n)
861573Srgrimes
87148834Sstefanf#define	h_strdup(a)	strdup(a)
8884260Sobrien#define	h_malloc(a)	malloc(a)
8984260Sobrien#define	h_realloc(a, b)	realloc((a), (b))
9084260Sobrien#define	h_free(a)	free(a)
911573Srgrimes
92148834Sstefanftypedef struct {
93148834Sstefanf    int		num;
94148834Sstefanf    char	*str;
95148834Sstefanf} HistEventPrivate;
961573Srgrimes
97148834Sstefanf
98148834Sstefanf
9984260Sobrienprivate int history_setsize(History *, HistEvent *, int);
10084260Sobrienprivate int history_getsize(History *, HistEvent *);
101148834Sstefanfprivate int history_setunique(History *, HistEvent *, int);
102148834Sstefanfprivate int history_getunique(History *, HistEvent *);
10384260Sobrienprivate int history_set_fun(History *, History *);
10484260Sobrienprivate int history_load(History *, const char *);
10584260Sobrienprivate int history_save(History *, const char *);
10684260Sobrienprivate int history_prev_event(History *, HistEvent *, int);
10784260Sobrienprivate int history_next_event(History *, HistEvent *, int);
10884260Sobrienprivate int history_next_string(History *, HistEvent *, const char *);
10984260Sobrienprivate int history_prev_string(History *, HistEvent *, const char *);
1101573Srgrimes
1111573Srgrimes
1121573Srgrimes/***********************************************************************/
1131573Srgrimes
1141573Srgrimes/*
1151573Srgrimes * Builtin- history implementation
1161573Srgrimes */
1171573Srgrimestypedef struct hentry_t {
11884260Sobrien	HistEvent ev;		/* What we return		 */
119237448Spfg	void *data;		/* data				 */
12084260Sobrien	struct hentry_t *next;	/* Next entry			 */
12184260Sobrien	struct hentry_t *prev;	/* Previous entry		 */
122148834Sstefanf} hentry_t;
1231573Srgrimes
1241573Srgrimestypedef struct history_t {
125148834Sstefanf	hentry_t list;		/* Fake list header element	*/
126148834Sstefanf	hentry_t *cursor;	/* Current element in the list	*/
127148834Sstefanf	int max;		/* Maximum number of events	*/
128148834Sstefanf	int cur;		/* Current number of events	*/
12984260Sobrien	int eventid;		/* For generation of unique event id	 */
130148834Sstefanf	int flags;		/* History flags		*/
131148834Sstefanf#define H_UNIQUE	1	/* Store only unique elements	*/
132148834Sstefanf} history_t;
1331573Srgrimes
134148834Sstefanfprivate int history_def_next(ptr_t, HistEvent *);
13584260Sobrienprivate int history_def_first(ptr_t, HistEvent *);
136148834Sstefanfprivate int history_def_prev(ptr_t, HistEvent *);
13784260Sobrienprivate int history_def_last(ptr_t, HistEvent *);
13884260Sobrienprivate int history_def_curr(ptr_t, HistEvent *);
139148834Sstefanfprivate int history_def_set(ptr_t, HistEvent *, const int);
140148834Sstefanfprivate void history_def_clear(ptr_t, HistEvent *);
14184260Sobrienprivate int history_def_enter(ptr_t, HistEvent *, const char *);
14284260Sobrienprivate int history_def_add(ptr_t, HistEvent *, const char *);
143148834Sstefanfprivate int history_def_del(ptr_t, HistEvent *, const int);
144148834Sstefanf
145148834Sstefanfprivate int history_def_init(ptr_t *, HistEvent *, int);
14684260Sobrienprivate int history_def_insert(history_t *, HistEvent *, const char *);
14784260Sobrienprivate void history_def_delete(history_t *, HistEvent *, hentry_t *);
1481573Srgrimes
149237448Spfgprivate int history_deldata_nth(history_t *, HistEvent *, int, void **);
150237448Spfgprivate int history_set_nth(ptr_t, HistEvent *, int);
151237448Spfg
152148834Sstefanf#define	history_def_setsize(p, num)(void) (((history_t *)p)->max = (num))
153148834Sstefanf#define	history_def_getsize(p)  (((history_t *)p)->cur)
154148834Sstefanf#define	history_def_getunique(p) (((((history_t *)p)->flags) & H_UNIQUE) != 0)
155148834Sstefanf#define	history_def_setunique(p, uni) \
156148834Sstefanf    if (uni) \
157148834Sstefanf	(((history_t *)p)->flags) |= H_UNIQUE; \
158148834Sstefanf    else \
159148834Sstefanf	(((history_t *)p)->flags) &= ~H_UNIQUE
1601573Srgrimes
16184260Sobrien#define	he_strerror(code)	he_errlist[code]
16284260Sobrien#define	he_seterrev(evp, code)	{\
16384260Sobrien				    evp->num = code;\
16484260Sobrien				    evp->str = he_strerror(code);\
16584260Sobrien				}
1661573Srgrimes
16784260Sobrien/* error messages */
16884260Sobrienstatic const char *const he_errlist[] = {
16984260Sobrien	"OK",
17084260Sobrien	"unknown error",
17184260Sobrien	"malloc() failed",
17284260Sobrien	"first event not found",
17384260Sobrien	"last event not found",
17484260Sobrien	"empty list",
17584260Sobrien	"no next event",
17684260Sobrien	"no previous event",
17784260Sobrien	"current event is invalid",
17884260Sobrien	"event not found",
17984260Sobrien	"can't read history from file",
18084260Sobrien	"can't write history",
18184260Sobrien	"required parameter(s) not supplied",
18284260Sobrien	"history size negative",
18384260Sobrien	"function not allowed with other history-functions-set the default",
18484260Sobrien	"bad parameters"
18584260Sobrien};
18684260Sobrien/* error codes */
18784260Sobrien#define	_HE_OK                   0
18884260Sobrien#define	_HE_UNKNOWN		 1
18984260Sobrien#define	_HE_MALLOC_FAILED        2
19084260Sobrien#define	_HE_FIRST_NOTFOUND       3
19184260Sobrien#define	_HE_LAST_NOTFOUND        4
19284260Sobrien#define	_HE_EMPTY_LIST           5
19384260Sobrien#define	_HE_END_REACHED          6
19484260Sobrien#define	_HE_START_REACHED	 7
19584260Sobrien#define	_HE_CURR_INVALID	 8
19684260Sobrien#define	_HE_NOT_FOUND		 9
19784260Sobrien#define	_HE_HIST_READ		10
19884260Sobrien#define	_HE_HIST_WRITE		11
19984260Sobrien#define	_HE_PARAM_MISSING	12
20084260Sobrien#define	_HE_SIZE_NEGATIVE	13
20184260Sobrien#define	_HE_NOT_ALLOWED		14
20284260Sobrien#define	_HE_BAD_PARAM		15
20384260Sobrien
2041573Srgrimes/* history_def_first():
2051573Srgrimes *	Default function to return the first event in the history.
2061573Srgrimes */
20784260Sobrienprivate int
20884260Sobrienhistory_def_first(ptr_t p, HistEvent *ev)
2091573Srgrimes{
21084260Sobrien	history_t *h = (history_t *) p;
21184260Sobrien
21284260Sobrien	h->cursor = h->list.next;
21384260Sobrien	if (h->cursor != &h->list)
21484260Sobrien		*ev = h->cursor->ev;
21584260Sobrien	else {
21684260Sobrien		he_seterrev(ev, _HE_FIRST_NOTFOUND);
21784260Sobrien		return (-1);
21884260Sobrien	}
21984260Sobrien
22084260Sobrien	return (0);
2211573Srgrimes}
2221573Srgrimes
22384260Sobrien
2241573Srgrimes/* history_def_last():
2251573Srgrimes *	Default function to return the last event in the history.
2261573Srgrimes */
22784260Sobrienprivate int
22884260Sobrienhistory_def_last(ptr_t p, HistEvent *ev)
2291573Srgrimes{
23084260Sobrien	history_t *h = (history_t *) p;
23184260Sobrien
23284260Sobrien	h->cursor = h->list.prev;
23384260Sobrien	if (h->cursor != &h->list)
23484260Sobrien		*ev = h->cursor->ev;
23584260Sobrien	else {
23684260Sobrien		he_seterrev(ev, _HE_LAST_NOTFOUND);
23784260Sobrien		return (-1);
23884260Sobrien	}
23984260Sobrien
24084260Sobrien	return (0);
2411573Srgrimes}
2421573Srgrimes
24384260Sobrien
2441573Srgrimes/* history_def_next():
2451573Srgrimes *	Default function to return the next event in the history.
2461573Srgrimes */
24784260Sobrienprivate int
24884260Sobrienhistory_def_next(ptr_t p, HistEvent *ev)
2491573Srgrimes{
25084260Sobrien	history_t *h = (history_t *) p;
2511573Srgrimes
252148834Sstefanf	if (h->cursor == &h->list) {
25384260Sobrien		he_seterrev(ev, _HE_EMPTY_LIST);
25484260Sobrien		return (-1);
25584260Sobrien	}
2561573Srgrimes
257148834Sstefanf	if (h->cursor->next == &h->list) {
25884260Sobrien		he_seterrev(ev, _HE_END_REACHED);
25984260Sobrien		return (-1);
26084260Sobrien	}
26184260Sobrien
262148834Sstefanf        h->cursor = h->cursor->next;
263148834Sstefanf        *ev = h->cursor->ev;
264148834Sstefanf
26584260Sobrien	return (0);
2661573Srgrimes}
2671573Srgrimes
2681573Srgrimes
2691573Srgrimes/* history_def_prev():
2701573Srgrimes *	Default function to return the previous event in the history.
2711573Srgrimes */
27284260Sobrienprivate int
27384260Sobrienhistory_def_prev(ptr_t p, HistEvent *ev)
2741573Srgrimes{
27584260Sobrien	history_t *h = (history_t *) p;
2761573Srgrimes
277148834Sstefanf	if (h->cursor == &h->list) {
27884260Sobrien		he_seterrev(ev,
27984260Sobrien		    (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST);
28084260Sobrien		return (-1);
28184260Sobrien	}
2821573Srgrimes
283148834Sstefanf	if (h->cursor->prev == &h->list) {
28484260Sobrien		he_seterrev(ev, _HE_START_REACHED);
28584260Sobrien		return (-1);
28684260Sobrien	}
28784260Sobrien
288148834Sstefanf        h->cursor = h->cursor->prev;
289148834Sstefanf        *ev = h->cursor->ev;
290148834Sstefanf
29184260Sobrien	return (0);
2921573Srgrimes}
2931573Srgrimes
2941573Srgrimes
2951573Srgrimes/* history_def_curr():
2961573Srgrimes *	Default function to return the current event in the history.
2971573Srgrimes */
29884260Sobrienprivate int
29984260Sobrienhistory_def_curr(ptr_t p, HistEvent *ev)
3001573Srgrimes{
30184260Sobrien	history_t *h = (history_t *) p;
3021573Srgrimes
30384260Sobrien	if (h->cursor != &h->list)
30484260Sobrien		*ev = h->cursor->ev;
30584260Sobrien	else {
30684260Sobrien		he_seterrev(ev,
30784260Sobrien		    (h->cur > 0) ? _HE_CURR_INVALID : _HE_EMPTY_LIST);
30884260Sobrien		return (-1);
30984260Sobrien	}
31084260Sobrien
31184260Sobrien	return (0);
3121573Srgrimes}
3131573Srgrimes
3141573Srgrimes
31584260Sobrien/* history_def_set():
31684260Sobrien *	Default function to set the current event in the history to the
31784260Sobrien *	given one.
31884260Sobrien */
31984260Sobrienprivate int
32084260Sobrienhistory_def_set(ptr_t p, HistEvent *ev, const int n)
32184260Sobrien{
32284260Sobrien	history_t *h = (history_t *) p;
32384260Sobrien
32484260Sobrien	if (h->cur == 0) {
32584260Sobrien		he_seterrev(ev, _HE_EMPTY_LIST);
32684260Sobrien		return (-1);
32784260Sobrien	}
32884260Sobrien	if (h->cursor == &h->list || h->cursor->ev.num != n) {
32984260Sobrien		for (h->cursor = h->list.next; h->cursor != &h->list;
33084260Sobrien		    h->cursor = h->cursor->next)
33184260Sobrien			if (h->cursor->ev.num == n)
33284260Sobrien				break;
33384260Sobrien	}
33484260Sobrien	if (h->cursor == &h->list) {
33584260Sobrien		he_seterrev(ev, _HE_NOT_FOUND);
33684260Sobrien		return (-1);
33784260Sobrien	}
33884260Sobrien	return (0);
33984260Sobrien}
34084260Sobrien
34184260Sobrien
342237448Spfg/* history_set_nth():
343237448Spfg *	Default function to set the current event in the history to the
344237448Spfg *	n-th one.
345237448Spfg */
346237448Spfgprivate int
347237448Spfghistory_set_nth(ptr_t p, HistEvent *ev, int n)
348237448Spfg{
349237448Spfg	history_t *h = (history_t *) p;
350237448Spfg
351237448Spfg	if (h->cur == 0) {
352237448Spfg		he_seterrev(ev, _HE_EMPTY_LIST);
353237448Spfg		return (-1);
354237448Spfg	}
355237448Spfg	for (h->cursor = h->list.prev; h->cursor != &h->list;
356237448Spfg	    h->cursor = h->cursor->prev)
357237448Spfg		if (n-- <= 0)
358237448Spfg			break;
359237448Spfg	if (h->cursor == &h->list) {
360237448Spfg		he_seterrev(ev, _HE_NOT_FOUND);
361237448Spfg		return (-1);
362237448Spfg	}
363237448Spfg	return (0);
364237448Spfg}
365237448Spfg
366237448Spfg
3671573Srgrimes/* history_def_add():
3681573Srgrimes *	Append string to element
3691573Srgrimes */
37084260Sobrienprivate int
37184260Sobrienhistory_def_add(ptr_t p, HistEvent *ev, const char *str)
3721573Srgrimes{
37384260Sobrien	history_t *h = (history_t *) p;
37484260Sobrien	size_t len;
37584260Sobrien	char *s;
376148834Sstefanf	HistEventPrivate *evp = (void *)&h->cursor->ev;
3771573Srgrimes
37884260Sobrien	if (h->cursor == &h->list)
37984260Sobrien		return (history_def_enter(p, ev, str));
380148834Sstefanf	len = strlen(evp->str) + strlen(str) + 1;
38184260Sobrien	s = (char *) h_malloc(len);
382148834Sstefanf	if (s == NULL) {
38384260Sobrien		he_seterrev(ev, _HE_MALLOC_FAILED);
38484260Sobrien		return (-1);
38584260Sobrien	}
38684260Sobrien	(void) strlcpy(s, h->cursor->ev.str, len);
38784260Sobrien	(void) strlcat(s, str, len);
388148834Sstefanf	h_free((ptr_t)evp->str);
389148834Sstefanf	evp->str = s;
39084260Sobrien	*ev = h->cursor->ev;
39184260Sobrien	return (0);
3921573Srgrimes}
3931573Srgrimes
3941573Srgrimes
395237448Spfgprivate int
396237448Spfghistory_deldata_nth(history_t *h, HistEvent *ev,
397237448Spfg    int num, void **data)
398237448Spfg{
399237448Spfg	if (history_set_nth(h, ev, num) != 0)
400237448Spfg		return (-1);
401237448Spfg	/* magic value to skip delete (just set to n-th history) */
402237448Spfg	if (data == (void **)-1)
403237448Spfg		return (0);
404237448Spfg	ev->str = strdup(h->cursor->ev.str);
405237448Spfg	ev->num = h->cursor->ev.num;
406237448Spfg	if (data)
407237448Spfg		*data = h->cursor->data;
408237448Spfg	history_def_delete(h, ev, h->cursor);
409237448Spfg	return (0);
410237448Spfg}
411237448Spfg
412237448Spfg
413148834Sstefanf/* history_def_del():
414148834Sstefanf *	Delete element hp of the h list
415148834Sstefanf */
416148834Sstefanf/* ARGSUSED */
417148834Sstefanfprivate int
418148834Sstefanfhistory_def_del(ptr_t p, HistEvent *ev __unused,
419148834Sstefanf    const int num)
420148834Sstefanf{
421148834Sstefanf	history_t *h = (history_t *) p;
422148834Sstefanf	if (history_def_set(h, ev, num) != 0)
423148834Sstefanf		return (-1);
424148834Sstefanf	ev->str = strdup(h->cursor->ev.str);
425148834Sstefanf	ev->num = h->cursor->ev.num;
426148834Sstefanf	history_def_delete(h, ev, h->cursor);
427148834Sstefanf	return (0);
428148834Sstefanf}
429148834Sstefanf
430148834Sstefanf
4311573Srgrimes/* history_def_delete():
4321573Srgrimes *	Delete element hp of the h list
4331573Srgrimes */
43484260Sobrien/* ARGSUSED */
4351573Srgrimesprivate void
436148834Sstefanfhistory_def_delete(history_t *h,
437148834Sstefanf		   HistEvent *ev __unused, hentry_t *hp)
4381573Srgrimes{
439148834Sstefanf	HistEventPrivate *evp = (void *)&hp->ev;
44084260Sobrien	if (hp == &h->list)
44184260Sobrien		abort();
442237448Spfg	if (h->cursor == hp) {
443148834Sstefanf		h->cursor = hp->prev;
444237448Spfg		if (h->cursor == &h->list)
445237448Spfg			h->cursor = hp->next;
446237448Spfg	}
44784260Sobrien	hp->prev->next = hp->next;
44884260Sobrien	hp->next->prev = hp->prev;
449148834Sstefanf	h_free((ptr_t) evp->str);
45084260Sobrien	h_free(hp);
45184260Sobrien	h->cur--;
4521573Srgrimes}
4531573Srgrimes
4541573Srgrimes
4551573Srgrimes/* history_def_insert():
4561573Srgrimes *	Insert element with string str in the h list
4571573Srgrimes */
45884260Sobrienprivate int
45984260Sobrienhistory_def_insert(history_t *h, HistEvent *ev, const char *str)
4601573Srgrimes{
4611573Srgrimes
46284260Sobrien	h->cursor = (hentry_t *) h_malloc(sizeof(hentry_t));
463148834Sstefanf	if (h->cursor == NULL)
464148834Sstefanf		goto oomem;
465148834Sstefanf	if ((h->cursor->ev.str = h_strdup(str)) == NULL) {
466148834Sstefanf		h_free((ptr_t)h->cursor);
467148834Sstefanf		goto oomem;
46884260Sobrien	}
469237448Spfg	h->cursor->data = NULL;
47084260Sobrien	h->cursor->ev.num = ++h->eventid;
47184260Sobrien	h->cursor->next = h->list.next;
47284260Sobrien	h->cursor->prev = &h->list;
47384260Sobrien	h->list.next->prev = h->cursor;
47484260Sobrien	h->list.next = h->cursor;
47584260Sobrien	h->cur++;
47684260Sobrien
47784260Sobrien	*ev = h->cursor->ev;
47884260Sobrien	return (0);
479148834Sstefanfoomem:
480148834Sstefanf	he_seterrev(ev, _HE_MALLOC_FAILED);
481148834Sstefanf	return (-1);
4821573Srgrimes}
4831573Srgrimes
4841573Srgrimes
4851573Srgrimes/* history_def_enter():
4861573Srgrimes *	Default function to enter an item in the history
4871573Srgrimes */
48884260Sobrienprivate int
48984260Sobrienhistory_def_enter(ptr_t p, HistEvent *ev, const char *str)
4901573Srgrimes{
49184260Sobrien	history_t *h = (history_t *) p;
4921573Srgrimes
493148834Sstefanf	if ((h->flags & H_UNIQUE) != 0 && h->list.next != &h->list &&
494148834Sstefanf	    strcmp(h->list.next->ev.str, str) == 0)
495148834Sstefanf	    return (0);
496148834Sstefanf
49784260Sobrien	if (history_def_insert(h, ev, str) == -1)
49884260Sobrien		return (-1);	/* error, keep error message */
4991573Srgrimes
50084260Sobrien	/*
50184260Sobrien         * Always keep at least one entry.
50284260Sobrien         * This way we don't have to check for the empty list.
50384260Sobrien         */
504148834Sstefanf	while (h->cur > h->max && h->cur > 0)
50584260Sobrien		history_def_delete(h, ev, h->list.prev);
5061573Srgrimes
507148834Sstefanf	return (1);
5081573Srgrimes}
5091573Srgrimes
5101573Srgrimes
5111573Srgrimes/* history_def_init():
5121573Srgrimes *	Default history initialization function
5131573Srgrimes */
51484260Sobrien/* ARGSUSED */
515148834Sstefanfprivate int
516148834Sstefanfhistory_def_init(ptr_t *p, HistEvent *ev __unused, int n)
5171573Srgrimes{
51884260Sobrien	history_t *h = (history_t *) h_malloc(sizeof(history_t));
519148834Sstefanf	if (h == NULL)
520148834Sstefanf		return -1;
52184260Sobrien
52284260Sobrien	if (n <= 0)
52384260Sobrien		n = 0;
52484260Sobrien	h->eventid = 0;
52584260Sobrien	h->cur = 0;
52684260Sobrien	h->max = n;
52784260Sobrien	h->list.next = h->list.prev = &h->list;
52884260Sobrien	h->list.ev.str = NULL;
52984260Sobrien	h->list.ev.num = 0;
53084260Sobrien	h->cursor = &h->list;
531148834Sstefanf	h->flags = 0;
53284260Sobrien	*p = (ptr_t) h;
533148834Sstefanf	return 0;
5341573Srgrimes}
5351573Srgrimes
5361573Srgrimes
53726926Smsmith/* history_def_clear():
5381573Srgrimes *	Default history cleanup function
5391573Srgrimes */
5401573Srgrimesprivate void
54184260Sobrienhistory_def_clear(ptr_t p, HistEvent *ev)
5421573Srgrimes{
54384260Sobrien	history_t *h = (history_t *) p;
5441573Srgrimes
54584260Sobrien	while (h->list.prev != &h->list)
54684260Sobrien		history_def_delete(h, ev, h->list.prev);
54784260Sobrien	h->eventid = 0;
54884260Sobrien	h->cur = 0;
5491573Srgrimes}
5501573Srgrimes
55184260Sobrien
55284260Sobrien
55384260Sobrien
5541573Srgrimes/************************************************************************/
5551573Srgrimes
5561573Srgrimes/* history_init():
5571573Srgrimes *	Initialization function.
5581573Srgrimes */
5591573Srgrimespublic History *
56084260Sobrienhistory_init(void)
5611573Srgrimes{
562148834Sstefanf	HistEvent ev;
56384260Sobrien	History *h = (History *) h_malloc(sizeof(History));
564148834Sstefanf	if (h == NULL)
565148834Sstefanf		return NULL;
5661573Srgrimes
567148834Sstefanf	if (history_def_init(&h->h_ref, &ev, 0) == -1) {
568148834Sstefanf		h_free((ptr_t)h);
569148834Sstefanf		return NULL;
570148834Sstefanf	}
57184260Sobrien	h->h_ent = -1;
57284260Sobrien	h->h_next = history_def_next;
57384260Sobrien	h->h_first = history_def_first;
57484260Sobrien	h->h_last = history_def_last;
57584260Sobrien	h->h_prev = history_def_prev;
57684260Sobrien	h->h_curr = history_def_curr;
57784260Sobrien	h->h_set = history_def_set;
57884260Sobrien	h->h_clear = history_def_clear;
57984260Sobrien	h->h_enter = history_def_enter;
58084260Sobrien	h->h_add = history_def_add;
581148834Sstefanf	h->h_del = history_def_del;
5821573Srgrimes
58384260Sobrien	return (h);
5841573Srgrimes}
5851573Srgrimes
5861573Srgrimes
5871573Srgrimes/* history_end():
5881573Srgrimes *	clean up history;
5891573Srgrimes */
5901573Srgrimespublic void
59184260Sobrienhistory_end(History *h)
5921573Srgrimes{
59384260Sobrien	HistEvent ev;
59484260Sobrien
59584260Sobrien	if (h->h_next == history_def_next)
59684260Sobrien		history_def_clear(h->h_ref, &ev);
597167464Sstefanf	h_free(h->h_ref);
598148834Sstefanf	h_free(h);
5991573Srgrimes}
6001573Srgrimes
6011573Srgrimes
6021573Srgrimes
60384260Sobrien/* history_setsize():
6041573Srgrimes *	Set history number of events
6051573Srgrimes */
6061573Srgrimesprivate int
60784260Sobrienhistory_setsize(History *h, HistEvent *ev, int num)
6081573Srgrimes{
60984260Sobrien
61084260Sobrien	if (h->h_next != history_def_next) {
61184260Sobrien		he_seterrev(ev, _HE_NOT_ALLOWED);
61284260Sobrien		return (-1);
61384260Sobrien	}
61484260Sobrien	if (num < 0) {
61584260Sobrien		he_seterrev(ev, _HE_BAD_PARAM);
61684260Sobrien		return (-1);
61784260Sobrien	}
61884260Sobrien	history_def_setsize(h->h_ref, num);
61984260Sobrien	return (0);
6201573Srgrimes}
6211573Srgrimes
6221573Srgrimes
62384260Sobrien/* history_getsize():
62484260Sobrien *      Get number of events currently in history
62584260Sobrien */
62684260Sobrienprivate int
62784260Sobrienhistory_getsize(History *h, HistEvent *ev)
62884260Sobrien{
62984260Sobrien	if (h->h_next != history_def_next) {
63084260Sobrien		he_seterrev(ev, _HE_NOT_ALLOWED);
63184260Sobrien		return (-1);
63284260Sobrien	}
633148834Sstefanf	ev->num = history_def_getsize(h->h_ref);
634148834Sstefanf	if (ev->num < -1) {
63584260Sobrien		he_seterrev(ev, _HE_SIZE_NEGATIVE);
63684260Sobrien		return (-1);
63784260Sobrien	}
63884260Sobrien	return (0);
63984260Sobrien}
64084260Sobrien
64184260Sobrien
642148834Sstefanf/* history_setunique():
643148834Sstefanf *	Set if adjacent equal events should not be entered in history.
644148834Sstefanf */
645148834Sstefanfprivate int
646148834Sstefanfhistory_setunique(History *h, HistEvent *ev, int uni)
647148834Sstefanf{
648148834Sstefanf
649148834Sstefanf	if (h->h_next != history_def_next) {
650148834Sstefanf		he_seterrev(ev, _HE_NOT_ALLOWED);
651148834Sstefanf		return (-1);
652148834Sstefanf	}
653148834Sstefanf	history_def_setunique(h->h_ref, uni);
654148834Sstefanf	return (0);
655148834Sstefanf}
656148834Sstefanf
657148834Sstefanf
658148834Sstefanf/* history_getunique():
659148834Sstefanf *	Get if adjacent equal events should not be entered in history.
660148834Sstefanf */
661148834Sstefanfprivate int
662148834Sstefanfhistory_getunique(History *h, HistEvent *ev)
663148834Sstefanf{
664148834Sstefanf	if (h->h_next != history_def_next) {
665148834Sstefanf		he_seterrev(ev, _HE_NOT_ALLOWED);
666148834Sstefanf		return (-1);
667148834Sstefanf	}
668148834Sstefanf	ev->num = history_def_getunique(h->h_ref);
669148834Sstefanf	return (0);
670148834Sstefanf}
671148834Sstefanf
672148834Sstefanf
6731573Srgrimes/* history_set_fun():
6741573Srgrimes *	Set history functions
6751573Srgrimes */
6761573Srgrimesprivate int
67784260Sobrienhistory_set_fun(History *h, History *nh)
6781573Srgrimes{
67984260Sobrien	HistEvent ev;
68084260Sobrien
68184260Sobrien	if (nh->h_first == NULL || nh->h_next == NULL || nh->h_last == NULL ||
68284260Sobrien	    nh->h_prev == NULL || nh->h_curr == NULL || nh->h_set == NULL ||
68384260Sobrien	    nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL ||
684148834Sstefanf	    nh->h_del == NULL || nh->h_ref == NULL) {
68584260Sobrien		if (h->h_next != history_def_next) {
68684260Sobrien			history_def_init(&h->h_ref, &ev, 0);
68784260Sobrien			h->h_first = history_def_first;
68884260Sobrien			h->h_next = history_def_next;
68984260Sobrien			h->h_last = history_def_last;
69084260Sobrien			h->h_prev = history_def_prev;
69184260Sobrien			h->h_curr = history_def_curr;
69284260Sobrien			h->h_set = history_def_set;
69384260Sobrien			h->h_clear = history_def_clear;
69484260Sobrien			h->h_enter = history_def_enter;
69584260Sobrien			h->h_add = history_def_add;
696148834Sstefanf			h->h_del = history_def_del;
69784260Sobrien		}
69884260Sobrien		return (-1);
6991573Srgrimes	}
70084260Sobrien	if (h->h_next == history_def_next)
70184260Sobrien		history_def_clear(h->h_ref, &ev);
7021573Srgrimes
70384260Sobrien	h->h_ent = -1;
70484260Sobrien	h->h_first = nh->h_first;
70584260Sobrien	h->h_next = nh->h_next;
70684260Sobrien	h->h_last = nh->h_last;
70784260Sobrien	h->h_prev = nh->h_prev;
70884260Sobrien	h->h_curr = nh->h_curr;
70984260Sobrien	h->h_set = nh->h_set;
71084260Sobrien	h->h_clear = nh->h_clear;
71184260Sobrien	h->h_enter = nh->h_enter;
71284260Sobrien	h->h_add = nh->h_add;
713148834Sstefanf	h->h_del = nh->h_del;
7141573Srgrimes
71584260Sobrien	return (0);
7161573Srgrimes}
7171573Srgrimes
7181573Srgrimes
71926926Smsmith/* history_load():
72026926Smsmith *	History load function
72126926Smsmith */
72226926Smsmithprivate int
72384260Sobrienhistory_load(History *h, const char *fname)
72426926Smsmith{
72584260Sobrien	FILE *fp;
72684260Sobrien	char *line;
72784260Sobrien	size_t sz, max_size;
72884260Sobrien	char *ptr;
72984260Sobrien	int i = -1;
73084260Sobrien	HistEvent ev;
73126926Smsmith
73284260Sobrien	if ((fp = fopen(fname, "r")) == NULL)
73384260Sobrien		return (i);
73426926Smsmith
73584260Sobrien	if ((line = fgetln(fp, &sz)) == NULL)
73684260Sobrien		goto done;
73726926Smsmith
73884260Sobrien	if (strncmp(line, hist_cookie, sz) != 0)
73984260Sobrien		goto done;
74026926Smsmith
74184260Sobrien	ptr = h_malloc(max_size = 1024);
742148834Sstefanf	if (ptr == NULL)
743148834Sstefanf		goto done;
74484260Sobrien	for (i = 0; (line = fgetln(fp, &sz)) != NULL; i++) {
74584260Sobrien		char c = line[sz];
74684260Sobrien
74784260Sobrien		if (sz != 0 && line[sz - 1] == '\n')
74884260Sobrien			line[--sz] = '\0';
74984260Sobrien		else
75084260Sobrien			line[sz] = '\0';
75184260Sobrien
75284260Sobrien		if (max_size < sz) {
753148834Sstefanf			char *nptr;
754148834Sstefanf			max_size = (sz + 1024) & ~1023;
755148834Sstefanf			nptr = h_realloc(ptr, max_size);
756148834Sstefanf			if (nptr == NULL) {
757148834Sstefanf				i = -1;
758148834Sstefanf				goto oomem;
759148834Sstefanf			}
760148834Sstefanf			ptr = nptr;
76184260Sobrien		}
76284260Sobrien		(void) strunvis(ptr, line);
76384260Sobrien		line[sz] = c;
764148834Sstefanf		if (HENTER(h, &ev, ptr) == -1) {
765237448Spfg			i = -1;
766237448Spfg			goto oomem;
767148834Sstefanf		}
76884260Sobrien	}
769148834Sstefanfoomem:
770148834Sstefanf	h_free((ptr_t)ptr);
77126926Smsmithdone:
77284260Sobrien	(void) fclose(fp);
77384260Sobrien	return (i);
77426926Smsmith}
77526926Smsmith
77626926Smsmith
77726926Smsmith/* history_save():
77826926Smsmith *	History save function
77926926Smsmith */
78026926Smsmithprivate int
78184260Sobrienhistory_save(History *h, const char *fname)
78226926Smsmith{
78384260Sobrien	FILE *fp;
78484260Sobrien	HistEvent ev;
785148834Sstefanf	int i = -1, retval;
78684260Sobrien	size_t len, max_size;
78784260Sobrien	char *ptr;
78826926Smsmith
78984260Sobrien	if ((fp = fopen(fname, "w")) == NULL)
79084260Sobrien		return (-1);
79126926Smsmith
792148834Sstefanf	if (fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1)
793148834Sstefanf		goto done;
794148834Sstefanf	if (fputs(hist_cookie, fp) == EOF)
795148834Sstefanf		goto done;
79684260Sobrien	ptr = h_malloc(max_size = 1024);
797148834Sstefanf	if (ptr == NULL)
798148834Sstefanf		goto done;
799148834Sstefanf	for (i = 0, retval = HLAST(h, &ev);
80084260Sobrien	    retval != -1;
80184260Sobrien	    retval = HPREV(h, &ev), i++) {
80284260Sobrien		len = strlen(ev.str) * 4;
80384260Sobrien		if (len >= max_size) {
804148834Sstefanf			char *nptr;
805148834Sstefanf			max_size = (len + 1024) & ~1023;
806148834Sstefanf			nptr = h_realloc(ptr, max_size);
807148834Sstefanf			if (nptr == NULL) {
808148834Sstefanf				i = -1;
809148834Sstefanf				goto oomem;
810148834Sstefanf			}
811148834Sstefanf			ptr = nptr;
81284260Sobrien		}
81384260Sobrien		(void) strvis(ptr, ev.str, VIS_WHITE);
814105095Stjr		(void) fprintf(fp, "%s\n", ptr);
81584260Sobrien	}
816148834Sstefanfoomem:
817148834Sstefanf	h_free((ptr_t)ptr);
818148834Sstefanfdone:
81984260Sobrien	(void) fclose(fp);
82084260Sobrien	return (i);
82126926Smsmith}
82226926Smsmith
82326926Smsmith
8241573Srgrimes/* history_prev_event():
8251573Srgrimes *	Find the previous event, with number given
8261573Srgrimes */
82784260Sobrienprivate int
82884260Sobrienhistory_prev_event(History *h, HistEvent *ev, int num)
8291573Srgrimes{
83084260Sobrien	int retval;
83184260Sobrien
83284260Sobrien	for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
83384260Sobrien		if (ev->num == num)
83484260Sobrien			return (0);
83584260Sobrien
83684260Sobrien	he_seterrev(ev, _HE_NOT_FOUND);
83784260Sobrien	return (-1);
8381573Srgrimes}
8391573Srgrimes
8401573Srgrimes
841237448Spfgprivate int
842237448Spfghistory_next_evdata(History *h, HistEvent *ev, int num, void **d)
843237448Spfg{
844237448Spfg	int retval;
845237448Spfg
846237448Spfg	for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
847237448Spfg		if (num-- <= 0) {
848237448Spfg			if (d)
849237448Spfg				*d = ((history_t *)h->h_ref)->cursor->data;
850237448Spfg			return (0);
851237448Spfg		}
852237448Spfg
853237448Spfg	he_seterrev(ev, _HE_NOT_FOUND);
854237448Spfg	return (-1);
855237448Spfg}
856237448Spfg
857237448Spfg
8581573Srgrimes/* history_next_event():
8591573Srgrimes *	Find the next event, with number given
8601573Srgrimes */
86184260Sobrienprivate int
86284260Sobrienhistory_next_event(History *h, HistEvent *ev, int num)
8631573Srgrimes{
86484260Sobrien	int retval;
86584260Sobrien
86684260Sobrien	for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
86784260Sobrien		if (ev->num == num)
86884260Sobrien			return (0);
86984260Sobrien
87084260Sobrien	he_seterrev(ev, _HE_NOT_FOUND);
87184260Sobrien	return (-1);
8721573Srgrimes}
8731573Srgrimes
8741573Srgrimes
8751573Srgrimes/* history_prev_string():
8761573Srgrimes *	Find the previous event beginning with string
8771573Srgrimes */
87884260Sobrienprivate int
87984260Sobrienhistory_prev_string(History *h, HistEvent *ev, const char *str)
8801573Srgrimes{
88184260Sobrien	size_t len = strlen(str);
88284260Sobrien	int retval;
8831573Srgrimes
88484260Sobrien	for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
88584260Sobrien		if (strncmp(str, ev->str, len) == 0)
88684260Sobrien			return (0);
88784260Sobrien
88884260Sobrien	he_seterrev(ev, _HE_NOT_FOUND);
88984260Sobrien	return (-1);
8901573Srgrimes}
8911573Srgrimes
8921573Srgrimes
8931573Srgrimes/* history_next_string():
8941573Srgrimes *	Find the next event beginning with string
8951573Srgrimes */
89684260Sobrienprivate int
89784260Sobrienhistory_next_string(History *h, HistEvent *ev, const char *str)
8981573Srgrimes{
89984260Sobrien	size_t len = strlen(str);
90084260Sobrien	int retval;
9011573Srgrimes
90284260Sobrien	for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
90384260Sobrien		if (strncmp(str, ev->str, len) == 0)
90484260Sobrien			return (0);
90584260Sobrien
90684260Sobrien	he_seterrev(ev, _HE_NOT_FOUND);
90784260Sobrien	return (-1);
9081573Srgrimes}
9091573Srgrimes
9101573Srgrimes
9111573Srgrimes/* history():
9121573Srgrimes *	User interface to history functions.
9131573Srgrimes */
91484260Sobrienint
91584260Sobrienhistory(History *h, HistEvent *ev, int fun, ...)
9161573Srgrimes{
91784260Sobrien	va_list va;
91884260Sobrien	const char *str;
91984260Sobrien	int retval;
9201573Srgrimes
92184260Sobrien	va_start(va, fun);
9221573Srgrimes
92384260Sobrien	he_seterrev(ev, _HE_OK);
9241573Srgrimes
92584260Sobrien	switch (fun) {
92684260Sobrien	case H_GETSIZE:
92784260Sobrien		retval = history_getsize(h, ev);
92884260Sobrien		break;
9291573Srgrimes
93084260Sobrien	case H_SETSIZE:
93184260Sobrien		retval = history_setsize(h, ev, va_arg(va, int));
93284260Sobrien		break;
9331573Srgrimes
934148834Sstefanf	case H_GETUNIQUE:
935148834Sstefanf		retval = history_getunique(h, ev);
936148834Sstefanf		break;
937148834Sstefanf
938148834Sstefanf	case H_SETUNIQUE:
939148834Sstefanf		retval = history_setunique(h, ev, va_arg(va, int));
940148834Sstefanf		break;
941148834Sstefanf
94284260Sobrien	case H_ADD:
94384260Sobrien		str = va_arg(va, const char *);
94484260Sobrien		retval = HADD(h, ev, str);
94584260Sobrien		break;
9461573Srgrimes
947148834Sstefanf	case H_DEL:
948148834Sstefanf		retval = HDEL(h, ev, va_arg(va, const int));
949148834Sstefanf		break;
950148834Sstefanf
95184260Sobrien	case H_ENTER:
95284260Sobrien		str = va_arg(va, const char *);
95384260Sobrien		if ((retval = HENTER(h, ev, str)) != -1)
95484260Sobrien			h->h_ent = ev->num;
95584260Sobrien		break;
9561573Srgrimes
95784260Sobrien	case H_APPEND:
95884260Sobrien		str = va_arg(va, const char *);
95984260Sobrien		if ((retval = HSET(h, ev, h->h_ent)) != -1)
96084260Sobrien			retval = HADD(h, ev, str);
96184260Sobrien		break;
9621573Srgrimes
96384260Sobrien	case H_FIRST:
96484260Sobrien		retval = HFIRST(h, ev);
96584260Sobrien		break;
9661573Srgrimes
96784260Sobrien	case H_NEXT:
96884260Sobrien		retval = HNEXT(h, ev);
96984260Sobrien		break;
97026926Smsmith
97184260Sobrien	case H_LAST:
97284260Sobrien		retval = HLAST(h, ev);
97384260Sobrien		break;
9741573Srgrimes
97584260Sobrien	case H_PREV:
97684260Sobrien		retval = HPREV(h, ev);
97784260Sobrien		break;
9781573Srgrimes
97984260Sobrien	case H_CURR:
98084260Sobrien		retval = HCURR(h, ev);
98184260Sobrien		break;
9821573Srgrimes
98384260Sobrien	case H_SET:
98484260Sobrien		retval = HSET(h, ev, va_arg(va, const int));
98584260Sobrien		break;
9861573Srgrimes
98784260Sobrien	case H_CLEAR:
98884260Sobrien		HCLEAR(h, ev);
98984260Sobrien		retval = 0;
99084260Sobrien		break;
9911573Srgrimes
99284260Sobrien	case H_LOAD:
99384260Sobrien		retval = history_load(h, va_arg(va, const char *));
99484260Sobrien		if (retval == -1)
99584260Sobrien			he_seterrev(ev, _HE_HIST_READ);
99684260Sobrien		break;
99784260Sobrien
99884260Sobrien	case H_SAVE:
99984260Sobrien		retval = history_save(h, va_arg(va, const char *));
100084260Sobrien		if (retval == -1)
100184260Sobrien			he_seterrev(ev, _HE_HIST_WRITE);
100284260Sobrien		break;
100384260Sobrien
100484260Sobrien	case H_PREV_EVENT:
100584260Sobrien		retval = history_prev_event(h, ev, va_arg(va, int));
100684260Sobrien		break;
100784260Sobrien
100884260Sobrien	case H_NEXT_EVENT:
100984260Sobrien		retval = history_next_event(h, ev, va_arg(va, int));
101084260Sobrien		break;
101184260Sobrien
101284260Sobrien	case H_PREV_STR:
101384260Sobrien		retval = history_prev_string(h, ev, va_arg(va, const char *));
101484260Sobrien		break;
101584260Sobrien
101684260Sobrien	case H_NEXT_STR:
101784260Sobrien		retval = history_next_string(h, ev, va_arg(va, const char *));
101884260Sobrien		break;
101984260Sobrien
102084260Sobrien	case H_FUNC:
10211573Srgrimes	{
102284260Sobrien		History hf;
10231573Srgrimes
102484260Sobrien		hf.h_ref = va_arg(va, ptr_t);
102584260Sobrien		h->h_ent = -1;
102684260Sobrien		hf.h_first = va_arg(va, history_gfun_t);
102784260Sobrien		hf.h_next = va_arg(va, history_gfun_t);
102884260Sobrien		hf.h_last = va_arg(va, history_gfun_t);
102984260Sobrien		hf.h_prev = va_arg(va, history_gfun_t);
103084260Sobrien		hf.h_curr = va_arg(va, history_gfun_t);
103184260Sobrien		hf.h_set = va_arg(va, history_sfun_t);
103284260Sobrien		hf.h_clear = va_arg(va, history_vfun_t);
103384260Sobrien		hf.h_enter = va_arg(va, history_efun_t);
103484260Sobrien		hf.h_add = va_arg(va, history_efun_t);
1035148834Sstefanf		hf.h_del = va_arg(va, history_sfun_t);
103684260Sobrien
103784260Sobrien		if ((retval = history_set_fun(h, &hf)) == -1)
103884260Sobrien			he_seterrev(ev, _HE_PARAM_MISSING);
103984260Sobrien		break;
10401573Srgrimes	}
10411573Srgrimes
104284260Sobrien	case H_END:
104384260Sobrien		history_end(h);
104484260Sobrien		retval = 0;
104584260Sobrien		break;
10461573Srgrimes
1047237448Spfg	case H_NEXT_EVDATA:
1048237448Spfg	{
1049237448Spfg		int num = va_arg(va, int);
1050237448Spfg		void **d = va_arg(va, void **);
1051237448Spfg		retval = history_next_evdata(h, ev, num, d);
1052237448Spfg		break;
1053237448Spfg	}
1054237448Spfg
1055237448Spfg	case H_DELDATA:
1056237448Spfg	{
1057237448Spfg		int num = va_arg(va, int);
1058237448Spfg		void **d = va_arg(va, void **);
1059237448Spfg		retval = history_deldata_nth((history_t *)h->h_ref, ev, num, d);
1060237448Spfg		break;
1061237448Spfg	}
1062237448Spfg
1063237448Spfg	case H_REPLACE: /* only use after H_NEXT_EVDATA */
1064237448Spfg	{
1065237448Spfg		const char *line = va_arg(va, const char *);
1066237448Spfg		void *d = va_arg(va, void *);
1067237448Spfg		const char *s;
1068237448Spfg		if(!line || !(s = strdup(line))) {
1069237448Spfg			retval = -1;
1070237448Spfg			break;
1071237448Spfg		}
1072237448Spfg		((history_t *)h->h_ref)->cursor->ev.str = s;
1073237448Spfg		((history_t *)h->h_ref)->cursor->data = d;
1074237448Spfg		retval = 0;
1075237448Spfg		break;
1076237448Spfg	}
1077237448Spfg
107884260Sobrien	default:
107984260Sobrien		retval = -1;
108084260Sobrien		he_seterrev(ev, _HE_UNKNOWN);
108184260Sobrien		break;
108284260Sobrien	}
108384260Sobrien	va_end(va);
1084237448Spfg	return retval;
10851573Srgrimes}
1086