xref: /dflybsd-src/contrib/libedit/src/history.c (revision 60ecde0cdffa503f18fd5ad9437b34567263aecf)
1*60ecde0cSDaniel Fojt /*	$NetBSD: history.c,v 1.63 2019/10/08 19:17:57 christos Exp $	*/
232fe07f8SJohn Marino 
332fe07f8SJohn Marino /*-
432fe07f8SJohn Marino  * Copyright (c) 1992, 1993
532fe07f8SJohn Marino  *	The Regents of the University of California.  All rights reserved.
632fe07f8SJohn Marino  *
732fe07f8SJohn Marino  * This code is derived from software contributed to Berkeley by
832fe07f8SJohn Marino  * Christos Zoulas of Cornell University.
932fe07f8SJohn Marino  *
1032fe07f8SJohn Marino  * Redistribution and use in source and binary forms, with or without
1132fe07f8SJohn Marino  * modification, are permitted provided that the following conditions
1232fe07f8SJohn Marino  * are met:
1332fe07f8SJohn Marino  * 1. Redistributions of source code must retain the above copyright
1432fe07f8SJohn Marino  *    notice, this list of conditions and the following disclaimer.
1532fe07f8SJohn Marino  * 2. Redistributions in binary form must reproduce the above copyright
1632fe07f8SJohn Marino  *    notice, this list of conditions and the following disclaimer in the
1732fe07f8SJohn Marino  *    documentation and/or other materials provided with the distribution.
1832fe07f8SJohn Marino  * 3. Neither the name of the University nor the names of its contributors
1932fe07f8SJohn Marino  *    may be used to endorse or promote products derived from this software
2032fe07f8SJohn Marino  *    without specific prior written permission.
2132fe07f8SJohn Marino  *
2232fe07f8SJohn Marino  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2332fe07f8SJohn Marino  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2432fe07f8SJohn Marino  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2532fe07f8SJohn Marino  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2632fe07f8SJohn Marino  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2732fe07f8SJohn Marino  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2832fe07f8SJohn Marino  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2932fe07f8SJohn Marino  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3032fe07f8SJohn Marino  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3132fe07f8SJohn Marino  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3232fe07f8SJohn Marino  * SUCH DAMAGE.
3332fe07f8SJohn Marino  */
3432fe07f8SJohn Marino 
3532fe07f8SJohn Marino #ifndef NARROWCHAR
3632fe07f8SJohn Marino #include "config.h"
3732fe07f8SJohn Marino #endif
3832fe07f8SJohn Marino 
3932fe07f8SJohn Marino #if !defined(lint) && !defined(SCCSID)
4032fe07f8SJohn Marino #if 0
4132fe07f8SJohn Marino static char sccsid[] = "@(#)history.c	8.1 (Berkeley) 6/4/93";
4232fe07f8SJohn Marino #else
43*60ecde0cSDaniel Fojt __RCSID("$NetBSD: history.c,v 1.63 2019/10/08 19:17:57 christos Exp $");
4432fe07f8SJohn Marino #endif
4532fe07f8SJohn Marino #endif /* not lint && not SCCSID */
4632fe07f8SJohn Marino 
4732fe07f8SJohn Marino /*
4832fe07f8SJohn Marino  * hist.c: TYPE(History) access functions
4932fe07f8SJohn Marino  */
5032fe07f8SJohn Marino #include <sys/stat.h>
5112db70c8Szrj #include <stdarg.h>
5212db70c8Szrj #include <stdlib.h>
5312db70c8Szrj #include <string.h>
5412db70c8Szrj #include <vis.h>
5532fe07f8SJohn Marino 
5632fe07f8SJohn Marino static const char hist_cookie[] = "_HiStOrY_V2_\n";
5732fe07f8SJohn Marino 
5832fe07f8SJohn Marino #include "histedit.h"
5912db70c8Szrj 
6012db70c8Szrj 
6112db70c8Szrj #ifdef NARROWCHAR
6212db70c8Szrj 
6312db70c8Szrj #define	Char			char
6412db70c8Szrj #define	FUN(prefix, rest)	prefix ## _ ## rest
6512db70c8Szrj #define	FUNW(type)		type
6612db70c8Szrj #define	TYPE(type)		type
6712db70c8Szrj #define	STR(x)			x
6812db70c8Szrj 
6912db70c8Szrj #define	Strlen(s)		strlen(s)
7012db70c8Szrj #define	Strdup(s)		strdup(s)
7112db70c8Szrj #define	Strcmp(d, s)		strcmp(d, s)
7212db70c8Szrj #define	Strncmp(d, s, n)	strncmp(d, s, n)
7312db70c8Szrj #define	Strncpy(d, s, n)	strncpy(d, s, n)
7412db70c8Szrj #define	Strncat(d, s, n)	strncat(d, s, n)
7512db70c8Szrj #define	ct_decode_string(s, b)	(s)
7612db70c8Szrj #define	ct_encode_string(s, b)	(s)
7712db70c8Szrj 
7812db70c8Szrj #else
7932fe07f8SJohn Marino #include "chartype.h"
8032fe07f8SJohn Marino 
8112db70c8Szrj #define	Char			wchar_t
8212db70c8Szrj #define	FUN(prefix, rest)	prefix ## _w ## rest
8312db70c8Szrj #define	FUNW(type)		type ## _w
8412db70c8Szrj #define	TYPE(type)		type ## W
8512db70c8Szrj #define	STR(x)			L ## x
8612db70c8Szrj 
8712db70c8Szrj #define	Strlen(s)		wcslen(s)
8812db70c8Szrj #define	Strdup(s)		wcsdup(s)
8912db70c8Szrj #define	Strcmp(d, s)		wcscmp(d, s)
9012db70c8Szrj #define	Strncmp(d, s, n)	wcsncmp(d, s, n)
9112db70c8Szrj #define	Strncpy(d, s, n)	wcsncpy(d, s, n)
9212db70c8Szrj #define	Strncat(d, s, n)	wcsncat(d, s, n)
9312db70c8Szrj 
9412db70c8Szrj #endif
9512db70c8Szrj 
9612db70c8Szrj 
9732fe07f8SJohn Marino typedef int (*history_gfun_t)(void *, TYPE(HistEvent) *);
9832fe07f8SJohn Marino typedef int (*history_efun_t)(void *, TYPE(HistEvent) *, const Char *);
9932fe07f8SJohn Marino typedef void (*history_vfun_t)(void *, TYPE(HistEvent) *);
10032fe07f8SJohn Marino typedef int (*history_sfun_t)(void *, TYPE(HistEvent) *, const int);
10132fe07f8SJohn Marino 
TYPE(history)10232fe07f8SJohn Marino struct TYPE(history) {
10332fe07f8SJohn Marino 	void *h_ref;		/* Argument for history fcns	 */
10432fe07f8SJohn Marino 	int h_ent;		/* Last entry point for history	 */
10532fe07f8SJohn Marino 	history_gfun_t h_first;	/* Get the first element	 */
10632fe07f8SJohn Marino 	history_gfun_t h_next;	/* Get the next element		 */
10732fe07f8SJohn Marino 	history_gfun_t h_last;	/* Get the last element		 */
10832fe07f8SJohn Marino 	history_gfun_t h_prev;	/* Get the previous element	 */
10932fe07f8SJohn Marino 	history_gfun_t h_curr;	/* Get the current element	 */
11032fe07f8SJohn Marino 	history_sfun_t h_set;	/* Set the current element	 */
11132fe07f8SJohn Marino 	history_sfun_t h_del;	/* Set the given element	 */
11232fe07f8SJohn Marino 	history_vfun_t h_clear;	/* Clear the history list	 */
11332fe07f8SJohn Marino 	history_efun_t h_enter;	/* Add an element		 */
11432fe07f8SJohn Marino 	history_efun_t h_add;	/* Append to an element		 */
11532fe07f8SJohn Marino };
11632fe07f8SJohn Marino 
11732fe07f8SJohn Marino #define	HNEXT(h, ev)		(*(h)->h_next)((h)->h_ref, ev)
11832fe07f8SJohn Marino #define	HFIRST(h, ev)		(*(h)->h_first)((h)->h_ref, ev)
11932fe07f8SJohn Marino #define	HPREV(h, ev)		(*(h)->h_prev)((h)->h_ref, ev)
12032fe07f8SJohn Marino #define	HLAST(h, ev)		(*(h)->h_last)((h)->h_ref, ev)
12132fe07f8SJohn Marino #define	HCURR(h, ev)		(*(h)->h_curr)((h)->h_ref, ev)
12232fe07f8SJohn Marino #define	HSET(h, ev, n)		(*(h)->h_set)((h)->h_ref, ev, n)
12332fe07f8SJohn Marino #define	HCLEAR(h, ev)		(*(h)->h_clear)((h)->h_ref, ev)
12432fe07f8SJohn Marino #define	HENTER(h, ev, str)	(*(h)->h_enter)((h)->h_ref, ev, str)
12532fe07f8SJohn Marino #define	HADD(h, ev, str)	(*(h)->h_add)((h)->h_ref, ev, str)
12632fe07f8SJohn Marino #define	HDEL(h, ev, n)		(*(h)->h_del)((h)->h_ref, ev, n)
12732fe07f8SJohn Marino 
12832fe07f8SJohn Marino #define	h_strdup(a)	Strdup(a)
12932fe07f8SJohn Marino #define	h_malloc(a)	malloc(a)
13032fe07f8SJohn Marino #define	h_realloc(a, b)	realloc((a), (b))
13132fe07f8SJohn Marino #define	h_free(a)	free(a)
13232fe07f8SJohn Marino 
13332fe07f8SJohn Marino typedef struct {
13432fe07f8SJohn Marino     int		num;
13532fe07f8SJohn Marino     Char	*str;
13632fe07f8SJohn Marino } HistEventPrivate;
13732fe07f8SJohn Marino 
13832fe07f8SJohn Marino 
13912db70c8Szrj static int history_setsize(TYPE(History) *, TYPE(HistEvent) *, int);
14012db70c8Szrj static int history_getsize(TYPE(History) *, TYPE(HistEvent) *);
14112db70c8Szrj static int history_setunique(TYPE(History) *, TYPE(HistEvent) *, int);
14212db70c8Szrj static int history_getunique(TYPE(History) *, TYPE(HistEvent) *);
14312db70c8Szrj static int history_set_fun(TYPE(History) *, TYPE(History) *);
14412db70c8Szrj static int history_load(TYPE(History) *, const char *);
14512db70c8Szrj static int history_save(TYPE(History) *, const char *);
146ae19eda8Szrj static int history_save_fp(TYPE(History) *, size_t, FILE *);
14712db70c8Szrj static int history_prev_event(TYPE(History) *, TYPE(HistEvent) *, int);
14812db70c8Szrj static int history_next_event(TYPE(History) *, TYPE(HistEvent) *, int);
14912db70c8Szrj static int history_next_string(TYPE(History) *, TYPE(HistEvent) *,
15012db70c8Szrj     const Char *);
15112db70c8Szrj static int history_prev_string(TYPE(History) *, TYPE(HistEvent) *,
15212db70c8Szrj     const Char *);
15332fe07f8SJohn Marino 
15432fe07f8SJohn Marino 
15532fe07f8SJohn Marino /***********************************************************************/
15632fe07f8SJohn Marino 
15732fe07f8SJohn Marino /*
15832fe07f8SJohn Marino  * Builtin- history implementation
15932fe07f8SJohn Marino  */
16032fe07f8SJohn Marino typedef struct hentry_t {
16132fe07f8SJohn Marino 	TYPE(HistEvent) ev;		/* What we return		 */
16232fe07f8SJohn Marino 	void *data;		/* data				 */
16332fe07f8SJohn Marino 	struct hentry_t *next;	/* Next entry			 */
16432fe07f8SJohn Marino 	struct hentry_t *prev;	/* Previous entry		 */
16532fe07f8SJohn Marino } hentry_t;
16632fe07f8SJohn Marino 
16732fe07f8SJohn Marino typedef struct history_t {
16832fe07f8SJohn Marino 	hentry_t list;		/* Fake list header element	*/
16932fe07f8SJohn Marino 	hentry_t *cursor;	/* Current element in the list	*/
17032fe07f8SJohn Marino 	int max;		/* Maximum number of events	*/
17132fe07f8SJohn Marino 	int cur;		/* Current number of events	*/
17232fe07f8SJohn Marino 	int eventid;		/* For generation of unique event id	 */
17332fe07f8SJohn Marino 	int flags;		/* TYPE(History) flags		*/
17432fe07f8SJohn Marino #define H_UNIQUE	1	/* Store only unique elements	*/
17532fe07f8SJohn Marino } history_t;
17632fe07f8SJohn Marino 
17712db70c8Szrj static int history_def_next(void *, TYPE(HistEvent) *);
17812db70c8Szrj static int history_def_first(void *, TYPE(HistEvent) *);
17912db70c8Szrj static int history_def_prev(void *, TYPE(HistEvent) *);
18012db70c8Szrj static int history_def_last(void *, TYPE(HistEvent) *);
18112db70c8Szrj static int history_def_curr(void *, TYPE(HistEvent) *);
18212db70c8Szrj static int history_def_set(void *, TYPE(HistEvent) *, const int);
18312db70c8Szrj static void history_def_clear(void *, TYPE(HistEvent) *);
18412db70c8Szrj static int history_def_enter(void *, TYPE(HistEvent) *, const Char *);
18512db70c8Szrj static int history_def_add(void *, TYPE(HistEvent) *, const Char *);
18612db70c8Szrj static int history_def_del(void *, TYPE(HistEvent) *, const int);
18732fe07f8SJohn Marino 
18812db70c8Szrj static int history_def_init(void **, TYPE(HistEvent) *, int);
18912db70c8Szrj static int history_def_insert(history_t *, TYPE(HistEvent) *, const Char *);
19012db70c8Szrj static void history_def_delete(history_t *, TYPE(HistEvent) *, hentry_t *);
19132fe07f8SJohn Marino 
19212db70c8Szrj static int history_deldata_nth(history_t *, TYPE(HistEvent) *, int, void **);
19312db70c8Szrj static int history_set_nth(void *, TYPE(HistEvent) *, int);
19432fe07f8SJohn Marino 
19532fe07f8SJohn Marino #define	history_def_setsize(p, num)(void) (((history_t *)p)->max = (num))
19632fe07f8SJohn Marino #define	history_def_getsize(p)  (((history_t *)p)->cur)
19732fe07f8SJohn Marino #define	history_def_getunique(p) (((((history_t *)p)->flags) & H_UNIQUE) != 0)
19832fe07f8SJohn Marino #define	history_def_setunique(p, uni) \
19932fe07f8SJohn Marino     if (uni) \
20032fe07f8SJohn Marino 	(((history_t *)p)->flags) |= H_UNIQUE; \
20132fe07f8SJohn Marino     else \
20232fe07f8SJohn Marino 	(((history_t *)p)->flags) &= ~H_UNIQUE
20332fe07f8SJohn Marino 
20432fe07f8SJohn Marino #define	he_strerror(code)	he_errlist[code]
20532fe07f8SJohn Marino #define	he_seterrev(evp, code)	{\
20632fe07f8SJohn Marino 				    evp->num = code;\
20732fe07f8SJohn Marino 				    evp->str = he_strerror(code);\
20832fe07f8SJohn Marino 				}
20932fe07f8SJohn Marino 
21032fe07f8SJohn Marino /* error messages */
21132fe07f8SJohn Marino static const Char *const he_errlist[] = {
21232fe07f8SJohn Marino 	STR("OK"),
21332fe07f8SJohn Marino 	STR("unknown error"),
21432fe07f8SJohn Marino 	STR("malloc() failed"),
21532fe07f8SJohn Marino 	STR("first event not found"),
21632fe07f8SJohn Marino 	STR("last event not found"),
21732fe07f8SJohn Marino 	STR("empty list"),
21832fe07f8SJohn Marino 	STR("no next event"),
21932fe07f8SJohn Marino 	STR("no previous event"),
22032fe07f8SJohn Marino 	STR("current event is invalid"),
22132fe07f8SJohn Marino 	STR("event not found"),
22232fe07f8SJohn Marino 	STR("can't read history from file"),
22332fe07f8SJohn Marino 	STR("can't write history"),
22432fe07f8SJohn Marino 	STR("required parameter(s) not supplied"),
22532fe07f8SJohn Marino 	STR("history size negative"),
22632fe07f8SJohn Marino 	STR("function not allowed with other history-functions-set the default"),
22732fe07f8SJohn Marino 	STR("bad parameters")
22832fe07f8SJohn Marino };
22932fe07f8SJohn Marino /* error codes */
23032fe07f8SJohn Marino #define	_HE_OK                   0
23132fe07f8SJohn Marino #define	_HE_UNKNOWN		 1
23232fe07f8SJohn Marino #define	_HE_MALLOC_FAILED        2
23332fe07f8SJohn Marino #define	_HE_FIRST_NOTFOUND       3
23432fe07f8SJohn Marino #define	_HE_LAST_NOTFOUND        4
23532fe07f8SJohn Marino #define	_HE_EMPTY_LIST           5
23632fe07f8SJohn Marino #define	_HE_END_REACHED          6
23732fe07f8SJohn Marino #define	_HE_START_REACHED	 7
23832fe07f8SJohn Marino #define	_HE_CURR_INVALID	 8
23932fe07f8SJohn Marino #define	_HE_NOT_FOUND		 9
24032fe07f8SJohn Marino #define	_HE_HIST_READ		10
24132fe07f8SJohn Marino #define	_HE_HIST_WRITE		11
24232fe07f8SJohn Marino #define	_HE_PARAM_MISSING	12
24332fe07f8SJohn Marino #define	_HE_SIZE_NEGATIVE	13
24432fe07f8SJohn Marino #define	_HE_NOT_ALLOWED		14
24532fe07f8SJohn Marino #define	_HE_BAD_PARAM		15
24632fe07f8SJohn Marino 
24732fe07f8SJohn Marino /* history_def_first():
24832fe07f8SJohn Marino  *	Default function to return the first event in the history.
24932fe07f8SJohn Marino  */
25012db70c8Szrj static int
history_def_first(void * p,TYPE (HistEvent)* ev)25132fe07f8SJohn Marino history_def_first(void *p, TYPE(HistEvent) *ev)
25232fe07f8SJohn Marino {
25332fe07f8SJohn Marino 	history_t *h = (history_t *) p;
25432fe07f8SJohn Marino 
25532fe07f8SJohn Marino 	h->cursor = h->list.next;
25632fe07f8SJohn Marino 	if (h->cursor != &h->list)
25732fe07f8SJohn Marino 		*ev = h->cursor->ev;
25832fe07f8SJohn Marino 	else {
25932fe07f8SJohn Marino 		he_seterrev(ev, _HE_FIRST_NOTFOUND);
26032fe07f8SJohn Marino 		return -1;
26132fe07f8SJohn Marino 	}
26232fe07f8SJohn Marino 
26332fe07f8SJohn Marino 	return 0;
26432fe07f8SJohn Marino }
26532fe07f8SJohn Marino 
26632fe07f8SJohn Marino 
26732fe07f8SJohn Marino /* history_def_last():
26832fe07f8SJohn Marino  *	Default function to return the last event in the history.
26932fe07f8SJohn Marino  */
27012db70c8Szrj static int
history_def_last(void * p,TYPE (HistEvent)* ev)27132fe07f8SJohn Marino history_def_last(void *p, TYPE(HistEvent) *ev)
27232fe07f8SJohn Marino {
27332fe07f8SJohn Marino 	history_t *h = (history_t *) p;
27432fe07f8SJohn Marino 
27532fe07f8SJohn Marino 	h->cursor = h->list.prev;
27632fe07f8SJohn Marino 	if (h->cursor != &h->list)
27732fe07f8SJohn Marino 		*ev = h->cursor->ev;
27832fe07f8SJohn Marino 	else {
27932fe07f8SJohn Marino 		he_seterrev(ev, _HE_LAST_NOTFOUND);
28032fe07f8SJohn Marino 		return -1;
28132fe07f8SJohn Marino 	}
28232fe07f8SJohn Marino 
28332fe07f8SJohn Marino 	return 0;
28432fe07f8SJohn Marino }
28532fe07f8SJohn Marino 
28632fe07f8SJohn Marino 
28732fe07f8SJohn Marino /* history_def_next():
28832fe07f8SJohn Marino  *	Default function to return the next event in the history.
28932fe07f8SJohn Marino  */
29012db70c8Szrj static int
history_def_next(void * p,TYPE (HistEvent)* ev)29132fe07f8SJohn Marino history_def_next(void *p, TYPE(HistEvent) *ev)
29232fe07f8SJohn Marino {
29332fe07f8SJohn Marino 	history_t *h = (history_t *) p;
29432fe07f8SJohn Marino 
29532fe07f8SJohn Marino 	if (h->cursor == &h->list) {
29632fe07f8SJohn Marino 		he_seterrev(ev, _HE_EMPTY_LIST);
29732fe07f8SJohn Marino 		return -1;
29832fe07f8SJohn Marino 	}
29932fe07f8SJohn Marino 
30032fe07f8SJohn Marino 	if (h->cursor->next == &h->list) {
30132fe07f8SJohn Marino 		he_seterrev(ev, _HE_END_REACHED);
30232fe07f8SJohn Marino 		return -1;
30332fe07f8SJohn Marino 	}
30432fe07f8SJohn Marino 
30532fe07f8SJohn Marino         h->cursor = h->cursor->next;
30632fe07f8SJohn Marino         *ev = h->cursor->ev;
30732fe07f8SJohn Marino 
30832fe07f8SJohn Marino 	return 0;
30932fe07f8SJohn Marino }
31032fe07f8SJohn Marino 
31132fe07f8SJohn Marino 
31232fe07f8SJohn Marino /* history_def_prev():
31332fe07f8SJohn Marino  *	Default function to return the previous event in the history.
31432fe07f8SJohn Marino  */
31512db70c8Szrj static int
history_def_prev(void * p,TYPE (HistEvent)* ev)31632fe07f8SJohn Marino history_def_prev(void *p, TYPE(HistEvent) *ev)
31732fe07f8SJohn Marino {
31832fe07f8SJohn Marino 	history_t *h = (history_t *) p;
31932fe07f8SJohn Marino 
32032fe07f8SJohn Marino 	if (h->cursor == &h->list) {
32132fe07f8SJohn Marino 		he_seterrev(ev,
32232fe07f8SJohn Marino 		    (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST);
32332fe07f8SJohn Marino 		return -1;
32432fe07f8SJohn Marino 	}
32532fe07f8SJohn Marino 
32632fe07f8SJohn Marino 	if (h->cursor->prev == &h->list) {
32732fe07f8SJohn Marino 		he_seterrev(ev, _HE_START_REACHED);
32832fe07f8SJohn Marino 		return -1;
32932fe07f8SJohn Marino 	}
33032fe07f8SJohn Marino 
33132fe07f8SJohn Marino         h->cursor = h->cursor->prev;
33232fe07f8SJohn Marino         *ev = h->cursor->ev;
33332fe07f8SJohn Marino 
33432fe07f8SJohn Marino 	return 0;
33532fe07f8SJohn Marino }
33632fe07f8SJohn Marino 
33732fe07f8SJohn Marino 
33832fe07f8SJohn Marino /* history_def_curr():
33932fe07f8SJohn Marino  *	Default function to return the current event in the history.
34032fe07f8SJohn Marino  */
34112db70c8Szrj static int
history_def_curr(void * p,TYPE (HistEvent)* ev)34232fe07f8SJohn Marino history_def_curr(void *p, TYPE(HistEvent) *ev)
34332fe07f8SJohn Marino {
34432fe07f8SJohn Marino 	history_t *h = (history_t *) p;
34532fe07f8SJohn Marino 
34632fe07f8SJohn Marino 	if (h->cursor != &h->list)
34732fe07f8SJohn Marino 		*ev = h->cursor->ev;
34832fe07f8SJohn Marino 	else {
34932fe07f8SJohn Marino 		he_seterrev(ev,
35032fe07f8SJohn Marino 		    (h->cur > 0) ? _HE_CURR_INVALID : _HE_EMPTY_LIST);
35132fe07f8SJohn Marino 		return -1;
35232fe07f8SJohn Marino 	}
35332fe07f8SJohn Marino 
35432fe07f8SJohn Marino 	return 0;
35532fe07f8SJohn Marino }
35632fe07f8SJohn Marino 
35732fe07f8SJohn Marino 
35832fe07f8SJohn Marino /* history_def_set():
35932fe07f8SJohn Marino  *	Default function to set the current event in the history to the
36032fe07f8SJohn Marino  *	given one.
36132fe07f8SJohn Marino  */
36212db70c8Szrj static int
history_def_set(void * p,TYPE (HistEvent)* ev,const int n)36332fe07f8SJohn Marino history_def_set(void *p, TYPE(HistEvent) *ev, const int n)
36432fe07f8SJohn Marino {
36532fe07f8SJohn Marino 	history_t *h = (history_t *) p;
36632fe07f8SJohn Marino 
36732fe07f8SJohn Marino 	if (h->cur == 0) {
36832fe07f8SJohn Marino 		he_seterrev(ev, _HE_EMPTY_LIST);
36932fe07f8SJohn Marino 		return -1;
37032fe07f8SJohn Marino 	}
37132fe07f8SJohn Marino 	if (h->cursor == &h->list || h->cursor->ev.num != n) {
37232fe07f8SJohn Marino 		for (h->cursor = h->list.next; h->cursor != &h->list;
37332fe07f8SJohn Marino 		    h->cursor = h->cursor->next)
37432fe07f8SJohn Marino 			if (h->cursor->ev.num == n)
37532fe07f8SJohn Marino 				break;
37632fe07f8SJohn Marino 	}
37732fe07f8SJohn Marino 	if (h->cursor == &h->list) {
37832fe07f8SJohn Marino 		he_seterrev(ev, _HE_NOT_FOUND);
37932fe07f8SJohn Marino 		return -1;
38032fe07f8SJohn Marino 	}
38132fe07f8SJohn Marino 	return 0;
38232fe07f8SJohn Marino }
38332fe07f8SJohn Marino 
38432fe07f8SJohn Marino 
38532fe07f8SJohn Marino /* history_set_nth():
38632fe07f8SJohn Marino  *	Default function to set the current event in the history to the
38732fe07f8SJohn Marino  *	n-th one.
38832fe07f8SJohn Marino  */
38912db70c8Szrj static int
history_set_nth(void * p,TYPE (HistEvent)* ev,int n)39032fe07f8SJohn Marino history_set_nth(void *p, TYPE(HistEvent) *ev, int n)
39132fe07f8SJohn Marino {
39232fe07f8SJohn Marino 	history_t *h = (history_t *) p;
39332fe07f8SJohn Marino 
39432fe07f8SJohn Marino 	if (h->cur == 0) {
39532fe07f8SJohn Marino 		he_seterrev(ev, _HE_EMPTY_LIST);
39632fe07f8SJohn Marino 		return -1;
39732fe07f8SJohn Marino 	}
39832fe07f8SJohn Marino 	for (h->cursor = h->list.prev; h->cursor != &h->list;
39932fe07f8SJohn Marino 	    h->cursor = h->cursor->prev)
40032fe07f8SJohn Marino 		if (n-- <= 0)
40132fe07f8SJohn Marino 			break;
40232fe07f8SJohn Marino 	if (h->cursor == &h->list) {
40332fe07f8SJohn Marino 		he_seterrev(ev, _HE_NOT_FOUND);
40432fe07f8SJohn Marino 		return -1;
40532fe07f8SJohn Marino 	}
40632fe07f8SJohn Marino 	return 0;
40732fe07f8SJohn Marino }
40832fe07f8SJohn Marino 
40932fe07f8SJohn Marino 
41032fe07f8SJohn Marino /* history_def_add():
41132fe07f8SJohn Marino  *	Append string to element
41232fe07f8SJohn Marino  */
41312db70c8Szrj static int
history_def_add(void * p,TYPE (HistEvent)* ev,const Char * str)41432fe07f8SJohn Marino history_def_add(void *p, TYPE(HistEvent) *ev, const Char *str)
41532fe07f8SJohn Marino {
41632fe07f8SJohn Marino 	history_t *h = (history_t *) p;
417*60ecde0cSDaniel Fojt 	size_t len, elen, slen;
41832fe07f8SJohn Marino 	Char *s;
41932fe07f8SJohn Marino 	HistEventPrivate *evp = (void *)&h->cursor->ev;
42032fe07f8SJohn Marino 
42132fe07f8SJohn Marino 	if (h->cursor == &h->list)
42232fe07f8SJohn Marino 		return history_def_enter(p, ev, str);
423*60ecde0cSDaniel Fojt 	elen = Strlen(evp->str);
424*60ecde0cSDaniel Fojt 	slen = Strlen(str);
425*60ecde0cSDaniel Fojt 	len = elen + slen + 1;
42632fe07f8SJohn Marino 	s = h_malloc(len * sizeof(*s));
42732fe07f8SJohn Marino 	if (s == NULL) {
42832fe07f8SJohn Marino 		he_seterrev(ev, _HE_MALLOC_FAILED);
42932fe07f8SJohn Marino 		return -1;
43032fe07f8SJohn Marino 	}
431*60ecde0cSDaniel Fojt 	memcpy(s, evp->str, elen * sizeof(*s));
432*60ecde0cSDaniel Fojt 	memcpy(s + elen, str, slen * sizeof(*s));
43332fe07f8SJohn Marino         s[len - 1] = '\0';
43432fe07f8SJohn Marino 	h_free(evp->str);
43532fe07f8SJohn Marino 	evp->str = s;
43632fe07f8SJohn Marino 	*ev = h->cursor->ev;
43732fe07f8SJohn Marino 	return 0;
43832fe07f8SJohn Marino }
43932fe07f8SJohn Marino 
44032fe07f8SJohn Marino 
44112db70c8Szrj static int
history_deldata_nth(history_t * h,TYPE (HistEvent)* ev,int num,void ** data)44232fe07f8SJohn Marino history_deldata_nth(history_t *h, TYPE(HistEvent) *ev,
44332fe07f8SJohn Marino     int num, void **data)
44432fe07f8SJohn Marino {
44532fe07f8SJohn Marino 	if (history_set_nth(h, ev, num) != 0)
44632fe07f8SJohn Marino 		return -1;
44732fe07f8SJohn Marino 	/* magic value to skip delete (just set to n-th history) */
44832fe07f8SJohn Marino 	if (data == (void **)-1)
44932fe07f8SJohn Marino 		return 0;
45032fe07f8SJohn Marino 	ev->str = Strdup(h->cursor->ev.str);
45132fe07f8SJohn Marino 	ev->num = h->cursor->ev.num;
45232fe07f8SJohn Marino 	if (data)
45332fe07f8SJohn Marino 		*data = h->cursor->data;
45432fe07f8SJohn Marino 	history_def_delete(h, ev, h->cursor);
45532fe07f8SJohn Marino 	return 0;
45632fe07f8SJohn Marino }
45732fe07f8SJohn Marino 
45832fe07f8SJohn Marino 
45932fe07f8SJohn Marino /* history_def_del():
46032fe07f8SJohn Marino  *	Delete element hp of the h list
46132fe07f8SJohn Marino  */
46232fe07f8SJohn Marino /* ARGSUSED */
46312db70c8Szrj static int
history_def_del(void * p,TYPE (HistEvent)* ev,const int num)46432fe07f8SJohn Marino history_def_del(void *p, TYPE(HistEvent) *ev __attribute__((__unused__)),
46532fe07f8SJohn Marino     const int num)
46632fe07f8SJohn Marino {
46732fe07f8SJohn Marino 	history_t *h = (history_t *) p;
46832fe07f8SJohn Marino 	if (history_def_set(h, ev, num) != 0)
46932fe07f8SJohn Marino 		return -1;
47032fe07f8SJohn Marino 	ev->str = Strdup(h->cursor->ev.str);
47132fe07f8SJohn Marino 	ev->num = h->cursor->ev.num;
47232fe07f8SJohn Marino 	history_def_delete(h, ev, h->cursor);
47332fe07f8SJohn Marino 	return 0;
47432fe07f8SJohn Marino }
47532fe07f8SJohn Marino 
47632fe07f8SJohn Marino 
47732fe07f8SJohn Marino /* history_def_delete():
47832fe07f8SJohn Marino  *	Delete element hp of the h list
47932fe07f8SJohn Marino  */
48032fe07f8SJohn Marino /* ARGSUSED */
48112db70c8Szrj static void
history_def_delete(history_t * h,TYPE (HistEvent)* ev,hentry_t * hp)48232fe07f8SJohn Marino history_def_delete(history_t *h,
48332fe07f8SJohn Marino 		   TYPE(HistEvent) *ev __attribute__((__unused__)), hentry_t *hp)
48432fe07f8SJohn Marino {
48532fe07f8SJohn Marino 	HistEventPrivate *evp = (void *)&hp->ev;
48632fe07f8SJohn Marino 	if (hp == &h->list)
48732fe07f8SJohn Marino 		abort();
48832fe07f8SJohn Marino 	if (h->cursor == hp) {
48932fe07f8SJohn Marino 		h->cursor = hp->prev;
49032fe07f8SJohn Marino 		if (h->cursor == &h->list)
49132fe07f8SJohn Marino 			h->cursor = hp->next;
49232fe07f8SJohn Marino 	}
49332fe07f8SJohn Marino 	hp->prev->next = hp->next;
49432fe07f8SJohn Marino 	hp->next->prev = hp->prev;
49532fe07f8SJohn Marino 	h_free(evp->str);
49632fe07f8SJohn Marino 	h_free(hp);
49732fe07f8SJohn Marino 	h->cur--;
49832fe07f8SJohn Marino }
49932fe07f8SJohn Marino 
50032fe07f8SJohn Marino 
50132fe07f8SJohn Marino /* history_def_insert():
50232fe07f8SJohn Marino  *	Insert element with string str in the h list
50332fe07f8SJohn Marino  */
50412db70c8Szrj static int
history_def_insert(history_t * h,TYPE (HistEvent)* ev,const Char * str)50532fe07f8SJohn Marino history_def_insert(history_t *h, TYPE(HistEvent) *ev, const Char *str)
50632fe07f8SJohn Marino {
50732fe07f8SJohn Marino 	hentry_t *c;
50832fe07f8SJohn Marino 
50932fe07f8SJohn Marino 	c = h_malloc(sizeof(*c));
51032fe07f8SJohn Marino 	if (c == NULL)
51132fe07f8SJohn Marino 		goto oomem;
51232fe07f8SJohn Marino 	if ((c->ev.str = h_strdup(str)) == NULL) {
51332fe07f8SJohn Marino 		h_free(c);
51432fe07f8SJohn Marino 		goto oomem;
51532fe07f8SJohn Marino 	}
51632fe07f8SJohn Marino 	c->data = NULL;
51732fe07f8SJohn Marino 	c->ev.num = ++h->eventid;
51832fe07f8SJohn Marino 	c->next = h->list.next;
51932fe07f8SJohn Marino 	c->prev = &h->list;
52032fe07f8SJohn Marino 	h->list.next->prev = c;
52132fe07f8SJohn Marino 	h->list.next = c;
52232fe07f8SJohn Marino 	h->cur++;
52332fe07f8SJohn Marino 	h->cursor = c;
52432fe07f8SJohn Marino 
52532fe07f8SJohn Marino 	*ev = c->ev;
52632fe07f8SJohn Marino 	return 0;
52732fe07f8SJohn Marino oomem:
52832fe07f8SJohn Marino 	he_seterrev(ev, _HE_MALLOC_FAILED);
52932fe07f8SJohn Marino 	return -1;
53032fe07f8SJohn Marino }
53132fe07f8SJohn Marino 
53232fe07f8SJohn Marino 
53332fe07f8SJohn Marino /* history_def_enter():
53432fe07f8SJohn Marino  *	Default function to enter an item in the history
53532fe07f8SJohn Marino  */
53612db70c8Szrj static int
history_def_enter(void * p,TYPE (HistEvent)* ev,const Char * str)53732fe07f8SJohn Marino history_def_enter(void *p, TYPE(HistEvent) *ev, const Char *str)
53832fe07f8SJohn Marino {
53932fe07f8SJohn Marino 	history_t *h = (history_t *) p;
54032fe07f8SJohn Marino 
54132fe07f8SJohn Marino 	if ((h->flags & H_UNIQUE) != 0 && h->list.next != &h->list &&
54232fe07f8SJohn Marino 	    Strcmp(h->list.next->ev.str, str) == 0)
54332fe07f8SJohn Marino 	    return 0;
54432fe07f8SJohn Marino 
54532fe07f8SJohn Marino 	if (history_def_insert(h, ev, str) == -1)
54632fe07f8SJohn Marino 		return -1;	/* error, keep error message */
54732fe07f8SJohn Marino 
54832fe07f8SJohn Marino 	/*
54932fe07f8SJohn Marino          * Always keep at least one entry.
55032fe07f8SJohn Marino          * This way we don't have to check for the empty list.
55132fe07f8SJohn Marino          */
55232fe07f8SJohn Marino 	while (h->cur > h->max && h->cur > 0)
55332fe07f8SJohn Marino 		history_def_delete(h, ev, h->list.prev);
55432fe07f8SJohn Marino 
55532fe07f8SJohn Marino 	return 1;
55632fe07f8SJohn Marino }
55732fe07f8SJohn Marino 
55832fe07f8SJohn Marino 
55932fe07f8SJohn Marino /* history_def_init():
56032fe07f8SJohn Marino  *	Default history initialization function
56132fe07f8SJohn Marino  */
56232fe07f8SJohn Marino /* ARGSUSED */
56312db70c8Szrj static int
history_def_init(void ** p,TYPE (HistEvent)* ev,int n)56432fe07f8SJohn Marino history_def_init(void **p, TYPE(HistEvent) *ev __attribute__((__unused__)), int n)
56532fe07f8SJohn Marino {
56632fe07f8SJohn Marino 	history_t *h = (history_t *) h_malloc(sizeof(*h));
56732fe07f8SJohn Marino 	if (h == NULL)
56832fe07f8SJohn Marino 		return -1;
56932fe07f8SJohn Marino 
57032fe07f8SJohn Marino 	if (n <= 0)
57132fe07f8SJohn Marino 		n = 0;
57232fe07f8SJohn Marino 	h->eventid = 0;
57332fe07f8SJohn Marino 	h->cur = 0;
57432fe07f8SJohn Marino 	h->max = n;
57532fe07f8SJohn Marino 	h->list.next = h->list.prev = &h->list;
57632fe07f8SJohn Marino 	h->list.ev.str = NULL;
57732fe07f8SJohn Marino 	h->list.ev.num = 0;
57832fe07f8SJohn Marino 	h->cursor = &h->list;
57932fe07f8SJohn Marino 	h->flags = 0;
58032fe07f8SJohn Marino 	*p = h;
58132fe07f8SJohn Marino 	return 0;
58232fe07f8SJohn Marino }
58332fe07f8SJohn Marino 
58432fe07f8SJohn Marino 
58532fe07f8SJohn Marino /* history_def_clear():
58632fe07f8SJohn Marino  *	Default history cleanup function
58732fe07f8SJohn Marino  */
58812db70c8Szrj static void
history_def_clear(void * p,TYPE (HistEvent)* ev)58932fe07f8SJohn Marino history_def_clear(void *p, TYPE(HistEvent) *ev)
59032fe07f8SJohn Marino {
59132fe07f8SJohn Marino 	history_t *h = (history_t *) p;
59232fe07f8SJohn Marino 
59332fe07f8SJohn Marino 	while (h->list.prev != &h->list)
59432fe07f8SJohn Marino 		history_def_delete(h, ev, h->list.prev);
59532fe07f8SJohn Marino 	h->cursor = &h->list;
59632fe07f8SJohn Marino 	h->eventid = 0;
59732fe07f8SJohn Marino 	h->cur = 0;
59832fe07f8SJohn Marino }
59932fe07f8SJohn Marino 
60032fe07f8SJohn Marino 
60132fe07f8SJohn Marino 
60232fe07f8SJohn Marino 
60332fe07f8SJohn Marino /************************************************************************/
60432fe07f8SJohn Marino 
60532fe07f8SJohn Marino /* history_init():
60632fe07f8SJohn Marino  *	Initialization function.
60732fe07f8SJohn Marino  */
TYPE(History)60812db70c8Szrj TYPE(History) *
60932fe07f8SJohn Marino FUN(history,init)(void)
61032fe07f8SJohn Marino {
61132fe07f8SJohn Marino 	TYPE(HistEvent) ev;
61232fe07f8SJohn Marino 	TYPE(History) *h = (TYPE(History) *) h_malloc(sizeof(*h));
61332fe07f8SJohn Marino 	if (h == NULL)
61432fe07f8SJohn Marino 		return NULL;
61532fe07f8SJohn Marino 
61632fe07f8SJohn Marino 	if (history_def_init(&h->h_ref, &ev, 0) == -1) {
61732fe07f8SJohn Marino 		h_free(h);
61832fe07f8SJohn Marino 		return NULL;
61932fe07f8SJohn Marino 	}
62032fe07f8SJohn Marino 	h->h_ent = -1;
62132fe07f8SJohn Marino 	h->h_next = history_def_next;
62232fe07f8SJohn Marino 	h->h_first = history_def_first;
62332fe07f8SJohn Marino 	h->h_last = history_def_last;
62432fe07f8SJohn Marino 	h->h_prev = history_def_prev;
62532fe07f8SJohn Marino 	h->h_curr = history_def_curr;
62632fe07f8SJohn Marino 	h->h_set = history_def_set;
62732fe07f8SJohn Marino 	h->h_clear = history_def_clear;
62832fe07f8SJohn Marino 	h->h_enter = history_def_enter;
62932fe07f8SJohn Marino 	h->h_add = history_def_add;
63032fe07f8SJohn Marino 	h->h_del = history_def_del;
63132fe07f8SJohn Marino 
63232fe07f8SJohn Marino 	return h;
63332fe07f8SJohn Marino }
63432fe07f8SJohn Marino 
63532fe07f8SJohn Marino 
63632fe07f8SJohn Marino /* history_end():
63732fe07f8SJohn Marino  *	clean up history;
63832fe07f8SJohn Marino  */
63912db70c8Szrj void
FUN(history,end)64032fe07f8SJohn Marino FUN(history,end)(TYPE(History) *h)
64132fe07f8SJohn Marino {
64232fe07f8SJohn Marino 	TYPE(HistEvent) ev;
64332fe07f8SJohn Marino 
64432fe07f8SJohn Marino 	if (h->h_next == history_def_next)
64532fe07f8SJohn Marino 		history_def_clear(h->h_ref, &ev);
64632fe07f8SJohn Marino 	h_free(h->h_ref);
64732fe07f8SJohn Marino 	h_free(h);
64832fe07f8SJohn Marino }
64932fe07f8SJohn Marino 
65032fe07f8SJohn Marino 
65132fe07f8SJohn Marino 
65232fe07f8SJohn Marino /* history_setsize():
65332fe07f8SJohn Marino  *	Set history number of events
65432fe07f8SJohn Marino  */
65512db70c8Szrj static int
history_setsize(TYPE (History)* h,TYPE (HistEvent)* ev,int num)65632fe07f8SJohn Marino history_setsize(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
65732fe07f8SJohn Marino {
65832fe07f8SJohn Marino 
65932fe07f8SJohn Marino 	if (h->h_next != history_def_next) {
66032fe07f8SJohn Marino 		he_seterrev(ev, _HE_NOT_ALLOWED);
66132fe07f8SJohn Marino 		return -1;
66232fe07f8SJohn Marino 	}
66332fe07f8SJohn Marino 	if (num < 0) {
66432fe07f8SJohn Marino 		he_seterrev(ev, _HE_BAD_PARAM);
66532fe07f8SJohn Marino 		return -1;
66632fe07f8SJohn Marino 	}
66732fe07f8SJohn Marino 	history_def_setsize(h->h_ref, num);
66832fe07f8SJohn Marino 	return 0;
66932fe07f8SJohn Marino }
67032fe07f8SJohn Marino 
67132fe07f8SJohn Marino 
67232fe07f8SJohn Marino /* history_getsize():
67332fe07f8SJohn Marino  *      Get number of events currently in history
67432fe07f8SJohn Marino  */
67512db70c8Szrj static int
history_getsize(TYPE (History)* h,TYPE (HistEvent)* ev)67632fe07f8SJohn Marino history_getsize(TYPE(History) *h, TYPE(HistEvent) *ev)
67732fe07f8SJohn Marino {
67832fe07f8SJohn Marino 	if (h->h_next != history_def_next) {
67932fe07f8SJohn Marino 		he_seterrev(ev, _HE_NOT_ALLOWED);
68032fe07f8SJohn Marino 		return -1;
68132fe07f8SJohn Marino 	}
68232fe07f8SJohn Marino 	ev->num = history_def_getsize(h->h_ref);
68332fe07f8SJohn Marino 	if (ev->num < -1) {
68432fe07f8SJohn Marino 		he_seterrev(ev, _HE_SIZE_NEGATIVE);
68532fe07f8SJohn Marino 		return -1;
68632fe07f8SJohn Marino 	}
68732fe07f8SJohn Marino 	return 0;
68832fe07f8SJohn Marino }
68932fe07f8SJohn Marino 
69032fe07f8SJohn Marino 
69132fe07f8SJohn Marino /* history_setunique():
69232fe07f8SJohn Marino  *	Set if adjacent equal events should not be entered in history.
69332fe07f8SJohn Marino  */
69412db70c8Szrj static int
history_setunique(TYPE (History)* h,TYPE (HistEvent)* ev,int uni)69532fe07f8SJohn Marino history_setunique(TYPE(History) *h, TYPE(HistEvent) *ev, int uni)
69632fe07f8SJohn Marino {
69732fe07f8SJohn Marino 
69832fe07f8SJohn Marino 	if (h->h_next != history_def_next) {
69932fe07f8SJohn Marino 		he_seterrev(ev, _HE_NOT_ALLOWED);
70032fe07f8SJohn Marino 		return -1;
70132fe07f8SJohn Marino 	}
70232fe07f8SJohn Marino 	history_def_setunique(h->h_ref, uni);
70332fe07f8SJohn Marino 	return 0;
70432fe07f8SJohn Marino }
70532fe07f8SJohn Marino 
70632fe07f8SJohn Marino 
70732fe07f8SJohn Marino /* history_getunique():
70832fe07f8SJohn Marino  *	Get if adjacent equal events should not be entered in history.
70932fe07f8SJohn Marino  */
71012db70c8Szrj static int
history_getunique(TYPE (History)* h,TYPE (HistEvent)* ev)71132fe07f8SJohn Marino history_getunique(TYPE(History) *h, TYPE(HistEvent) *ev)
71232fe07f8SJohn Marino {
71332fe07f8SJohn Marino 	if (h->h_next != history_def_next) {
71432fe07f8SJohn Marino 		he_seterrev(ev, _HE_NOT_ALLOWED);
71532fe07f8SJohn Marino 		return -1;
71632fe07f8SJohn Marino 	}
71732fe07f8SJohn Marino 	ev->num = history_def_getunique(h->h_ref);
71832fe07f8SJohn Marino 	return 0;
71932fe07f8SJohn Marino }
72032fe07f8SJohn Marino 
72132fe07f8SJohn Marino 
72232fe07f8SJohn Marino /* history_set_fun():
72332fe07f8SJohn Marino  *	Set history functions
72432fe07f8SJohn Marino  */
72512db70c8Szrj static int
history_set_fun(TYPE (History)* h,TYPE (History)* nh)72632fe07f8SJohn Marino history_set_fun(TYPE(History) *h, TYPE(History) *nh)
72732fe07f8SJohn Marino {
72832fe07f8SJohn Marino 	TYPE(HistEvent) ev;
72932fe07f8SJohn Marino 
73032fe07f8SJohn Marino 	if (nh->h_first == NULL || nh->h_next == NULL || nh->h_last == NULL ||
73132fe07f8SJohn Marino 	    nh->h_prev == NULL || nh->h_curr == NULL || nh->h_set == NULL ||
73232fe07f8SJohn Marino 	    nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL ||
73332fe07f8SJohn Marino 	    nh->h_del == NULL || nh->h_ref == NULL) {
73432fe07f8SJohn Marino 		if (h->h_next != history_def_next) {
73532fe07f8SJohn Marino 			if (history_def_init(&h->h_ref, &ev, 0) == -1)
73632fe07f8SJohn Marino 				return -1;
73732fe07f8SJohn Marino 			h->h_first = history_def_first;
73832fe07f8SJohn Marino 			h->h_next = history_def_next;
73932fe07f8SJohn Marino 			h->h_last = history_def_last;
74032fe07f8SJohn Marino 			h->h_prev = history_def_prev;
74132fe07f8SJohn Marino 			h->h_curr = history_def_curr;
74232fe07f8SJohn Marino 			h->h_set = history_def_set;
74332fe07f8SJohn Marino 			h->h_clear = history_def_clear;
74432fe07f8SJohn Marino 			h->h_enter = history_def_enter;
74532fe07f8SJohn Marino 			h->h_add = history_def_add;
74632fe07f8SJohn Marino 			h->h_del = history_def_del;
74732fe07f8SJohn Marino 		}
74832fe07f8SJohn Marino 		return -1;
74932fe07f8SJohn Marino 	}
75032fe07f8SJohn Marino 	if (h->h_next == history_def_next)
75132fe07f8SJohn Marino 		history_def_clear(h->h_ref, &ev);
75232fe07f8SJohn Marino 
75332fe07f8SJohn Marino 	h->h_ent = -1;
75432fe07f8SJohn Marino 	h->h_first = nh->h_first;
75532fe07f8SJohn Marino 	h->h_next = nh->h_next;
75632fe07f8SJohn Marino 	h->h_last = nh->h_last;
75732fe07f8SJohn Marino 	h->h_prev = nh->h_prev;
75832fe07f8SJohn Marino 	h->h_curr = nh->h_curr;
75932fe07f8SJohn Marino 	h->h_set = nh->h_set;
76032fe07f8SJohn Marino 	h->h_clear = nh->h_clear;
76132fe07f8SJohn Marino 	h->h_enter = nh->h_enter;
76232fe07f8SJohn Marino 	h->h_add = nh->h_add;
76332fe07f8SJohn Marino 	h->h_del = nh->h_del;
76432fe07f8SJohn Marino 
76532fe07f8SJohn Marino 	return 0;
76632fe07f8SJohn Marino }
76732fe07f8SJohn Marino 
76832fe07f8SJohn Marino 
76932fe07f8SJohn Marino /* history_load():
77032fe07f8SJohn Marino  *	TYPE(History) load function
77132fe07f8SJohn Marino  */
77212db70c8Szrj static int
history_load(TYPE (History)* h,const char * fname)77332fe07f8SJohn Marino history_load(TYPE(History) *h, const char *fname)
77432fe07f8SJohn Marino {
77532fe07f8SJohn Marino 	FILE *fp;
77632fe07f8SJohn Marino 	char *line;
77712db70c8Szrj 	size_t llen;
77812db70c8Szrj 	ssize_t sz;
77912db70c8Szrj 	size_t max_size;
78032fe07f8SJohn Marino 	char *ptr;
78132fe07f8SJohn Marino 	int i = -1;
78232fe07f8SJohn Marino 	TYPE(HistEvent) ev;
783ae19eda8Szrj 	Char *decode_result;
78412db70c8Szrj #ifndef NARROWCHAR
78532fe07f8SJohn Marino 	static ct_buffer_t conv;
78632fe07f8SJohn Marino #endif
78732fe07f8SJohn Marino 
78832fe07f8SJohn Marino 	if ((fp = fopen(fname, "r")) == NULL)
78932fe07f8SJohn Marino 		return i;
79032fe07f8SJohn Marino 
79112db70c8Szrj 	line = NULL;
79212db70c8Szrj 	llen = 0;
79312db70c8Szrj 	if ((sz = getline(&line, &llen, fp)) == -1)
79432fe07f8SJohn Marino 		goto done;
79532fe07f8SJohn Marino 
79612db70c8Szrj 	if (strncmp(line, hist_cookie, (size_t)sz) != 0)
79732fe07f8SJohn Marino 		goto done;
79832fe07f8SJohn Marino 
79932fe07f8SJohn Marino 	ptr = h_malloc((max_size = 1024) * sizeof(*ptr));
80032fe07f8SJohn Marino 	if (ptr == NULL)
80132fe07f8SJohn Marino 		goto done;
80212db70c8Szrj 	for (i = 0; (sz = getline(&line, &llen, fp)) != -1; i++) {
80312db70c8Szrj 		if (sz > 0 && line[sz - 1] == '\n')
80432fe07f8SJohn Marino 			line[--sz] = '\0';
80512db70c8Szrj 		if (max_size < (size_t)sz) {
80632fe07f8SJohn Marino 			char *nptr;
80712db70c8Szrj 			max_size = ((size_t)sz + 1024) & (size_t)~1023;
80832fe07f8SJohn Marino 			nptr = h_realloc(ptr, max_size * sizeof(*ptr));
80932fe07f8SJohn Marino 			if (nptr == NULL) {
81032fe07f8SJohn Marino 				i = -1;
81132fe07f8SJohn Marino 				goto oomem;
81232fe07f8SJohn Marino 			}
81332fe07f8SJohn Marino 			ptr = nptr;
81432fe07f8SJohn Marino 		}
81532fe07f8SJohn Marino 		(void) strunvis(ptr, line);
816ae19eda8Szrj 		decode_result = ct_decode_string(ptr, &conv);
817ae19eda8Szrj 		if (decode_result == NULL)
818ae19eda8Szrj 			continue;
819ae19eda8Szrj 		if (HENTER(h, &ev, decode_result) == -1) {
82032fe07f8SJohn Marino 			i = -1;
82132fe07f8SJohn Marino 			goto oomem;
82232fe07f8SJohn Marino 		}
82332fe07f8SJohn Marino 	}
82432fe07f8SJohn Marino oomem:
82532fe07f8SJohn Marino 	h_free(ptr);
82632fe07f8SJohn Marino done:
82712db70c8Szrj 	free(line);
82832fe07f8SJohn Marino 	(void) fclose(fp);
82932fe07f8SJohn Marino 	return i;
83032fe07f8SJohn Marino }
83132fe07f8SJohn Marino 
83232fe07f8SJohn Marino 
83384b940c1SJohn Marino /* history_save_fp():
83432fe07f8SJohn Marino  *	TYPE(History) save function
83532fe07f8SJohn Marino  */
83612db70c8Szrj static int
history_save_fp(TYPE (History)* h,size_t nelem,FILE * fp)837ae19eda8Szrj history_save_fp(TYPE(History) *h, size_t nelem, FILE *fp)
83832fe07f8SJohn Marino {
83932fe07f8SJohn Marino 	TYPE(HistEvent) ev;
84032fe07f8SJohn Marino 	int i = -1, retval;
84132fe07f8SJohn Marino 	size_t len, max_size;
84232fe07f8SJohn Marino 	char *ptr;
84332fe07f8SJohn Marino 	const char *str;
84412db70c8Szrj #ifndef NARROWCHAR
84532fe07f8SJohn Marino 	static ct_buffer_t conv;
84632fe07f8SJohn Marino #endif
84732fe07f8SJohn Marino 
84832fe07f8SJohn Marino 	if (fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1)
84932fe07f8SJohn Marino 		goto done;
850ae19eda8Szrj 	if (ftell(fp) == 0 && fputs(hist_cookie, fp) == EOF)
85132fe07f8SJohn Marino 		goto done;
85232fe07f8SJohn Marino 	ptr = h_malloc((max_size = 1024) * sizeof(*ptr));
85332fe07f8SJohn Marino 	if (ptr == NULL)
85432fe07f8SJohn Marino 		goto done;
855ae19eda8Szrj 	if (nelem != (size_t)-1) {
856ae19eda8Szrj 		for (retval = HFIRST(h, &ev); retval != -1 && nelem-- > 0;
857ae19eda8Szrj 		    retval = HNEXT(h, &ev))
858ae19eda8Szrj 			continue;
859ae19eda8Szrj 	} else
860ae19eda8Szrj 		retval = -1;
861ae19eda8Szrj 
862ae19eda8Szrj 	if (retval == -1)
863ae19eda8Szrj 		retval = HLAST(h, &ev);
864ae19eda8Szrj 
865ae19eda8Szrj 	for (i = 0; retval != -1; retval = HPREV(h, &ev), i++) {
86632fe07f8SJohn Marino 		str = ct_encode_string(ev.str, &conv);
86712db70c8Szrj 		len = strlen(str) * 4 + 1;
86812db70c8Szrj 		if (len > max_size) {
86932fe07f8SJohn Marino 			char *nptr;
87032fe07f8SJohn Marino 			max_size = (len + 1024) & (size_t)~1023;
87132fe07f8SJohn Marino 			nptr = h_realloc(ptr, max_size * sizeof(*ptr));
87232fe07f8SJohn Marino 			if (nptr == NULL) {
87332fe07f8SJohn Marino 				i = -1;
87432fe07f8SJohn Marino 				goto oomem;
87532fe07f8SJohn Marino 			}
87632fe07f8SJohn Marino 			ptr = nptr;
87732fe07f8SJohn Marino 		}
87832fe07f8SJohn Marino 		(void) strvis(ptr, str, VIS_WHITE);
87932fe07f8SJohn Marino 		(void) fprintf(fp, "%s\n", ptr);
88032fe07f8SJohn Marino 	}
88132fe07f8SJohn Marino oomem:
88232fe07f8SJohn Marino 	h_free(ptr);
88332fe07f8SJohn Marino done:
88484b940c1SJohn Marino 	return i;
88584b940c1SJohn Marino }
88684b940c1SJohn Marino 
88784b940c1SJohn Marino 
88884b940c1SJohn Marino /* history_save():
88984b940c1SJohn Marino  *    History save function
89084b940c1SJohn Marino  */
89112db70c8Szrj static int
history_save(TYPE (History)* h,const char * fname)89284b940c1SJohn Marino history_save(TYPE(History) *h, const char *fname)
89384b940c1SJohn Marino {
89484b940c1SJohn Marino     FILE *fp;
89584b940c1SJohn Marino     int i;
89684b940c1SJohn Marino 
89784b940c1SJohn Marino     if ((fp = fopen(fname, "w")) == NULL)
89884b940c1SJohn Marino 	return -1;
89984b940c1SJohn Marino 
900ae19eda8Szrj     i = history_save_fp(h, (size_t)-1, fp);
90184b940c1SJohn Marino 
90232fe07f8SJohn Marino     (void) fclose(fp);
90332fe07f8SJohn Marino     return i;
90432fe07f8SJohn Marino }
90532fe07f8SJohn Marino 
90632fe07f8SJohn Marino 
90732fe07f8SJohn Marino /* history_prev_event():
90832fe07f8SJohn Marino  *	Find the previous event, with number given
90932fe07f8SJohn Marino  */
91012db70c8Szrj static int
history_prev_event(TYPE (History)* h,TYPE (HistEvent)* ev,int num)91132fe07f8SJohn Marino history_prev_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
91232fe07f8SJohn Marino {
91332fe07f8SJohn Marino 	int retval;
91432fe07f8SJohn Marino 
91532fe07f8SJohn Marino 	for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
91632fe07f8SJohn Marino 		if (ev->num == num)
91732fe07f8SJohn Marino 			return 0;
91832fe07f8SJohn Marino 
91932fe07f8SJohn Marino 	he_seterrev(ev, _HE_NOT_FOUND);
92032fe07f8SJohn Marino 	return -1;
92132fe07f8SJohn Marino }
92232fe07f8SJohn Marino 
92332fe07f8SJohn Marino 
92412db70c8Szrj static int
history_next_evdata(TYPE (History)* h,TYPE (HistEvent)* ev,int num,void ** d)92532fe07f8SJohn Marino history_next_evdata(TYPE(History) *h, TYPE(HistEvent) *ev, int num, void **d)
92632fe07f8SJohn Marino {
92732fe07f8SJohn Marino 	int retval;
92832fe07f8SJohn Marino 
92932fe07f8SJohn Marino 	for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
93032fe07f8SJohn Marino 		if (ev->num == num) {
93132fe07f8SJohn Marino 			if (d)
93232fe07f8SJohn Marino 				*d = ((history_t *)h->h_ref)->cursor->data;
93332fe07f8SJohn Marino 			return 0;
93432fe07f8SJohn Marino 		}
93532fe07f8SJohn Marino 
93632fe07f8SJohn Marino 	he_seterrev(ev, _HE_NOT_FOUND);
93732fe07f8SJohn Marino 	return -1;
93832fe07f8SJohn Marino }
93932fe07f8SJohn Marino 
94032fe07f8SJohn Marino 
94132fe07f8SJohn Marino /* history_next_event():
94232fe07f8SJohn Marino  *	Find the next event, with number given
94332fe07f8SJohn Marino  */
94412db70c8Szrj static int
history_next_event(TYPE (History)* h,TYPE (HistEvent)* ev,int num)94532fe07f8SJohn Marino history_next_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
94632fe07f8SJohn Marino {
94732fe07f8SJohn Marino 	int retval;
94832fe07f8SJohn Marino 
94932fe07f8SJohn Marino 	for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
95032fe07f8SJohn Marino 		if (ev->num == num)
95132fe07f8SJohn Marino 			return 0;
95232fe07f8SJohn Marino 
95332fe07f8SJohn Marino 	he_seterrev(ev, _HE_NOT_FOUND);
95432fe07f8SJohn Marino 	return -1;
95532fe07f8SJohn Marino }
95632fe07f8SJohn Marino 
95732fe07f8SJohn Marino 
95832fe07f8SJohn Marino /* history_prev_string():
95932fe07f8SJohn Marino  *	Find the previous event beginning with string
96032fe07f8SJohn Marino  */
96112db70c8Szrj static int
history_prev_string(TYPE (History)* h,TYPE (HistEvent)* ev,const Char * str)96232fe07f8SJohn Marino history_prev_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str)
96332fe07f8SJohn Marino {
96432fe07f8SJohn Marino 	size_t len = Strlen(str);
96532fe07f8SJohn Marino 	int retval;
96632fe07f8SJohn Marino 
96732fe07f8SJohn Marino 	for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
96832fe07f8SJohn Marino 		if (Strncmp(str, ev->str, len) == 0)
96932fe07f8SJohn Marino 			return 0;
97032fe07f8SJohn Marino 
97132fe07f8SJohn Marino 	he_seterrev(ev, _HE_NOT_FOUND);
97232fe07f8SJohn Marino 	return -1;
97332fe07f8SJohn Marino }
97432fe07f8SJohn Marino 
97532fe07f8SJohn Marino 
97632fe07f8SJohn Marino /* history_next_string():
97732fe07f8SJohn Marino  *	Find the next event beginning with string
97832fe07f8SJohn Marino  */
97912db70c8Szrj static int
history_next_string(TYPE (History)* h,TYPE (HistEvent)* ev,const Char * str)98032fe07f8SJohn Marino history_next_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str)
98132fe07f8SJohn Marino {
98232fe07f8SJohn Marino 	size_t len = Strlen(str);
98332fe07f8SJohn Marino 	int retval;
98432fe07f8SJohn Marino 
98532fe07f8SJohn Marino 	for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
98632fe07f8SJohn Marino 		if (Strncmp(str, ev->str, len) == 0)
98732fe07f8SJohn Marino 			return 0;
98832fe07f8SJohn Marino 
98932fe07f8SJohn Marino 	he_seterrev(ev, _HE_NOT_FOUND);
99032fe07f8SJohn Marino 	return -1;
99132fe07f8SJohn Marino }
99232fe07f8SJohn Marino 
99332fe07f8SJohn Marino 
99432fe07f8SJohn Marino /* history():
99532fe07f8SJohn Marino  *	User interface to history functions.
99632fe07f8SJohn Marino  */
99732fe07f8SJohn Marino int
FUNW(history)99832fe07f8SJohn Marino FUNW(history)(TYPE(History) *h, TYPE(HistEvent) *ev, int fun, ...)
99932fe07f8SJohn Marino {
100032fe07f8SJohn Marino 	va_list va;
100132fe07f8SJohn Marino 	const Char *str;
100232fe07f8SJohn Marino 	int retval;
100332fe07f8SJohn Marino 
100432fe07f8SJohn Marino 	va_start(va, fun);
100532fe07f8SJohn Marino 
100632fe07f8SJohn Marino 	he_seterrev(ev, _HE_OK);
100732fe07f8SJohn Marino 
100832fe07f8SJohn Marino 	switch (fun) {
100932fe07f8SJohn Marino 	case H_GETSIZE:
101032fe07f8SJohn Marino 		retval = history_getsize(h, ev);
101132fe07f8SJohn Marino 		break;
101232fe07f8SJohn Marino 
101332fe07f8SJohn Marino 	case H_SETSIZE:
101432fe07f8SJohn Marino 		retval = history_setsize(h, ev, va_arg(va, int));
101532fe07f8SJohn Marino 		break;
101632fe07f8SJohn Marino 
101732fe07f8SJohn Marino 	case H_GETUNIQUE:
101832fe07f8SJohn Marino 		retval = history_getunique(h, ev);
101932fe07f8SJohn Marino 		break;
102032fe07f8SJohn Marino 
102132fe07f8SJohn Marino 	case H_SETUNIQUE:
102232fe07f8SJohn Marino 		retval = history_setunique(h, ev, va_arg(va, int));
102332fe07f8SJohn Marino 		break;
102432fe07f8SJohn Marino 
102532fe07f8SJohn Marino 	case H_ADD:
102632fe07f8SJohn Marino 		str = va_arg(va, const Char *);
102732fe07f8SJohn Marino 		retval = HADD(h, ev, str);
102832fe07f8SJohn Marino 		break;
102932fe07f8SJohn Marino 
103032fe07f8SJohn Marino 	case H_DEL:
103132fe07f8SJohn Marino 		retval = HDEL(h, ev, va_arg(va, const int));
103232fe07f8SJohn Marino 		break;
103332fe07f8SJohn Marino 
103432fe07f8SJohn Marino 	case H_ENTER:
103532fe07f8SJohn Marino 		str = va_arg(va, const Char *);
103632fe07f8SJohn Marino 		if ((retval = HENTER(h, ev, str)) != -1)
103732fe07f8SJohn Marino 			h->h_ent = ev->num;
103832fe07f8SJohn Marino 		break;
103932fe07f8SJohn Marino 
104032fe07f8SJohn Marino 	case H_APPEND:
104132fe07f8SJohn Marino 		str = va_arg(va, const Char *);
104232fe07f8SJohn Marino 		if ((retval = HSET(h, ev, h->h_ent)) != -1)
104332fe07f8SJohn Marino 			retval = HADD(h, ev, str);
104432fe07f8SJohn Marino 		break;
104532fe07f8SJohn Marino 
104632fe07f8SJohn Marino 	case H_FIRST:
104732fe07f8SJohn Marino 		retval = HFIRST(h, ev);
104832fe07f8SJohn Marino 		break;
104932fe07f8SJohn Marino 
105032fe07f8SJohn Marino 	case H_NEXT:
105132fe07f8SJohn Marino 		retval = HNEXT(h, ev);
105232fe07f8SJohn Marino 		break;
105332fe07f8SJohn Marino 
105432fe07f8SJohn Marino 	case H_LAST:
105532fe07f8SJohn Marino 		retval = HLAST(h, ev);
105632fe07f8SJohn Marino 		break;
105732fe07f8SJohn Marino 
105832fe07f8SJohn Marino 	case H_PREV:
105932fe07f8SJohn Marino 		retval = HPREV(h, ev);
106032fe07f8SJohn Marino 		break;
106132fe07f8SJohn Marino 
106232fe07f8SJohn Marino 	case H_CURR:
106332fe07f8SJohn Marino 		retval = HCURR(h, ev);
106432fe07f8SJohn Marino 		break;
106532fe07f8SJohn Marino 
106632fe07f8SJohn Marino 	case H_SET:
106732fe07f8SJohn Marino 		retval = HSET(h, ev, va_arg(va, const int));
106832fe07f8SJohn Marino 		break;
106932fe07f8SJohn Marino 
107032fe07f8SJohn Marino 	case H_CLEAR:
107132fe07f8SJohn Marino 		HCLEAR(h, ev);
107232fe07f8SJohn Marino 		retval = 0;
107332fe07f8SJohn Marino 		break;
107432fe07f8SJohn Marino 
107532fe07f8SJohn Marino 	case H_LOAD:
107632fe07f8SJohn Marino 		retval = history_load(h, va_arg(va, const char *));
107732fe07f8SJohn Marino 		if (retval == -1)
107832fe07f8SJohn Marino 			he_seterrev(ev, _HE_HIST_READ);
107932fe07f8SJohn Marino 		break;
108032fe07f8SJohn Marino 
108132fe07f8SJohn Marino 	case H_SAVE:
108232fe07f8SJohn Marino 		retval = history_save(h, va_arg(va, const char *));
108332fe07f8SJohn Marino 		if (retval == -1)
108432fe07f8SJohn Marino 			he_seterrev(ev, _HE_HIST_WRITE);
108532fe07f8SJohn Marino 		break;
108632fe07f8SJohn Marino 
108784b940c1SJohn Marino 	case H_SAVE_FP:
1088ae19eda8Szrj 		retval = history_save_fp(h, (size_t)-1, va_arg(va, FILE *));
108984b940c1SJohn Marino 		if (retval == -1)
109084b940c1SJohn Marino 		    he_seterrev(ev, _HE_HIST_WRITE);
109184b940c1SJohn Marino 		break;
109284b940c1SJohn Marino 
1093ae19eda8Szrj 	case H_NSAVE_FP:
1094ae19eda8Szrj 	{
1095ae19eda8Szrj 		size_t sz = va_arg(va, size_t);
1096ae19eda8Szrj 		retval = history_save_fp(h, sz, va_arg(va, FILE *));
1097ae19eda8Szrj 		if (retval == -1)
1098ae19eda8Szrj 		    he_seterrev(ev, _HE_HIST_WRITE);
1099ae19eda8Szrj 		break;
1100ae19eda8Szrj 	}
1101ae19eda8Szrj 
110232fe07f8SJohn Marino 	case H_PREV_EVENT:
110332fe07f8SJohn Marino 		retval = history_prev_event(h, ev, va_arg(va, int));
110432fe07f8SJohn Marino 		break;
110532fe07f8SJohn Marino 
110632fe07f8SJohn Marino 	case H_NEXT_EVENT:
110732fe07f8SJohn Marino 		retval = history_next_event(h, ev, va_arg(va, int));
110832fe07f8SJohn Marino 		break;
110932fe07f8SJohn Marino 
111032fe07f8SJohn Marino 	case H_PREV_STR:
111132fe07f8SJohn Marino 		retval = history_prev_string(h, ev, va_arg(va, const Char *));
111232fe07f8SJohn Marino 		break;
111332fe07f8SJohn Marino 
111432fe07f8SJohn Marino 	case H_NEXT_STR:
111532fe07f8SJohn Marino 		retval = history_next_string(h, ev, va_arg(va, const Char *));
111632fe07f8SJohn Marino 		break;
111732fe07f8SJohn Marino 
111832fe07f8SJohn Marino 	case H_FUNC:
111932fe07f8SJohn Marino 	{
112032fe07f8SJohn Marino 		TYPE(History) hf;
112132fe07f8SJohn Marino 
112232fe07f8SJohn Marino 		hf.h_ref = va_arg(va, void *);
112332fe07f8SJohn Marino 		h->h_ent = -1;
112432fe07f8SJohn Marino 		hf.h_first = va_arg(va, history_gfun_t);
112532fe07f8SJohn Marino 		hf.h_next = va_arg(va, history_gfun_t);
112632fe07f8SJohn Marino 		hf.h_last = va_arg(va, history_gfun_t);
112732fe07f8SJohn Marino 		hf.h_prev = va_arg(va, history_gfun_t);
112832fe07f8SJohn Marino 		hf.h_curr = va_arg(va, history_gfun_t);
112932fe07f8SJohn Marino 		hf.h_set = va_arg(va, history_sfun_t);
113032fe07f8SJohn Marino 		hf.h_clear = va_arg(va, history_vfun_t);
113132fe07f8SJohn Marino 		hf.h_enter = va_arg(va, history_efun_t);
113232fe07f8SJohn Marino 		hf.h_add = va_arg(va, history_efun_t);
113332fe07f8SJohn Marino 		hf.h_del = va_arg(va, history_sfun_t);
113432fe07f8SJohn Marino 
113532fe07f8SJohn Marino 		if ((retval = history_set_fun(h, &hf)) == -1)
113632fe07f8SJohn Marino 			he_seterrev(ev, _HE_PARAM_MISSING);
113732fe07f8SJohn Marino 		break;
113832fe07f8SJohn Marino 	}
113932fe07f8SJohn Marino 
114032fe07f8SJohn Marino 	case H_END:
114132fe07f8SJohn Marino 		FUN(history,end)(h);
114232fe07f8SJohn Marino 		retval = 0;
114332fe07f8SJohn Marino 		break;
114432fe07f8SJohn Marino 
114532fe07f8SJohn Marino 	case H_NEXT_EVDATA:
114632fe07f8SJohn Marino 	{
114732fe07f8SJohn Marino 		int num = va_arg(va, int);
114832fe07f8SJohn Marino 		void **d = va_arg(va, void **);
114932fe07f8SJohn Marino 		retval = history_next_evdata(h, ev, num, d);
115032fe07f8SJohn Marino 		break;
115132fe07f8SJohn Marino 	}
115232fe07f8SJohn Marino 
115332fe07f8SJohn Marino 	case H_DELDATA:
115432fe07f8SJohn Marino 	{
115532fe07f8SJohn Marino 		int num = va_arg(va, int);
115632fe07f8SJohn Marino 		void **d = va_arg(va, void **);
115732fe07f8SJohn Marino 		retval = history_deldata_nth((history_t *)h->h_ref, ev, num, d);
115832fe07f8SJohn Marino 		break;
115932fe07f8SJohn Marino 	}
116032fe07f8SJohn Marino 
116132fe07f8SJohn Marino 	case H_REPLACE: /* only use after H_NEXT_EVDATA */
116232fe07f8SJohn Marino 	{
116332fe07f8SJohn Marino 		const Char *line = va_arg(va, const Char *);
116432fe07f8SJohn Marino 		void *d = va_arg(va, void *);
116532fe07f8SJohn Marino 		const Char *s;
116632fe07f8SJohn Marino 		if(!line || !(s = Strdup(line))) {
116732fe07f8SJohn Marino 			retval = -1;
116832fe07f8SJohn Marino 			break;
116932fe07f8SJohn Marino 		}
117032fe07f8SJohn Marino 		((history_t *)h->h_ref)->cursor->ev.str = s;
117132fe07f8SJohn Marino 		((history_t *)h->h_ref)->cursor->data = d;
117232fe07f8SJohn Marino 		retval = 0;
117332fe07f8SJohn Marino 		break;
117432fe07f8SJohn Marino 	}
117532fe07f8SJohn Marino 
117632fe07f8SJohn Marino 	default:
117732fe07f8SJohn Marino 		retval = -1;
117832fe07f8SJohn Marino 		he_seterrev(ev, _HE_UNKNOWN);
117932fe07f8SJohn Marino 		break;
118032fe07f8SJohn Marino 	}
118132fe07f8SJohn Marino 	va_end(va);
118232fe07f8SJohn Marino 	return retval;
118332fe07f8SJohn Marino }
1184