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