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