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