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