Home | History | Annotate | Line # | Download | only in libedit
history.c revision 1.54
      1 /*	$NetBSD: history.c,v 1.54 2016/04/11 00:22: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.54 2016/04/11 00:22:48 christos Exp $");
     41 #endif
     42 #endif /* not lint && not SCCSID */
     43 
     44 /*
     45  * hist.c: TYPE(History) access functions
     46  */
     47 #include <sys/stat.h>
     48 #include <stdarg.h>
     49 #include <stdlib.h>
     50 #include <string.h>
     51 #include <vis.h>
     52 
     53 static const char hist_cookie[] = "_HiStOrY_V2_\n";
     54 
     55 #include "histedit.h"
     56 #include "chartype.h"
     57 
     58 
     59 #ifdef NARROWCHAR
     60 
     61 #define	FUN(prefix, rest)	prefix ## _ ## rest
     62 #define	FUNW(type)		type
     63 #define	TYPE(type)		type
     64 #define	STR(x)			x
     65 
     66 #define	Strlen(s)		strlen(s)
     67 #define	Strdup(s)		strdup(s)
     68 #define	Strcmp(d, s)		strcmp(d, s)
     69 #define	Strncmp(d, s, n)	strncmp(d, s, n)
     70 #define	Strncpy(d, s, n)	strncpy(d, s, n)
     71 #define	Strncat(d, s, n)	strncat(d, s, n)
     72 
     73 #else
     74 
     75 #define	FUN(prefix, rest)	prefix ## _w ## rest
     76 #define	FUNW(type)		type ## _w
     77 #define	TYPE(type)		type ## W
     78 #define	STR(x)			L ## x
     79 
     80 #define	Strlen(s)		wcslen(s)
     81 #define	Strdup(s)		wcsdup(s)
     82 #define	Strcmp(d, s)		wcscmp(d, s)
     83 #define	Strncmp(d, s, n)	wcsncmp(d, s, n)
     84 #define	Strncpy(d, s, n)	wcsncpy(d, s, n)
     85 #define	Strncat(d, s, n)	wcsncat(d, s, n)
     86 
     87 #endif
     88 
     89 
     90 typedef int (*history_gfun_t)(void *, TYPE(HistEvent) *);
     91 typedef int (*history_efun_t)(void *, TYPE(HistEvent) *, const Char *);
     92 typedef void (*history_vfun_t)(void *, TYPE(HistEvent) *);
     93 typedef int (*history_sfun_t)(void *, TYPE(HistEvent) *, const int);
     94 
     95 struct TYPE(history) {
     96 	void *h_ref;		/* Argument for history fcns	 */
     97 	int h_ent;		/* Last entry point for history	 */
     98 	history_gfun_t h_first;	/* Get the first element	 */
     99 	history_gfun_t h_next;	/* Get the next element		 */
    100 	history_gfun_t h_last;	/* Get the last element		 */
    101 	history_gfun_t h_prev;	/* Get the previous element	 */
    102 	history_gfun_t h_curr;	/* Get the current element	 */
    103 	history_sfun_t h_set;	/* Set the current element	 */
    104 	history_sfun_t h_del;	/* Set the given element	 */
    105 	history_vfun_t h_clear;	/* Clear the history list	 */
    106 	history_efun_t h_enter;	/* Add an element		 */
    107 	history_efun_t h_add;	/* Append to an element		 */
    108 };
    109 
    110 #define	HNEXT(h, ev)		(*(h)->h_next)((h)->h_ref, ev)
    111 #define	HFIRST(h, ev)		(*(h)->h_first)((h)->h_ref, ev)
    112 #define	HPREV(h, ev)		(*(h)->h_prev)((h)->h_ref, ev)
    113 #define	HLAST(h, ev)		(*(h)->h_last)((h)->h_ref, ev)
    114 #define	HCURR(h, ev)		(*(h)->h_curr)((h)->h_ref, ev)
    115 #define	HSET(h, ev, n)		(*(h)->h_set)((h)->h_ref, ev, n)
    116 #define	HCLEAR(h, ev)		(*(h)->h_clear)((h)->h_ref, ev)
    117 #define	HENTER(h, ev, str)	(*(h)->h_enter)((h)->h_ref, ev, str)
    118 #define	HADD(h, ev, str)	(*(h)->h_add)((h)->h_ref, ev, str)
    119 #define	HDEL(h, ev, n)		(*(h)->h_del)((h)->h_ref, ev, n)
    120 
    121 #define	h_strdup(a)	Strdup(a)
    122 #define	h_malloc(a)	malloc(a)
    123 #define	h_realloc(a, b)	realloc((a), (b))
    124 #define	h_free(a)	free(a)
    125 
    126 typedef struct {
    127     int		num;
    128     Char	*str;
    129 } HistEventPrivate;
    130 
    131 
    132 
    133 private int history_setsize(TYPE(History) *, TYPE(HistEvent) *, int);
    134 private int history_getsize(TYPE(History) *, TYPE(HistEvent) *);
    135 private int history_setunique(TYPE(History) *, TYPE(HistEvent) *, int);
    136 private int history_getunique(TYPE(History) *, TYPE(HistEvent) *);
    137 private int history_set_fun(TYPE(History) *, TYPE(History) *);
    138 private int history_load(TYPE(History) *, const char *);
    139 private int history_save(TYPE(History) *, const char *);
    140 private int history_save_fp(TYPE(History) *, FILE *);
    141 private int history_prev_event(TYPE(History) *, TYPE(HistEvent) *, int);
    142 private int history_next_event(TYPE(History) *, TYPE(HistEvent) *, int);
    143 private int history_next_string(TYPE(History) *, TYPE(HistEvent) *, const Char *);
    144 private int history_prev_string(TYPE(History) *, TYPE(HistEvent) *, 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 private int history_def_next(void *, TYPE(HistEvent) *);
    170 private int history_def_first(void *, TYPE(HistEvent) *);
    171 private int history_def_prev(void *, TYPE(HistEvent) *);
    172 private int history_def_last(void *, TYPE(HistEvent) *);
    173 private int history_def_curr(void *, TYPE(HistEvent) *);
    174 private int history_def_set(void *, TYPE(HistEvent) *, const int);
    175 private void history_def_clear(void *, TYPE(HistEvent) *);
    176 private int history_def_enter(void *, TYPE(HistEvent) *, const Char *);
    177 private int history_def_add(void *, TYPE(HistEvent) *, const Char *);
    178 private int history_def_del(void *, TYPE(HistEvent) *, const int);
    179 
    180 private int history_def_init(void **, TYPE(HistEvent) *, int);
    181 private int history_def_insert(history_t *, TYPE(HistEvent) *, const Char *);
    182 private void history_def_delete(history_t *, TYPE(HistEvent) *, hentry_t *);
    183 
    184 private int history_deldata_nth(history_t *, TYPE(HistEvent) *, int, void **);
    185 private 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 private 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 private 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 private 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 private 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 private 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 private 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 private 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 private 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 = h_malloc(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 	h_free(evp->str);
    425 	evp->str = s;
    426 	*ev = h->cursor->ev;
    427 	return 0;
    428 }
    429 
    430 
    431 private 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 private 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 private 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 	h_free(evp->str);
    486 	h_free(hp);
    487 	h->cur--;
    488 }
    489 
    490 
    491 /* history_def_insert():
    492  *	Insert element with string str in the h list
    493  */
    494 private int
    495 history_def_insert(history_t *h, TYPE(HistEvent) *ev, const Char *str)
    496 {
    497 	hentry_t *c;
    498 
    499 	c = h_malloc(sizeof(*c));
    500 	if (c == NULL)
    501 		goto oomem;
    502 	if ((c->ev.str = h_strdup(str)) == NULL) {
    503 		h_free(c);
    504 		goto oomem;
    505 	}
    506 	c->data = NULL;
    507 	c->ev.num = ++h->eventid;
    508 	c->next = h->list.next;
    509 	c->prev = &h->list;
    510 	h->list.next->prev = c;
    511 	h->list.next = c;
    512 	h->cur++;
    513 	h->cursor = c;
    514 
    515 	*ev = c->ev;
    516 	return 0;
    517 oomem:
    518 	he_seterrev(ev, _HE_MALLOC_FAILED);
    519 	return -1;
    520 }
    521 
    522 
    523 /* history_def_enter():
    524  *	Default function to enter an item in the history
    525  */
    526 private int
    527 history_def_enter(void *p, TYPE(HistEvent) *ev, const Char *str)
    528 {
    529 	history_t *h = (history_t *) p;
    530 
    531 	if ((h->flags & H_UNIQUE) != 0 && h->list.next != &h->list &&
    532 	    Strcmp(h->list.next->ev.str, str) == 0)
    533 	    return 0;
    534 
    535 	if (history_def_insert(h, ev, str) == -1)
    536 		return -1;	/* error, keep error message */
    537 
    538 	/*
    539          * Always keep at least one entry.
    540          * This way we don't have to check for the empty list.
    541          */
    542 	while (h->cur > h->max && h->cur > 0)
    543 		history_def_delete(h, ev, h->list.prev);
    544 
    545 	return 1;
    546 }
    547 
    548 
    549 /* history_def_init():
    550  *	Default history initialization function
    551  */
    552 /* ARGSUSED */
    553 private int
    554 history_def_init(void **p, TYPE(HistEvent) *ev __attribute__((__unused__)), int n)
    555 {
    556 	history_t *h = (history_t *) h_malloc(sizeof(*h));
    557 	if (h == NULL)
    558 		return -1;
    559 
    560 	if (n <= 0)
    561 		n = 0;
    562 	h->eventid = 0;
    563 	h->cur = 0;
    564 	h->max = n;
    565 	h->list.next = h->list.prev = &h->list;
    566 	h->list.ev.str = NULL;
    567 	h->list.ev.num = 0;
    568 	h->cursor = &h->list;
    569 	h->flags = 0;
    570 	*p = h;
    571 	return 0;
    572 }
    573 
    574 
    575 /* history_def_clear():
    576  *	Default history cleanup function
    577  */
    578 private void
    579 history_def_clear(void *p, TYPE(HistEvent) *ev)
    580 {
    581 	history_t *h = (history_t *) p;
    582 
    583 	while (h->list.prev != &h->list)
    584 		history_def_delete(h, ev, h->list.prev);
    585 	h->cursor = &h->list;
    586 	h->eventid = 0;
    587 	h->cur = 0;
    588 }
    589 
    590 
    591 
    592 
    593 /************************************************************************/
    594 
    595 /* history_init():
    596  *	Initialization function.
    597  */
    598 public TYPE(History) *
    599 FUN(history,init)(void)
    600 {
    601 	TYPE(HistEvent) ev;
    602 	TYPE(History) *h = (TYPE(History) *) h_malloc(sizeof(*h));
    603 	if (h == NULL)
    604 		return NULL;
    605 
    606 	if (history_def_init(&h->h_ref, &ev, 0) == -1) {
    607 		h_free(h);
    608 		return NULL;
    609 	}
    610 	h->h_ent = -1;
    611 	h->h_next = history_def_next;
    612 	h->h_first = history_def_first;
    613 	h->h_last = history_def_last;
    614 	h->h_prev = history_def_prev;
    615 	h->h_curr = history_def_curr;
    616 	h->h_set = history_def_set;
    617 	h->h_clear = history_def_clear;
    618 	h->h_enter = history_def_enter;
    619 	h->h_add = history_def_add;
    620 	h->h_del = history_def_del;
    621 
    622 	return h;
    623 }
    624 
    625 
    626 /* history_end():
    627  *	clean up history;
    628  */
    629 public void
    630 FUN(history,end)(TYPE(History) *h)
    631 {
    632 	TYPE(HistEvent) ev;
    633 
    634 	if (h->h_next == history_def_next)
    635 		history_def_clear(h->h_ref, &ev);
    636 	h_free(h->h_ref);
    637 	h_free(h);
    638 }
    639 
    640 
    641 
    642 /* history_setsize():
    643  *	Set history number of events
    644  */
    645 private int
    646 history_setsize(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
    647 {
    648 
    649 	if (h->h_next != history_def_next) {
    650 		he_seterrev(ev, _HE_NOT_ALLOWED);
    651 		return -1;
    652 	}
    653 	if (num < 0) {
    654 		he_seterrev(ev, _HE_BAD_PARAM);
    655 		return -1;
    656 	}
    657 	history_def_setsize(h->h_ref, num);
    658 	return 0;
    659 }
    660 
    661 
    662 /* history_getsize():
    663  *      Get number of events currently in history
    664  */
    665 private int
    666 history_getsize(TYPE(History) *h, TYPE(HistEvent) *ev)
    667 {
    668 	if (h->h_next != history_def_next) {
    669 		he_seterrev(ev, _HE_NOT_ALLOWED);
    670 		return -1;
    671 	}
    672 	ev->num = history_def_getsize(h->h_ref);
    673 	if (ev->num < -1) {
    674 		he_seterrev(ev, _HE_SIZE_NEGATIVE);
    675 		return -1;
    676 	}
    677 	return 0;
    678 }
    679 
    680 
    681 /* history_setunique():
    682  *	Set if adjacent equal events should not be entered in history.
    683  */
    684 private int
    685 history_setunique(TYPE(History) *h, TYPE(HistEvent) *ev, int uni)
    686 {
    687 
    688 	if (h->h_next != history_def_next) {
    689 		he_seterrev(ev, _HE_NOT_ALLOWED);
    690 		return -1;
    691 	}
    692 	history_def_setunique(h->h_ref, uni);
    693 	return 0;
    694 }
    695 
    696 
    697 /* history_getunique():
    698  *	Get if adjacent equal events should not be entered in history.
    699  */
    700 private int
    701 history_getunique(TYPE(History) *h, TYPE(HistEvent) *ev)
    702 {
    703 	if (h->h_next != history_def_next) {
    704 		he_seterrev(ev, _HE_NOT_ALLOWED);
    705 		return -1;
    706 	}
    707 	ev->num = history_def_getunique(h->h_ref);
    708 	return 0;
    709 }
    710 
    711 
    712 /* history_set_fun():
    713  *	Set history functions
    714  */
    715 private int
    716 history_set_fun(TYPE(History) *h, TYPE(History) *nh)
    717 {
    718 	TYPE(HistEvent) ev;
    719 
    720 	if (nh->h_first == NULL || nh->h_next == NULL || nh->h_last == NULL ||
    721 	    nh->h_prev == NULL || nh->h_curr == NULL || nh->h_set == NULL ||
    722 	    nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL ||
    723 	    nh->h_del == NULL || nh->h_ref == NULL) {
    724 		if (h->h_next != history_def_next) {
    725 			if (history_def_init(&h->h_ref, &ev, 0) == -1)
    726 				return -1;
    727 			h->h_first = history_def_first;
    728 			h->h_next = history_def_next;
    729 			h->h_last = history_def_last;
    730 			h->h_prev = history_def_prev;
    731 			h->h_curr = history_def_curr;
    732 			h->h_set = history_def_set;
    733 			h->h_clear = history_def_clear;
    734 			h->h_enter = history_def_enter;
    735 			h->h_add = history_def_add;
    736 			h->h_del = history_def_del;
    737 		}
    738 		return -1;
    739 	}
    740 	if (h->h_next == history_def_next)
    741 		history_def_clear(h->h_ref, &ev);
    742 
    743 	h->h_ent = -1;
    744 	h->h_first = nh->h_first;
    745 	h->h_next = nh->h_next;
    746 	h->h_last = nh->h_last;
    747 	h->h_prev = nh->h_prev;
    748 	h->h_curr = nh->h_curr;
    749 	h->h_set = nh->h_set;
    750 	h->h_clear = nh->h_clear;
    751 	h->h_enter = nh->h_enter;
    752 	h->h_add = nh->h_add;
    753 	h->h_del = nh->h_del;
    754 
    755 	return 0;
    756 }
    757 
    758 
    759 /* history_load():
    760  *	TYPE(History) load function
    761  */
    762 private int
    763 history_load(TYPE(History) *h, const char *fname)
    764 {
    765 	FILE *fp;
    766 	char *line;
    767 	size_t llen;
    768 	ssize_t sz;
    769 	size_t max_size;
    770 	char *ptr;
    771 	int i = -1;
    772 	TYPE(HistEvent) ev;
    773 #ifndef NARROWCHAR
    774 	static ct_buffer_t conv;
    775 #endif
    776 
    777 	if ((fp = fopen(fname, "r")) == NULL)
    778 		return i;
    779 
    780 	line = NULL;
    781 	llen = 0;
    782 	if ((sz = getline(&line, &llen, fp)) == -1)
    783 		goto done;
    784 
    785 	if (strncmp(line, hist_cookie, (size_t)sz) != 0)
    786 		goto done;
    787 
    788 	ptr = h_malloc((max_size = 1024) * sizeof(*ptr));
    789 	if (ptr == NULL)
    790 		goto done;
    791 	for (i = 0; (sz = getline(&line, &llen, fp)) != -1; i++) {
    792 		if (sz > 0 && line[sz - 1] == '\n')
    793 			line[--sz] = '\0';
    794 		if (max_size < (size_t)sz) {
    795 			char *nptr;
    796 			max_size = ((size_t)sz + 1024) & (size_t)~1023;
    797 			nptr = h_realloc(ptr, max_size * sizeof(*ptr));
    798 			if (nptr == NULL) {
    799 				i = -1;
    800 				goto oomem;
    801 			}
    802 			ptr = nptr;
    803 		}
    804 		(void) strunvis(ptr, line);
    805 		if (HENTER(h, &ev, ct_decode_string(ptr, &conv)) == -1) {
    806 			i = -1;
    807 			goto oomem;
    808 		}
    809 	}
    810 oomem:
    811 	h_free(ptr);
    812 done:
    813 	free(line);
    814 	(void) fclose(fp);
    815 	return i;
    816 }
    817 
    818 
    819 /* history_save_fp():
    820  *	TYPE(History) save function
    821  */
    822 private int
    823 history_save_fp(TYPE(History) *h, FILE *fp)
    824 {
    825 	TYPE(HistEvent) ev;
    826 	int i = -1, retval;
    827 	size_t len, max_size;
    828 	char *ptr;
    829 	const char *str;
    830 #ifndef NARROWCHAR
    831 	static ct_buffer_t conv;
    832 #endif
    833 
    834 	if (fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1)
    835 		goto done;
    836 	if (fputs(hist_cookie, fp) == EOF)
    837 		goto done;
    838 	ptr = h_malloc((max_size = 1024) * sizeof(*ptr));
    839 	if (ptr == NULL)
    840 		goto done;
    841 	for (i = 0, retval = HLAST(h, &ev);
    842 	    retval != -1;
    843 	    retval = HPREV(h, &ev), i++) {
    844 		str = ct_encode_string(ev.str, &conv);
    845 		len = strlen(str) * 4 + 1;
    846 		if (len > max_size) {
    847 			char *nptr;
    848 			max_size = (len + 1024) & (size_t)~1023;
    849 			nptr = h_realloc(ptr, max_size * sizeof(*ptr));
    850 			if (nptr == NULL) {
    851 				i = -1;
    852 				goto oomem;
    853 			}
    854 			ptr = nptr;
    855 		}
    856 		(void) strvis(ptr, str, VIS_WHITE);
    857 		(void) fprintf(fp, "%s\n", ptr);
    858 	}
    859 oomem:
    860 	h_free(ptr);
    861 done:
    862 	return i;
    863 }
    864 
    865 
    866 /* history_save():
    867  *    History save function
    868  */
    869 private int
    870 history_save(TYPE(History) *h, const char *fname)
    871 {
    872     FILE *fp;
    873     int i;
    874 
    875     if ((fp = fopen(fname, "w")) == NULL)
    876 	return -1;
    877 
    878     i = history_save_fp(h, fp);
    879 
    880     (void) fclose(fp);
    881     return i;
    882 }
    883 
    884 
    885 /* history_prev_event():
    886  *	Find the previous event, with number given
    887  */
    888 private int
    889 history_prev_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
    890 {
    891 	int retval;
    892 
    893 	for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
    894 		if (ev->num == num)
    895 			return 0;
    896 
    897 	he_seterrev(ev, _HE_NOT_FOUND);
    898 	return -1;
    899 }
    900 
    901 
    902 private int
    903 history_next_evdata(TYPE(History) *h, TYPE(HistEvent) *ev, int num, void **d)
    904 {
    905 	int retval;
    906 
    907 	for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
    908 		if (ev->num == num) {
    909 			if (d)
    910 				*d = ((history_t *)h->h_ref)->cursor->data;
    911 			return 0;
    912 		}
    913 
    914 	he_seterrev(ev, _HE_NOT_FOUND);
    915 	return -1;
    916 }
    917 
    918 
    919 /* history_next_event():
    920  *	Find the next event, with number given
    921  */
    922 private int
    923 history_next_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
    924 {
    925 	int retval;
    926 
    927 	for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
    928 		if (ev->num == num)
    929 			return 0;
    930 
    931 	he_seterrev(ev, _HE_NOT_FOUND);
    932 	return -1;
    933 }
    934 
    935 
    936 /* history_prev_string():
    937  *	Find the previous event beginning with string
    938  */
    939 private int
    940 history_prev_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str)
    941 {
    942 	size_t len = Strlen(str);
    943 	int retval;
    944 
    945 	for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
    946 		if (Strncmp(str, ev->str, len) == 0)
    947 			return 0;
    948 
    949 	he_seterrev(ev, _HE_NOT_FOUND);
    950 	return -1;
    951 }
    952 
    953 
    954 /* history_next_string():
    955  *	Find the next event beginning with string
    956  */
    957 private int
    958 history_next_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str)
    959 {
    960 	size_t len = Strlen(str);
    961 	int retval;
    962 
    963 	for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
    964 		if (Strncmp(str, ev->str, len) == 0)
    965 			return 0;
    966 
    967 	he_seterrev(ev, _HE_NOT_FOUND);
    968 	return -1;
    969 }
    970 
    971 
    972 /* history():
    973  *	User interface to history functions.
    974  */
    975 int
    976 FUNW(history)(TYPE(History) *h, TYPE(HistEvent) *ev, int fun, ...)
    977 {
    978 	va_list va;
    979 	const Char *str;
    980 	int retval;
    981 
    982 	va_start(va, fun);
    983 
    984 	he_seterrev(ev, _HE_OK);
    985 
    986 	switch (fun) {
    987 	case H_GETSIZE:
    988 		retval = history_getsize(h, ev);
    989 		break;
    990 
    991 	case H_SETSIZE:
    992 		retval = history_setsize(h, ev, va_arg(va, int));
    993 		break;
    994 
    995 	case H_GETUNIQUE:
    996 		retval = history_getunique(h, ev);
    997 		break;
    998 
    999 	case H_SETUNIQUE:
   1000 		retval = history_setunique(h, ev, va_arg(va, int));
   1001 		break;
   1002 
   1003 	case H_ADD:
   1004 		str = va_arg(va, const Char *);
   1005 		retval = HADD(h, ev, str);
   1006 		break;
   1007 
   1008 	case H_DEL:
   1009 		retval = HDEL(h, ev, va_arg(va, const int));
   1010 		break;
   1011 
   1012 	case H_ENTER:
   1013 		str = va_arg(va, const Char *);
   1014 		if ((retval = HENTER(h, ev, str)) != -1)
   1015 			h->h_ent = ev->num;
   1016 		break;
   1017 
   1018 	case H_APPEND:
   1019 		str = va_arg(va, const Char *);
   1020 		if ((retval = HSET(h, ev, h->h_ent)) != -1)
   1021 			retval = HADD(h, ev, str);
   1022 		break;
   1023 
   1024 	case H_FIRST:
   1025 		retval = HFIRST(h, ev);
   1026 		break;
   1027 
   1028 	case H_NEXT:
   1029 		retval = HNEXT(h, ev);
   1030 		break;
   1031 
   1032 	case H_LAST:
   1033 		retval = HLAST(h, ev);
   1034 		break;
   1035 
   1036 	case H_PREV:
   1037 		retval = HPREV(h, ev);
   1038 		break;
   1039 
   1040 	case H_CURR:
   1041 		retval = HCURR(h, ev);
   1042 		break;
   1043 
   1044 	case H_SET:
   1045 		retval = HSET(h, ev, va_arg(va, const int));
   1046 		break;
   1047 
   1048 	case H_CLEAR:
   1049 		HCLEAR(h, ev);
   1050 		retval = 0;
   1051 		break;
   1052 
   1053 	case H_LOAD:
   1054 		retval = history_load(h, va_arg(va, const char *));
   1055 		if (retval == -1)
   1056 			he_seterrev(ev, _HE_HIST_READ);
   1057 		break;
   1058 
   1059 	case H_SAVE:
   1060 		retval = history_save(h, va_arg(va, const char *));
   1061 		if (retval == -1)
   1062 			he_seterrev(ev, _HE_HIST_WRITE);
   1063 		break;
   1064 
   1065 	case H_SAVE_FP:
   1066 		retval = history_save_fp(h, va_arg(va, FILE *));
   1067 		if (retval == -1)
   1068 		    he_seterrev(ev, _HE_HIST_WRITE);
   1069 		break;
   1070 
   1071 	case H_PREV_EVENT:
   1072 		retval = history_prev_event(h, ev, va_arg(va, int));
   1073 		break;
   1074 
   1075 	case H_NEXT_EVENT:
   1076 		retval = history_next_event(h, ev, va_arg(va, int));
   1077 		break;
   1078 
   1079 	case H_PREV_STR:
   1080 		retval = history_prev_string(h, ev, va_arg(va, const Char *));
   1081 		break;
   1082 
   1083 	case H_NEXT_STR:
   1084 		retval = history_next_string(h, ev, va_arg(va, const Char *));
   1085 		break;
   1086 
   1087 	case H_FUNC:
   1088 	{
   1089 		TYPE(History) hf;
   1090 
   1091 		hf.h_ref = va_arg(va, void *);
   1092 		h->h_ent = -1;
   1093 		hf.h_first = va_arg(va, history_gfun_t);
   1094 		hf.h_next = va_arg(va, history_gfun_t);
   1095 		hf.h_last = va_arg(va, history_gfun_t);
   1096 		hf.h_prev = va_arg(va, history_gfun_t);
   1097 		hf.h_curr = va_arg(va, history_gfun_t);
   1098 		hf.h_set = va_arg(va, history_sfun_t);
   1099 		hf.h_clear = va_arg(va, history_vfun_t);
   1100 		hf.h_enter = va_arg(va, history_efun_t);
   1101 		hf.h_add = va_arg(va, history_efun_t);
   1102 		hf.h_del = va_arg(va, history_sfun_t);
   1103 
   1104 		if ((retval = history_set_fun(h, &hf)) == -1)
   1105 			he_seterrev(ev, _HE_PARAM_MISSING);
   1106 		break;
   1107 	}
   1108 
   1109 	case H_END:
   1110 		FUN(history,end)(h);
   1111 		retval = 0;
   1112 		break;
   1113 
   1114 	case H_NEXT_EVDATA:
   1115 	{
   1116 		int num = va_arg(va, int);
   1117 		void **d = va_arg(va, void **);
   1118 		retval = history_next_evdata(h, ev, num, d);
   1119 		break;
   1120 	}
   1121 
   1122 	case H_DELDATA:
   1123 	{
   1124 		int num = va_arg(va, int);
   1125 		void **d = va_arg(va, void **);
   1126 		retval = history_deldata_nth((history_t *)h->h_ref, ev, num, d);
   1127 		break;
   1128 	}
   1129 
   1130 	case H_REPLACE: /* only use after H_NEXT_EVDATA */
   1131 	{
   1132 		const Char *line = va_arg(va, const Char *);
   1133 		void *d = va_arg(va, void *);
   1134 		const Char *s;
   1135 		if(!line || !(s = Strdup(line))) {
   1136 			retval = -1;
   1137 			break;
   1138 		}
   1139 		((history_t *)h->h_ref)->cursor->ev.str = s;
   1140 		((history_t *)h->h_ref)->cursor->data = d;
   1141 		retval = 0;
   1142 		break;
   1143 	}
   1144 
   1145 	default:
   1146 		retval = -1;
   1147 		he_seterrev(ev, _HE_UNKNOWN);
   1148 		break;
   1149 	}
   1150 	va_end(va);
   1151 	return retval;
   1152 }
   1153