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