xref: /openbsd-src/lib/libedit/history.c (revision 5b133f3f277e80f096764111e64f3a1284acb179)
1*5b133f3fSguenther /*	$OpenBSD: history.c,v 1.29 2023/03/08 04:43:05 guenther Exp $	*/
2aed0ee81Snicm /*	$NetBSD: history.c,v 1.37 2010/01/03 18:27:10 christos Exp $	*/
3babb851aSmillert 
4df930be7Sderaadt /*-
5df930be7Sderaadt  * Copyright (c) 1992, 1993
6df930be7Sderaadt  *	The Regents of the University of California.  All rights reserved.
7df930be7Sderaadt  *
8df930be7Sderaadt  * This code is derived from software contributed to Berkeley by
9df930be7Sderaadt  * Christos Zoulas of Cornell University.
10df930be7Sderaadt  *
11df930be7Sderaadt  * Redistribution and use in source and binary forms, with or without
12df930be7Sderaadt  * modification, are permitted provided that the following conditions
13df930be7Sderaadt  * are met:
14df930be7Sderaadt  * 1. Redistributions of source code must retain the above copyright
15df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer.
16df930be7Sderaadt  * 2. Redistributions in binary form must reproduce the above copyright
17df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer in the
18df930be7Sderaadt  *    documentation and/or other materials provided with the distribution.
196580fee3Smillert  * 3. Neither the name of the University nor the names of its contributors
20df930be7Sderaadt  *    may be used to endorse or promote products derived from this software
21df930be7Sderaadt  *    without specific prior written permission.
22df930be7Sderaadt  *
23df930be7Sderaadt  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24df930be7Sderaadt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25df930be7Sderaadt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26df930be7Sderaadt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27df930be7Sderaadt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28df930be7Sderaadt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29df930be7Sderaadt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30df930be7Sderaadt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31df930be7Sderaadt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32df930be7Sderaadt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33df930be7Sderaadt  * SUCH DAMAGE.
34df930be7Sderaadt  */
35df930be7Sderaadt 
36d484b7d0Sotto #include "config.h"
37df930be7Sderaadt 
38df930be7Sderaadt /*
39aed0ee81Snicm  * hist.c: TYPE(History) access functions
40df930be7Sderaadt  */
417ccfa089Sschwarze #include <sys/stat.h>
42df930be7Sderaadt #include <stdarg.h>
437ccfa089Sschwarze #include <stdlib.h>
447ccfa089Sschwarze #include <string.h>
45d484b7d0Sotto #ifdef HAVE_VIS_H
46d484b7d0Sotto #include <vis.h>
47d484b7d0Sotto #else
48d484b7d0Sotto #include "np/vis.h"
49d484b7d0Sotto #endif
50df930be7Sderaadt 
51d484b7d0Sotto static const char hist_cookie[] = "_HiStOrY_V2_\n";
528bd3f282Sderaadt 
53df930be7Sderaadt #include "histedit.h"
54df930be7Sderaadt 
555c93237dSschwarze 
565c93237dSschwarze #ifdef NARROWCHAR
575c93237dSschwarze 
58e3191321Sschwarze #define	Char			char
595c93237dSschwarze #define	FUN(prefix, rest)	prefix ## _ ## rest
605c93237dSschwarze #define	FUNW(type)		type
615c93237dSschwarze #define	TYPE(type)		type
625c93237dSschwarze #define	STR(x)			x
635c93237dSschwarze 
645c93237dSschwarze #define	Strlen(s)		strlen(s)
655c93237dSschwarze #define	Strdup(s)		strdup(s)
665c93237dSschwarze #define	Strcmp(d, s)		strcmp(d, s)
675c93237dSschwarze #define	Strncmp(d, s, n)	strncmp(d, s, n)
685c93237dSschwarze #define	Strncpy(d, s, n)	strncpy(d, s, n)
695c93237dSschwarze #define	Strncat(d, s, n)	strncat(d, s, n)
708dc8c690Sschwarze #define	ct_decode_string(s, b)	(s)
718dc8c690Sschwarze #define	ct_encode_string(s, b)	(s)
725c93237dSschwarze 
735c93237dSschwarze #else
748dc8c690Sschwarze #include "chartype.h"
755c93237dSschwarze 
76e3191321Sschwarze #define	Char			wchar_t
775c93237dSschwarze #define	FUN(prefix, rest)	prefix ## _w ## rest
785c93237dSschwarze #define	FUNW(type)		type ## _w
795c93237dSschwarze #define	TYPE(type)		type ## W
805c93237dSschwarze #define	STR(x)			L ## x
815c93237dSschwarze 
825c93237dSschwarze #define	Strlen(s)		wcslen(s)
835c93237dSschwarze #define	Strdup(s)		wcsdup(s)
845c93237dSschwarze #define	Strcmp(d, s)		wcscmp(d, s)
855c93237dSschwarze #define	Strncmp(d, s, n)	wcsncmp(d, s, n)
865c93237dSschwarze #define	Strncpy(d, s, n)	wcsncpy(d, s, n)
875c93237dSschwarze #define	Strncat(d, s, n)	wcsncat(d, s, n)
885c93237dSschwarze 
895c93237dSschwarze #endif
905c93237dSschwarze 
915c93237dSschwarze 
927b85e16bSschwarze typedef int (*history_gfun_t)(void *, TYPE(HistEvent) *);
937b85e16bSschwarze typedef int (*history_efun_t)(void *, TYPE(HistEvent) *, const Char *);
947b85e16bSschwarze typedef void (*history_vfun_t)(void *, TYPE(HistEvent) *);
957b85e16bSschwarze typedef int (*history_sfun_t)(void *, TYPE(HistEvent) *, const int);
96df930be7Sderaadt 
TYPE(history)97aed0ee81Snicm struct TYPE(history) {
987b85e16bSschwarze 	void *h_ref;		/* Argument for history fcns	 */
99d484b7d0Sotto 	int h_ent;		/* Last entry point for history	 */
100df930be7Sderaadt 	history_gfun_t h_first;	/* Get the first element	 */
101df930be7Sderaadt 	history_gfun_t h_next;	/* Get the next element		 */
102df930be7Sderaadt 	history_gfun_t h_last;	/* Get the last element		 */
103df930be7Sderaadt 	history_gfun_t h_prev;	/* Get the previous element	 */
104df930be7Sderaadt 	history_gfun_t h_curr;	/* Get the current element	 */
105d484b7d0Sotto 	history_sfun_t h_set;	/* Set the current element	 */
106aed0ee81Snicm 	history_sfun_t h_del;	/* Set the given element	 */
1078bd3f282Sderaadt 	history_vfun_t h_clear;	/* Clear the history list	 */
108df930be7Sderaadt 	history_efun_t h_enter;	/* Add an element		 */
109df930be7Sderaadt 	history_efun_t h_add;	/* Append to an element		 */
110df930be7Sderaadt };
111df930be7Sderaadt 
112d484b7d0Sotto #define	HNEXT(h, ev)		(*(h)->h_next)((h)->h_ref, ev)
113d484b7d0Sotto #define	HFIRST(h, ev)		(*(h)->h_first)((h)->h_ref, ev)
114d484b7d0Sotto #define	HPREV(h, ev)		(*(h)->h_prev)((h)->h_ref, ev)
115d484b7d0Sotto #define	HLAST(h, ev)		(*(h)->h_last)((h)->h_ref, ev)
116d484b7d0Sotto #define	HCURR(h, ev)		(*(h)->h_curr)((h)->h_ref, ev)
117d484b7d0Sotto #define	HSET(h, ev, n)		(*(h)->h_set)((h)->h_ref, ev, n)
118d484b7d0Sotto #define	HCLEAR(h, ev)		(*(h)->h_clear)((h)->h_ref, ev)
119d484b7d0Sotto #define	HENTER(h, ev, str)	(*(h)->h_enter)((h)->h_ref, ev, str)
120d484b7d0Sotto #define	HADD(h, ev, str)	(*(h)->h_add)((h)->h_ref, ev, str)
121aed0ee81Snicm #define	HDEL(h, ev, n)		(*(h)->h_del)((h)->h_ref, ev, n)
122df930be7Sderaadt 
123aed0ee81Snicm #define	h_strdup(a)	Strdup(a)
124df930be7Sderaadt 
125d484b7d0Sotto typedef struct {
126d484b7d0Sotto     int		num;
127aed0ee81Snicm     Char	*str;
128d484b7d0Sotto } HistEventPrivate;
129df930be7Sderaadt 
130d484b7d0Sotto 
131ddc81437Sschwarze static int history_setsize(TYPE(History) *, TYPE(HistEvent) *, int);
132ddc81437Sschwarze static int history_getsize(TYPE(History) *, TYPE(HistEvent) *);
133ddc81437Sschwarze static int history_setunique(TYPE(History) *, TYPE(HistEvent) *, int);
134ddc81437Sschwarze static int history_getunique(TYPE(History) *, TYPE(HistEvent) *);
135ddc81437Sschwarze static int history_set_fun(TYPE(History) *, TYPE(History) *);
136ddc81437Sschwarze static int history_load(TYPE(History) *, const char *);
137ddc81437Sschwarze static int history_save(TYPE(History) *, const char *);
138ddc81437Sschwarze static int history_save_fp(TYPE(History) *, FILE *);
139ddc81437Sschwarze static int history_prev_event(TYPE(History) *, TYPE(HistEvent) *, int);
140ddc81437Sschwarze static int history_next_event(TYPE(History) *, TYPE(HistEvent) *, int);
141ddc81437Sschwarze static int history_next_string(TYPE(History) *, TYPE(HistEvent) *,
142ddc81437Sschwarze     const Char *);
143ddc81437Sschwarze static int history_prev_string(TYPE(History) *, TYPE(HistEvent) *,
144ddc81437Sschwarze     const Char *);
145df930be7Sderaadt 
146df930be7Sderaadt 
147df930be7Sderaadt /***********************************************************************/
148df930be7Sderaadt 
149df930be7Sderaadt /*
150df930be7Sderaadt  * Builtin- history implementation
151df930be7Sderaadt  */
152df930be7Sderaadt typedef struct hentry_t {
153aed0ee81Snicm 	TYPE(HistEvent) ev;		/* What we return		 */
154aed0ee81Snicm 	void *data;		/* data				 */
155df930be7Sderaadt 	struct hentry_t *next;	/* Next entry			 */
156df930be7Sderaadt 	struct hentry_t *prev;	/* Previous entry		 */
157df930be7Sderaadt } hentry_t;
158df930be7Sderaadt 
159df930be7Sderaadt typedef struct history_t {
160df930be7Sderaadt 	hentry_t list;		/* Fake list header element	*/
161df930be7Sderaadt 	hentry_t *cursor;	/* Current element in the list	*/
162df930be7Sderaadt 	int max;		/* Maximum number of events	*/
163df930be7Sderaadt 	int cur;		/* Current number of events	*/
164d484b7d0Sotto 	int eventid;		/* For generation of unique event id	 */
165aed0ee81Snicm 	int flags;		/* TYPE(History) flags		*/
166d484b7d0Sotto #define H_UNIQUE	1	/* Store only unique elements	*/
167df930be7Sderaadt } history_t;
168df930be7Sderaadt 
169ddc81437Sschwarze static int history_def_next(void *, TYPE(HistEvent) *);
170ddc81437Sschwarze static int history_def_first(void *, TYPE(HistEvent) *);
171ddc81437Sschwarze static int history_def_prev(void *, TYPE(HistEvent) *);
172ddc81437Sschwarze static int history_def_last(void *, TYPE(HistEvent) *);
173ddc81437Sschwarze static int history_def_curr(void *, TYPE(HistEvent) *);
174ddc81437Sschwarze static int history_def_set(void *, TYPE(HistEvent) *, const int);
175ddc81437Sschwarze static void history_def_clear(void *, TYPE(HistEvent) *);
176ddc81437Sschwarze static int history_def_enter(void *, TYPE(HistEvent) *, const Char *);
177ddc81437Sschwarze static int history_def_add(void *, TYPE(HistEvent) *, const Char *);
178ddc81437Sschwarze static int history_def_del(void *, TYPE(HistEvent) *, const int);
179aed0ee81Snicm 
180ddc81437Sschwarze static int history_def_init(void **, TYPE(HistEvent) *, int);
181ddc81437Sschwarze static int history_def_insert(history_t *, TYPE(HistEvent) *, const Char *);
182ddc81437Sschwarze static void history_def_delete(history_t *, TYPE(HistEvent) *, hentry_t *);
183aed0ee81Snicm 
184ddc81437Sschwarze static int history_deldata_nth(history_t *, TYPE(HistEvent) *, int, void **);
185ddc81437Sschwarze static int history_set_nth(void *, TYPE(HistEvent) *, int);
186df930be7Sderaadt 
187d484b7d0Sotto #define	history_def_setsize(p, num)(void) (((history_t *)p)->max = (num))
188d484b7d0Sotto #define	history_def_getsize(p)  (((history_t *)p)->cur)
189d484b7d0Sotto #define	history_def_getunique(p) (((((history_t *)p)->flags) & H_UNIQUE) != 0)
190d484b7d0Sotto #define	history_def_setunique(p, uni) \
191d484b7d0Sotto     if (uni) \
192d484b7d0Sotto 	(((history_t *)p)->flags) |= H_UNIQUE; \
193d484b7d0Sotto     else \
194d484b7d0Sotto 	(((history_t *)p)->flags) &= ~H_UNIQUE
195df930be7Sderaadt 
196d484b7d0Sotto #define	he_strerror(code)	he_errlist[code]
197d484b7d0Sotto #define	he_seterrev(evp, code)	{\
198d484b7d0Sotto 				    evp->num = code;\
199d484b7d0Sotto 				    evp->str = he_strerror(code);\
200d484b7d0Sotto 				}
201d484b7d0Sotto 
202d484b7d0Sotto /* error messages */
203aed0ee81Snicm static const Char *const he_errlist[] = {
204aed0ee81Snicm 	STR("OK"),
205aed0ee81Snicm 	STR("unknown error"),
206aed0ee81Snicm 	STR("malloc() failed"),
207aed0ee81Snicm 	STR("first event not found"),
208aed0ee81Snicm 	STR("last event not found"),
209aed0ee81Snicm 	STR("empty list"),
210aed0ee81Snicm 	STR("no next event"),
211aed0ee81Snicm 	STR("no previous event"),
212aed0ee81Snicm 	STR("current event is invalid"),
213aed0ee81Snicm 	STR("event not found"),
214aed0ee81Snicm 	STR("can't read history from file"),
215aed0ee81Snicm 	STR("can't write history"),
216aed0ee81Snicm 	STR("required parameter(s) not supplied"),
217aed0ee81Snicm 	STR("history size negative"),
218aed0ee81Snicm 	STR("function not allowed with other history-functions-set the default"),
219aed0ee81Snicm 	STR("bad parameters")
220d484b7d0Sotto };
221d484b7d0Sotto /* error codes */
222d484b7d0Sotto #define	_HE_OK                   0
223d484b7d0Sotto #define	_HE_UNKNOWN		 1
224d484b7d0Sotto #define	_HE_MALLOC_FAILED        2
225d484b7d0Sotto #define	_HE_FIRST_NOTFOUND       3
226d484b7d0Sotto #define	_HE_LAST_NOTFOUND        4
227d484b7d0Sotto #define	_HE_EMPTY_LIST           5
228d484b7d0Sotto #define	_HE_END_REACHED          6
229d484b7d0Sotto #define	_HE_START_REACHED	 7
230d484b7d0Sotto #define	_HE_CURR_INVALID	 8
231d484b7d0Sotto #define	_HE_NOT_FOUND		 9
232d484b7d0Sotto #define	_HE_HIST_READ		10
233d484b7d0Sotto #define	_HE_HIST_WRITE		11
234d484b7d0Sotto #define	_HE_PARAM_MISSING	12
235d484b7d0Sotto #define	_HE_SIZE_NEGATIVE	13
236d484b7d0Sotto #define	_HE_NOT_ALLOWED		14
237d484b7d0Sotto #define	_HE_BAD_PARAM		15
238df930be7Sderaadt 
239df930be7Sderaadt /* history_def_first():
240df930be7Sderaadt  *	Default function to return the first event in the history.
241df930be7Sderaadt  */
242ddc81437Sschwarze static int
history_def_first(void * p,TYPE (HistEvent)* ev)2437b85e16bSschwarze history_def_first(void *p, TYPE(HistEvent) *ev)
244df930be7Sderaadt {
245df930be7Sderaadt 	history_t *h = (history_t *) p;
246d484b7d0Sotto 
247df930be7Sderaadt 	h->cursor = h->list.next;
248df930be7Sderaadt 	if (h->cursor != &h->list)
249d484b7d0Sotto 		*ev = h->cursor->ev;
250d484b7d0Sotto 	else {
251d484b7d0Sotto 		he_seterrev(ev, _HE_FIRST_NOTFOUND);
25228d54ee8Sschwarze 		return -1;
253df930be7Sderaadt 	}
254df930be7Sderaadt 
25528d54ee8Sschwarze 	return 0;
256d484b7d0Sotto }
257d484b7d0Sotto 
258d484b7d0Sotto 
259df930be7Sderaadt /* history_def_last():
260df930be7Sderaadt  *	Default function to return the last event in the history.
261df930be7Sderaadt  */
262ddc81437Sschwarze static int
history_def_last(void * p,TYPE (HistEvent)* ev)2637b85e16bSschwarze history_def_last(void *p, TYPE(HistEvent) *ev)
264df930be7Sderaadt {
265df930be7Sderaadt 	history_t *h = (history_t *) p;
266d484b7d0Sotto 
267df930be7Sderaadt 	h->cursor = h->list.prev;
268df930be7Sderaadt 	if (h->cursor != &h->list)
269d484b7d0Sotto 		*ev = h->cursor->ev;
270d484b7d0Sotto 	else {
271d484b7d0Sotto 		he_seterrev(ev, _HE_LAST_NOTFOUND);
27228d54ee8Sschwarze 		return -1;
273df930be7Sderaadt 	}
274df930be7Sderaadt 
27528d54ee8Sschwarze 	return 0;
276d484b7d0Sotto }
277d484b7d0Sotto 
278d484b7d0Sotto 
279df930be7Sderaadt /* history_def_next():
280df930be7Sderaadt  *	Default function to return the next event in the history.
281df930be7Sderaadt  */
282ddc81437Sschwarze static int
history_def_next(void * p,TYPE (HistEvent)* ev)2837b85e16bSschwarze history_def_next(void *p, TYPE(HistEvent) *ev)
284df930be7Sderaadt {
285df930be7Sderaadt 	history_t *h = (history_t *) p;
286df930be7Sderaadt 
287aed0ee81Snicm 	if (h->cursor == &h->list) {
288d484b7d0Sotto 		he_seterrev(ev, _HE_EMPTY_LIST);
28928d54ee8Sschwarze 		return -1;
290d484b7d0Sotto 	}
291df930be7Sderaadt 
292aed0ee81Snicm 	if (h->cursor->next == &h->list) {
293d484b7d0Sotto 		he_seterrev(ev, _HE_END_REACHED);
29428d54ee8Sschwarze 		return -1;
295d484b7d0Sotto 	}
296d484b7d0Sotto 
297aed0ee81Snicm         h->cursor = h->cursor->next;
298aed0ee81Snicm         *ev = h->cursor->ev;
299aed0ee81Snicm 
30028d54ee8Sschwarze 	return 0;
301df930be7Sderaadt }
302df930be7Sderaadt 
303df930be7Sderaadt 
304df930be7Sderaadt /* history_def_prev():
305df930be7Sderaadt  *	Default function to return the previous event in the history.
306df930be7Sderaadt  */
307ddc81437Sschwarze static int
history_def_prev(void * p,TYPE (HistEvent)* ev)3087b85e16bSschwarze history_def_prev(void *p, TYPE(HistEvent) *ev)
309df930be7Sderaadt {
310df930be7Sderaadt 	history_t *h = (history_t *) p;
311df930be7Sderaadt 
312aed0ee81Snicm 	if (h->cursor == &h->list) {
313d484b7d0Sotto 		he_seterrev(ev,
314d484b7d0Sotto 		    (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST);
31528d54ee8Sschwarze 		return -1;
316d484b7d0Sotto 	}
317df930be7Sderaadt 
318aed0ee81Snicm 	if (h->cursor->prev == &h->list) {
319d484b7d0Sotto 		he_seterrev(ev, _HE_START_REACHED);
32028d54ee8Sschwarze 		return -1;
321d484b7d0Sotto 	}
322d484b7d0Sotto 
323aed0ee81Snicm         h->cursor = h->cursor->prev;
324aed0ee81Snicm         *ev = h->cursor->ev;
325aed0ee81Snicm 
32628d54ee8Sschwarze 	return 0;
327df930be7Sderaadt }
328df930be7Sderaadt 
329df930be7Sderaadt 
330df930be7Sderaadt /* history_def_curr():
331df930be7Sderaadt  *	Default function to return the current event in the history.
332df930be7Sderaadt  */
333ddc81437Sschwarze static int
history_def_curr(void * p,TYPE (HistEvent)* ev)3347b85e16bSschwarze history_def_curr(void *p, TYPE(HistEvent) *ev)
335df930be7Sderaadt {
336df930be7Sderaadt 	history_t *h = (history_t *) p;
337df930be7Sderaadt 
338df930be7Sderaadt 	if (h->cursor != &h->list)
339d484b7d0Sotto 		*ev = h->cursor->ev;
340d484b7d0Sotto 	else {
341d484b7d0Sotto 		he_seterrev(ev,
342d484b7d0Sotto 		    (h->cur > 0) ? _HE_CURR_INVALID : _HE_EMPTY_LIST);
34328d54ee8Sschwarze 		return -1;
344df930be7Sderaadt 	}
345df930be7Sderaadt 
34628d54ee8Sschwarze 	return 0;
347d484b7d0Sotto }
348d484b7d0Sotto 
349d484b7d0Sotto 
350d484b7d0Sotto /* history_def_set():
351d484b7d0Sotto  *	Default function to set the current event in the history to the
352d484b7d0Sotto  *	given one.
353d484b7d0Sotto  */
354ddc81437Sschwarze static int
history_def_set(void * p,TYPE (HistEvent)* ev,const int n)3557b85e16bSschwarze history_def_set(void *p, TYPE(HistEvent) *ev, const int n)
356d484b7d0Sotto {
357d484b7d0Sotto 	history_t *h = (history_t *) p;
358d484b7d0Sotto 
359d484b7d0Sotto 	if (h->cur == 0) {
360d484b7d0Sotto 		he_seterrev(ev, _HE_EMPTY_LIST);
36128d54ee8Sschwarze 		return -1;
362d484b7d0Sotto 	}
363d484b7d0Sotto 	if (h->cursor == &h->list || h->cursor->ev.num != n) {
364d484b7d0Sotto 		for (h->cursor = h->list.next; h->cursor != &h->list;
365d484b7d0Sotto 		    h->cursor = h->cursor->next)
366d484b7d0Sotto 			if (h->cursor->ev.num == n)
367d484b7d0Sotto 				break;
368d484b7d0Sotto 	}
369d484b7d0Sotto 	if (h->cursor == &h->list) {
370d484b7d0Sotto 		he_seterrev(ev, _HE_NOT_FOUND);
37128d54ee8Sschwarze 		return -1;
372d484b7d0Sotto 	}
37328d54ee8Sschwarze 	return 0;
374d484b7d0Sotto }
375d484b7d0Sotto 
376d484b7d0Sotto 
377aed0ee81Snicm /* history_set_nth():
378aed0ee81Snicm  *	Default function to set the current event in the history to the
379aed0ee81Snicm  *	n-th one.
380aed0ee81Snicm  */
381ddc81437Sschwarze static int
history_set_nth(void * p,TYPE (HistEvent)* ev,int n)3827b85e16bSschwarze history_set_nth(void *p, TYPE(HistEvent) *ev, int n)
383aed0ee81Snicm {
384aed0ee81Snicm 	history_t *h = (history_t *) p;
385aed0ee81Snicm 
386aed0ee81Snicm 	if (h->cur == 0) {
387aed0ee81Snicm 		he_seterrev(ev, _HE_EMPTY_LIST);
38828d54ee8Sschwarze 		return -1;
389aed0ee81Snicm 	}
390aed0ee81Snicm 	for (h->cursor = h->list.prev; h->cursor != &h->list;
391aed0ee81Snicm 	    h->cursor = h->cursor->prev)
392aed0ee81Snicm 		if (n-- <= 0)
393aed0ee81Snicm 			break;
394aed0ee81Snicm 	if (h->cursor == &h->list) {
395aed0ee81Snicm 		he_seterrev(ev, _HE_NOT_FOUND);
39628d54ee8Sschwarze 		return -1;
397aed0ee81Snicm 	}
39828d54ee8Sschwarze 	return 0;
399aed0ee81Snicm }
400aed0ee81Snicm 
401aed0ee81Snicm 
402df930be7Sderaadt /* history_def_add():
403df930be7Sderaadt  *	Append string to element
404df930be7Sderaadt  */
405ddc81437Sschwarze static int
history_def_add(void * p,TYPE (HistEvent)* ev,const Char * str)4067b85e16bSschwarze history_def_add(void *p, TYPE(HistEvent) *ev, const Char *str)
407df930be7Sderaadt {
408df930be7Sderaadt 	history_t *h = (history_t *) p;
409df930be7Sderaadt 	size_t len;
410aed0ee81Snicm 	Char *s;
411d484b7d0Sotto 	HistEventPrivate *evp = (void *)&h->cursor->ev;
412df930be7Sderaadt 
413df930be7Sderaadt 	if (h->cursor == &h->list)
41428d54ee8Sschwarze 		return history_def_enter(p, ev, str);
415aed0ee81Snicm 	len = Strlen(evp->str) + Strlen(str) + 1;
416014b1be8Sderaadt 	s = reallocarray(NULL, len, sizeof(*s));
417d484b7d0Sotto 	if (s == NULL) {
418d484b7d0Sotto 		he_seterrev(ev, _HE_MALLOC_FAILED);
41928d54ee8Sschwarze 		return -1;
420d484b7d0Sotto 	}
421aed0ee81Snicm 	(void) Strncpy(s, h->cursor->ev.str, len);
422aed0ee81Snicm         s[len - 1] = '\0';
423aed0ee81Snicm 	(void) Strncat(s, str, len - Strlen(s) - 1);
4247b85e16bSschwarze 	free(evp->str);
425d484b7d0Sotto 	evp->str = s;
426d484b7d0Sotto 	*ev = h->cursor->ev;
42728d54ee8Sschwarze 	return 0;
428df930be7Sderaadt }
429df930be7Sderaadt 
430df930be7Sderaadt 
431ddc81437Sschwarze static int
history_deldata_nth(history_t * h,TYPE (HistEvent)* ev,int num,void ** data)432aed0ee81Snicm history_deldata_nth(history_t *h, TYPE(HistEvent) *ev,
433aed0ee81Snicm     int num, void **data)
434aed0ee81Snicm {
435aed0ee81Snicm 	if (history_set_nth(h, ev, num) != 0)
43628d54ee8Sschwarze 		return -1;
437aed0ee81Snicm 	/* magic value to skip delete (just set to n-th history) */
438aed0ee81Snicm 	if (data == (void **)-1)
43928d54ee8Sschwarze 		return 0;
440aed0ee81Snicm 	ev->str = Strdup(h->cursor->ev.str);
441aed0ee81Snicm 	ev->num = h->cursor->ev.num;
442aed0ee81Snicm 	if (data)
443aed0ee81Snicm 		*data = h->cursor->data;
444aed0ee81Snicm 	history_def_delete(h, ev, h->cursor);
44528d54ee8Sschwarze 	return 0;
446aed0ee81Snicm }
447aed0ee81Snicm 
448aed0ee81Snicm 
449aed0ee81Snicm /* history_def_del():
450aed0ee81Snicm  *	Delete element hp of the h list
451aed0ee81Snicm  */
452ddc81437Sschwarze static int
history_def_del(void * p,TYPE (HistEvent)* ev,const int num)4537b85e16bSschwarze history_def_del(void *p, TYPE(HistEvent) *ev __attribute__((__unused__)),
454aed0ee81Snicm     const int num)
455aed0ee81Snicm {
456aed0ee81Snicm 	history_t *h = (history_t *) p;
457aed0ee81Snicm 	if (history_def_set(h, ev, num) != 0)
45828d54ee8Sschwarze 		return -1;
459aed0ee81Snicm 	ev->str = Strdup(h->cursor->ev.str);
460aed0ee81Snicm 	ev->num = h->cursor->ev.num;
461aed0ee81Snicm 	history_def_delete(h, ev, h->cursor);
46228d54ee8Sschwarze 	return 0;
463aed0ee81Snicm }
464aed0ee81Snicm 
465aed0ee81Snicm 
466df930be7Sderaadt /* history_def_delete():
467df930be7Sderaadt  *	Delete element hp of the h list
468df930be7Sderaadt  */
469ddc81437Sschwarze static void
history_def_delete(history_t * h,TYPE (HistEvent)* ev,hentry_t * hp)470d484b7d0Sotto history_def_delete(history_t *h,
471aed0ee81Snicm 		   TYPE(HistEvent) *ev __attribute__((__unused__)), hentry_t *hp)
472df930be7Sderaadt {
473d484b7d0Sotto 	HistEventPrivate *evp = (void *)&hp->ev;
474df930be7Sderaadt 	if (hp == &h->list)
475df930be7Sderaadt 		abort();
476aed0ee81Snicm 	if (h->cursor == hp) {
477aed0ee81Snicm 		h->cursor = hp->prev;
478aed0ee81Snicm 		if (h->cursor == &h->list)
479aed0ee81Snicm 			h->cursor = hp->next;
480aed0ee81Snicm 	}
481df930be7Sderaadt 	hp->prev->next = hp->next;
482df930be7Sderaadt 	hp->next->prev = hp->prev;
4837b85e16bSschwarze 	free(evp->str);
484014b1be8Sderaadt 	free(hp);
485df930be7Sderaadt 	h->cur--;
486df930be7Sderaadt }
487df930be7Sderaadt 
488df930be7Sderaadt 
489df930be7Sderaadt /* history_def_insert():
490df930be7Sderaadt  *	Insert element with string str in the h list
491df930be7Sderaadt  */
492ddc81437Sschwarze static int
history_def_insert(history_t * h,TYPE (HistEvent)* ev,const Char * str)493aed0ee81Snicm history_def_insert(history_t *h, TYPE(HistEvent) *ev, const Char *str)
494df930be7Sderaadt {
495d484b7d0Sotto 
496014b1be8Sderaadt 	h->cursor = (hentry_t *) malloc(sizeof(hentry_t));
497d484b7d0Sotto 	if (h->cursor == NULL)
498d484b7d0Sotto 		goto oomem;
4996e02e073Sotto 	if ((h->cursor->ev.str = h_strdup(str)) == NULL) {
5007b85e16bSschwarze 		free(h->cursor);
501d484b7d0Sotto 		goto oomem;
502d484b7d0Sotto 	}
503aed0ee81Snicm 	h->cursor->data = NULL;
504d484b7d0Sotto 	h->cursor->ev.num = ++h->eventid;
505df930be7Sderaadt 	h->cursor->next = h->list.next;
506df930be7Sderaadt 	h->cursor->prev = &h->list;
507df930be7Sderaadt 	h->list.next->prev = h->cursor;
508df930be7Sderaadt 	h->list.next = h->cursor;
509df930be7Sderaadt 	h->cur++;
510df930be7Sderaadt 
511d484b7d0Sotto 	*ev = h->cursor->ev;
51228d54ee8Sschwarze 	return 0;
513d484b7d0Sotto oomem:
514d484b7d0Sotto 	he_seterrev(ev, _HE_MALLOC_FAILED);
51528d54ee8Sschwarze 	return -1;
516df930be7Sderaadt }
517df930be7Sderaadt 
518df930be7Sderaadt 
519df930be7Sderaadt /* history_def_enter():
520df930be7Sderaadt  *	Default function to enter an item in the history
521df930be7Sderaadt  */
522ddc81437Sschwarze static int
history_def_enter(void * p,TYPE (HistEvent)* ev,const Char * str)5237b85e16bSschwarze history_def_enter(void *p, TYPE(HistEvent) *ev, const Char *str)
524df930be7Sderaadt {
525df930be7Sderaadt 	history_t *h = (history_t *) p;
526df930be7Sderaadt 
527d484b7d0Sotto 	if ((h->flags & H_UNIQUE) != 0 && h->list.next != &h->list &&
528aed0ee81Snicm 	    Strcmp(h->list.next->ev.str, str) == 0)
52928d54ee8Sschwarze 	    return 0;
530df930be7Sderaadt 
531d484b7d0Sotto 	if (history_def_insert(h, ev, str) == -1)
53228d54ee8Sschwarze 		return -1;	/* error, keep error message */
533df930be7Sderaadt 
534df930be7Sderaadt 	/*
535df930be7Sderaadt          * Always keep at least one entry.
536df930be7Sderaadt          * This way we don't have to check for the empty list.
537df930be7Sderaadt          */
538d484b7d0Sotto 	while (h->cur > h->max && h->cur > 0)
539d484b7d0Sotto 		history_def_delete(h, ev, h->list.prev);
540d484b7d0Sotto 
54128d54ee8Sschwarze 	return 1;
542df930be7Sderaadt }
543df930be7Sderaadt 
544df930be7Sderaadt 
545df930be7Sderaadt /* history_def_init():
546df930be7Sderaadt  *	Default history initialization function
547df930be7Sderaadt  */
548ddc81437Sschwarze static int
history_def_init(void ** p,TYPE (HistEvent)* ev,int n)5497b85e16bSschwarze history_def_init(void **p, TYPE(HistEvent) *ev __attribute__((__unused__)), int n)
550df930be7Sderaadt {
551014b1be8Sderaadt 	history_t *h = (history_t *) malloc(sizeof(history_t));
552d484b7d0Sotto 	if (h == NULL)
553d484b7d0Sotto 		return -1;
554d484b7d0Sotto 
555df930be7Sderaadt 	if (n <= 0)
556df930be7Sderaadt 		n = 0;
557d484b7d0Sotto 	h->eventid = 0;
558df930be7Sderaadt 	h->cur = 0;
559df930be7Sderaadt 	h->max = n;
560df930be7Sderaadt 	h->list.next = h->list.prev = &h->list;
561df930be7Sderaadt 	h->list.ev.str = NULL;
562df930be7Sderaadt 	h->list.ev.num = 0;
563df930be7Sderaadt 	h->cursor = &h->list;
564d484b7d0Sotto 	h->flags = 0;
5657b85e16bSschwarze 	*p = h;
566d484b7d0Sotto 	return 0;
567df930be7Sderaadt }
568df930be7Sderaadt 
569df930be7Sderaadt 
5708bd3f282Sderaadt /* history_def_clear():
571df930be7Sderaadt  *	Default history cleanup function
572df930be7Sderaadt  */
573ddc81437Sschwarze static void
history_def_clear(void * p,TYPE (HistEvent)* ev)5747b85e16bSschwarze history_def_clear(void *p, TYPE(HistEvent) *ev)
575df930be7Sderaadt {
576df930be7Sderaadt 	history_t *h = (history_t *) p;
577df930be7Sderaadt 
578df930be7Sderaadt 	while (h->list.prev != &h->list)
579d484b7d0Sotto 		history_def_delete(h, ev, h->list.prev);
580d484b7d0Sotto 	h->eventid = 0;
5818bd3f282Sderaadt 	h->cur = 0;
582df930be7Sderaadt }
583df930be7Sderaadt 
5848bd3f282Sderaadt 
5858bd3f282Sderaadt 
5868bd3f282Sderaadt 
587df930be7Sderaadt /************************************************************************/
588df930be7Sderaadt 
589df930be7Sderaadt /* history_init():
590df930be7Sderaadt  *	Initialization function.
591df930be7Sderaadt  */
TYPE(History)592ddc81437Sschwarze TYPE(History) *
593aed0ee81Snicm FUN(history,init)(void)
594df930be7Sderaadt {
595aed0ee81Snicm 	TYPE(HistEvent) ev;
596014b1be8Sderaadt 	TYPE(History) *h = (TYPE(History) *) malloc(sizeof(TYPE(History)));
597d484b7d0Sotto 	if (h == NULL)
598d484b7d0Sotto 		return NULL;
599df930be7Sderaadt 
600d484b7d0Sotto 	if (history_def_init(&h->h_ref, &ev, 0) == -1) {
6017b85e16bSschwarze 		free(h);
602d484b7d0Sotto 		return NULL;
603d484b7d0Sotto 	}
604d484b7d0Sotto 	h->h_ent = -1;
605df930be7Sderaadt 	h->h_next = history_def_next;
606df930be7Sderaadt 	h->h_first = history_def_first;
607df930be7Sderaadt 	h->h_last = history_def_last;
608df930be7Sderaadt 	h->h_prev = history_def_prev;
609df930be7Sderaadt 	h->h_curr = history_def_curr;
610d484b7d0Sotto 	h->h_set = history_def_set;
6118bd3f282Sderaadt 	h->h_clear = history_def_clear;
612df930be7Sderaadt 	h->h_enter = history_def_enter;
613df930be7Sderaadt 	h->h_add = history_def_add;
614aed0ee81Snicm 	h->h_del = history_def_del;
615df930be7Sderaadt 
61628d54ee8Sschwarze 	return h;
617df930be7Sderaadt }
618df930be7Sderaadt 
619df930be7Sderaadt 
620df930be7Sderaadt /* history_end():
621df930be7Sderaadt  *	clean up history;
622df930be7Sderaadt  */
623ddc81437Sschwarze void
FUN(history,end)624aed0ee81Snicm FUN(history,end)(TYPE(History) *h)
625df930be7Sderaadt {
626aed0ee81Snicm 	TYPE(HistEvent) ev;
627d484b7d0Sotto 
628df930be7Sderaadt 	if (h->h_next == history_def_next)
629d484b7d0Sotto 		history_def_clear(h->h_ref, &ev);
630014b1be8Sderaadt 	free(h->h_ref);
631014b1be8Sderaadt 	free(h);
632df930be7Sderaadt }
633df930be7Sderaadt 
634df930be7Sderaadt 
635df930be7Sderaadt 
636d484b7d0Sotto /* history_setsize():
637df930be7Sderaadt  *	Set history number of events
638df930be7Sderaadt  */
639ddc81437Sschwarze static int
history_setsize(TYPE (History)* h,TYPE (HistEvent)* ev,int num)640aed0ee81Snicm history_setsize(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
641df930be7Sderaadt {
642d484b7d0Sotto 
643d484b7d0Sotto 	if (h->h_next != history_def_next) {
644d484b7d0Sotto 		he_seterrev(ev, _HE_NOT_ALLOWED);
64528d54ee8Sschwarze 		return -1;
646d484b7d0Sotto 	}
647d484b7d0Sotto 	if (num < 0) {
648d484b7d0Sotto 		he_seterrev(ev, _HE_BAD_PARAM);
64928d54ee8Sschwarze 		return -1;
650d484b7d0Sotto 	}
651d484b7d0Sotto 	history_def_setsize(h->h_ref, num);
65228d54ee8Sschwarze 	return 0;
653d484b7d0Sotto }
654d484b7d0Sotto 
655d484b7d0Sotto 
656d484b7d0Sotto /* history_getsize():
657d484b7d0Sotto  *      Get number of events currently in history
658d484b7d0Sotto  */
659ddc81437Sschwarze static int
history_getsize(TYPE (History)* h,TYPE (HistEvent)* ev)660aed0ee81Snicm history_getsize(TYPE(History) *h, TYPE(HistEvent) *ev)
661d484b7d0Sotto {
662d484b7d0Sotto 	if (h->h_next != history_def_next) {
663d484b7d0Sotto 		he_seterrev(ev, _HE_NOT_ALLOWED);
66428d54ee8Sschwarze 		return -1;
665d484b7d0Sotto 	}
666d484b7d0Sotto 	ev->num = history_def_getsize(h->h_ref);
667d484b7d0Sotto 	if (ev->num < -1) {
668d484b7d0Sotto 		he_seterrev(ev, _HE_SIZE_NEGATIVE);
66928d54ee8Sschwarze 		return -1;
670d484b7d0Sotto 	}
67128d54ee8Sschwarze 	return 0;
672d484b7d0Sotto }
673d484b7d0Sotto 
674d484b7d0Sotto 
675d484b7d0Sotto /* history_setunique():
676d484b7d0Sotto  *	Set if adjacent equal events should not be entered in history.
677d484b7d0Sotto  */
678ddc81437Sschwarze static int
history_setunique(TYPE (History)* h,TYPE (HistEvent)* ev,int uni)679aed0ee81Snicm history_setunique(TYPE(History) *h, TYPE(HistEvent) *ev, int uni)
680d484b7d0Sotto {
681d484b7d0Sotto 
682d484b7d0Sotto 	if (h->h_next != history_def_next) {
683d484b7d0Sotto 		he_seterrev(ev, _HE_NOT_ALLOWED);
68428d54ee8Sschwarze 		return -1;
685d484b7d0Sotto 	}
686d484b7d0Sotto 	history_def_setunique(h->h_ref, uni);
68728d54ee8Sschwarze 	return 0;
688d484b7d0Sotto }
689d484b7d0Sotto 
690d484b7d0Sotto 
691d484b7d0Sotto /* history_getunique():
692d484b7d0Sotto  *	Get if adjacent equal events should not be entered in history.
693d484b7d0Sotto  */
694ddc81437Sschwarze static int
history_getunique(TYPE (History)* h,TYPE (HistEvent)* ev)695aed0ee81Snicm history_getunique(TYPE(History) *h, TYPE(HistEvent) *ev)
696d484b7d0Sotto {
697d484b7d0Sotto 	if (h->h_next != history_def_next) {
698d484b7d0Sotto 		he_seterrev(ev, _HE_NOT_ALLOWED);
69928d54ee8Sschwarze 		return -1;
700d484b7d0Sotto 	}
701d484b7d0Sotto 	ev->num = history_def_getunique(h->h_ref);
70228d54ee8Sschwarze 	return 0;
703df930be7Sderaadt }
704df930be7Sderaadt 
705df930be7Sderaadt 
706df930be7Sderaadt /* history_set_fun():
707df930be7Sderaadt  *	Set history functions
708df930be7Sderaadt  */
709ddc81437Sschwarze static int
history_set_fun(TYPE (History)* h,TYPE (History)* nh)710aed0ee81Snicm history_set_fun(TYPE(History) *h, TYPE(History) *nh)
711df930be7Sderaadt {
712aed0ee81Snicm 	TYPE(HistEvent) ev;
713d484b7d0Sotto 
714d484b7d0Sotto 	if (nh->h_first == NULL || nh->h_next == NULL || nh->h_last == NULL ||
715d484b7d0Sotto 	    nh->h_prev == NULL || nh->h_curr == NULL || nh->h_set == NULL ||
7168bd3f282Sderaadt 	    nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL ||
717aed0ee81Snicm 	    nh->h_del == NULL || nh->h_ref == NULL) {
718df930be7Sderaadt 		if (h->h_next != history_def_next) {
719d484b7d0Sotto 			history_def_init(&h->h_ref, &ev, 0);
720df930be7Sderaadt 			h->h_first = history_def_first;
721df930be7Sderaadt 			h->h_next = history_def_next;
722df930be7Sderaadt 			h->h_last = history_def_last;
723df930be7Sderaadt 			h->h_prev = history_def_prev;
724df930be7Sderaadt 			h->h_curr = history_def_curr;
725d484b7d0Sotto 			h->h_set = history_def_set;
7268bd3f282Sderaadt 			h->h_clear = history_def_clear;
727df930be7Sderaadt 			h->h_enter = history_def_enter;
728df930be7Sderaadt 			h->h_add = history_def_add;
729aed0ee81Snicm 			h->h_del = history_def_del;
730df930be7Sderaadt 		}
73128d54ee8Sschwarze 		return -1;
732df930be7Sderaadt 	}
733df930be7Sderaadt 	if (h->h_next == history_def_next)
734d484b7d0Sotto 		history_def_clear(h->h_ref, &ev);
735df930be7Sderaadt 
736d484b7d0Sotto 	h->h_ent = -1;
7378bd3f282Sderaadt 	h->h_first = nh->h_first;
7388bd3f282Sderaadt 	h->h_next = nh->h_next;
7398bd3f282Sderaadt 	h->h_last = nh->h_last;
7408bd3f282Sderaadt 	h->h_prev = nh->h_prev;
7418bd3f282Sderaadt 	h->h_curr = nh->h_curr;
742d484b7d0Sotto 	h->h_set = nh->h_set;
7438bd3f282Sderaadt 	h->h_clear = nh->h_clear;
7448bd3f282Sderaadt 	h->h_enter = nh->h_enter;
7458bd3f282Sderaadt 	h->h_add = nh->h_add;
746aed0ee81Snicm 	h->h_del = nh->h_del;
7478bd3f282Sderaadt 
74828d54ee8Sschwarze 	return 0;
749df930be7Sderaadt }
750df930be7Sderaadt 
751df930be7Sderaadt 
7528bd3f282Sderaadt /* history_load():
753aed0ee81Snicm  *	TYPE(History) load function
7548bd3f282Sderaadt  */
755ddc81437Sschwarze static int
history_load(TYPE (History)* h,const char * fname)756aed0ee81Snicm history_load(TYPE(History) *h, const char *fname)
7578bd3f282Sderaadt {
7588bd3f282Sderaadt 	FILE *fp;
759f3a50c9eSschwarze 	char *line;
760f3a50c9eSschwarze 	size_t llen;
761f3a50c9eSschwarze 	ssize_t sz;
762f3a50c9eSschwarze 	size_t max_size;
763d484b7d0Sotto 	char *ptr;
7648bd3f282Sderaadt 	int i = -1;
765aed0ee81Snicm 	TYPE(HistEvent) ev;
76659aed043Sschwarze #ifndef NARROWCHAR
767aed0ee81Snicm 	static ct_buffer_t conv;
768aed0ee81Snicm #endif
7698bd3f282Sderaadt 
7708bd3f282Sderaadt 	if ((fp = fopen(fname, "r")) == NULL)
77128d54ee8Sschwarze 		return i;
7728bd3f282Sderaadt 
773f3a50c9eSschwarze 	line = NULL;
774f3a50c9eSschwarze 	llen = 0;
775f3a50c9eSschwarze 	if ((sz = getline(&line, &llen, fp)) == -1)
7768bd3f282Sderaadt 		goto done;
7778bd3f282Sderaadt 
7788bd3f282Sderaadt 	if (strncmp(line, hist_cookie, sz) != 0)
7798bd3f282Sderaadt 		goto done;
7808bd3f282Sderaadt 
781014b1be8Sderaadt 	ptr = malloc(max_size = 1024);
782d484b7d0Sotto 	if (ptr == NULL)
783d484b7d0Sotto 		goto done;
784f3a50c9eSschwarze 	for (i = 0; (sz = getline(&line, &llen, fp)) != -1; i++) {
785f3a50c9eSschwarze 		if (sz > 0 && line[sz - 1] == '\n')
786f3a50c9eSschwarze 			line[--sz] = '\0';
787f3a50c9eSschwarze 		if (max_size < sz) {
788d484b7d0Sotto 			char *nptr;
789aed0ee81Snicm 			max_size = (sz + 1024) & ~1023;
790014b1be8Sderaadt 			nptr = realloc(ptr, max_size);
791d484b7d0Sotto 			if (nptr == NULL) {
792d484b7d0Sotto 				i = -1;
793d484b7d0Sotto 				goto oomem;
794d484b7d0Sotto 			}
795d484b7d0Sotto 			ptr = nptr;
796d484b7d0Sotto 		}
797d484b7d0Sotto 		(void) strunvis(ptr, line);
798aed0ee81Snicm 		if (HENTER(h, &ev, ct_decode_string(ptr, &conv)) == -1) {
799aed0ee81Snicm 			i = -1;
800aed0ee81Snicm 			goto oomem;
801d484b7d0Sotto 		}
802d484b7d0Sotto 	}
803d484b7d0Sotto oomem:
8047b85e16bSschwarze 	free(ptr);
8058bd3f282Sderaadt done:
806f3a50c9eSschwarze 	free(line);
8078bd3f282Sderaadt 	(void) fclose(fp);
80828d54ee8Sschwarze 	return i;
8098bd3f282Sderaadt }
8108bd3f282Sderaadt 
8118bd3f282Sderaadt 
812d47027c4Snicm /* history_save_fp():
813aed0ee81Snicm  *	TYPE(History) save function
8148bd3f282Sderaadt  */
815ddc81437Sschwarze static int
history_save_fp(TYPE (History)* h,FILE * fp)816d47027c4Snicm history_save_fp(TYPE(History) *h, FILE *fp)
8178bd3f282Sderaadt {
818aed0ee81Snicm 	TYPE(HistEvent) ev;
819d484b7d0Sotto 	int i = -1, retval;
820d484b7d0Sotto 	size_t len, max_size;
821d484b7d0Sotto 	char *ptr;
82259aed043Sschwarze #ifndef NARROWCHAR
823aed0ee81Snicm 	static ct_buffer_t conv;
824aed0ee81Snicm #endif
8258bd3f282Sderaadt 
826d484b7d0Sotto 	if (fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1)
827d484b7d0Sotto 		goto done;
828d484b7d0Sotto 	if (fputs(hist_cookie, fp) == EOF)
829d484b7d0Sotto 		goto done;
830014b1be8Sderaadt 	ptr = malloc(max_size = 1024);
831d484b7d0Sotto 	if (ptr == NULL)
832d484b7d0Sotto 		goto done;
833d484b7d0Sotto 	for (i = 0, retval = HLAST(h, &ev);
834d484b7d0Sotto 	    retval != -1;
835d484b7d0Sotto 	    retval = HPREV(h, &ev), i++) {
8369e89f419Stobias 		len = Strlen(ev.str) * 4 + 1;
8379e89f419Stobias 		if (len > max_size) {
838d484b7d0Sotto 			char *nptr;
839aed0ee81Snicm 			max_size = (len + 1024) & ~1023;
840014b1be8Sderaadt 			nptr = realloc(ptr, max_size);
841d484b7d0Sotto 			if (nptr == NULL) {
842d484b7d0Sotto 				i = -1;
843d484b7d0Sotto 				goto oomem;
844d484b7d0Sotto 			}
845d484b7d0Sotto 			ptr = nptr;
846d484b7d0Sotto 		}
847aed0ee81Snicm 		(void) strnvis(ptr, ct_encode_string(ev.str, &conv), max_size,
848aed0ee81Snicm 		    VIS_WHITE);
849d484b7d0Sotto 		(void) fprintf(fp, "%s\n", ptr);
850d484b7d0Sotto 	}
851d484b7d0Sotto oomem:
8527b85e16bSschwarze 	free(ptr);
853d484b7d0Sotto done:
85428d54ee8Sschwarze 	return i;
8558bd3f282Sderaadt }
8568bd3f282Sderaadt 
8578bd3f282Sderaadt 
858d47027c4Snicm /* history_save():
859d47027c4Snicm  *    History save function
860d47027c4Snicm  */
861ddc81437Sschwarze static int
history_save(TYPE (History)* h,const char * fname)862d47027c4Snicm history_save(TYPE(History) *h, const char *fname)
863d47027c4Snicm {
864d47027c4Snicm 	FILE *fp;
865d47027c4Snicm 	int i;
866d47027c4Snicm 
867d47027c4Snicm 	if ((fp = fopen(fname, "w")) == NULL)
868d47027c4Snicm 		return -1;
869d47027c4Snicm 
870d47027c4Snicm 	i = history_save_fp(h, fp);
871d47027c4Snicm 
872d47027c4Snicm 	(void) fclose(fp);
873d47027c4Snicm 	return i;
874d47027c4Snicm }
875d47027c4Snicm 
876d47027c4Snicm 
877df930be7Sderaadt /* history_prev_event():
878df930be7Sderaadt  *	Find the previous event, with number given
879df930be7Sderaadt  */
880ddc81437Sschwarze static int
history_prev_event(TYPE (History)* h,TYPE (HistEvent)* ev,int num)881aed0ee81Snicm history_prev_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
882df930be7Sderaadt {
883d484b7d0Sotto 	int retval;
884d484b7d0Sotto 
885d484b7d0Sotto 	for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
886df930be7Sderaadt 		if (ev->num == num)
88728d54ee8Sschwarze 			return 0;
888d484b7d0Sotto 
889d484b7d0Sotto 	he_seterrev(ev, _HE_NOT_FOUND);
89028d54ee8Sschwarze 	return -1;
891df930be7Sderaadt }
892df930be7Sderaadt 
893df930be7Sderaadt 
894ddc81437Sschwarze static int
history_next_evdata(TYPE (History)* h,TYPE (HistEvent)* ev,int num,void ** d)895aed0ee81Snicm history_next_evdata(TYPE(History) *h, TYPE(HistEvent) *ev, int num, void **d)
896aed0ee81Snicm {
897aed0ee81Snicm 	int retval;
898aed0ee81Snicm 
899aed0ee81Snicm 	for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
9005f805b19Sokan 		if (ev->num == num) {
901aed0ee81Snicm 			if (d)
902aed0ee81Snicm 				*d = ((history_t *)h->h_ref)->cursor->data;
90328d54ee8Sschwarze 			return 0;
904aed0ee81Snicm 		}
905aed0ee81Snicm 
906aed0ee81Snicm 	he_seterrev(ev, _HE_NOT_FOUND);
90728d54ee8Sschwarze 	return -1;
908aed0ee81Snicm }
909aed0ee81Snicm 
910aed0ee81Snicm 
911df930be7Sderaadt /* history_next_event():
912df930be7Sderaadt  *	Find the next event, with number given
913df930be7Sderaadt  */
914ddc81437Sschwarze static int
history_next_event(TYPE (History)* h,TYPE (HistEvent)* ev,int num)915aed0ee81Snicm history_next_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
916df930be7Sderaadt {
917d484b7d0Sotto 	int retval;
918d484b7d0Sotto 
919d484b7d0Sotto 	for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
920df930be7Sderaadt 		if (ev->num == num)
92128d54ee8Sschwarze 			return 0;
922d484b7d0Sotto 
923d484b7d0Sotto 	he_seterrev(ev, _HE_NOT_FOUND);
92428d54ee8Sschwarze 	return -1;
925df930be7Sderaadt }
926df930be7Sderaadt 
927df930be7Sderaadt 
928df930be7Sderaadt /* history_prev_string():
929df930be7Sderaadt  *	Find the previous event beginning with string
930df930be7Sderaadt  */
931ddc81437Sschwarze static int
history_prev_string(TYPE (History)* h,TYPE (HistEvent)* ev,const Char * str)932aed0ee81Snicm history_prev_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str)
933df930be7Sderaadt {
934aed0ee81Snicm 	size_t len = Strlen(str);
935d484b7d0Sotto 	int retval;
936df930be7Sderaadt 
937d484b7d0Sotto 	for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
938aed0ee81Snicm 		if (Strncmp(str, ev->str, len) == 0)
93928d54ee8Sschwarze 			return 0;
940d484b7d0Sotto 
941d484b7d0Sotto 	he_seterrev(ev, _HE_NOT_FOUND);
94228d54ee8Sschwarze 	return -1;
943df930be7Sderaadt }
944df930be7Sderaadt 
945df930be7Sderaadt 
946df930be7Sderaadt /* history_next_string():
947df930be7Sderaadt  *	Find the next event beginning with string
948df930be7Sderaadt  */
949ddc81437Sschwarze static int
history_next_string(TYPE (History)* h,TYPE (HistEvent)* ev,const Char * str)950aed0ee81Snicm history_next_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str)
951df930be7Sderaadt {
952aed0ee81Snicm 	size_t len = Strlen(str);
953d484b7d0Sotto 	int retval;
954df930be7Sderaadt 
955d484b7d0Sotto 	for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
956aed0ee81Snicm 		if (Strncmp(str, ev->str, len) == 0)
95728d54ee8Sschwarze 			return 0;
958d484b7d0Sotto 
959d484b7d0Sotto 	he_seterrev(ev, _HE_NOT_FOUND);
96028d54ee8Sschwarze 	return -1;
961df930be7Sderaadt }
962df930be7Sderaadt 
963df930be7Sderaadt 
964df930be7Sderaadt /* history():
965df930be7Sderaadt  *	User interface to history functions.
966df930be7Sderaadt  */
967d484b7d0Sotto int
FUNW(history)968aed0ee81Snicm FUNW(history)(TYPE(History) *h, TYPE(HistEvent) *ev, int fun, ...)
969df930be7Sderaadt {
970df930be7Sderaadt 	va_list va;
971aed0ee81Snicm 	const Char *str;
972d484b7d0Sotto 	int retval;
973df930be7Sderaadt 
974df930be7Sderaadt 	va_start(va, fun);
975df930be7Sderaadt 
976d484b7d0Sotto 	he_seterrev(ev, _HE_OK);
977d484b7d0Sotto 
978df930be7Sderaadt 	switch (fun) {
979d484b7d0Sotto 	case H_GETSIZE:
980d484b7d0Sotto 		retval = history_getsize(h, ev);
981d484b7d0Sotto 		break;
982d484b7d0Sotto 
983d484b7d0Sotto 	case H_SETSIZE:
984d484b7d0Sotto 		retval = history_setsize(h, ev, va_arg(va, int));
985d484b7d0Sotto 		break;
986d484b7d0Sotto 
987d484b7d0Sotto 	case H_GETUNIQUE:
988d484b7d0Sotto 		retval = history_getunique(h, ev);
989d484b7d0Sotto 		break;
990d484b7d0Sotto 
991d484b7d0Sotto 	case H_SETUNIQUE:
992d484b7d0Sotto 		retval = history_setunique(h, ev, va_arg(va, int));
993d484b7d0Sotto 		break;
994d484b7d0Sotto 
995df930be7Sderaadt 	case H_ADD:
996aed0ee81Snicm 		str = va_arg(va, const Char *);
997d484b7d0Sotto 		retval = HADD(h, ev, str);
998df930be7Sderaadt 		break;
999df930be7Sderaadt 
1000aed0ee81Snicm 	case H_DEL:
1001aed0ee81Snicm 		retval = HDEL(h, ev, va_arg(va, const int));
1002aed0ee81Snicm 		break;
1003aed0ee81Snicm 
1004df930be7Sderaadt 	case H_ENTER:
1005aed0ee81Snicm 		str = va_arg(va, const Char *);
1006d484b7d0Sotto 		if ((retval = HENTER(h, ev, str)) != -1)
1007d484b7d0Sotto 			h->h_ent = ev->num;
1008d484b7d0Sotto 		break;
1009d484b7d0Sotto 
1010d484b7d0Sotto 	case H_APPEND:
1011aed0ee81Snicm 		str = va_arg(va, const Char *);
1012d484b7d0Sotto 		if ((retval = HSET(h, ev, h->h_ent)) != -1)
1013d484b7d0Sotto 			retval = HADD(h, ev, str);
1014df930be7Sderaadt 		break;
1015df930be7Sderaadt 
1016df930be7Sderaadt 	case H_FIRST:
1017d484b7d0Sotto 		retval = HFIRST(h, ev);
1018df930be7Sderaadt 		break;
1019df930be7Sderaadt 
1020df930be7Sderaadt 	case H_NEXT:
1021d484b7d0Sotto 		retval = HNEXT(h, ev);
1022df930be7Sderaadt 		break;
1023df930be7Sderaadt 
1024df930be7Sderaadt 	case H_LAST:
1025d484b7d0Sotto 		retval = HLAST(h, ev);
1026df930be7Sderaadt 		break;
1027df930be7Sderaadt 
1028df930be7Sderaadt 	case H_PREV:
1029d484b7d0Sotto 		retval = HPREV(h, ev);
1030df930be7Sderaadt 		break;
1031df930be7Sderaadt 
1032df930be7Sderaadt 	case H_CURR:
1033d484b7d0Sotto 		retval = HCURR(h, ev);
1034d484b7d0Sotto 		break;
1035d484b7d0Sotto 
1036d484b7d0Sotto 	case H_SET:
1037d484b7d0Sotto 		retval = HSET(h, ev, va_arg(va, const int));
1038df930be7Sderaadt 		break;
1039df930be7Sderaadt 
10408bd3f282Sderaadt 	case H_CLEAR:
1041d484b7d0Sotto 		HCLEAR(h, ev);
1042d484b7d0Sotto 		retval = 0;
10438bd3f282Sderaadt 		break;
10448bd3f282Sderaadt 
10458bd3f282Sderaadt 	case H_LOAD:
1046d484b7d0Sotto 		retval = history_load(h, va_arg(va, const char *));
1047d484b7d0Sotto 		if (retval == -1)
1048d484b7d0Sotto 			he_seterrev(ev, _HE_HIST_READ);
10498bd3f282Sderaadt 		break;
10508bd3f282Sderaadt 
10518bd3f282Sderaadt 	case H_SAVE:
1052d484b7d0Sotto 		retval = history_save(h, va_arg(va, const char *));
1053d484b7d0Sotto 		if (retval == -1)
1054d484b7d0Sotto 			he_seterrev(ev, _HE_HIST_WRITE);
10558bd3f282Sderaadt 		break;
10568bd3f282Sderaadt 
1057d47027c4Snicm 	case H_SAVE_FP:
1058d47027c4Snicm 		retval = history_save_fp(h, va_arg(va, FILE *));
1059d47027c4Snicm 		if (retval == -1)
1060d47027c4Snicm 		    he_seterrev(ev, _HE_HIST_WRITE);
1061d47027c4Snicm 		break;
1062d47027c4Snicm 
1063df930be7Sderaadt 	case H_PREV_EVENT:
1064d484b7d0Sotto 		retval = history_prev_event(h, ev, va_arg(va, int));
1065df930be7Sderaadt 		break;
1066df930be7Sderaadt 
1067df930be7Sderaadt 	case H_NEXT_EVENT:
1068d484b7d0Sotto 		retval = history_next_event(h, ev, va_arg(va, int));
1069df930be7Sderaadt 		break;
1070df930be7Sderaadt 
1071df930be7Sderaadt 	case H_PREV_STR:
1072aed0ee81Snicm 		retval = history_prev_string(h, ev, va_arg(va, const Char *));
1073df930be7Sderaadt 		break;
1074df930be7Sderaadt 
1075df930be7Sderaadt 	case H_NEXT_STR:
1076aed0ee81Snicm 		retval = history_next_string(h, ev, va_arg(va, const Char *));
1077df930be7Sderaadt 		break;
1078df930be7Sderaadt 
1079df930be7Sderaadt 	case H_FUNC:
1080df930be7Sderaadt 	{
1081aed0ee81Snicm 		TYPE(History) hf;
1082d484b7d0Sotto 
10837b85e16bSschwarze 		hf.h_ref = va_arg(va, void *);
1084d484b7d0Sotto 		h->h_ent = -1;
10858bd3f282Sderaadt 		hf.h_first = va_arg(va, history_gfun_t);
10868bd3f282Sderaadt 		hf.h_next = va_arg(va, history_gfun_t);
10878bd3f282Sderaadt 		hf.h_last = va_arg(va, history_gfun_t);
10888bd3f282Sderaadt 		hf.h_prev = va_arg(va, history_gfun_t);
10898bd3f282Sderaadt 		hf.h_curr = va_arg(va, history_gfun_t);
1090d484b7d0Sotto 		hf.h_set = va_arg(va, history_sfun_t);
10918bd3f282Sderaadt 		hf.h_clear = va_arg(va, history_vfun_t);
10928bd3f282Sderaadt 		hf.h_enter = va_arg(va, history_efun_t);
10938bd3f282Sderaadt 		hf.h_add = va_arg(va, history_efun_t);
1094aed0ee81Snicm 		hf.h_del = va_arg(va, history_sfun_t);
1095df930be7Sderaadt 
1096d484b7d0Sotto 		if ((retval = history_set_fun(h, &hf)) == -1)
1097d484b7d0Sotto 			he_seterrev(ev, _HE_PARAM_MISSING);
1098df930be7Sderaadt 		break;
1099d484b7d0Sotto 	}
1100df930be7Sderaadt 
1101df930be7Sderaadt 	case H_END:
1102aed0ee81Snicm 		FUN(history,end)(h);
1103d484b7d0Sotto 		retval = 0;
1104df930be7Sderaadt 		break;
1105df930be7Sderaadt 
1106aed0ee81Snicm 	case H_NEXT_EVDATA:
1107aed0ee81Snicm 	{
1108aed0ee81Snicm 		int num = va_arg(va, int);
1109aed0ee81Snicm 		void **d = va_arg(va, void **);
1110aed0ee81Snicm 		retval = history_next_evdata(h, ev, num, d);
1111aed0ee81Snicm 		break;
1112aed0ee81Snicm 	}
1113aed0ee81Snicm 
1114aed0ee81Snicm 	case H_DELDATA:
1115aed0ee81Snicm 	{
1116aed0ee81Snicm 		int num = va_arg(va, int);
1117aed0ee81Snicm 		void **d = va_arg(va, void **);
1118aed0ee81Snicm 		retval = history_deldata_nth((history_t *)h->h_ref, ev, num, d);
1119aed0ee81Snicm 		break;
1120aed0ee81Snicm 	}
1121aed0ee81Snicm 
1122aed0ee81Snicm 	case H_REPLACE: /* only use after H_NEXT_EVDATA */
1123aed0ee81Snicm 	{
1124aed0ee81Snicm 		const Char *line = va_arg(va, const Char *);
1125aed0ee81Snicm 		void *d = va_arg(va, void *);
1126aed0ee81Snicm 		const Char *s;
1127aed0ee81Snicm 		if(!line || !(s = Strdup(line))) {
1128aed0ee81Snicm 			retval = -1;
1129aed0ee81Snicm 			break;
1130aed0ee81Snicm 		}
1131aed0ee81Snicm 		((history_t *)h->h_ref)->cursor->ev.str = s;
1132aed0ee81Snicm 		((history_t *)h->h_ref)->cursor->data = d;
1133aed0ee81Snicm 		retval = 0;
1134aed0ee81Snicm 		break;
1135aed0ee81Snicm 	}
1136aed0ee81Snicm 
1137df930be7Sderaadt 	default:
1138d484b7d0Sotto 		retval = -1;
1139d484b7d0Sotto 		he_seterrev(ev, _HE_UNKNOWN);
1140df930be7Sderaadt 		break;
1141df930be7Sderaadt 	}
1142df930be7Sderaadt 	va_end(va);
1143aed0ee81Snicm 	return retval;
1144df930be7Sderaadt }
1145