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