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