xref: /dragonfly/contrib/libedit/src/history.c (revision 7d2302ac)
1 /*	$NetBSD: history.c,v 1.62 2018/09/13 09:03:40 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 #ifndef NARROWCHAR
36 #include "config.h"
37 #endif
38 
39 #if !defined(lint) && !defined(SCCSID)
40 #if 0
41 static char sccsid[] = "@(#)history.c	8.1 (Berkeley) 6/4/93";
42 #else
43 __RCSID("$NetBSD: history.c,v 1.62 2018/09/13 09:03:40 kre Exp $");
44 #endif
45 #endif /* not lint && not SCCSID */
46 
47 /*
48  * hist.c: TYPE(History) access functions
49  */
50 #include <sys/stat.h>
51 #include <stdarg.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <vis.h>
55 
56 static const char hist_cookie[] = "_HiStOrY_V2_\n";
57 
58 #include "histedit.h"
59 
60 
61 #ifdef NARROWCHAR
62 
63 #define	Char			char
64 #define	FUN(prefix, rest)	prefix ## _ ## rest
65 #define	FUNW(type)		type
66 #define	TYPE(type)		type
67 #define	STR(x)			x
68 
69 #define	Strlen(s)		strlen(s)
70 #define	Strdup(s)		strdup(s)
71 #define	Strcmp(d, s)		strcmp(d, s)
72 #define	Strncmp(d, s, n)	strncmp(d, s, n)
73 #define	Strncpy(d, s, n)	strncpy(d, s, n)
74 #define	Strncat(d, s, n)	strncat(d, s, n)
75 #define	ct_decode_string(s, b)	(s)
76 #define	ct_encode_string(s, b)	(s)
77 
78 #else
79 #include "chartype.h"
80 
81 #define	Char			wchar_t
82 #define	FUN(prefix, rest)	prefix ## _w ## rest
83 #define	FUNW(type)		type ## _w
84 #define	TYPE(type)		type ## W
85 #define	STR(x)			L ## x
86 
87 #define	Strlen(s)		wcslen(s)
88 #define	Strdup(s)		wcsdup(s)
89 #define	Strcmp(d, s)		wcscmp(d, s)
90 #define	Strncmp(d, s, n)	wcsncmp(d, s, n)
91 #define	Strncpy(d, s, n)	wcsncpy(d, s, n)
92 #define	Strncat(d, s, n)	wcsncat(d, s, n)
93 
94 #endif
95 
96 
97 typedef int (*history_gfun_t)(void *, TYPE(HistEvent) *);
98 typedef int (*history_efun_t)(void *, TYPE(HistEvent) *, const Char *);
99 typedef void (*history_vfun_t)(void *, TYPE(HistEvent) *);
100 typedef int (*history_sfun_t)(void *, TYPE(HistEvent) *, const int);
101 
102 struct TYPE(history) {
103 	void *h_ref;		/* Argument for history fcns	 */
104 	int h_ent;		/* Last entry point for history	 */
105 	history_gfun_t h_first;	/* Get the first element	 */
106 	history_gfun_t h_next;	/* Get the next element		 */
107 	history_gfun_t h_last;	/* Get the last element		 */
108 	history_gfun_t h_prev;	/* Get the previous element	 */
109 	history_gfun_t h_curr;	/* Get the current element	 */
110 	history_sfun_t h_set;	/* Set the current element	 */
111 	history_sfun_t h_del;	/* Set the given element	 */
112 	history_vfun_t h_clear;	/* Clear the history list	 */
113 	history_efun_t h_enter;	/* Add an element		 */
114 	history_efun_t h_add;	/* Append to an element		 */
115 };
116 
117 #define	HNEXT(h, ev)		(*(h)->h_next)((h)->h_ref, ev)
118 #define	HFIRST(h, ev)		(*(h)->h_first)((h)->h_ref, ev)
119 #define	HPREV(h, ev)		(*(h)->h_prev)((h)->h_ref, ev)
120 #define	HLAST(h, ev)		(*(h)->h_last)((h)->h_ref, ev)
121 #define	HCURR(h, ev)		(*(h)->h_curr)((h)->h_ref, ev)
122 #define	HSET(h, ev, n)		(*(h)->h_set)((h)->h_ref, ev, n)
123 #define	HCLEAR(h, ev)		(*(h)->h_clear)((h)->h_ref, ev)
124 #define	HENTER(h, ev, str)	(*(h)->h_enter)((h)->h_ref, ev, str)
125 #define	HADD(h, ev, str)	(*(h)->h_add)((h)->h_ref, ev, str)
126 #define	HDEL(h, ev, n)		(*(h)->h_del)((h)->h_ref, ev, n)
127 
128 #define	h_strdup(a)	Strdup(a)
129 #define	h_malloc(a)	malloc(a)
130 #define	h_realloc(a, b)	realloc((a), (b))
131 #define	h_free(a)	free(a)
132 
133 typedef struct {
134     int		num;
135     Char	*str;
136 } HistEventPrivate;
137 
138 
139 static int history_setsize(TYPE(History) *, TYPE(HistEvent) *, int);
140 static int history_getsize(TYPE(History) *, TYPE(HistEvent) *);
141 static int history_setunique(TYPE(History) *, TYPE(HistEvent) *, int);
142 static int history_getunique(TYPE(History) *, TYPE(HistEvent) *);
143 static int history_set_fun(TYPE(History) *, TYPE(History) *);
144 static int history_load(TYPE(History) *, const char *);
145 static int history_save(TYPE(History) *, const char *);
146 static int history_save_fp(TYPE(History) *, size_t, FILE *);
147 static int history_prev_event(TYPE(History) *, TYPE(HistEvent) *, int);
148 static int history_next_event(TYPE(History) *, TYPE(HistEvent) *, int);
149 static int history_next_string(TYPE(History) *, TYPE(HistEvent) *,
150     const Char *);
151 static int history_prev_string(TYPE(History) *, TYPE(HistEvent) *,
152     const Char *);
153 
154 
155 /***********************************************************************/
156 
157 /*
158  * Builtin- history implementation
159  */
160 typedef struct hentry_t {
161 	TYPE(HistEvent) ev;		/* What we return		 */
162 	void *data;		/* data				 */
163 	struct hentry_t *next;	/* Next entry			 */
164 	struct hentry_t *prev;	/* Previous entry		 */
165 } hentry_t;
166 
167 typedef struct history_t {
168 	hentry_t list;		/* Fake list header element	*/
169 	hentry_t *cursor;	/* Current element in the list	*/
170 	int max;		/* Maximum number of events	*/
171 	int cur;		/* Current number of events	*/
172 	int eventid;		/* For generation of unique event id	 */
173 	int flags;		/* TYPE(History) flags		*/
174 #define H_UNIQUE	1	/* Store only unique elements	*/
175 } history_t;
176 
177 static int history_def_next(void *, TYPE(HistEvent) *);
178 static int history_def_first(void *, TYPE(HistEvent) *);
179 static int history_def_prev(void *, TYPE(HistEvent) *);
180 static int history_def_last(void *, TYPE(HistEvent) *);
181 static int history_def_curr(void *, TYPE(HistEvent) *);
182 static int history_def_set(void *, TYPE(HistEvent) *, const int);
183 static void history_def_clear(void *, TYPE(HistEvent) *);
184 static int history_def_enter(void *, TYPE(HistEvent) *, const Char *);
185 static int history_def_add(void *, TYPE(HistEvent) *, const Char *);
186 static int history_def_del(void *, TYPE(HistEvent) *, const int);
187 
188 static int history_def_init(void **, TYPE(HistEvent) *, int);
189 static int history_def_insert(history_t *, TYPE(HistEvent) *, const Char *);
190 static void history_def_delete(history_t *, TYPE(HistEvent) *, hentry_t *);
191 
192 static int history_deldata_nth(history_t *, TYPE(HistEvent) *, int, void **);
193 static int history_set_nth(void *, TYPE(HistEvent) *, int);
194 
195 #define	history_def_setsize(p, num)(void) (((history_t *)p)->max = (num))
196 #define	history_def_getsize(p)  (((history_t *)p)->cur)
197 #define	history_def_getunique(p) (((((history_t *)p)->flags) & H_UNIQUE) != 0)
198 #define	history_def_setunique(p, uni) \
199     if (uni) \
200 	(((history_t *)p)->flags) |= H_UNIQUE; \
201     else \
202 	(((history_t *)p)->flags) &= ~H_UNIQUE
203 
204 #define	he_strerror(code)	he_errlist[code]
205 #define	he_seterrev(evp, code)	{\
206 				    evp->num = code;\
207 				    evp->str = he_strerror(code);\
208 				}
209 
210 /* error messages */
211 static const Char *const he_errlist[] = {
212 	STR("OK"),
213 	STR("unknown error"),
214 	STR("malloc() failed"),
215 	STR("first event not found"),
216 	STR("last event not found"),
217 	STR("empty list"),
218 	STR("no next event"),
219 	STR("no previous event"),
220 	STR("current event is invalid"),
221 	STR("event not found"),
222 	STR("can't read history from file"),
223 	STR("can't write history"),
224 	STR("required parameter(s) not supplied"),
225 	STR("history size negative"),
226 	STR("function not allowed with other history-functions-set the default"),
227 	STR("bad parameters")
228 };
229 /* error codes */
230 #define	_HE_OK                   0
231 #define	_HE_UNKNOWN		 1
232 #define	_HE_MALLOC_FAILED        2
233 #define	_HE_FIRST_NOTFOUND       3
234 #define	_HE_LAST_NOTFOUND        4
235 #define	_HE_EMPTY_LIST           5
236 #define	_HE_END_REACHED          6
237 #define	_HE_START_REACHED	 7
238 #define	_HE_CURR_INVALID	 8
239 #define	_HE_NOT_FOUND		 9
240 #define	_HE_HIST_READ		10
241 #define	_HE_HIST_WRITE		11
242 #define	_HE_PARAM_MISSING	12
243 #define	_HE_SIZE_NEGATIVE	13
244 #define	_HE_NOT_ALLOWED		14
245 #define	_HE_BAD_PARAM		15
246 
247 /* history_def_first():
248  *	Default function to return the first event in the history.
249  */
250 static int
251 history_def_first(void *p, TYPE(HistEvent) *ev)
252 {
253 	history_t *h = (history_t *) p;
254 
255 	h->cursor = h->list.next;
256 	if (h->cursor != &h->list)
257 		*ev = h->cursor->ev;
258 	else {
259 		he_seterrev(ev, _HE_FIRST_NOTFOUND);
260 		return -1;
261 	}
262 
263 	return 0;
264 }
265 
266 
267 /* history_def_last():
268  *	Default function to return the last event in the history.
269  */
270 static int
271 history_def_last(void *p, TYPE(HistEvent) *ev)
272 {
273 	history_t *h = (history_t *) p;
274 
275 	h->cursor = h->list.prev;
276 	if (h->cursor != &h->list)
277 		*ev = h->cursor->ev;
278 	else {
279 		he_seterrev(ev, _HE_LAST_NOTFOUND);
280 		return -1;
281 	}
282 
283 	return 0;
284 }
285 
286 
287 /* history_def_next():
288  *	Default function to return the next event in the history.
289  */
290 static int
291 history_def_next(void *p, TYPE(HistEvent) *ev)
292 {
293 	history_t *h = (history_t *) p;
294 
295 	if (h->cursor == &h->list) {
296 		he_seterrev(ev, _HE_EMPTY_LIST);
297 		return -1;
298 	}
299 
300 	if (h->cursor->next == &h->list) {
301 		he_seterrev(ev, _HE_END_REACHED);
302 		return -1;
303 	}
304 
305         h->cursor = h->cursor->next;
306         *ev = h->cursor->ev;
307 
308 	return 0;
309 }
310 
311 
312 /* history_def_prev():
313  *	Default function to return the previous event in the history.
314  */
315 static int
316 history_def_prev(void *p, TYPE(HistEvent) *ev)
317 {
318 	history_t *h = (history_t *) p;
319 
320 	if (h->cursor == &h->list) {
321 		he_seterrev(ev,
322 		    (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST);
323 		return -1;
324 	}
325 
326 	if (h->cursor->prev == &h->list) {
327 		he_seterrev(ev, _HE_START_REACHED);
328 		return -1;
329 	}
330 
331         h->cursor = h->cursor->prev;
332         *ev = h->cursor->ev;
333 
334 	return 0;
335 }
336 
337 
338 /* history_def_curr():
339  *	Default function to return the current event in the history.
340  */
341 static int
342 history_def_curr(void *p, TYPE(HistEvent) *ev)
343 {
344 	history_t *h = (history_t *) p;
345 
346 	if (h->cursor != &h->list)
347 		*ev = h->cursor->ev;
348 	else {
349 		he_seterrev(ev,
350 		    (h->cur > 0) ? _HE_CURR_INVALID : _HE_EMPTY_LIST);
351 		return -1;
352 	}
353 
354 	return 0;
355 }
356 
357 
358 /* history_def_set():
359  *	Default function to set the current event in the history to the
360  *	given one.
361  */
362 static int
363 history_def_set(void *p, TYPE(HistEvent) *ev, const int n)
364 {
365 	history_t *h = (history_t *) p;
366 
367 	if (h->cur == 0) {
368 		he_seterrev(ev, _HE_EMPTY_LIST);
369 		return -1;
370 	}
371 	if (h->cursor == &h->list || h->cursor->ev.num != n) {
372 		for (h->cursor = h->list.next; h->cursor != &h->list;
373 		    h->cursor = h->cursor->next)
374 			if (h->cursor->ev.num == n)
375 				break;
376 	}
377 	if (h->cursor == &h->list) {
378 		he_seterrev(ev, _HE_NOT_FOUND);
379 		return -1;
380 	}
381 	return 0;
382 }
383 
384 
385 /* history_set_nth():
386  *	Default function to set the current event in the history to the
387  *	n-th one.
388  */
389 static int
390 history_set_nth(void *p, TYPE(HistEvent) *ev, int n)
391 {
392 	history_t *h = (history_t *) p;
393 
394 	if (h->cur == 0) {
395 		he_seterrev(ev, _HE_EMPTY_LIST);
396 		return -1;
397 	}
398 	for (h->cursor = h->list.prev; h->cursor != &h->list;
399 	    h->cursor = h->cursor->prev)
400 		if (n-- <= 0)
401 			break;
402 	if (h->cursor == &h->list) {
403 		he_seterrev(ev, _HE_NOT_FOUND);
404 		return -1;
405 	}
406 	return 0;
407 }
408 
409 
410 /* history_def_add():
411  *	Append string to element
412  */
413 static int
414 history_def_add(void *p, TYPE(HistEvent) *ev, const Char *str)
415 {
416 	history_t *h = (history_t *) p;
417 	size_t len;
418 	Char *s;
419 	HistEventPrivate *evp = (void *)&h->cursor->ev;
420 
421 	if (h->cursor == &h->list)
422 		return history_def_enter(p, ev, str);
423 	len = Strlen(evp->str) + Strlen(str) + 1;
424 	s = h_malloc(len * sizeof(*s));
425 	if (s == NULL) {
426 		he_seterrev(ev, _HE_MALLOC_FAILED);
427 		return -1;
428 	}
429 	(void) Strncpy(s, h->cursor->ev.str, len);
430         s[len - 1] = '\0';
431 	(void) Strncat(s, str, len - Strlen(s) - 1);
432 	h_free(evp->str);
433 	evp->str = s;
434 	*ev = h->cursor->ev;
435 	return 0;
436 }
437 
438 
439 static int
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
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
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
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
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
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
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  */
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
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
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
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
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
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
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
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
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 (fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1)
847 		goto done;
848 	if (ftell(fp) == 0 && fputs(hist_cookie, fp) == EOF)
849 		goto done;
850 	ptr = h_malloc((max_size = 1024) * sizeof(*ptr));
851 	if (ptr == NULL)
852 		goto done;
853 	if (nelem != (size_t)-1) {
854 		for (retval = HFIRST(h, &ev); retval != -1 && nelem-- > 0;
855 		    retval = HNEXT(h, &ev))
856 			continue;
857 	} else
858 		retval = -1;
859 
860 	if (retval == -1)
861 		retval = HLAST(h, &ev);
862 
863 	for (i = 0; retval != -1; retval = HPREV(h, &ev), i++) {
864 		str = ct_encode_string(ev.str, &conv);
865 		len = strlen(str) * 4 + 1;
866 		if (len > max_size) {
867 			char *nptr;
868 			max_size = (len + 1024) & (size_t)~1023;
869 			nptr = h_realloc(ptr, max_size * sizeof(*ptr));
870 			if (nptr == NULL) {
871 				i = -1;
872 				goto oomem;
873 			}
874 			ptr = nptr;
875 		}
876 		(void) strvis(ptr, str, VIS_WHITE);
877 		(void) fprintf(fp, "%s\n", ptr);
878 	}
879 oomem:
880 	h_free(ptr);
881 done:
882 	return i;
883 }
884 
885 
886 /* history_save():
887  *    History save function
888  */
889 static int
890 history_save(TYPE(History) *h, const char *fname)
891 {
892     FILE *fp;
893     int i;
894 
895     if ((fp = fopen(fname, "w")) == NULL)
896 	return -1;
897 
898     i = history_save_fp(h, (size_t)-1, fp);
899 
900     (void) fclose(fp);
901     return i;
902 }
903 
904 
905 /* history_prev_event():
906  *	Find the previous event, with number given
907  */
908 static int
909 history_prev_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
910 {
911 	int retval;
912 
913 	for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
914 		if (ev->num == num)
915 			return 0;
916 
917 	he_seterrev(ev, _HE_NOT_FOUND);
918 	return -1;
919 }
920 
921 
922 static int
923 history_next_evdata(TYPE(History) *h, TYPE(HistEvent) *ev, int num, void **d)
924 {
925 	int retval;
926 
927 	for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
928 		if (ev->num == num) {
929 			if (d)
930 				*d = ((history_t *)h->h_ref)->cursor->data;
931 			return 0;
932 		}
933 
934 	he_seterrev(ev, _HE_NOT_FOUND);
935 	return -1;
936 }
937 
938 
939 /* history_next_event():
940  *	Find the next event, with number given
941  */
942 static int
943 history_next_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
944 {
945 	int retval;
946 
947 	for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
948 		if (ev->num == num)
949 			return 0;
950 
951 	he_seterrev(ev, _HE_NOT_FOUND);
952 	return -1;
953 }
954 
955 
956 /* history_prev_string():
957  *	Find the previous event beginning with string
958  */
959 static int
960 history_prev_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str)
961 {
962 	size_t len = Strlen(str);
963 	int retval;
964 
965 	for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
966 		if (Strncmp(str, ev->str, len) == 0)
967 			return 0;
968 
969 	he_seterrev(ev, _HE_NOT_FOUND);
970 	return -1;
971 }
972 
973 
974 /* history_next_string():
975  *	Find the next event beginning with string
976  */
977 static int
978 history_next_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str)
979 {
980 	size_t len = Strlen(str);
981 	int retval;
982 
983 	for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
984 		if (Strncmp(str, ev->str, len) == 0)
985 			return 0;
986 
987 	he_seterrev(ev, _HE_NOT_FOUND);
988 	return -1;
989 }
990 
991 
992 /* history():
993  *	User interface to history functions.
994  */
995 int
996 FUNW(history)(TYPE(History) *h, TYPE(HistEvent) *ev, int fun, ...)
997 {
998 	va_list va;
999 	const Char *str;
1000 	int retval;
1001 
1002 	va_start(va, fun);
1003 
1004 	he_seterrev(ev, _HE_OK);
1005 
1006 	switch (fun) {
1007 	case H_GETSIZE:
1008 		retval = history_getsize(h, ev);
1009 		break;
1010 
1011 	case H_SETSIZE:
1012 		retval = history_setsize(h, ev, va_arg(va, int));
1013 		break;
1014 
1015 	case H_GETUNIQUE:
1016 		retval = history_getunique(h, ev);
1017 		break;
1018 
1019 	case H_SETUNIQUE:
1020 		retval = history_setunique(h, ev, va_arg(va, int));
1021 		break;
1022 
1023 	case H_ADD:
1024 		str = va_arg(va, const Char *);
1025 		retval = HADD(h, ev, str);
1026 		break;
1027 
1028 	case H_DEL:
1029 		retval = HDEL(h, ev, va_arg(va, const int));
1030 		break;
1031 
1032 	case H_ENTER:
1033 		str = va_arg(va, const Char *);
1034 		if ((retval = HENTER(h, ev, str)) != -1)
1035 			h->h_ent = ev->num;
1036 		break;
1037 
1038 	case H_APPEND:
1039 		str = va_arg(va, const Char *);
1040 		if ((retval = HSET(h, ev, h->h_ent)) != -1)
1041 			retval = HADD(h, ev, str);
1042 		break;
1043 
1044 	case H_FIRST:
1045 		retval = HFIRST(h, ev);
1046 		break;
1047 
1048 	case H_NEXT:
1049 		retval = HNEXT(h, ev);
1050 		break;
1051 
1052 	case H_LAST:
1053 		retval = HLAST(h, ev);
1054 		break;
1055 
1056 	case H_PREV:
1057 		retval = HPREV(h, ev);
1058 		break;
1059 
1060 	case H_CURR:
1061 		retval = HCURR(h, ev);
1062 		break;
1063 
1064 	case H_SET:
1065 		retval = HSET(h, ev, va_arg(va, const int));
1066 		break;
1067 
1068 	case H_CLEAR:
1069 		HCLEAR(h, ev);
1070 		retval = 0;
1071 		break;
1072 
1073 	case H_LOAD:
1074 		retval = history_load(h, va_arg(va, const char *));
1075 		if (retval == -1)
1076 			he_seterrev(ev, _HE_HIST_READ);
1077 		break;
1078 
1079 	case H_SAVE:
1080 		retval = history_save(h, va_arg(va, const char *));
1081 		if (retval == -1)
1082 			he_seterrev(ev, _HE_HIST_WRITE);
1083 		break;
1084 
1085 	case H_SAVE_FP:
1086 		retval = history_save_fp(h, (size_t)-1, va_arg(va, FILE *));
1087 		if (retval == -1)
1088 		    he_seterrev(ev, _HE_HIST_WRITE);
1089 		break;
1090 
1091 	case H_NSAVE_FP:
1092 	{
1093 		size_t sz = va_arg(va, size_t);
1094 		retval = history_save_fp(h, sz, va_arg(va, FILE *));
1095 		if (retval == -1)
1096 		    he_seterrev(ev, _HE_HIST_WRITE);
1097 		break;
1098 	}
1099 
1100 	case H_PREV_EVENT:
1101 		retval = history_prev_event(h, ev, va_arg(va, int));
1102 		break;
1103 
1104 	case H_NEXT_EVENT:
1105 		retval = history_next_event(h, ev, va_arg(va, int));
1106 		break;
1107 
1108 	case H_PREV_STR:
1109 		retval = history_prev_string(h, ev, va_arg(va, const Char *));
1110 		break;
1111 
1112 	case H_NEXT_STR:
1113 		retval = history_next_string(h, ev, va_arg(va, const Char *));
1114 		break;
1115 
1116 	case H_FUNC:
1117 	{
1118 		TYPE(History) hf;
1119 
1120 		hf.h_ref = va_arg(va, void *);
1121 		h->h_ent = -1;
1122 		hf.h_first = va_arg(va, history_gfun_t);
1123 		hf.h_next = va_arg(va, history_gfun_t);
1124 		hf.h_last = va_arg(va, history_gfun_t);
1125 		hf.h_prev = va_arg(va, history_gfun_t);
1126 		hf.h_curr = va_arg(va, history_gfun_t);
1127 		hf.h_set = va_arg(va, history_sfun_t);
1128 		hf.h_clear = va_arg(va, history_vfun_t);
1129 		hf.h_enter = va_arg(va, history_efun_t);
1130 		hf.h_add = va_arg(va, history_efun_t);
1131 		hf.h_del = va_arg(va, history_sfun_t);
1132 
1133 		if ((retval = history_set_fun(h, &hf)) == -1)
1134 			he_seterrev(ev, _HE_PARAM_MISSING);
1135 		break;
1136 	}
1137 
1138 	case H_END:
1139 		FUN(history,end)(h);
1140 		retval = 0;
1141 		break;
1142 
1143 	case H_NEXT_EVDATA:
1144 	{
1145 		int num = va_arg(va, int);
1146 		void **d = va_arg(va, void **);
1147 		retval = history_next_evdata(h, ev, num, d);
1148 		break;
1149 	}
1150 
1151 	case H_DELDATA:
1152 	{
1153 		int num = va_arg(va, int);
1154 		void **d = va_arg(va, void **);
1155 		retval = history_deldata_nth((history_t *)h->h_ref, ev, num, d);
1156 		break;
1157 	}
1158 
1159 	case H_REPLACE: /* only use after H_NEXT_EVDATA */
1160 	{
1161 		const Char *line = va_arg(va, const Char *);
1162 		void *d = va_arg(va, void *);
1163 		const Char *s;
1164 		if(!line || !(s = Strdup(line))) {
1165 			retval = -1;
1166 			break;
1167 		}
1168 		((history_t *)h->h_ref)->cursor->ev.str = s;
1169 		((history_t *)h->h_ref)->cursor->data = d;
1170 		retval = 0;
1171 		break;
1172 	}
1173 
1174 	default:
1175 		retval = -1;
1176 		he_seterrev(ev, _HE_UNKNOWN);
1177 		break;
1178 	}
1179 	va_end(va);
1180 	return retval;
1181 }
1182