xref: /freebsd-src/contrib/libedit/history.c (revision d0ef721ed3dc99bddc1e48605a6921ec60322efc)
1*d0ef721eSBaptiste Daroussin /*	$NetBSD: history.c,v 1.62 2018/09/13 09:03:40 kre Exp $	*/
2*d0ef721eSBaptiste Daroussin 
3*d0ef721eSBaptiste Daroussin /*-
4*d0ef721eSBaptiste Daroussin  * Copyright (c) 1992, 1993
5*d0ef721eSBaptiste Daroussin  *	The Regents of the University of California.  All rights reserved.
6*d0ef721eSBaptiste Daroussin  *
7*d0ef721eSBaptiste Daroussin  * This code is derived from software contributed to Berkeley by
8*d0ef721eSBaptiste Daroussin  * Christos Zoulas of Cornell University.
9*d0ef721eSBaptiste Daroussin  *
10*d0ef721eSBaptiste Daroussin  * Redistribution and use in source and binary forms, with or without
11*d0ef721eSBaptiste Daroussin  * modification, are permitted provided that the following conditions
12*d0ef721eSBaptiste Daroussin  * are met:
13*d0ef721eSBaptiste Daroussin  * 1. Redistributions of source code must retain the above copyright
14*d0ef721eSBaptiste Daroussin  *    notice, this list of conditions and the following disclaimer.
15*d0ef721eSBaptiste Daroussin  * 2. Redistributions in binary form must reproduce the above copyright
16*d0ef721eSBaptiste Daroussin  *    notice, this list of conditions and the following disclaimer in the
17*d0ef721eSBaptiste Daroussin  *    documentation and/or other materials provided with the distribution.
18*d0ef721eSBaptiste Daroussin  * 3. Neither the name of the University nor the names of its contributors
19*d0ef721eSBaptiste Daroussin  *    may be used to endorse or promote products derived from this software
20*d0ef721eSBaptiste Daroussin  *    without specific prior written permission.
21*d0ef721eSBaptiste Daroussin  *
22*d0ef721eSBaptiste Daroussin  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23*d0ef721eSBaptiste Daroussin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24*d0ef721eSBaptiste Daroussin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25*d0ef721eSBaptiste Daroussin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26*d0ef721eSBaptiste Daroussin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27*d0ef721eSBaptiste Daroussin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28*d0ef721eSBaptiste Daroussin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29*d0ef721eSBaptiste Daroussin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30*d0ef721eSBaptiste Daroussin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31*d0ef721eSBaptiste Daroussin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32*d0ef721eSBaptiste Daroussin  * SUCH DAMAGE.
33*d0ef721eSBaptiste Daroussin  */
34*d0ef721eSBaptiste Daroussin 
35*d0ef721eSBaptiste Daroussin #include "config.h"
36*d0ef721eSBaptiste Daroussin #if !defined(lint) && !defined(SCCSID)
37*d0ef721eSBaptiste Daroussin #if 0
38*d0ef721eSBaptiste Daroussin static char sccsid[] = "@(#)history.c	8.1 (Berkeley) 6/4/93";
39*d0ef721eSBaptiste Daroussin #else
40*d0ef721eSBaptiste Daroussin __RCSID("$NetBSD: history.c,v 1.62 2018/09/13 09:03:40 kre Exp $");
41*d0ef721eSBaptiste Daroussin #endif
42*d0ef721eSBaptiste Daroussin #endif /* not lint && not SCCSID */
43*d0ef721eSBaptiste Daroussin 
44*d0ef721eSBaptiste Daroussin /*
45*d0ef721eSBaptiste Daroussin  * hist.c: TYPE(History) access functions
46*d0ef721eSBaptiste Daroussin  */
47*d0ef721eSBaptiste Daroussin #include <sys/stat.h>
48*d0ef721eSBaptiste Daroussin #include <stdarg.h>
49*d0ef721eSBaptiste Daroussin #include <stdlib.h>
50*d0ef721eSBaptiste Daroussin #include <string.h>
51*d0ef721eSBaptiste Daroussin #include <vis.h>
52*d0ef721eSBaptiste Daroussin 
53*d0ef721eSBaptiste Daroussin static const char hist_cookie[] = "_HiStOrY_V2_\n";
54*d0ef721eSBaptiste Daroussin 
55*d0ef721eSBaptiste Daroussin #include "histedit.h"
56*d0ef721eSBaptiste Daroussin 
57*d0ef721eSBaptiste Daroussin 
58*d0ef721eSBaptiste Daroussin #ifdef NARROWCHAR
59*d0ef721eSBaptiste Daroussin 
60*d0ef721eSBaptiste Daroussin #define	Char			char
61*d0ef721eSBaptiste Daroussin #define	FUN(prefix, rest)	prefix ## _ ## rest
62*d0ef721eSBaptiste Daroussin #define	FUNW(type)		type
63*d0ef721eSBaptiste Daroussin #define	TYPE(type)		type
64*d0ef721eSBaptiste Daroussin #define	STR(x)			x
65*d0ef721eSBaptiste Daroussin 
66*d0ef721eSBaptiste Daroussin #define	Strlen(s)		strlen(s)
67*d0ef721eSBaptiste Daroussin #define	Strdup(s)		strdup(s)
68*d0ef721eSBaptiste Daroussin #define	Strcmp(d, s)		strcmp(d, s)
69*d0ef721eSBaptiste Daroussin #define	Strncmp(d, s, n)	strncmp(d, s, n)
70*d0ef721eSBaptiste Daroussin #define	Strncpy(d, s, n)	strncpy(d, s, n)
71*d0ef721eSBaptiste Daroussin #define	Strncat(d, s, n)	strncat(d, s, n)
72*d0ef721eSBaptiste Daroussin #define	ct_decode_string(s, b)	(s)
73*d0ef721eSBaptiste Daroussin #define	ct_encode_string(s, b)	(s)
74*d0ef721eSBaptiste Daroussin 
75*d0ef721eSBaptiste Daroussin #else
76*d0ef721eSBaptiste Daroussin #include "chartype.h"
77*d0ef721eSBaptiste Daroussin 
78*d0ef721eSBaptiste Daroussin #define	Char			wchar_t
79*d0ef721eSBaptiste Daroussin #define	FUN(prefix, rest)	prefix ## _w ## rest
80*d0ef721eSBaptiste Daroussin #define	FUNW(type)		type ## _w
81*d0ef721eSBaptiste Daroussin #define	TYPE(type)		type ## W
82*d0ef721eSBaptiste Daroussin #define	STR(x)			L ## x
83*d0ef721eSBaptiste Daroussin 
84*d0ef721eSBaptiste Daroussin #define	Strlen(s)		wcslen(s)
85*d0ef721eSBaptiste Daroussin #define	Strdup(s)		wcsdup(s)
86*d0ef721eSBaptiste Daroussin #define	Strcmp(d, s)		wcscmp(d, s)
87*d0ef721eSBaptiste Daroussin #define	Strncmp(d, s, n)	wcsncmp(d, s, n)
88*d0ef721eSBaptiste Daroussin #define	Strncpy(d, s, n)	wcsncpy(d, s, n)
89*d0ef721eSBaptiste Daroussin #define	Strncat(d, s, n)	wcsncat(d, s, n)
90*d0ef721eSBaptiste Daroussin 
91*d0ef721eSBaptiste Daroussin #endif
92*d0ef721eSBaptiste Daroussin 
93*d0ef721eSBaptiste Daroussin 
94*d0ef721eSBaptiste Daroussin typedef int (*history_gfun_t)(void *, TYPE(HistEvent) *);
95*d0ef721eSBaptiste Daroussin typedef int (*history_efun_t)(void *, TYPE(HistEvent) *, const Char *);
96*d0ef721eSBaptiste Daroussin typedef void (*history_vfun_t)(void *, TYPE(HistEvent) *);
97*d0ef721eSBaptiste Daroussin typedef int (*history_sfun_t)(void *, TYPE(HistEvent) *, const int);
98*d0ef721eSBaptiste Daroussin 
99*d0ef721eSBaptiste Daroussin struct TYPE(history) {
100*d0ef721eSBaptiste Daroussin 	void *h_ref;		/* Argument for history fcns	 */
101*d0ef721eSBaptiste Daroussin 	int h_ent;		/* Last entry point for history	 */
102*d0ef721eSBaptiste Daroussin 	history_gfun_t h_first;	/* Get the first element	 */
103*d0ef721eSBaptiste Daroussin 	history_gfun_t h_next;	/* Get the next element		 */
104*d0ef721eSBaptiste Daroussin 	history_gfun_t h_last;	/* Get the last element		 */
105*d0ef721eSBaptiste Daroussin 	history_gfun_t h_prev;	/* Get the previous element	 */
106*d0ef721eSBaptiste Daroussin 	history_gfun_t h_curr;	/* Get the current element	 */
107*d0ef721eSBaptiste Daroussin 	history_sfun_t h_set;	/* Set the current element	 */
108*d0ef721eSBaptiste Daroussin 	history_sfun_t h_del;	/* Set the given element	 */
109*d0ef721eSBaptiste Daroussin 	history_vfun_t h_clear;	/* Clear the history list	 */
110*d0ef721eSBaptiste Daroussin 	history_efun_t h_enter;	/* Add an element		 */
111*d0ef721eSBaptiste Daroussin 	history_efun_t h_add;	/* Append to an element		 */
112*d0ef721eSBaptiste Daroussin };
113*d0ef721eSBaptiste Daroussin 
114*d0ef721eSBaptiste Daroussin #define	HNEXT(h, ev)		(*(h)->h_next)((h)->h_ref, ev)
115*d0ef721eSBaptiste Daroussin #define	HFIRST(h, ev)		(*(h)->h_first)((h)->h_ref, ev)
116*d0ef721eSBaptiste Daroussin #define	HPREV(h, ev)		(*(h)->h_prev)((h)->h_ref, ev)
117*d0ef721eSBaptiste Daroussin #define	HLAST(h, ev)		(*(h)->h_last)((h)->h_ref, ev)
118*d0ef721eSBaptiste Daroussin #define	HCURR(h, ev)		(*(h)->h_curr)((h)->h_ref, ev)
119*d0ef721eSBaptiste Daroussin #define	HSET(h, ev, n)		(*(h)->h_set)((h)->h_ref, ev, n)
120*d0ef721eSBaptiste Daroussin #define	HCLEAR(h, ev)		(*(h)->h_clear)((h)->h_ref, ev)
121*d0ef721eSBaptiste Daroussin #define	HENTER(h, ev, str)	(*(h)->h_enter)((h)->h_ref, ev, str)
122*d0ef721eSBaptiste Daroussin #define	HADD(h, ev, str)	(*(h)->h_add)((h)->h_ref, ev, str)
123*d0ef721eSBaptiste Daroussin #define	HDEL(h, ev, n)		(*(h)->h_del)((h)->h_ref, ev, n)
124*d0ef721eSBaptiste Daroussin 
125*d0ef721eSBaptiste Daroussin #define	h_strdup(a)	Strdup(a)
126*d0ef721eSBaptiste Daroussin #define	h_malloc(a)	malloc(a)
127*d0ef721eSBaptiste Daroussin #define	h_realloc(a, b)	realloc((a), (b))
128*d0ef721eSBaptiste Daroussin #define	h_free(a)	free(a)
129*d0ef721eSBaptiste Daroussin 
130*d0ef721eSBaptiste Daroussin typedef struct {
131*d0ef721eSBaptiste Daroussin     int		num;
132*d0ef721eSBaptiste Daroussin     Char	*str;
133*d0ef721eSBaptiste Daroussin } HistEventPrivate;
134*d0ef721eSBaptiste Daroussin 
135*d0ef721eSBaptiste Daroussin 
136*d0ef721eSBaptiste Daroussin static int history_setsize(TYPE(History) *, TYPE(HistEvent) *, int);
137*d0ef721eSBaptiste Daroussin static int history_getsize(TYPE(History) *, TYPE(HistEvent) *);
138*d0ef721eSBaptiste Daroussin static int history_setunique(TYPE(History) *, TYPE(HistEvent) *, int);
139*d0ef721eSBaptiste Daroussin static int history_getunique(TYPE(History) *, TYPE(HistEvent) *);
140*d0ef721eSBaptiste Daroussin static int history_set_fun(TYPE(History) *, TYPE(History) *);
141*d0ef721eSBaptiste Daroussin static int history_load(TYPE(History) *, const char *);
142*d0ef721eSBaptiste Daroussin static int history_save(TYPE(History) *, const char *);
143*d0ef721eSBaptiste Daroussin static int history_save_fp(TYPE(History) *, size_t, FILE *);
144*d0ef721eSBaptiste Daroussin static int history_prev_event(TYPE(History) *, TYPE(HistEvent) *, int);
145*d0ef721eSBaptiste Daroussin static int history_next_event(TYPE(History) *, TYPE(HistEvent) *, int);
146*d0ef721eSBaptiste Daroussin static int history_next_string(TYPE(History) *, TYPE(HistEvent) *,
147*d0ef721eSBaptiste Daroussin     const Char *);
148*d0ef721eSBaptiste Daroussin static int history_prev_string(TYPE(History) *, TYPE(HistEvent) *,
149*d0ef721eSBaptiste Daroussin     const Char *);
150*d0ef721eSBaptiste Daroussin 
151*d0ef721eSBaptiste Daroussin 
152*d0ef721eSBaptiste Daroussin /***********************************************************************/
153*d0ef721eSBaptiste Daroussin 
154*d0ef721eSBaptiste Daroussin /*
155*d0ef721eSBaptiste Daroussin  * Builtin- history implementation
156*d0ef721eSBaptiste Daroussin  */
157*d0ef721eSBaptiste Daroussin typedef struct hentry_t {
158*d0ef721eSBaptiste Daroussin 	TYPE(HistEvent) ev;		/* What we return		 */
159*d0ef721eSBaptiste Daroussin 	void *data;		/* data				 */
160*d0ef721eSBaptiste Daroussin 	struct hentry_t *next;	/* Next entry			 */
161*d0ef721eSBaptiste Daroussin 	struct hentry_t *prev;	/* Previous entry		 */
162*d0ef721eSBaptiste Daroussin } hentry_t;
163*d0ef721eSBaptiste Daroussin 
164*d0ef721eSBaptiste Daroussin typedef struct history_t {
165*d0ef721eSBaptiste Daroussin 	hentry_t list;		/* Fake list header element	*/
166*d0ef721eSBaptiste Daroussin 	hentry_t *cursor;	/* Current element in the list	*/
167*d0ef721eSBaptiste Daroussin 	int max;		/* Maximum number of events	*/
168*d0ef721eSBaptiste Daroussin 	int cur;		/* Current number of events	*/
169*d0ef721eSBaptiste Daroussin 	int eventid;		/* For generation of unique event id	 */
170*d0ef721eSBaptiste Daroussin 	int flags;		/* TYPE(History) flags		*/
171*d0ef721eSBaptiste Daroussin #define H_UNIQUE	1	/* Store only unique elements	*/
172*d0ef721eSBaptiste Daroussin } history_t;
173*d0ef721eSBaptiste Daroussin 
174*d0ef721eSBaptiste Daroussin static int history_def_next(void *, TYPE(HistEvent) *);
175*d0ef721eSBaptiste Daroussin static int history_def_first(void *, TYPE(HistEvent) *);
176*d0ef721eSBaptiste Daroussin static int history_def_prev(void *, TYPE(HistEvent) *);
177*d0ef721eSBaptiste Daroussin static int history_def_last(void *, TYPE(HistEvent) *);
178*d0ef721eSBaptiste Daroussin static int history_def_curr(void *, TYPE(HistEvent) *);
179*d0ef721eSBaptiste Daroussin static int history_def_set(void *, TYPE(HistEvent) *, const int);
180*d0ef721eSBaptiste Daroussin static void history_def_clear(void *, TYPE(HistEvent) *);
181*d0ef721eSBaptiste Daroussin static int history_def_enter(void *, TYPE(HistEvent) *, const Char *);
182*d0ef721eSBaptiste Daroussin static int history_def_add(void *, TYPE(HistEvent) *, const Char *);
183*d0ef721eSBaptiste Daroussin static int history_def_del(void *, TYPE(HistEvent) *, const int);
184*d0ef721eSBaptiste Daroussin 
185*d0ef721eSBaptiste Daroussin static int history_def_init(void **, TYPE(HistEvent) *, int);
186*d0ef721eSBaptiste Daroussin static int history_def_insert(history_t *, TYPE(HistEvent) *, const Char *);
187*d0ef721eSBaptiste Daroussin static void history_def_delete(history_t *, TYPE(HistEvent) *, hentry_t *);
188*d0ef721eSBaptiste Daroussin 
189*d0ef721eSBaptiste Daroussin static int history_deldata_nth(history_t *, TYPE(HistEvent) *, int, void **);
190*d0ef721eSBaptiste Daroussin static int history_set_nth(void *, TYPE(HistEvent) *, int);
191*d0ef721eSBaptiste Daroussin 
192*d0ef721eSBaptiste Daroussin #define	history_def_setsize(p, num)(void) (((history_t *)p)->max = (num))
193*d0ef721eSBaptiste Daroussin #define	history_def_getsize(p)  (((history_t *)p)->cur)
194*d0ef721eSBaptiste Daroussin #define	history_def_getunique(p) (((((history_t *)p)->flags) & H_UNIQUE) != 0)
195*d0ef721eSBaptiste Daroussin #define	history_def_setunique(p, uni) \
196*d0ef721eSBaptiste Daroussin     if (uni) \
197*d0ef721eSBaptiste Daroussin 	(((history_t *)p)->flags) |= H_UNIQUE; \
198*d0ef721eSBaptiste Daroussin     else \
199*d0ef721eSBaptiste Daroussin 	(((history_t *)p)->flags) &= ~H_UNIQUE
200*d0ef721eSBaptiste Daroussin 
201*d0ef721eSBaptiste Daroussin #define	he_strerror(code)	he_errlist[code]
202*d0ef721eSBaptiste Daroussin #define	he_seterrev(evp, code)	{\
203*d0ef721eSBaptiste Daroussin 				    evp->num = code;\
204*d0ef721eSBaptiste Daroussin 				    evp->str = he_strerror(code);\
205*d0ef721eSBaptiste Daroussin 				}
206*d0ef721eSBaptiste Daroussin 
207*d0ef721eSBaptiste Daroussin /* error messages */
208*d0ef721eSBaptiste Daroussin static const Char *const he_errlist[] = {
209*d0ef721eSBaptiste Daroussin 	STR("OK"),
210*d0ef721eSBaptiste Daroussin 	STR("unknown error"),
211*d0ef721eSBaptiste Daroussin 	STR("malloc() failed"),
212*d0ef721eSBaptiste Daroussin 	STR("first event not found"),
213*d0ef721eSBaptiste Daroussin 	STR("last event not found"),
214*d0ef721eSBaptiste Daroussin 	STR("empty list"),
215*d0ef721eSBaptiste Daroussin 	STR("no next event"),
216*d0ef721eSBaptiste Daroussin 	STR("no previous event"),
217*d0ef721eSBaptiste Daroussin 	STR("current event is invalid"),
218*d0ef721eSBaptiste Daroussin 	STR("event not found"),
219*d0ef721eSBaptiste Daroussin 	STR("can't read history from file"),
220*d0ef721eSBaptiste Daroussin 	STR("can't write history"),
221*d0ef721eSBaptiste Daroussin 	STR("required parameter(s) not supplied"),
222*d0ef721eSBaptiste Daroussin 	STR("history size negative"),
223*d0ef721eSBaptiste Daroussin 	STR("function not allowed with other history-functions-set the default"),
224*d0ef721eSBaptiste Daroussin 	STR("bad parameters")
225*d0ef721eSBaptiste Daroussin };
226*d0ef721eSBaptiste Daroussin /* error codes */
227*d0ef721eSBaptiste Daroussin #define	_HE_OK                   0
228*d0ef721eSBaptiste Daroussin #define	_HE_UNKNOWN		 1
229*d0ef721eSBaptiste Daroussin #define	_HE_MALLOC_FAILED        2
230*d0ef721eSBaptiste Daroussin #define	_HE_FIRST_NOTFOUND       3
231*d0ef721eSBaptiste Daroussin #define	_HE_LAST_NOTFOUND        4
232*d0ef721eSBaptiste Daroussin #define	_HE_EMPTY_LIST           5
233*d0ef721eSBaptiste Daroussin #define	_HE_END_REACHED          6
234*d0ef721eSBaptiste Daroussin #define	_HE_START_REACHED	 7
235*d0ef721eSBaptiste Daroussin #define	_HE_CURR_INVALID	 8
236*d0ef721eSBaptiste Daroussin #define	_HE_NOT_FOUND		 9
237*d0ef721eSBaptiste Daroussin #define	_HE_HIST_READ		10
238*d0ef721eSBaptiste Daroussin #define	_HE_HIST_WRITE		11
239*d0ef721eSBaptiste Daroussin #define	_HE_PARAM_MISSING	12
240*d0ef721eSBaptiste Daroussin #define	_HE_SIZE_NEGATIVE	13
241*d0ef721eSBaptiste Daroussin #define	_HE_NOT_ALLOWED		14
242*d0ef721eSBaptiste Daroussin #define	_HE_BAD_PARAM		15
243*d0ef721eSBaptiste Daroussin 
244*d0ef721eSBaptiste Daroussin /* history_def_first():
245*d0ef721eSBaptiste Daroussin  *	Default function to return the first event in the history.
246*d0ef721eSBaptiste Daroussin  */
247*d0ef721eSBaptiste Daroussin static int
248*d0ef721eSBaptiste Daroussin history_def_first(void *p, TYPE(HistEvent) *ev)
249*d0ef721eSBaptiste Daroussin {
250*d0ef721eSBaptiste Daroussin 	history_t *h = (history_t *) p;
251*d0ef721eSBaptiste Daroussin 
252*d0ef721eSBaptiste Daroussin 	h->cursor = h->list.next;
253*d0ef721eSBaptiste Daroussin 	if (h->cursor != &h->list)
254*d0ef721eSBaptiste Daroussin 		*ev = h->cursor->ev;
255*d0ef721eSBaptiste Daroussin 	else {
256*d0ef721eSBaptiste Daroussin 		he_seterrev(ev, _HE_FIRST_NOTFOUND);
257*d0ef721eSBaptiste Daroussin 		return -1;
258*d0ef721eSBaptiste Daroussin 	}
259*d0ef721eSBaptiste Daroussin 
260*d0ef721eSBaptiste Daroussin 	return 0;
261*d0ef721eSBaptiste Daroussin }
262*d0ef721eSBaptiste Daroussin 
263*d0ef721eSBaptiste Daroussin 
264*d0ef721eSBaptiste Daroussin /* history_def_last():
265*d0ef721eSBaptiste Daroussin  *	Default function to return the last event in the history.
266*d0ef721eSBaptiste Daroussin  */
267*d0ef721eSBaptiste Daroussin static int
268*d0ef721eSBaptiste Daroussin history_def_last(void *p, TYPE(HistEvent) *ev)
269*d0ef721eSBaptiste Daroussin {
270*d0ef721eSBaptiste Daroussin 	history_t *h = (history_t *) p;
271*d0ef721eSBaptiste Daroussin 
272*d0ef721eSBaptiste Daroussin 	h->cursor = h->list.prev;
273*d0ef721eSBaptiste Daroussin 	if (h->cursor != &h->list)
274*d0ef721eSBaptiste Daroussin 		*ev = h->cursor->ev;
275*d0ef721eSBaptiste Daroussin 	else {
276*d0ef721eSBaptiste Daroussin 		he_seterrev(ev, _HE_LAST_NOTFOUND);
277*d0ef721eSBaptiste Daroussin 		return -1;
278*d0ef721eSBaptiste Daroussin 	}
279*d0ef721eSBaptiste Daroussin 
280*d0ef721eSBaptiste Daroussin 	return 0;
281*d0ef721eSBaptiste Daroussin }
282*d0ef721eSBaptiste Daroussin 
283*d0ef721eSBaptiste Daroussin 
284*d0ef721eSBaptiste Daroussin /* history_def_next():
285*d0ef721eSBaptiste Daroussin  *	Default function to return the next event in the history.
286*d0ef721eSBaptiste Daroussin  */
287*d0ef721eSBaptiste Daroussin static int
288*d0ef721eSBaptiste Daroussin history_def_next(void *p, TYPE(HistEvent) *ev)
289*d0ef721eSBaptiste Daroussin {
290*d0ef721eSBaptiste Daroussin 	history_t *h = (history_t *) p;
291*d0ef721eSBaptiste Daroussin 
292*d0ef721eSBaptiste Daroussin 	if (h->cursor == &h->list) {
293*d0ef721eSBaptiste Daroussin 		he_seterrev(ev, _HE_EMPTY_LIST);
294*d0ef721eSBaptiste Daroussin 		return -1;
295*d0ef721eSBaptiste Daroussin 	}
296*d0ef721eSBaptiste Daroussin 
297*d0ef721eSBaptiste Daroussin 	if (h->cursor->next == &h->list) {
298*d0ef721eSBaptiste Daroussin 		he_seterrev(ev, _HE_END_REACHED);
299*d0ef721eSBaptiste Daroussin 		return -1;
300*d0ef721eSBaptiste Daroussin 	}
301*d0ef721eSBaptiste Daroussin 
302*d0ef721eSBaptiste Daroussin         h->cursor = h->cursor->next;
303*d0ef721eSBaptiste Daroussin         *ev = h->cursor->ev;
304*d0ef721eSBaptiste Daroussin 
305*d0ef721eSBaptiste Daroussin 	return 0;
306*d0ef721eSBaptiste Daroussin }
307*d0ef721eSBaptiste Daroussin 
308*d0ef721eSBaptiste Daroussin 
309*d0ef721eSBaptiste Daroussin /* history_def_prev():
310*d0ef721eSBaptiste Daroussin  *	Default function to return the previous event in the history.
311*d0ef721eSBaptiste Daroussin  */
312*d0ef721eSBaptiste Daroussin static int
313*d0ef721eSBaptiste Daroussin history_def_prev(void *p, TYPE(HistEvent) *ev)
314*d0ef721eSBaptiste Daroussin {
315*d0ef721eSBaptiste Daroussin 	history_t *h = (history_t *) p;
316*d0ef721eSBaptiste Daroussin 
317*d0ef721eSBaptiste Daroussin 	if (h->cursor == &h->list) {
318*d0ef721eSBaptiste Daroussin 		he_seterrev(ev,
319*d0ef721eSBaptiste Daroussin 		    (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST);
320*d0ef721eSBaptiste Daroussin 		return -1;
321*d0ef721eSBaptiste Daroussin 	}
322*d0ef721eSBaptiste Daroussin 
323*d0ef721eSBaptiste Daroussin 	if (h->cursor->prev == &h->list) {
324*d0ef721eSBaptiste Daroussin 		he_seterrev(ev, _HE_START_REACHED);
325*d0ef721eSBaptiste Daroussin 		return -1;
326*d0ef721eSBaptiste Daroussin 	}
327*d0ef721eSBaptiste Daroussin 
328*d0ef721eSBaptiste Daroussin         h->cursor = h->cursor->prev;
329*d0ef721eSBaptiste Daroussin         *ev = h->cursor->ev;
330*d0ef721eSBaptiste Daroussin 
331*d0ef721eSBaptiste Daroussin 	return 0;
332*d0ef721eSBaptiste Daroussin }
333*d0ef721eSBaptiste Daroussin 
334*d0ef721eSBaptiste Daroussin 
335*d0ef721eSBaptiste Daroussin /* history_def_curr():
336*d0ef721eSBaptiste Daroussin  *	Default function to return the current event in the history.
337*d0ef721eSBaptiste Daroussin  */
338*d0ef721eSBaptiste Daroussin static int
339*d0ef721eSBaptiste Daroussin history_def_curr(void *p, TYPE(HistEvent) *ev)
340*d0ef721eSBaptiste Daroussin {
341*d0ef721eSBaptiste Daroussin 	history_t *h = (history_t *) p;
342*d0ef721eSBaptiste Daroussin 
343*d0ef721eSBaptiste Daroussin 	if (h->cursor != &h->list)
344*d0ef721eSBaptiste Daroussin 		*ev = h->cursor->ev;
345*d0ef721eSBaptiste Daroussin 	else {
346*d0ef721eSBaptiste Daroussin 		he_seterrev(ev,
347*d0ef721eSBaptiste Daroussin 		    (h->cur > 0) ? _HE_CURR_INVALID : _HE_EMPTY_LIST);
348*d0ef721eSBaptiste Daroussin 		return -1;
349*d0ef721eSBaptiste Daroussin 	}
350*d0ef721eSBaptiste Daroussin 
351*d0ef721eSBaptiste Daroussin 	return 0;
352*d0ef721eSBaptiste Daroussin }
353*d0ef721eSBaptiste Daroussin 
354*d0ef721eSBaptiste Daroussin 
355*d0ef721eSBaptiste Daroussin /* history_def_set():
356*d0ef721eSBaptiste Daroussin  *	Default function to set the current event in the history to the
357*d0ef721eSBaptiste Daroussin  *	given one.
358*d0ef721eSBaptiste Daroussin  */
359*d0ef721eSBaptiste Daroussin static int
360*d0ef721eSBaptiste Daroussin history_def_set(void *p, TYPE(HistEvent) *ev, const int n)
361*d0ef721eSBaptiste Daroussin {
362*d0ef721eSBaptiste Daroussin 	history_t *h = (history_t *) p;
363*d0ef721eSBaptiste Daroussin 
364*d0ef721eSBaptiste Daroussin 	if (h->cur == 0) {
365*d0ef721eSBaptiste Daroussin 		he_seterrev(ev, _HE_EMPTY_LIST);
366*d0ef721eSBaptiste Daroussin 		return -1;
367*d0ef721eSBaptiste Daroussin 	}
368*d0ef721eSBaptiste Daroussin 	if (h->cursor == &h->list || h->cursor->ev.num != n) {
369*d0ef721eSBaptiste Daroussin 		for (h->cursor = h->list.next; h->cursor != &h->list;
370*d0ef721eSBaptiste Daroussin 		    h->cursor = h->cursor->next)
371*d0ef721eSBaptiste Daroussin 			if (h->cursor->ev.num == n)
372*d0ef721eSBaptiste Daroussin 				break;
373*d0ef721eSBaptiste Daroussin 	}
374*d0ef721eSBaptiste Daroussin 	if (h->cursor == &h->list) {
375*d0ef721eSBaptiste Daroussin 		he_seterrev(ev, _HE_NOT_FOUND);
376*d0ef721eSBaptiste Daroussin 		return -1;
377*d0ef721eSBaptiste Daroussin 	}
378*d0ef721eSBaptiste Daroussin 	return 0;
379*d0ef721eSBaptiste Daroussin }
380*d0ef721eSBaptiste Daroussin 
381*d0ef721eSBaptiste Daroussin 
382*d0ef721eSBaptiste Daroussin /* history_set_nth():
383*d0ef721eSBaptiste Daroussin  *	Default function to set the current event in the history to the
384*d0ef721eSBaptiste Daroussin  *	n-th one.
385*d0ef721eSBaptiste Daroussin  */
386*d0ef721eSBaptiste Daroussin static int
387*d0ef721eSBaptiste Daroussin history_set_nth(void *p, TYPE(HistEvent) *ev, int n)
388*d0ef721eSBaptiste Daroussin {
389*d0ef721eSBaptiste Daroussin 	history_t *h = (history_t *) p;
390*d0ef721eSBaptiste Daroussin 
391*d0ef721eSBaptiste Daroussin 	if (h->cur == 0) {
392*d0ef721eSBaptiste Daroussin 		he_seterrev(ev, _HE_EMPTY_LIST);
393*d0ef721eSBaptiste Daroussin 		return -1;
394*d0ef721eSBaptiste Daroussin 	}
395*d0ef721eSBaptiste Daroussin 	for (h->cursor = h->list.prev; h->cursor != &h->list;
396*d0ef721eSBaptiste Daroussin 	    h->cursor = h->cursor->prev)
397*d0ef721eSBaptiste Daroussin 		if (n-- <= 0)
398*d0ef721eSBaptiste Daroussin 			break;
399*d0ef721eSBaptiste Daroussin 	if (h->cursor == &h->list) {
400*d0ef721eSBaptiste Daroussin 		he_seterrev(ev, _HE_NOT_FOUND);
401*d0ef721eSBaptiste Daroussin 		return -1;
402*d0ef721eSBaptiste Daroussin 	}
403*d0ef721eSBaptiste Daroussin 	return 0;
404*d0ef721eSBaptiste Daroussin }
405*d0ef721eSBaptiste Daroussin 
406*d0ef721eSBaptiste Daroussin 
407*d0ef721eSBaptiste Daroussin /* history_def_add():
408*d0ef721eSBaptiste Daroussin  *	Append string to element
409*d0ef721eSBaptiste Daroussin  */
410*d0ef721eSBaptiste Daroussin static int
411*d0ef721eSBaptiste Daroussin history_def_add(void *p, TYPE(HistEvent) *ev, const Char *str)
412*d0ef721eSBaptiste Daroussin {
413*d0ef721eSBaptiste Daroussin 	history_t *h = (history_t *) p;
414*d0ef721eSBaptiste Daroussin 	size_t len;
415*d0ef721eSBaptiste Daroussin 	Char *s;
416*d0ef721eSBaptiste Daroussin 	HistEventPrivate *evp = (void *)&h->cursor->ev;
417*d0ef721eSBaptiste Daroussin 
418*d0ef721eSBaptiste Daroussin 	if (h->cursor == &h->list)
419*d0ef721eSBaptiste Daroussin 		return history_def_enter(p, ev, str);
420*d0ef721eSBaptiste Daroussin 	len = Strlen(evp->str) + Strlen(str) + 1;
421*d0ef721eSBaptiste Daroussin 	s = h_malloc(len * sizeof(*s));
422*d0ef721eSBaptiste Daroussin 	if (s == NULL) {
423*d0ef721eSBaptiste Daroussin 		he_seterrev(ev, _HE_MALLOC_FAILED);
424*d0ef721eSBaptiste Daroussin 		return -1;
425*d0ef721eSBaptiste Daroussin 	}
426*d0ef721eSBaptiste Daroussin 	(void) Strncpy(s, h->cursor->ev.str, len);
427*d0ef721eSBaptiste Daroussin         s[len - 1] = '\0';
428*d0ef721eSBaptiste Daroussin 	(void) Strncat(s, str, len - Strlen(s) - 1);
429*d0ef721eSBaptiste Daroussin 	h_free(evp->str);
430*d0ef721eSBaptiste Daroussin 	evp->str = s;
431*d0ef721eSBaptiste Daroussin 	*ev = h->cursor->ev;
432*d0ef721eSBaptiste Daroussin 	return 0;
433*d0ef721eSBaptiste Daroussin }
434*d0ef721eSBaptiste Daroussin 
435*d0ef721eSBaptiste Daroussin 
436*d0ef721eSBaptiste Daroussin static int
437*d0ef721eSBaptiste Daroussin history_deldata_nth(history_t *h, TYPE(HistEvent) *ev,
438*d0ef721eSBaptiste Daroussin     int num, void **data)
439*d0ef721eSBaptiste Daroussin {
440*d0ef721eSBaptiste Daroussin 	if (history_set_nth(h, ev, num) != 0)
441*d0ef721eSBaptiste Daroussin 		return -1;
442*d0ef721eSBaptiste Daroussin 	/* magic value to skip delete (just set to n-th history) */
443*d0ef721eSBaptiste Daroussin 	if (data == (void **)-1)
444*d0ef721eSBaptiste Daroussin 		return 0;
445*d0ef721eSBaptiste Daroussin 	ev->str = Strdup(h->cursor->ev.str);
446*d0ef721eSBaptiste Daroussin 	ev->num = h->cursor->ev.num;
447*d0ef721eSBaptiste Daroussin 	if (data)
448*d0ef721eSBaptiste Daroussin 		*data = h->cursor->data;
449*d0ef721eSBaptiste Daroussin 	history_def_delete(h, ev, h->cursor);
450*d0ef721eSBaptiste Daroussin 	return 0;
451*d0ef721eSBaptiste Daroussin }
452*d0ef721eSBaptiste Daroussin 
453*d0ef721eSBaptiste Daroussin 
454*d0ef721eSBaptiste Daroussin /* history_def_del():
455*d0ef721eSBaptiste Daroussin  *	Delete element hp of the h list
456*d0ef721eSBaptiste Daroussin  */
457*d0ef721eSBaptiste Daroussin /* ARGSUSED */
458*d0ef721eSBaptiste Daroussin static int
459*d0ef721eSBaptiste Daroussin history_def_del(void *p, TYPE(HistEvent) *ev __attribute__((__unused__)),
460*d0ef721eSBaptiste Daroussin     const int num)
461*d0ef721eSBaptiste Daroussin {
462*d0ef721eSBaptiste Daroussin 	history_t *h = (history_t *) p;
463*d0ef721eSBaptiste Daroussin 	if (history_def_set(h, ev, num) != 0)
464*d0ef721eSBaptiste Daroussin 		return -1;
465*d0ef721eSBaptiste Daroussin 	ev->str = Strdup(h->cursor->ev.str);
466*d0ef721eSBaptiste Daroussin 	ev->num = h->cursor->ev.num;
467*d0ef721eSBaptiste Daroussin 	history_def_delete(h, ev, h->cursor);
468*d0ef721eSBaptiste Daroussin 	return 0;
469*d0ef721eSBaptiste Daroussin }
470*d0ef721eSBaptiste Daroussin 
471*d0ef721eSBaptiste Daroussin 
472*d0ef721eSBaptiste Daroussin /* history_def_delete():
473*d0ef721eSBaptiste Daroussin  *	Delete element hp of the h list
474*d0ef721eSBaptiste Daroussin  */
475*d0ef721eSBaptiste Daroussin /* ARGSUSED */
476*d0ef721eSBaptiste Daroussin static void
477*d0ef721eSBaptiste Daroussin history_def_delete(history_t *h,
478*d0ef721eSBaptiste Daroussin 		   TYPE(HistEvent) *ev __attribute__((__unused__)), hentry_t *hp)
479*d0ef721eSBaptiste Daroussin {
480*d0ef721eSBaptiste Daroussin 	HistEventPrivate *evp = (void *)&hp->ev;
481*d0ef721eSBaptiste Daroussin 	if (hp == &h->list)
482*d0ef721eSBaptiste Daroussin 		abort();
483*d0ef721eSBaptiste Daroussin 	if (h->cursor == hp) {
484*d0ef721eSBaptiste Daroussin 		h->cursor = hp->prev;
485*d0ef721eSBaptiste Daroussin 		if (h->cursor == &h->list)
486*d0ef721eSBaptiste Daroussin 			h->cursor = hp->next;
487*d0ef721eSBaptiste Daroussin 	}
488*d0ef721eSBaptiste Daroussin 	hp->prev->next = hp->next;
489*d0ef721eSBaptiste Daroussin 	hp->next->prev = hp->prev;
490*d0ef721eSBaptiste Daroussin 	h_free(evp->str);
491*d0ef721eSBaptiste Daroussin 	h_free(hp);
492*d0ef721eSBaptiste Daroussin 	h->cur--;
493*d0ef721eSBaptiste Daroussin }
494*d0ef721eSBaptiste Daroussin 
495*d0ef721eSBaptiste Daroussin 
496*d0ef721eSBaptiste Daroussin /* history_def_insert():
497*d0ef721eSBaptiste Daroussin  *	Insert element with string str in the h list
498*d0ef721eSBaptiste Daroussin  */
499*d0ef721eSBaptiste Daroussin static int
500*d0ef721eSBaptiste Daroussin history_def_insert(history_t *h, TYPE(HistEvent) *ev, const Char *str)
501*d0ef721eSBaptiste Daroussin {
502*d0ef721eSBaptiste Daroussin 	hentry_t *c;
503*d0ef721eSBaptiste Daroussin 
504*d0ef721eSBaptiste Daroussin 	c = h_malloc(sizeof(*c));
505*d0ef721eSBaptiste Daroussin 	if (c == NULL)
506*d0ef721eSBaptiste Daroussin 		goto oomem;
507*d0ef721eSBaptiste Daroussin 	if ((c->ev.str = h_strdup(str)) == NULL) {
508*d0ef721eSBaptiste Daroussin 		h_free(c);
509*d0ef721eSBaptiste Daroussin 		goto oomem;
510*d0ef721eSBaptiste Daroussin 	}
511*d0ef721eSBaptiste Daroussin 	c->data = NULL;
512*d0ef721eSBaptiste Daroussin 	c->ev.num = ++h->eventid;
513*d0ef721eSBaptiste Daroussin 	c->next = h->list.next;
514*d0ef721eSBaptiste Daroussin 	c->prev = &h->list;
515*d0ef721eSBaptiste Daroussin 	h->list.next->prev = c;
516*d0ef721eSBaptiste Daroussin 	h->list.next = c;
517*d0ef721eSBaptiste Daroussin 	h->cur++;
518*d0ef721eSBaptiste Daroussin 	h->cursor = c;
519*d0ef721eSBaptiste Daroussin 
520*d0ef721eSBaptiste Daroussin 	*ev = c->ev;
521*d0ef721eSBaptiste Daroussin 	return 0;
522*d0ef721eSBaptiste Daroussin oomem:
523*d0ef721eSBaptiste Daroussin 	he_seterrev(ev, _HE_MALLOC_FAILED);
524*d0ef721eSBaptiste Daroussin 	return -1;
525*d0ef721eSBaptiste Daroussin }
526*d0ef721eSBaptiste Daroussin 
527*d0ef721eSBaptiste Daroussin 
528*d0ef721eSBaptiste Daroussin /* history_def_enter():
529*d0ef721eSBaptiste Daroussin  *	Default function to enter an item in the history
530*d0ef721eSBaptiste Daroussin  */
531*d0ef721eSBaptiste Daroussin static int
532*d0ef721eSBaptiste Daroussin history_def_enter(void *p, TYPE(HistEvent) *ev, const Char *str)
533*d0ef721eSBaptiste Daroussin {
534*d0ef721eSBaptiste Daroussin 	history_t *h = (history_t *) p;
535*d0ef721eSBaptiste Daroussin 
536*d0ef721eSBaptiste Daroussin 	if ((h->flags & H_UNIQUE) != 0 && h->list.next != &h->list &&
537*d0ef721eSBaptiste Daroussin 	    Strcmp(h->list.next->ev.str, str) == 0)
538*d0ef721eSBaptiste Daroussin 	    return 0;
539*d0ef721eSBaptiste Daroussin 
540*d0ef721eSBaptiste Daroussin 	if (history_def_insert(h, ev, str) == -1)
541*d0ef721eSBaptiste Daroussin 		return -1;	/* error, keep error message */
542*d0ef721eSBaptiste Daroussin 
543*d0ef721eSBaptiste Daroussin 	/*
544*d0ef721eSBaptiste Daroussin          * Always keep at least one entry.
545*d0ef721eSBaptiste Daroussin          * This way we don't have to check for the empty list.
546*d0ef721eSBaptiste Daroussin          */
547*d0ef721eSBaptiste Daroussin 	while (h->cur > h->max && h->cur > 0)
548*d0ef721eSBaptiste Daroussin 		history_def_delete(h, ev, h->list.prev);
549*d0ef721eSBaptiste Daroussin 
550*d0ef721eSBaptiste Daroussin 	return 1;
551*d0ef721eSBaptiste Daroussin }
552*d0ef721eSBaptiste Daroussin 
553*d0ef721eSBaptiste Daroussin 
554*d0ef721eSBaptiste Daroussin /* history_def_init():
555*d0ef721eSBaptiste Daroussin  *	Default history initialization function
556*d0ef721eSBaptiste Daroussin  */
557*d0ef721eSBaptiste Daroussin /* ARGSUSED */
558*d0ef721eSBaptiste Daroussin static int
559*d0ef721eSBaptiste Daroussin history_def_init(void **p, TYPE(HistEvent) *ev __attribute__((__unused__)), int n)
560*d0ef721eSBaptiste Daroussin {
561*d0ef721eSBaptiste Daroussin 	history_t *h = (history_t *) h_malloc(sizeof(*h));
562*d0ef721eSBaptiste Daroussin 	if (h == NULL)
563*d0ef721eSBaptiste Daroussin 		return -1;
564*d0ef721eSBaptiste Daroussin 
565*d0ef721eSBaptiste Daroussin 	if (n <= 0)
566*d0ef721eSBaptiste Daroussin 		n = 0;
567*d0ef721eSBaptiste Daroussin 	h->eventid = 0;
568*d0ef721eSBaptiste Daroussin 	h->cur = 0;
569*d0ef721eSBaptiste Daroussin 	h->max = n;
570*d0ef721eSBaptiste Daroussin 	h->list.next = h->list.prev = &h->list;
571*d0ef721eSBaptiste Daroussin 	h->list.ev.str = NULL;
572*d0ef721eSBaptiste Daroussin 	h->list.ev.num = 0;
573*d0ef721eSBaptiste Daroussin 	h->cursor = &h->list;
574*d0ef721eSBaptiste Daroussin 	h->flags = 0;
575*d0ef721eSBaptiste Daroussin 	*p = h;
576*d0ef721eSBaptiste Daroussin 	return 0;
577*d0ef721eSBaptiste Daroussin }
578*d0ef721eSBaptiste Daroussin 
579*d0ef721eSBaptiste Daroussin 
580*d0ef721eSBaptiste Daroussin /* history_def_clear():
581*d0ef721eSBaptiste Daroussin  *	Default history cleanup function
582*d0ef721eSBaptiste Daroussin  */
583*d0ef721eSBaptiste Daroussin static void
584*d0ef721eSBaptiste Daroussin history_def_clear(void *p, TYPE(HistEvent) *ev)
585*d0ef721eSBaptiste Daroussin {
586*d0ef721eSBaptiste Daroussin 	history_t *h = (history_t *) p;
587*d0ef721eSBaptiste Daroussin 
588*d0ef721eSBaptiste Daroussin 	while (h->list.prev != &h->list)
589*d0ef721eSBaptiste Daroussin 		history_def_delete(h, ev, h->list.prev);
590*d0ef721eSBaptiste Daroussin 	h->cursor = &h->list;
591*d0ef721eSBaptiste Daroussin 	h->eventid = 0;
592*d0ef721eSBaptiste Daroussin 	h->cur = 0;
593*d0ef721eSBaptiste Daroussin }
594*d0ef721eSBaptiste Daroussin 
595*d0ef721eSBaptiste Daroussin 
596*d0ef721eSBaptiste Daroussin 
597*d0ef721eSBaptiste Daroussin 
598*d0ef721eSBaptiste Daroussin /************************************************************************/
599*d0ef721eSBaptiste Daroussin 
600*d0ef721eSBaptiste Daroussin /* history_init():
601*d0ef721eSBaptiste Daroussin  *	Initialization function.
602*d0ef721eSBaptiste Daroussin  */
603*d0ef721eSBaptiste Daroussin TYPE(History) *
604*d0ef721eSBaptiste Daroussin FUN(history,init)(void)
605*d0ef721eSBaptiste Daroussin {
606*d0ef721eSBaptiste Daroussin 	TYPE(HistEvent) ev;
607*d0ef721eSBaptiste Daroussin 	TYPE(History) *h = (TYPE(History) *) h_malloc(sizeof(*h));
608*d0ef721eSBaptiste Daroussin 	if (h == NULL)
609*d0ef721eSBaptiste Daroussin 		return NULL;
610*d0ef721eSBaptiste Daroussin 
611*d0ef721eSBaptiste Daroussin 	if (history_def_init(&h->h_ref, &ev, 0) == -1) {
612*d0ef721eSBaptiste Daroussin 		h_free(h);
613*d0ef721eSBaptiste Daroussin 		return NULL;
614*d0ef721eSBaptiste Daroussin 	}
615*d0ef721eSBaptiste Daroussin 	h->h_ent = -1;
616*d0ef721eSBaptiste Daroussin 	h->h_next = history_def_next;
617*d0ef721eSBaptiste Daroussin 	h->h_first = history_def_first;
618*d0ef721eSBaptiste Daroussin 	h->h_last = history_def_last;
619*d0ef721eSBaptiste Daroussin 	h->h_prev = history_def_prev;
620*d0ef721eSBaptiste Daroussin 	h->h_curr = history_def_curr;
621*d0ef721eSBaptiste Daroussin 	h->h_set = history_def_set;
622*d0ef721eSBaptiste Daroussin 	h->h_clear = history_def_clear;
623*d0ef721eSBaptiste Daroussin 	h->h_enter = history_def_enter;
624*d0ef721eSBaptiste Daroussin 	h->h_add = history_def_add;
625*d0ef721eSBaptiste Daroussin 	h->h_del = history_def_del;
626*d0ef721eSBaptiste Daroussin 
627*d0ef721eSBaptiste Daroussin 	return h;
628*d0ef721eSBaptiste Daroussin }
629*d0ef721eSBaptiste Daroussin 
630*d0ef721eSBaptiste Daroussin 
631*d0ef721eSBaptiste Daroussin /* history_end():
632*d0ef721eSBaptiste Daroussin  *	clean up history;
633*d0ef721eSBaptiste Daroussin  */
634*d0ef721eSBaptiste Daroussin void
635*d0ef721eSBaptiste Daroussin FUN(history,end)(TYPE(History) *h)
636*d0ef721eSBaptiste Daroussin {
637*d0ef721eSBaptiste Daroussin 	TYPE(HistEvent) ev;
638*d0ef721eSBaptiste Daroussin 
639*d0ef721eSBaptiste Daroussin 	if (h->h_next == history_def_next)
640*d0ef721eSBaptiste Daroussin 		history_def_clear(h->h_ref, &ev);
641*d0ef721eSBaptiste Daroussin 	h_free(h->h_ref);
642*d0ef721eSBaptiste Daroussin 	h_free(h);
643*d0ef721eSBaptiste Daroussin }
644*d0ef721eSBaptiste Daroussin 
645*d0ef721eSBaptiste Daroussin 
646*d0ef721eSBaptiste Daroussin 
647*d0ef721eSBaptiste Daroussin /* history_setsize():
648*d0ef721eSBaptiste Daroussin  *	Set history number of events
649*d0ef721eSBaptiste Daroussin  */
650*d0ef721eSBaptiste Daroussin static int
651*d0ef721eSBaptiste Daroussin history_setsize(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
652*d0ef721eSBaptiste Daroussin {
653*d0ef721eSBaptiste Daroussin 
654*d0ef721eSBaptiste Daroussin 	if (h->h_next != history_def_next) {
655*d0ef721eSBaptiste Daroussin 		he_seterrev(ev, _HE_NOT_ALLOWED);
656*d0ef721eSBaptiste Daroussin 		return -1;
657*d0ef721eSBaptiste Daroussin 	}
658*d0ef721eSBaptiste Daroussin 	if (num < 0) {
659*d0ef721eSBaptiste Daroussin 		he_seterrev(ev, _HE_BAD_PARAM);
660*d0ef721eSBaptiste Daroussin 		return -1;
661*d0ef721eSBaptiste Daroussin 	}
662*d0ef721eSBaptiste Daroussin 	history_def_setsize(h->h_ref, num);
663*d0ef721eSBaptiste Daroussin 	return 0;
664*d0ef721eSBaptiste Daroussin }
665*d0ef721eSBaptiste Daroussin 
666*d0ef721eSBaptiste Daroussin 
667*d0ef721eSBaptiste Daroussin /* history_getsize():
668*d0ef721eSBaptiste Daroussin  *      Get number of events currently in history
669*d0ef721eSBaptiste Daroussin  */
670*d0ef721eSBaptiste Daroussin static int
671*d0ef721eSBaptiste Daroussin history_getsize(TYPE(History) *h, TYPE(HistEvent) *ev)
672*d0ef721eSBaptiste Daroussin {
673*d0ef721eSBaptiste Daroussin 	if (h->h_next != history_def_next) {
674*d0ef721eSBaptiste Daroussin 		he_seterrev(ev, _HE_NOT_ALLOWED);
675*d0ef721eSBaptiste Daroussin 		return -1;
676*d0ef721eSBaptiste Daroussin 	}
677*d0ef721eSBaptiste Daroussin 	ev->num = history_def_getsize(h->h_ref);
678*d0ef721eSBaptiste Daroussin 	if (ev->num < -1) {
679*d0ef721eSBaptiste Daroussin 		he_seterrev(ev, _HE_SIZE_NEGATIVE);
680*d0ef721eSBaptiste Daroussin 		return -1;
681*d0ef721eSBaptiste Daroussin 	}
682*d0ef721eSBaptiste Daroussin 	return 0;
683*d0ef721eSBaptiste Daroussin }
684*d0ef721eSBaptiste Daroussin 
685*d0ef721eSBaptiste Daroussin 
686*d0ef721eSBaptiste Daroussin /* history_setunique():
687*d0ef721eSBaptiste Daroussin  *	Set if adjacent equal events should not be entered in history.
688*d0ef721eSBaptiste Daroussin  */
689*d0ef721eSBaptiste Daroussin static int
690*d0ef721eSBaptiste Daroussin history_setunique(TYPE(History) *h, TYPE(HistEvent) *ev, int uni)
691*d0ef721eSBaptiste Daroussin {
692*d0ef721eSBaptiste Daroussin 
693*d0ef721eSBaptiste Daroussin 	if (h->h_next != history_def_next) {
694*d0ef721eSBaptiste Daroussin 		he_seterrev(ev, _HE_NOT_ALLOWED);
695*d0ef721eSBaptiste Daroussin 		return -1;
696*d0ef721eSBaptiste Daroussin 	}
697*d0ef721eSBaptiste Daroussin 	history_def_setunique(h->h_ref, uni);
698*d0ef721eSBaptiste Daroussin 	return 0;
699*d0ef721eSBaptiste Daroussin }
700*d0ef721eSBaptiste Daroussin 
701*d0ef721eSBaptiste Daroussin 
702*d0ef721eSBaptiste Daroussin /* history_getunique():
703*d0ef721eSBaptiste Daroussin  *	Get if adjacent equal events should not be entered in history.
704*d0ef721eSBaptiste Daroussin  */
705*d0ef721eSBaptiste Daroussin static int
706*d0ef721eSBaptiste Daroussin history_getunique(TYPE(History) *h, TYPE(HistEvent) *ev)
707*d0ef721eSBaptiste Daroussin {
708*d0ef721eSBaptiste Daroussin 	if (h->h_next != history_def_next) {
709*d0ef721eSBaptiste Daroussin 		he_seterrev(ev, _HE_NOT_ALLOWED);
710*d0ef721eSBaptiste Daroussin 		return -1;
711*d0ef721eSBaptiste Daroussin 	}
712*d0ef721eSBaptiste Daroussin 	ev->num = history_def_getunique(h->h_ref);
713*d0ef721eSBaptiste Daroussin 	return 0;
714*d0ef721eSBaptiste Daroussin }
715*d0ef721eSBaptiste Daroussin 
716*d0ef721eSBaptiste Daroussin 
717*d0ef721eSBaptiste Daroussin /* history_set_fun():
718*d0ef721eSBaptiste Daroussin  *	Set history functions
719*d0ef721eSBaptiste Daroussin  */
720*d0ef721eSBaptiste Daroussin static int
721*d0ef721eSBaptiste Daroussin history_set_fun(TYPE(History) *h, TYPE(History) *nh)
722*d0ef721eSBaptiste Daroussin {
723*d0ef721eSBaptiste Daroussin 	TYPE(HistEvent) ev;
724*d0ef721eSBaptiste Daroussin 
725*d0ef721eSBaptiste Daroussin 	if (nh->h_first == NULL || nh->h_next == NULL || nh->h_last == NULL ||
726*d0ef721eSBaptiste Daroussin 	    nh->h_prev == NULL || nh->h_curr == NULL || nh->h_set == NULL ||
727*d0ef721eSBaptiste Daroussin 	    nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL ||
728*d0ef721eSBaptiste Daroussin 	    nh->h_del == NULL || nh->h_ref == NULL) {
729*d0ef721eSBaptiste Daroussin 		if (h->h_next != history_def_next) {
730*d0ef721eSBaptiste Daroussin 			if (history_def_init(&h->h_ref, &ev, 0) == -1)
731*d0ef721eSBaptiste Daroussin 				return -1;
732*d0ef721eSBaptiste Daroussin 			h->h_first = history_def_first;
733*d0ef721eSBaptiste Daroussin 			h->h_next = history_def_next;
734*d0ef721eSBaptiste Daroussin 			h->h_last = history_def_last;
735*d0ef721eSBaptiste Daroussin 			h->h_prev = history_def_prev;
736*d0ef721eSBaptiste Daroussin 			h->h_curr = history_def_curr;
737*d0ef721eSBaptiste Daroussin 			h->h_set = history_def_set;
738*d0ef721eSBaptiste Daroussin 			h->h_clear = history_def_clear;
739*d0ef721eSBaptiste Daroussin 			h->h_enter = history_def_enter;
740*d0ef721eSBaptiste Daroussin 			h->h_add = history_def_add;
741*d0ef721eSBaptiste Daroussin 			h->h_del = history_def_del;
742*d0ef721eSBaptiste Daroussin 		}
743*d0ef721eSBaptiste Daroussin 		return -1;
744*d0ef721eSBaptiste Daroussin 	}
745*d0ef721eSBaptiste Daroussin 	if (h->h_next == history_def_next)
746*d0ef721eSBaptiste Daroussin 		history_def_clear(h->h_ref, &ev);
747*d0ef721eSBaptiste Daroussin 
748*d0ef721eSBaptiste Daroussin 	h->h_ent = -1;
749*d0ef721eSBaptiste Daroussin 	h->h_first = nh->h_first;
750*d0ef721eSBaptiste Daroussin 	h->h_next = nh->h_next;
751*d0ef721eSBaptiste Daroussin 	h->h_last = nh->h_last;
752*d0ef721eSBaptiste Daroussin 	h->h_prev = nh->h_prev;
753*d0ef721eSBaptiste Daroussin 	h->h_curr = nh->h_curr;
754*d0ef721eSBaptiste Daroussin 	h->h_set = nh->h_set;
755*d0ef721eSBaptiste Daroussin 	h->h_clear = nh->h_clear;
756*d0ef721eSBaptiste Daroussin 	h->h_enter = nh->h_enter;
757*d0ef721eSBaptiste Daroussin 	h->h_add = nh->h_add;
758*d0ef721eSBaptiste Daroussin 	h->h_del = nh->h_del;
759*d0ef721eSBaptiste Daroussin 
760*d0ef721eSBaptiste Daroussin 	return 0;
761*d0ef721eSBaptiste Daroussin }
762*d0ef721eSBaptiste Daroussin 
763*d0ef721eSBaptiste Daroussin 
764*d0ef721eSBaptiste Daroussin /* history_load():
765*d0ef721eSBaptiste Daroussin  *	TYPE(History) load function
766*d0ef721eSBaptiste Daroussin  */
767*d0ef721eSBaptiste Daroussin static int
768*d0ef721eSBaptiste Daroussin history_load(TYPE(History) *h, const char *fname)
769*d0ef721eSBaptiste Daroussin {
770*d0ef721eSBaptiste Daroussin 	FILE *fp;
771*d0ef721eSBaptiste Daroussin 	char *line;
772*d0ef721eSBaptiste Daroussin 	size_t llen;
773*d0ef721eSBaptiste Daroussin 	ssize_t sz;
774*d0ef721eSBaptiste Daroussin 	size_t max_size;
775*d0ef721eSBaptiste Daroussin 	char *ptr;
776*d0ef721eSBaptiste Daroussin 	int i = -1;
777*d0ef721eSBaptiste Daroussin 	TYPE(HistEvent) ev;
778*d0ef721eSBaptiste Daroussin 	Char *decode_result;
779*d0ef721eSBaptiste Daroussin #ifndef NARROWCHAR
780*d0ef721eSBaptiste Daroussin 	static ct_buffer_t conv;
781*d0ef721eSBaptiste Daroussin #endif
782*d0ef721eSBaptiste Daroussin 
783*d0ef721eSBaptiste Daroussin 	if ((fp = fopen(fname, "r")) == NULL)
784*d0ef721eSBaptiste Daroussin 		return i;
785*d0ef721eSBaptiste Daroussin 
786*d0ef721eSBaptiste Daroussin 	line = NULL;
787*d0ef721eSBaptiste Daroussin 	llen = 0;
788*d0ef721eSBaptiste Daroussin 	if ((sz = getline(&line, &llen, fp)) == -1)
789*d0ef721eSBaptiste Daroussin 		goto done;
790*d0ef721eSBaptiste Daroussin 
791*d0ef721eSBaptiste Daroussin 	if (strncmp(line, hist_cookie, (size_t)sz) != 0)
792*d0ef721eSBaptiste Daroussin 		goto done;
793*d0ef721eSBaptiste Daroussin 
794*d0ef721eSBaptiste Daroussin 	ptr = h_malloc((max_size = 1024) * sizeof(*ptr));
795*d0ef721eSBaptiste Daroussin 	if (ptr == NULL)
796*d0ef721eSBaptiste Daroussin 		goto done;
797*d0ef721eSBaptiste Daroussin 	for (i = 0; (sz = getline(&line, &llen, fp)) != -1; i++) {
798*d0ef721eSBaptiste Daroussin 		if (sz > 0 && line[sz - 1] == '\n')
799*d0ef721eSBaptiste Daroussin 			line[--sz] = '\0';
800*d0ef721eSBaptiste Daroussin 		if (max_size < (size_t)sz) {
801*d0ef721eSBaptiste Daroussin 			char *nptr;
802*d0ef721eSBaptiste Daroussin 			max_size = ((size_t)sz + 1024) & (size_t)~1023;
803*d0ef721eSBaptiste Daroussin 			nptr = h_realloc(ptr, max_size * sizeof(*ptr));
804*d0ef721eSBaptiste Daroussin 			if (nptr == NULL) {
805*d0ef721eSBaptiste Daroussin 				i = -1;
806*d0ef721eSBaptiste Daroussin 				goto oomem;
807*d0ef721eSBaptiste Daroussin 			}
808*d0ef721eSBaptiste Daroussin 			ptr = nptr;
809*d0ef721eSBaptiste Daroussin 		}
810*d0ef721eSBaptiste Daroussin 		(void) strunvis(ptr, line);
811*d0ef721eSBaptiste Daroussin 		decode_result = ct_decode_string(ptr, &conv);
812*d0ef721eSBaptiste Daroussin 		if (decode_result == NULL)
813*d0ef721eSBaptiste Daroussin 			continue;
814*d0ef721eSBaptiste Daroussin 		if (HENTER(h, &ev, decode_result) == -1) {
815*d0ef721eSBaptiste Daroussin 			i = -1;
816*d0ef721eSBaptiste Daroussin 			goto oomem;
817*d0ef721eSBaptiste Daroussin 		}
818*d0ef721eSBaptiste Daroussin 	}
819*d0ef721eSBaptiste Daroussin oomem:
820*d0ef721eSBaptiste Daroussin 	h_free(ptr);
821*d0ef721eSBaptiste Daroussin done:
822*d0ef721eSBaptiste Daroussin 	free(line);
823*d0ef721eSBaptiste Daroussin 	(void) fclose(fp);
824*d0ef721eSBaptiste Daroussin 	return i;
825*d0ef721eSBaptiste Daroussin }
826*d0ef721eSBaptiste Daroussin 
827*d0ef721eSBaptiste Daroussin 
828*d0ef721eSBaptiste Daroussin /* history_save_fp():
829*d0ef721eSBaptiste Daroussin  *	TYPE(History) save function
830*d0ef721eSBaptiste Daroussin  */
831*d0ef721eSBaptiste Daroussin static int
832*d0ef721eSBaptiste Daroussin history_save_fp(TYPE(History) *h, size_t nelem, FILE *fp)
833*d0ef721eSBaptiste Daroussin {
834*d0ef721eSBaptiste Daroussin 	TYPE(HistEvent) ev;
835*d0ef721eSBaptiste Daroussin 	int i = -1, retval;
836*d0ef721eSBaptiste Daroussin 	size_t len, max_size;
837*d0ef721eSBaptiste Daroussin 	char *ptr;
838*d0ef721eSBaptiste Daroussin 	const char *str;
839*d0ef721eSBaptiste Daroussin #ifndef NARROWCHAR
840*d0ef721eSBaptiste Daroussin 	static ct_buffer_t conv;
841*d0ef721eSBaptiste Daroussin #endif
842*d0ef721eSBaptiste Daroussin 
843*d0ef721eSBaptiste Daroussin 	if (fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1)
844*d0ef721eSBaptiste Daroussin 		goto done;
845*d0ef721eSBaptiste Daroussin 	if (ftell(fp) == 0 && fputs(hist_cookie, fp) == EOF)
846*d0ef721eSBaptiste Daroussin 		goto done;
847*d0ef721eSBaptiste Daroussin 	ptr = h_malloc((max_size = 1024) * sizeof(*ptr));
848*d0ef721eSBaptiste Daroussin 	if (ptr == NULL)
849*d0ef721eSBaptiste Daroussin 		goto done;
850*d0ef721eSBaptiste Daroussin 	if (nelem != (size_t)-1) {
851*d0ef721eSBaptiste Daroussin 		for (retval = HFIRST(h, &ev); retval != -1 && nelem-- > 0;
852*d0ef721eSBaptiste Daroussin 		    retval = HNEXT(h, &ev))
853*d0ef721eSBaptiste Daroussin 			continue;
854*d0ef721eSBaptiste Daroussin 	} else
855*d0ef721eSBaptiste Daroussin 		retval = -1;
856*d0ef721eSBaptiste Daroussin 
857*d0ef721eSBaptiste Daroussin 	if (retval == -1)
858*d0ef721eSBaptiste Daroussin 		retval = HLAST(h, &ev);
859*d0ef721eSBaptiste Daroussin 
860*d0ef721eSBaptiste Daroussin 	for (i = 0; retval != -1; retval = HPREV(h, &ev), i++) {
861*d0ef721eSBaptiste Daroussin 		str = ct_encode_string(ev.str, &conv);
862*d0ef721eSBaptiste Daroussin 		len = strlen(str) * 4 + 1;
863*d0ef721eSBaptiste Daroussin 		if (len > max_size) {
864*d0ef721eSBaptiste Daroussin 			char *nptr;
865*d0ef721eSBaptiste Daroussin 			max_size = (len + 1024) & (size_t)~1023;
866*d0ef721eSBaptiste Daroussin 			nptr = h_realloc(ptr, max_size * sizeof(*ptr));
867*d0ef721eSBaptiste Daroussin 			if (nptr == NULL) {
868*d0ef721eSBaptiste Daroussin 				i = -1;
869*d0ef721eSBaptiste Daroussin 				goto oomem;
870*d0ef721eSBaptiste Daroussin 			}
871*d0ef721eSBaptiste Daroussin 			ptr = nptr;
872*d0ef721eSBaptiste Daroussin 		}
873*d0ef721eSBaptiste Daroussin 		(void) strvis(ptr, str, VIS_WHITE);
874*d0ef721eSBaptiste Daroussin 		(void) fprintf(fp, "%s\n", ptr);
875*d0ef721eSBaptiste Daroussin 	}
876*d0ef721eSBaptiste Daroussin oomem:
877*d0ef721eSBaptiste Daroussin 	h_free(ptr);
878*d0ef721eSBaptiste Daroussin done:
879*d0ef721eSBaptiste Daroussin 	return i;
880*d0ef721eSBaptiste Daroussin }
881*d0ef721eSBaptiste Daroussin 
882*d0ef721eSBaptiste Daroussin 
883*d0ef721eSBaptiste Daroussin /* history_save():
884*d0ef721eSBaptiste Daroussin  *    History save function
885*d0ef721eSBaptiste Daroussin  */
886*d0ef721eSBaptiste Daroussin static int
887*d0ef721eSBaptiste Daroussin history_save(TYPE(History) *h, const char *fname)
888*d0ef721eSBaptiste Daroussin {
889*d0ef721eSBaptiste Daroussin     FILE *fp;
890*d0ef721eSBaptiste Daroussin     int i;
891*d0ef721eSBaptiste Daroussin 
892*d0ef721eSBaptiste Daroussin     if ((fp = fopen(fname, "w")) == NULL)
893*d0ef721eSBaptiste Daroussin 	return -1;
894*d0ef721eSBaptiste Daroussin 
895*d0ef721eSBaptiste Daroussin     i = history_save_fp(h, (size_t)-1, fp);
896*d0ef721eSBaptiste Daroussin 
897*d0ef721eSBaptiste Daroussin     (void) fclose(fp);
898*d0ef721eSBaptiste Daroussin     return i;
899*d0ef721eSBaptiste Daroussin }
900*d0ef721eSBaptiste Daroussin 
901*d0ef721eSBaptiste Daroussin 
902*d0ef721eSBaptiste Daroussin /* history_prev_event():
903*d0ef721eSBaptiste Daroussin  *	Find the previous event, with number given
904*d0ef721eSBaptiste Daroussin  */
905*d0ef721eSBaptiste Daroussin static int
906*d0ef721eSBaptiste Daroussin history_prev_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
907*d0ef721eSBaptiste Daroussin {
908*d0ef721eSBaptiste Daroussin 	int retval;
909*d0ef721eSBaptiste Daroussin 
910*d0ef721eSBaptiste Daroussin 	for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
911*d0ef721eSBaptiste Daroussin 		if (ev->num == num)
912*d0ef721eSBaptiste Daroussin 			return 0;
913*d0ef721eSBaptiste Daroussin 
914*d0ef721eSBaptiste Daroussin 	he_seterrev(ev, _HE_NOT_FOUND);
915*d0ef721eSBaptiste Daroussin 	return -1;
916*d0ef721eSBaptiste Daroussin }
917*d0ef721eSBaptiste Daroussin 
918*d0ef721eSBaptiste Daroussin 
919*d0ef721eSBaptiste Daroussin static int
920*d0ef721eSBaptiste Daroussin history_next_evdata(TYPE(History) *h, TYPE(HistEvent) *ev, int num, void **d)
921*d0ef721eSBaptiste Daroussin {
922*d0ef721eSBaptiste Daroussin 	int retval;
923*d0ef721eSBaptiste Daroussin 
924*d0ef721eSBaptiste Daroussin 	for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
925*d0ef721eSBaptiste Daroussin 		if (ev->num == num) {
926*d0ef721eSBaptiste Daroussin 			if (d)
927*d0ef721eSBaptiste Daroussin 				*d = ((history_t *)h->h_ref)->cursor->data;
928*d0ef721eSBaptiste Daroussin 			return 0;
929*d0ef721eSBaptiste Daroussin 		}
930*d0ef721eSBaptiste Daroussin 
931*d0ef721eSBaptiste Daroussin 	he_seterrev(ev, _HE_NOT_FOUND);
932*d0ef721eSBaptiste Daroussin 	return -1;
933*d0ef721eSBaptiste Daroussin }
934*d0ef721eSBaptiste Daroussin 
935*d0ef721eSBaptiste Daroussin 
936*d0ef721eSBaptiste Daroussin /* history_next_event():
937*d0ef721eSBaptiste Daroussin  *	Find the next event, with number given
938*d0ef721eSBaptiste Daroussin  */
939*d0ef721eSBaptiste Daroussin static int
940*d0ef721eSBaptiste Daroussin history_next_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
941*d0ef721eSBaptiste Daroussin {
942*d0ef721eSBaptiste Daroussin 	int retval;
943*d0ef721eSBaptiste Daroussin 
944*d0ef721eSBaptiste Daroussin 	for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
945*d0ef721eSBaptiste Daroussin 		if (ev->num == num)
946*d0ef721eSBaptiste Daroussin 			return 0;
947*d0ef721eSBaptiste Daroussin 
948*d0ef721eSBaptiste Daroussin 	he_seterrev(ev, _HE_NOT_FOUND);
949*d0ef721eSBaptiste Daroussin 	return -1;
950*d0ef721eSBaptiste Daroussin }
951*d0ef721eSBaptiste Daroussin 
952*d0ef721eSBaptiste Daroussin 
953*d0ef721eSBaptiste Daroussin /* history_prev_string():
954*d0ef721eSBaptiste Daroussin  *	Find the previous event beginning with string
955*d0ef721eSBaptiste Daroussin  */
956*d0ef721eSBaptiste Daroussin static int
957*d0ef721eSBaptiste Daroussin history_prev_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str)
958*d0ef721eSBaptiste Daroussin {
959*d0ef721eSBaptiste Daroussin 	size_t len = Strlen(str);
960*d0ef721eSBaptiste Daroussin 	int retval;
961*d0ef721eSBaptiste Daroussin 
962*d0ef721eSBaptiste Daroussin 	for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
963*d0ef721eSBaptiste Daroussin 		if (Strncmp(str, ev->str, len) == 0)
964*d0ef721eSBaptiste Daroussin 			return 0;
965*d0ef721eSBaptiste Daroussin 
966*d0ef721eSBaptiste Daroussin 	he_seterrev(ev, _HE_NOT_FOUND);
967*d0ef721eSBaptiste Daroussin 	return -1;
968*d0ef721eSBaptiste Daroussin }
969*d0ef721eSBaptiste Daroussin 
970*d0ef721eSBaptiste Daroussin 
971*d0ef721eSBaptiste Daroussin /* history_next_string():
972*d0ef721eSBaptiste Daroussin  *	Find the next event beginning with string
973*d0ef721eSBaptiste Daroussin  */
974*d0ef721eSBaptiste Daroussin static int
975*d0ef721eSBaptiste Daroussin history_next_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str)
976*d0ef721eSBaptiste Daroussin {
977*d0ef721eSBaptiste Daroussin 	size_t len = Strlen(str);
978*d0ef721eSBaptiste Daroussin 	int retval;
979*d0ef721eSBaptiste Daroussin 
980*d0ef721eSBaptiste Daroussin 	for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
981*d0ef721eSBaptiste Daroussin 		if (Strncmp(str, ev->str, len) == 0)
982*d0ef721eSBaptiste Daroussin 			return 0;
983*d0ef721eSBaptiste Daroussin 
984*d0ef721eSBaptiste Daroussin 	he_seterrev(ev, _HE_NOT_FOUND);
985*d0ef721eSBaptiste Daroussin 	return -1;
986*d0ef721eSBaptiste Daroussin }
987*d0ef721eSBaptiste Daroussin 
988*d0ef721eSBaptiste Daroussin 
989*d0ef721eSBaptiste Daroussin /* history():
990*d0ef721eSBaptiste Daroussin  *	User interface to history functions.
991*d0ef721eSBaptiste Daroussin  */
992*d0ef721eSBaptiste Daroussin int
993*d0ef721eSBaptiste Daroussin FUNW(history)(TYPE(History) *h, TYPE(HistEvent) *ev, int fun, ...)
994*d0ef721eSBaptiste Daroussin {
995*d0ef721eSBaptiste Daroussin 	va_list va;
996*d0ef721eSBaptiste Daroussin 	const Char *str;
997*d0ef721eSBaptiste Daroussin 	int retval;
998*d0ef721eSBaptiste Daroussin 
999*d0ef721eSBaptiste Daroussin 	va_start(va, fun);
1000*d0ef721eSBaptiste Daroussin 
1001*d0ef721eSBaptiste Daroussin 	he_seterrev(ev, _HE_OK);
1002*d0ef721eSBaptiste Daroussin 
1003*d0ef721eSBaptiste Daroussin 	switch (fun) {
1004*d0ef721eSBaptiste Daroussin 	case H_GETSIZE:
1005*d0ef721eSBaptiste Daroussin 		retval = history_getsize(h, ev);
1006*d0ef721eSBaptiste Daroussin 		break;
1007*d0ef721eSBaptiste Daroussin 
1008*d0ef721eSBaptiste Daroussin 	case H_SETSIZE:
1009*d0ef721eSBaptiste Daroussin 		retval = history_setsize(h, ev, va_arg(va, int));
1010*d0ef721eSBaptiste Daroussin 		break;
1011*d0ef721eSBaptiste Daroussin 
1012*d0ef721eSBaptiste Daroussin 	case H_GETUNIQUE:
1013*d0ef721eSBaptiste Daroussin 		retval = history_getunique(h, ev);
1014*d0ef721eSBaptiste Daroussin 		break;
1015*d0ef721eSBaptiste Daroussin 
1016*d0ef721eSBaptiste Daroussin 	case H_SETUNIQUE:
1017*d0ef721eSBaptiste Daroussin 		retval = history_setunique(h, ev, va_arg(va, int));
1018*d0ef721eSBaptiste Daroussin 		break;
1019*d0ef721eSBaptiste Daroussin 
1020*d0ef721eSBaptiste Daroussin 	case H_ADD:
1021*d0ef721eSBaptiste Daroussin 		str = va_arg(va, const Char *);
1022*d0ef721eSBaptiste Daroussin 		retval = HADD(h, ev, str);
1023*d0ef721eSBaptiste Daroussin 		break;
1024*d0ef721eSBaptiste Daroussin 
1025*d0ef721eSBaptiste Daroussin 	case H_DEL:
1026*d0ef721eSBaptiste Daroussin 		retval = HDEL(h, ev, va_arg(va, const int));
1027*d0ef721eSBaptiste Daroussin 		break;
1028*d0ef721eSBaptiste Daroussin 
1029*d0ef721eSBaptiste Daroussin 	case H_ENTER:
1030*d0ef721eSBaptiste Daroussin 		str = va_arg(va, const Char *);
1031*d0ef721eSBaptiste Daroussin 		if ((retval = HENTER(h, ev, str)) != -1)
1032*d0ef721eSBaptiste Daroussin 			h->h_ent = ev->num;
1033*d0ef721eSBaptiste Daroussin 		break;
1034*d0ef721eSBaptiste Daroussin 
1035*d0ef721eSBaptiste Daroussin 	case H_APPEND:
1036*d0ef721eSBaptiste Daroussin 		str = va_arg(va, const Char *);
1037*d0ef721eSBaptiste Daroussin 		if ((retval = HSET(h, ev, h->h_ent)) != -1)
1038*d0ef721eSBaptiste Daroussin 			retval = HADD(h, ev, str);
1039*d0ef721eSBaptiste Daroussin 		break;
1040*d0ef721eSBaptiste Daroussin 
1041*d0ef721eSBaptiste Daroussin 	case H_FIRST:
1042*d0ef721eSBaptiste Daroussin 		retval = HFIRST(h, ev);
1043*d0ef721eSBaptiste Daroussin 		break;
1044*d0ef721eSBaptiste Daroussin 
1045*d0ef721eSBaptiste Daroussin 	case H_NEXT:
1046*d0ef721eSBaptiste Daroussin 		retval = HNEXT(h, ev);
1047*d0ef721eSBaptiste Daroussin 		break;
1048*d0ef721eSBaptiste Daroussin 
1049*d0ef721eSBaptiste Daroussin 	case H_LAST:
1050*d0ef721eSBaptiste Daroussin 		retval = HLAST(h, ev);
1051*d0ef721eSBaptiste Daroussin 		break;
1052*d0ef721eSBaptiste Daroussin 
1053*d0ef721eSBaptiste Daroussin 	case H_PREV:
1054*d0ef721eSBaptiste Daroussin 		retval = HPREV(h, ev);
1055*d0ef721eSBaptiste Daroussin 		break;
1056*d0ef721eSBaptiste Daroussin 
1057*d0ef721eSBaptiste Daroussin 	case H_CURR:
1058*d0ef721eSBaptiste Daroussin 		retval = HCURR(h, ev);
1059*d0ef721eSBaptiste Daroussin 		break;
1060*d0ef721eSBaptiste Daroussin 
1061*d0ef721eSBaptiste Daroussin 	case H_SET:
1062*d0ef721eSBaptiste Daroussin 		retval = HSET(h, ev, va_arg(va, const int));
1063*d0ef721eSBaptiste Daroussin 		break;
1064*d0ef721eSBaptiste Daroussin 
1065*d0ef721eSBaptiste Daroussin 	case H_CLEAR:
1066*d0ef721eSBaptiste Daroussin 		HCLEAR(h, ev);
1067*d0ef721eSBaptiste Daroussin 		retval = 0;
1068*d0ef721eSBaptiste Daroussin 		break;
1069*d0ef721eSBaptiste Daroussin 
1070*d0ef721eSBaptiste Daroussin 	case H_LOAD:
1071*d0ef721eSBaptiste Daroussin 		retval = history_load(h, va_arg(va, const char *));
1072*d0ef721eSBaptiste Daroussin 		if (retval == -1)
1073*d0ef721eSBaptiste Daroussin 			he_seterrev(ev, _HE_HIST_READ);
1074*d0ef721eSBaptiste Daroussin 		break;
1075*d0ef721eSBaptiste Daroussin 
1076*d0ef721eSBaptiste Daroussin 	case H_SAVE:
1077*d0ef721eSBaptiste Daroussin 		retval = history_save(h, va_arg(va, const char *));
1078*d0ef721eSBaptiste Daroussin 		if (retval == -1)
1079*d0ef721eSBaptiste Daroussin 			he_seterrev(ev, _HE_HIST_WRITE);
1080*d0ef721eSBaptiste Daroussin 		break;
1081*d0ef721eSBaptiste Daroussin 
1082*d0ef721eSBaptiste Daroussin 	case H_SAVE_FP:
1083*d0ef721eSBaptiste Daroussin 		retval = history_save_fp(h, (size_t)-1, va_arg(va, FILE *));
1084*d0ef721eSBaptiste Daroussin 		if (retval == -1)
1085*d0ef721eSBaptiste Daroussin 		    he_seterrev(ev, _HE_HIST_WRITE);
1086*d0ef721eSBaptiste Daroussin 		break;
1087*d0ef721eSBaptiste Daroussin 
1088*d0ef721eSBaptiste Daroussin 	case H_NSAVE_FP:
1089*d0ef721eSBaptiste Daroussin 	{
1090*d0ef721eSBaptiste Daroussin 		size_t sz = va_arg(va, size_t);
1091*d0ef721eSBaptiste Daroussin 		retval = history_save_fp(h, sz, va_arg(va, FILE *));
1092*d0ef721eSBaptiste Daroussin 		if (retval == -1)
1093*d0ef721eSBaptiste Daroussin 		    he_seterrev(ev, _HE_HIST_WRITE);
1094*d0ef721eSBaptiste Daroussin 		break;
1095*d0ef721eSBaptiste Daroussin 	}
1096*d0ef721eSBaptiste Daroussin 
1097*d0ef721eSBaptiste Daroussin 	case H_PREV_EVENT:
1098*d0ef721eSBaptiste Daroussin 		retval = history_prev_event(h, ev, va_arg(va, int));
1099*d0ef721eSBaptiste Daroussin 		break;
1100*d0ef721eSBaptiste Daroussin 
1101*d0ef721eSBaptiste Daroussin 	case H_NEXT_EVENT:
1102*d0ef721eSBaptiste Daroussin 		retval = history_next_event(h, ev, va_arg(va, int));
1103*d0ef721eSBaptiste Daroussin 		break;
1104*d0ef721eSBaptiste Daroussin 
1105*d0ef721eSBaptiste Daroussin 	case H_PREV_STR:
1106*d0ef721eSBaptiste Daroussin 		retval = history_prev_string(h, ev, va_arg(va, const Char *));
1107*d0ef721eSBaptiste Daroussin 		break;
1108*d0ef721eSBaptiste Daroussin 
1109*d0ef721eSBaptiste Daroussin 	case H_NEXT_STR:
1110*d0ef721eSBaptiste Daroussin 		retval = history_next_string(h, ev, va_arg(va, const Char *));
1111*d0ef721eSBaptiste Daroussin 		break;
1112*d0ef721eSBaptiste Daroussin 
1113*d0ef721eSBaptiste Daroussin 	case H_FUNC:
1114*d0ef721eSBaptiste Daroussin 	{
1115*d0ef721eSBaptiste Daroussin 		TYPE(History) hf;
1116*d0ef721eSBaptiste Daroussin 
1117*d0ef721eSBaptiste Daroussin 		hf.h_ref = va_arg(va, void *);
1118*d0ef721eSBaptiste Daroussin 		h->h_ent = -1;
1119*d0ef721eSBaptiste Daroussin 		hf.h_first = va_arg(va, history_gfun_t);
1120*d0ef721eSBaptiste Daroussin 		hf.h_next = va_arg(va, history_gfun_t);
1121*d0ef721eSBaptiste Daroussin 		hf.h_last = va_arg(va, history_gfun_t);
1122*d0ef721eSBaptiste Daroussin 		hf.h_prev = va_arg(va, history_gfun_t);
1123*d0ef721eSBaptiste Daroussin 		hf.h_curr = va_arg(va, history_gfun_t);
1124*d0ef721eSBaptiste Daroussin 		hf.h_set = va_arg(va, history_sfun_t);
1125*d0ef721eSBaptiste Daroussin 		hf.h_clear = va_arg(va, history_vfun_t);
1126*d0ef721eSBaptiste Daroussin 		hf.h_enter = va_arg(va, history_efun_t);
1127*d0ef721eSBaptiste Daroussin 		hf.h_add = va_arg(va, history_efun_t);
1128*d0ef721eSBaptiste Daroussin 		hf.h_del = va_arg(va, history_sfun_t);
1129*d0ef721eSBaptiste Daroussin 
1130*d0ef721eSBaptiste Daroussin 		if ((retval = history_set_fun(h, &hf)) == -1)
1131*d0ef721eSBaptiste Daroussin 			he_seterrev(ev, _HE_PARAM_MISSING);
1132*d0ef721eSBaptiste Daroussin 		break;
1133*d0ef721eSBaptiste Daroussin 	}
1134*d0ef721eSBaptiste Daroussin 
1135*d0ef721eSBaptiste Daroussin 	case H_END:
1136*d0ef721eSBaptiste Daroussin 		FUN(history,end)(h);
1137*d0ef721eSBaptiste Daroussin 		retval = 0;
1138*d0ef721eSBaptiste Daroussin 		break;
1139*d0ef721eSBaptiste Daroussin 
1140*d0ef721eSBaptiste Daroussin 	case H_NEXT_EVDATA:
1141*d0ef721eSBaptiste Daroussin 	{
1142*d0ef721eSBaptiste Daroussin 		int num = va_arg(va, int);
1143*d0ef721eSBaptiste Daroussin 		void **d = va_arg(va, void **);
1144*d0ef721eSBaptiste Daroussin 		retval = history_next_evdata(h, ev, num, d);
1145*d0ef721eSBaptiste Daroussin 		break;
1146*d0ef721eSBaptiste Daroussin 	}
1147*d0ef721eSBaptiste Daroussin 
1148*d0ef721eSBaptiste Daroussin 	case H_DELDATA:
1149*d0ef721eSBaptiste Daroussin 	{
1150*d0ef721eSBaptiste Daroussin 		int num = va_arg(va, int);
1151*d0ef721eSBaptiste Daroussin 		void **d = va_arg(va, void **);
1152*d0ef721eSBaptiste Daroussin 		retval = history_deldata_nth((history_t *)h->h_ref, ev, num, d);
1153*d0ef721eSBaptiste Daroussin 		break;
1154*d0ef721eSBaptiste Daroussin 	}
1155*d0ef721eSBaptiste Daroussin 
1156*d0ef721eSBaptiste Daroussin 	case H_REPLACE: /* only use after H_NEXT_EVDATA */
1157*d0ef721eSBaptiste Daroussin 	{
1158*d0ef721eSBaptiste Daroussin 		const Char *line = va_arg(va, const Char *);
1159*d0ef721eSBaptiste Daroussin 		void *d = va_arg(va, void *);
1160*d0ef721eSBaptiste Daroussin 		const Char *s;
1161*d0ef721eSBaptiste Daroussin 		if(!line || !(s = Strdup(line))) {
1162*d0ef721eSBaptiste Daroussin 			retval = -1;
1163*d0ef721eSBaptiste Daroussin 			break;
1164*d0ef721eSBaptiste Daroussin 		}
1165*d0ef721eSBaptiste Daroussin 		((history_t *)h->h_ref)->cursor->ev.str = s;
1166*d0ef721eSBaptiste Daroussin 		((history_t *)h->h_ref)->cursor->data = d;
1167*d0ef721eSBaptiste Daroussin 		retval = 0;
1168*d0ef721eSBaptiste Daroussin 		break;
1169*d0ef721eSBaptiste Daroussin 	}
1170*d0ef721eSBaptiste Daroussin 
1171*d0ef721eSBaptiste Daroussin 	default:
1172*d0ef721eSBaptiste Daroussin 		retval = -1;
1173*d0ef721eSBaptiste Daroussin 		he_seterrev(ev, _HE_UNKNOWN);
1174*d0ef721eSBaptiste Daroussin 		break;
1175*d0ef721eSBaptiste Daroussin 	}
1176*d0ef721eSBaptiste Daroussin 	va_end(va);
1177*d0ef721eSBaptiste Daroussin 	return retval;
1178*d0ef721eSBaptiste Daroussin }
1179