- Recollect TX descs, if et(4) is going to enter OACTIVE state.
[dragonfly.git] / lib / libedit / history.c
blob598c13f1ab08dfe3625e97048cbd83be7859f102
1 /*-
2 * Copyright (c) 1992, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Christos Zoulas of Cornell University.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
32 * @(#)history.c 8.1 (Berkeley) 6/4/93
33 * $NetBSD: history.c,v 1.32 2006/09/28 13:52:51 christos Exp $
34 * $DragonFly: src/lib/libedit/history.c,v 1.7 2007/05/05 00:27:39 pavalos Exp $
37 #include "config.h"
40 * hist.c: History access functions
42 #include <string.h>
43 #include <stdlib.h>
44 #include <stdarg.h>
45 #ifdef HAVE_VIS_H
46 #include <vis.h>
47 #else
48 #include "np/vis.h"
49 #endif
50 #include <sys/stat.h>
52 static const char hist_cookie[] = "_HiStOrY_V2_\n";
54 #include "histedit.h"
56 typedef int (*history_gfun_t)(ptr_t, HistEvent *);
57 typedef int (*history_efun_t)(ptr_t, HistEvent *, const char *);
58 typedef void (*history_vfun_t)(ptr_t, HistEvent *);
59 typedef int (*history_sfun_t)(ptr_t, HistEvent *, const int);
61 struct history {
62 ptr_t h_ref; /* Argument for history fcns */
63 int h_ent; /* Last entry point for history */
64 history_gfun_t h_first; /* Get the first element */
65 history_gfun_t h_next; /* Get the next element */
66 history_gfun_t h_last; /* Get the last element */
67 history_gfun_t h_prev; /* Get the previous element */
68 history_gfun_t h_curr; /* Get the current element */
69 history_sfun_t h_set; /* Set the current element */
70 history_sfun_t h_del; /* Set the given element */
71 history_vfun_t h_clear; /* Clear the history list */
72 history_efun_t h_enter; /* Add an element */
73 history_efun_t h_add; /* Append to an element */
76 #define HNEXT(h, ev) (*(h)->h_next)((h)->h_ref, ev)
77 #define HFIRST(h, ev) (*(h)->h_first)((h)->h_ref, ev)
78 #define HPREV(h, ev) (*(h)->h_prev)((h)->h_ref, ev)
79 #define HLAST(h, ev) (*(h)->h_last)((h)->h_ref, ev)
80 #define HCURR(h, ev) (*(h)->h_curr)((h)->h_ref, ev)
81 #define HSET(h, ev, n) (*(h)->h_set)((h)->h_ref, ev, n)
82 #define HCLEAR(h, ev) (*(h)->h_clear)((h)->h_ref, ev)
83 #define HENTER(h, ev, str) (*(h)->h_enter)((h)->h_ref, ev, str)
84 #define HADD(h, ev, str) (*(h)->h_add)((h)->h_ref, ev, str)
85 #define HDEL(h, ev, n) (*(h)->h_del)((h)->h_ref, ev, n)
87 #define h_strdup(a) strdup(a)
88 #define h_malloc(a) malloc(a)
89 #define h_realloc(a, b) realloc((a), (b))
90 #define h_free(a) free(a)
92 typedef struct {
93 int num;
94 char *str;
95 } HistEventPrivate;
99 private int history_setsize(History *, HistEvent *, int);
100 private int history_getsize(History *, HistEvent *);
101 private int history_setunique(History *, HistEvent *, int);
102 private int history_getunique(History *, HistEvent *);
103 private int history_set_fun(History *, History *);
104 private int history_load(History *, const char *);
105 private int history_save(History *, const char *);
106 private int history_prev_event(History *, HistEvent *, int);
107 private int history_next_event(History *, HistEvent *, int);
108 private int history_next_string(History *, HistEvent *, const char *);
109 private int history_prev_string(History *, HistEvent *, const char *);
112 /***********************************************************************/
115 * Builtin- history implementation
117 typedef struct hentry_t {
118 HistEvent ev; /* What we return */
119 struct hentry_t *next; /* Next entry */
120 struct hentry_t *prev; /* Previous entry */
121 } hentry_t;
123 typedef struct history_t {
124 hentry_t list; /* Fake list header element */
125 hentry_t *cursor; /* Current element in the list */
126 int max; /* Maximum number of events */
127 int cur; /* Current number of events */
128 int eventid; /* For generation of unique event id */
129 int flags; /* History flags */
130 #define H_UNIQUE 1 /* Store only unique elements */
131 } history_t;
133 private int history_def_next(ptr_t, HistEvent *);
134 private int history_def_first(ptr_t, HistEvent *);
135 private int history_def_prev(ptr_t, HistEvent *);
136 private int history_def_last(ptr_t, HistEvent *);
137 private int history_def_curr(ptr_t, HistEvent *);
138 private int history_def_set(ptr_t, HistEvent *, const int);
139 private void history_def_clear(ptr_t, HistEvent *);
140 private int history_def_enter(ptr_t, HistEvent *, const char *);
141 private int history_def_add(ptr_t, HistEvent *, const char *);
142 private int history_def_del(ptr_t, HistEvent *, const int);
144 private int history_def_init(ptr_t *, HistEvent *, int);
145 private int history_def_insert(history_t *, HistEvent *, const char *);
146 private void history_def_delete(history_t *, HistEvent *, hentry_t *);
148 #define history_def_setsize(p, num)(void) (((history_t *)p)->max = (num))
149 #define history_def_getsize(p) (((history_t *)p)->cur)
150 #define history_def_getunique(p) (((((history_t *)p)->flags) & H_UNIQUE) != 0)
151 #define history_def_setunique(p, uni) \
152 if (uni) \
153 (((history_t *)p)->flags) |= H_UNIQUE; \
154 else \
155 (((history_t *)p)->flags) &= ~H_UNIQUE
157 #define he_strerror(code) he_errlist[code]
158 #define he_seterrev(evp, code) {\
159 evp->num = code;\
160 evp->str = he_strerror(code);\
163 /* error messages */
164 static const char *const he_errlist[] = {
165 "OK",
166 "unknown error",
167 "malloc() failed",
168 "first event not found",
169 "last event not found",
170 "empty list",
171 "no next event",
172 "no previous event",
173 "current event is invalid",
174 "event not found",
175 "can't read history from file",
176 "can't write history",
177 "required parameter(s) not supplied",
178 "history size negative",
179 "function not allowed with other history-functions-set the default",
180 "bad parameters"
182 /* error codes */
183 #define _HE_OK 0
184 #define _HE_UNKNOWN 1
185 #define _HE_MALLOC_FAILED 2
186 #define _HE_FIRST_NOTFOUND 3
187 #define _HE_LAST_NOTFOUND 4
188 #define _HE_EMPTY_LIST 5
189 #define _HE_END_REACHED 6
190 #define _HE_START_REACHED 7
191 #define _HE_CURR_INVALID 8
192 #define _HE_NOT_FOUND 9
193 #define _HE_HIST_READ 10
194 #define _HE_HIST_WRITE 11
195 #define _HE_PARAM_MISSING 12
196 #define _HE_SIZE_NEGATIVE 13
197 #define _HE_NOT_ALLOWED 14
198 #define _HE_BAD_PARAM 15
200 /* history_def_first():
201 * Default function to return the first event in the history.
203 private int
204 history_def_first(ptr_t p, HistEvent *ev)
206 history_t *h = (history_t *) p;
208 h->cursor = h->list.next;
209 if (h->cursor != &h->list)
210 *ev = h->cursor->ev;
211 else {
212 he_seterrev(ev, _HE_FIRST_NOTFOUND);
213 return (-1);
216 return (0);
220 /* history_def_last():
221 * Default function to return the last event in the history.
223 private int
224 history_def_last(ptr_t p, HistEvent *ev)
226 history_t *h = (history_t *) p;
228 h->cursor = h->list.prev;
229 if (h->cursor != &h->list)
230 *ev = h->cursor->ev;
231 else {
232 he_seterrev(ev, _HE_LAST_NOTFOUND);
233 return (-1);
236 return (0);
240 /* history_def_next():
241 * Default function to return the next event in the history.
243 private int
244 history_def_next(ptr_t p, HistEvent *ev)
246 history_t *h = (history_t *) p;
248 if (h->cursor == &h->list) {
249 he_seterrev(ev, _HE_EMPTY_LIST);
250 return (-1);
253 if (h->cursor->next == &h->list) {
254 he_seterrev(ev, _HE_END_REACHED);
255 return (-1);
258 h->cursor = h->cursor->next;
259 *ev = h->cursor->ev;
261 return (0);
265 /* history_def_prev():
266 * Default function to return the previous event in the history.
268 private int
269 history_def_prev(ptr_t p, HistEvent *ev)
271 history_t *h = (history_t *) p;
273 if (h->cursor == &h->list) {
274 he_seterrev(ev,
275 (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST);
276 return (-1);
279 if (h->cursor->prev == &h->list) {
280 he_seterrev(ev, _HE_START_REACHED);
281 return (-1);
284 h->cursor = h->cursor->prev;
285 *ev = h->cursor->ev;
287 return (0);
291 /* history_def_curr():
292 * Default function to return the current event in the history.
294 private int
295 history_def_curr(ptr_t p, HistEvent *ev)
297 history_t *h = (history_t *) p;
299 if (h->cursor != &h->list)
300 *ev = h->cursor->ev;
301 else {
302 he_seterrev(ev,
303 (h->cur > 0) ? _HE_CURR_INVALID : _HE_EMPTY_LIST);
304 return (-1);
307 return (0);
311 /* history_def_set():
312 * Default function to set the current event in the history to the
313 * given one.
315 private int
316 history_def_set(ptr_t p, HistEvent *ev, const int n)
318 history_t *h = (history_t *) p;
320 if (h->cur == 0) {
321 he_seterrev(ev, _HE_EMPTY_LIST);
322 return (-1);
324 if (h->cursor == &h->list || h->cursor->ev.num != n) {
325 for (h->cursor = h->list.next; h->cursor != &h->list;
326 h->cursor = h->cursor->next)
327 if (h->cursor->ev.num == n)
328 break;
330 if (h->cursor == &h->list) {
331 he_seterrev(ev, _HE_NOT_FOUND);
332 return (-1);
334 return (0);
338 /* history_def_add():
339 * Append string to element
341 private int
342 history_def_add(ptr_t p, HistEvent *ev, const char *str)
344 history_t *h = (history_t *) p;
345 size_t len;
346 char *s;
347 HistEventPrivate *evp = (void *)&h->cursor->ev;
349 if (h->cursor == &h->list)
350 return (history_def_enter(p, ev, str));
351 len = strlen(evp->str) + strlen(str) + 1;
352 s = (char *) h_malloc(len);
353 if (s == NULL) {
354 he_seterrev(ev, _HE_MALLOC_FAILED);
355 return (-1);
357 (void) strlcpy(s, h->cursor->ev.str, len);
358 (void) strlcat(s, str, len);
359 h_free((ptr_t)evp->str);
360 evp->str = s;
361 *ev = h->cursor->ev;
362 return (0);
366 /* history_def_del():
367 * Delete element hp of the h list
369 /* ARGSUSED */
370 private int
371 history_def_del(ptr_t p, HistEvent *ev __attribute__((__unused__)),
372 const int num)
374 history_t *h = (history_t *) p;
375 if (history_def_set(h, ev, num) != 0)
376 return (-1);
377 ev->str = strdup(h->cursor->ev.str);
378 ev->num = h->cursor->ev.num;
379 history_def_delete(h, ev, h->cursor);
380 return (0);
384 /* history_def_delete():
385 * Delete element hp of the h list
387 /* ARGSUSED */
388 private void
389 history_def_delete(history_t *h,
390 HistEvent *ev __attribute__((__unused__)), hentry_t *hp)
392 HistEventPrivate *evp = (void *)&hp->ev;
393 if (hp == &h->list)
394 abort();
395 if (h->cursor == hp)
396 h->cursor = hp->prev;
397 hp->prev->next = hp->next;
398 hp->next->prev = hp->prev;
399 h_free((ptr_t) evp->str);
400 h_free(hp);
401 h->cur--;
405 /* history_def_insert():
406 * Insert element with string str in the h list
408 private int
409 history_def_insert(history_t *h, HistEvent *ev, const char *str)
412 h->cursor = (hentry_t *) h_malloc(sizeof(hentry_t));
413 if (h->cursor == NULL)
414 goto oomem;
415 if ((h->cursor->ev.str = h_strdup(str)) == NULL) {
416 h_free((ptr_t)h->cursor);
417 goto oomem;
419 h->cursor->ev.num = ++h->eventid;
420 h->cursor->next = h->list.next;
421 h->cursor->prev = &h->list;
422 h->list.next->prev = h->cursor;
423 h->list.next = h->cursor;
424 h->cur++;
426 *ev = h->cursor->ev;
427 return (0);
428 oomem:
429 he_seterrev(ev, _HE_MALLOC_FAILED);
430 return (-1);
434 /* history_def_enter():
435 * Default function to enter an item in the history
437 private int
438 history_def_enter(ptr_t p, HistEvent *ev, const char *str)
440 history_t *h = (history_t *) p;
442 if ((h->flags & H_UNIQUE) != 0 && h->list.next != &h->list &&
443 strcmp(h->list.next->ev.str, str) == 0)
444 return (0);
446 if (history_def_insert(h, ev, str) == -1)
447 return (-1); /* error, keep error message */
450 * Always keep at least one entry.
451 * This way we don't have to check for the empty list.
453 while (h->cur > h->max && h->cur > 0)
454 history_def_delete(h, ev, h->list.prev);
456 return (1);
460 /* history_def_init():
461 * Default history initialization function
463 /* ARGSUSED */
464 private int
465 history_def_init(ptr_t *p, HistEvent *ev __attribute__((__unused__)), int n)
467 history_t *h = (history_t *) h_malloc(sizeof(history_t));
468 if (h == NULL)
469 return -1;
471 if (n <= 0)
472 n = 0;
473 h->eventid = 0;
474 h->cur = 0;
475 h->max = n;
476 h->list.next = h->list.prev = &h->list;
477 h->list.ev.str = NULL;
478 h->list.ev.num = 0;
479 h->cursor = &h->list;
480 h->flags = 0;
481 *p = (ptr_t) h;
482 return 0;
486 /* history_def_clear():
487 * Default history cleanup function
489 private void
490 history_def_clear(ptr_t p, HistEvent *ev)
492 history_t *h = (history_t *) p;
494 while (h->list.prev != &h->list)
495 history_def_delete(h, ev, h->list.prev);
496 h->eventid = 0;
497 h->cur = 0;
503 /************************************************************************/
505 /* history_init():
506 * Initialization function.
508 public History *
509 history_init(void)
511 HistEvent ev;
512 History *h = (History *) h_malloc(sizeof(History));
513 if (h == NULL)
514 return NULL;
516 if (history_def_init(&h->h_ref, &ev, 0) == -1) {
517 h_free((ptr_t)h);
518 return NULL;
520 h->h_ent = -1;
521 h->h_next = history_def_next;
522 h->h_first = history_def_first;
523 h->h_last = history_def_last;
524 h->h_prev = history_def_prev;
525 h->h_curr = history_def_curr;
526 h->h_set = history_def_set;
527 h->h_clear = history_def_clear;
528 h->h_enter = history_def_enter;
529 h->h_add = history_def_add;
530 h->h_del = history_def_del;
532 return (h);
536 /* history_end():
537 * clean up history;
539 public void
540 history_end(History *h)
542 HistEvent ev;
544 if (h->h_next == history_def_next)
545 history_def_clear(h->h_ref, &ev);
546 h_free(h->h_ref);
547 h_free(h);
552 /* history_setsize():
553 * Set history number of events
555 private int
556 history_setsize(History *h, HistEvent *ev, int num)
559 if (h->h_next != history_def_next) {
560 he_seterrev(ev, _HE_NOT_ALLOWED);
561 return (-1);
563 if (num < 0) {
564 he_seterrev(ev, _HE_BAD_PARAM);
565 return (-1);
567 history_def_setsize(h->h_ref, num);
568 return (0);
572 /* history_getsize():
573 * Get number of events currently in history
575 private int
576 history_getsize(History *h, HistEvent *ev)
578 if (h->h_next != history_def_next) {
579 he_seterrev(ev, _HE_NOT_ALLOWED);
580 return (-1);
582 ev->num = history_def_getsize(h->h_ref);
583 if (ev->num < -1) {
584 he_seterrev(ev, _HE_SIZE_NEGATIVE);
585 return (-1);
587 return (0);
591 /* history_setunique():
592 * Set if adjacent equal events should not be entered in history.
594 private int
595 history_setunique(History *h, HistEvent *ev, int uni)
598 if (h->h_next != history_def_next) {
599 he_seterrev(ev, _HE_NOT_ALLOWED);
600 return (-1);
602 history_def_setunique(h->h_ref, uni);
603 return (0);
607 /* history_getunique():
608 * Get if adjacent equal events should not be entered in history.
610 private int
611 history_getunique(History *h, HistEvent *ev)
613 if (h->h_next != history_def_next) {
614 he_seterrev(ev, _HE_NOT_ALLOWED);
615 return (-1);
617 ev->num = history_def_getunique(h->h_ref);
618 return (0);
622 /* history_set_fun():
623 * Set history functions
625 private int
626 history_set_fun(History *h, History *nh)
628 HistEvent ev;
630 if (nh->h_first == NULL || nh->h_next == NULL || nh->h_last == NULL ||
631 nh->h_prev == NULL || nh->h_curr == NULL || nh->h_set == NULL ||
632 nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL ||
633 nh->h_del == NULL || nh->h_ref == NULL) {
634 if (h->h_next != history_def_next) {
635 history_def_init(&h->h_ref, &ev, 0);
636 h->h_first = history_def_first;
637 h->h_next = history_def_next;
638 h->h_last = history_def_last;
639 h->h_prev = history_def_prev;
640 h->h_curr = history_def_curr;
641 h->h_set = history_def_set;
642 h->h_clear = history_def_clear;
643 h->h_enter = history_def_enter;
644 h->h_add = history_def_add;
645 h->h_del = history_def_del;
647 return (-1);
649 if (h->h_next == history_def_next)
650 history_def_clear(h->h_ref, &ev);
652 h->h_ent = -1;
653 h->h_first = nh->h_first;
654 h->h_next = nh->h_next;
655 h->h_last = nh->h_last;
656 h->h_prev = nh->h_prev;
657 h->h_curr = nh->h_curr;
658 h->h_set = nh->h_set;
659 h->h_clear = nh->h_clear;
660 h->h_enter = nh->h_enter;
661 h->h_add = nh->h_add;
662 h->h_del = nh->h_del;
664 return (0);
668 /* history_load():
669 * History load function
671 private int
672 history_load(History *h, const char *fname)
674 FILE *fp;
675 char *line;
676 size_t sz, max_size;
677 char *ptr;
678 int i = -1;
679 HistEvent ev;
681 if ((fp = fopen(fname, "r")) == NULL)
682 return (i);
684 if ((line = fgetln(fp, &sz)) == NULL)
685 goto done;
687 if (strncmp(line, hist_cookie, sz) != 0)
688 goto done;
690 ptr = h_malloc(max_size = 1024);
691 if (ptr == NULL)
692 goto done;
693 for (i = 0; (line = fgetln(fp, &sz)) != NULL; i++) {
694 char c = line[sz];
696 if (sz != 0 && line[sz - 1] == '\n')
697 line[--sz] = '\0';
698 else
699 line[sz] = '\0';
701 if (max_size < sz) {
702 char *nptr;
703 max_size = (sz + 1024) & ~1023;
704 nptr = h_realloc(ptr, max_size);
705 if (nptr == NULL) {
706 i = -1;
707 goto oomem;
709 ptr = nptr;
711 (void) strunvis(ptr, line);
712 line[sz] = c;
713 if (HENTER(h, &ev, ptr) == -1) {
714 h_free((ptr_t)ptr);
715 return -1;
718 oomem:
719 h_free((ptr_t)ptr);
720 done:
721 (void) fclose(fp);
722 return (i);
726 /* history_save():
727 * History save function
729 private int
730 history_save(History *h, const char *fname)
732 FILE *fp;
733 HistEvent ev;
734 int i = -1, retval;
735 size_t len, max_size;
736 char *ptr;
738 if ((fp = fopen(fname, "w")) == NULL)
739 return (-1);
741 if (fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1)
742 goto done;
743 if (fputs(hist_cookie, fp) == EOF)
744 goto done;
745 ptr = h_malloc(max_size = 1024);
746 if (ptr == NULL)
747 goto done;
748 for (i = 0, retval = HLAST(h, &ev);
749 retval != -1;
750 retval = HPREV(h, &ev), i++) {
751 len = strlen(ev.str) * 4;
752 if (len >= max_size) {
753 char *nptr;
754 max_size = (len + 1024) & ~1023;
755 nptr = h_realloc(ptr, max_size);
756 if (nptr == NULL) {
757 i = -1;
758 goto oomem;
760 ptr = nptr;
762 (void) strvis(ptr, ev.str, VIS_WHITE);
763 (void) fprintf(fp, "%s\n", ptr);
765 oomem:
766 h_free((ptr_t)ptr);
767 done:
768 (void) fclose(fp);
769 return (i);
773 /* history_prev_event():
774 * Find the previous event, with number given
776 private int
777 history_prev_event(History *h, HistEvent *ev, int num)
779 int retval;
781 for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
782 if (ev->num == num)
783 return (0);
785 he_seterrev(ev, _HE_NOT_FOUND);
786 return (-1);
790 /* history_next_event():
791 * Find the next event, with number given
793 private int
794 history_next_event(History *h, HistEvent *ev, int num)
796 int retval;
798 for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
799 if (ev->num == num)
800 return (0);
802 he_seterrev(ev, _HE_NOT_FOUND);
803 return (-1);
807 /* history_prev_string():
808 * Find the previous event beginning with string
810 private int
811 history_prev_string(History *h, HistEvent *ev, const char *str)
813 size_t len = strlen(str);
814 int retval;
816 for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
817 if (strncmp(str, ev->str, len) == 0)
818 return (0);
820 he_seterrev(ev, _HE_NOT_FOUND);
821 return (-1);
825 /* history_next_string():
826 * Find the next event beginning with string
828 private int
829 history_next_string(History *h, HistEvent *ev, const char *str)
831 size_t len = strlen(str);
832 int retval;
834 for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
835 if (strncmp(str, ev->str, len) == 0)
836 return (0);
838 he_seterrev(ev, _HE_NOT_FOUND);
839 return (-1);
843 /* history():
844 * User interface to history functions.
847 history(History *h, HistEvent *ev, int fun, ...)
849 va_list va;
850 const char *str;
851 int retval;
853 va_start(va, fun);
855 he_seterrev(ev, _HE_OK);
857 switch (fun) {
858 case H_GETSIZE:
859 retval = history_getsize(h, ev);
860 break;
862 case H_SETSIZE:
863 retval = history_setsize(h, ev, va_arg(va, int));
864 break;
866 case H_GETUNIQUE:
867 retval = history_getunique(h, ev);
868 break;
870 case H_SETUNIQUE:
871 retval = history_setunique(h, ev, va_arg(va, int));
872 break;
874 case H_ADD:
875 str = va_arg(va, const char *);
876 retval = HADD(h, ev, str);
877 break;
879 case H_DEL:
880 retval = HDEL(h, ev, va_arg(va, const int));
881 break;
883 case H_ENTER:
884 str = va_arg(va, const char *);
885 if ((retval = HENTER(h, ev, str)) != -1)
886 h->h_ent = ev->num;
887 break;
889 case H_APPEND:
890 str = va_arg(va, const char *);
891 if ((retval = HSET(h, ev, h->h_ent)) != -1)
892 retval = HADD(h, ev, str);
893 break;
895 case H_FIRST:
896 retval = HFIRST(h, ev);
897 break;
899 case H_NEXT:
900 retval = HNEXT(h, ev);
901 break;
903 case H_LAST:
904 retval = HLAST(h, ev);
905 break;
907 case H_PREV:
908 retval = HPREV(h, ev);
909 break;
911 case H_CURR:
912 retval = HCURR(h, ev);
913 break;
915 case H_SET:
916 retval = HSET(h, ev, va_arg(va, const int));
917 break;
919 case H_CLEAR:
920 HCLEAR(h, ev);
921 retval = 0;
922 break;
924 case H_LOAD:
925 retval = history_load(h, va_arg(va, const char *));
926 if (retval == -1)
927 he_seterrev(ev, _HE_HIST_READ);
928 break;
930 case H_SAVE:
931 retval = history_save(h, va_arg(va, const char *));
932 if (retval == -1)
933 he_seterrev(ev, _HE_HIST_WRITE);
934 break;
936 case H_PREV_EVENT:
937 retval = history_prev_event(h, ev, va_arg(va, int));
938 break;
940 case H_NEXT_EVENT:
941 retval = history_next_event(h, ev, va_arg(va, int));
942 break;
944 case H_PREV_STR:
945 retval = history_prev_string(h, ev, va_arg(va, const char *));
946 break;
948 case H_NEXT_STR:
949 retval = history_next_string(h, ev, va_arg(va, const char *));
950 break;
952 case H_FUNC:
954 History hf;
956 hf.h_ref = va_arg(va, ptr_t);
957 h->h_ent = -1;
958 hf.h_first = va_arg(va, history_gfun_t);
959 hf.h_next = va_arg(va, history_gfun_t);
960 hf.h_last = va_arg(va, history_gfun_t);
961 hf.h_prev = va_arg(va, history_gfun_t);
962 hf.h_curr = va_arg(va, history_gfun_t);
963 hf.h_set = va_arg(va, history_sfun_t);
964 hf.h_clear = va_arg(va, history_vfun_t);
965 hf.h_enter = va_arg(va, history_efun_t);
966 hf.h_add = va_arg(va, history_efun_t);
967 hf.h_del = va_arg(va, history_sfun_t);
969 if ((retval = history_set_fun(h, &hf)) == -1)
970 he_seterrev(ev, _HE_PARAM_MISSING);
971 break;
974 case H_END:
975 history_end(h);
976 retval = 0;
977 break;
979 default:
980 retval = -1;
981 he_seterrev(ev, _HE_UNKNOWN);
982 break;
984 va_end(va);
985 return (retval);