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
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
32 * $NetBSD: history.c,v 1.34 2009/09/07 21:24:33 christos Exp $
35 #if !defined(lint) && !defined(SCCSID)
36 static char sccsid[] = "@(#)history.c 8.1 (Berkeley) 6/4/93";
37 #endif /* not lint && not SCCSID */
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD$");
42 * hist.c: History access functions
52 static const char hist_cookie[] = "_HiStOrY_V2_\n";
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);
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)
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_save_fp(History *, FILE*);
107 private int history_prev_event(History *, HistEvent *, int);
108 private int history_next_event(History *, HistEvent *, int);
109 private int history_next_string(History *, HistEvent *, const char *);
110 private int history_prev_string(History *, HistEvent *, const char *);
113 /***********************************************************************/
116 * Builtin- history implementation
118 typedef struct hentry_t {
119 HistEvent ev; /* What we return */
120 void *data; /* data */
121 struct hentry_t *next; /* Next entry */
122 struct hentry_t *prev; /* Previous entry */
125 typedef struct history_t {
126 hentry_t list; /* Fake list header element */
127 hentry_t *cursor; /* Current element in the list */
128 int max; /* Maximum number of events */
129 int cur; /* Current number of events */
130 int eventid; /* For generation of unique event id */
131 int flags; /* History flags */
132 #define H_UNIQUE 1 /* Store only unique elements */
135 private int history_def_next(ptr_t, HistEvent *);
136 private int history_def_first(ptr_t, HistEvent *);
137 private int history_def_prev(ptr_t, HistEvent *);
138 private int history_def_last(ptr_t, HistEvent *);
139 private int history_def_curr(ptr_t, HistEvent *);
140 private int history_def_set(ptr_t, HistEvent *, const int);
141 private void history_def_clear(ptr_t, HistEvent *);
142 private int history_def_enter(ptr_t, HistEvent *, const char *);
143 private int history_def_add(ptr_t, HistEvent *, const char *);
144 private int history_def_del(ptr_t, HistEvent *, const int);
146 private int history_def_init(ptr_t *, HistEvent *, int);
147 private int history_def_insert(history_t *, HistEvent *, const char *);
148 private void history_def_delete(history_t *, HistEvent *, hentry_t *);
150 private int history_deldata_nth(history_t *, HistEvent *, int, void **);
151 private int history_set_nth(ptr_t, HistEvent *, int);
153 #define history_def_setsize(p, num)(void) (((history_t *)p)->max = (num))
154 #define history_def_getsize(p) (((history_t *)p)->cur)
155 #define history_def_getunique(p) (((((history_t *)p)->flags) & H_UNIQUE) != 0)
156 #define history_def_setunique(p, uni) \
158 (((history_t *)p)->flags) |= H_UNIQUE; \
160 (((history_t *)p)->flags) &= ~H_UNIQUE
162 #define he_strerror(code) he_errlist[code]
163 #define he_seterrev(evp, code) {\
165 evp->str = he_strerror(code);\
169 static const char *const he_errlist[] = {
173 "first event not found",
174 "last event not found",
178 "current event is invalid",
180 "can't read history from file",
181 "can't write history",
182 "required parameter(s) not supplied",
183 "history size negative",
184 "function not allowed with other history-functions-set the default",
189 #define _HE_UNKNOWN 1
190 #define _HE_MALLOC_FAILED 2
191 #define _HE_FIRST_NOTFOUND 3
192 #define _HE_LAST_NOTFOUND 4
193 #define _HE_EMPTY_LIST 5
194 #define _HE_END_REACHED 6
195 #define _HE_START_REACHED 7
196 #define _HE_CURR_INVALID 8
197 #define _HE_NOT_FOUND 9
198 #define _HE_HIST_READ 10
199 #define _HE_HIST_WRITE 11
200 #define _HE_PARAM_MISSING 12
201 #define _HE_SIZE_NEGATIVE 13
202 #define _HE_NOT_ALLOWED 14
203 #define _HE_BAD_PARAM 15
205 /* history_def_first():
206 * Default function to return the first event in the history.
209 history_def_first(ptr_t p, HistEvent *ev)
211 history_t *h = (history_t *) p;
213 h->cursor = h->list.next;
214 if (h->cursor != &h->list)
217 he_seterrev(ev, _HE_FIRST_NOTFOUND);
225 /* history_def_last():
226 * Default function to return the last event in the history.
229 history_def_last(ptr_t p, HistEvent *ev)
231 history_t *h = (history_t *) p;
233 h->cursor = h->list.prev;
234 if (h->cursor != &h->list)
237 he_seterrev(ev, _HE_LAST_NOTFOUND);
245 /* history_def_next():
246 * Default function to return the next event in the history.
249 history_def_next(ptr_t p, HistEvent *ev)
251 history_t *h = (history_t *) p;
253 if (h->cursor == &h->list) {
254 he_seterrev(ev, _HE_EMPTY_LIST);
258 if (h->cursor->next == &h->list) {
259 he_seterrev(ev, _HE_END_REACHED);
263 h->cursor = h->cursor->next;
270 /* history_def_prev():
271 * Default function to return the previous event in the history.
274 history_def_prev(ptr_t p, HistEvent *ev)
276 history_t *h = (history_t *) p;
278 if (h->cursor == &h->list) {
280 (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST);
284 if (h->cursor->prev == &h->list) {
285 he_seterrev(ev, _HE_START_REACHED);
289 h->cursor = h->cursor->prev;
296 /* history_def_curr():
297 * Default function to return the current event in the history.
300 history_def_curr(ptr_t p, HistEvent *ev)
302 history_t *h = (history_t *) p;
304 if (h->cursor != &h->list)
308 (h->cur > 0) ? _HE_CURR_INVALID : _HE_EMPTY_LIST);
316 /* history_def_set():
317 * Default function to set the current event in the history to the
321 history_def_set(ptr_t p, HistEvent *ev, const int n)
323 history_t *h = (history_t *) p;
326 he_seterrev(ev, _HE_EMPTY_LIST);
329 if (h->cursor == &h->list || h->cursor->ev.num != n) {
330 for (h->cursor = h->list.next; h->cursor != &h->list;
331 h->cursor = h->cursor->next)
332 if (h->cursor->ev.num == n)
335 if (h->cursor == &h->list) {
336 he_seterrev(ev, _HE_NOT_FOUND);
343 /* history_set_nth():
344 * Default function to set the current event in the history to the
348 history_set_nth(ptr_t p, HistEvent *ev, int n)
350 history_t *h = (history_t *) p;
353 he_seterrev(ev, _HE_EMPTY_LIST);
356 for (h->cursor = h->list.prev; h->cursor != &h->list;
357 h->cursor = h->cursor->prev)
360 if (h->cursor == &h->list) {
361 he_seterrev(ev, _HE_NOT_FOUND);
368 /* history_def_add():
369 * Append string to element
372 history_def_add(ptr_t p, HistEvent *ev, const char *str)
374 history_t *h = (history_t *) p;
377 HistEventPrivate *evp = (void *)&h->cursor->ev;
379 if (h->cursor == &h->list)
380 return (history_def_enter(p, ev, str));
381 len = strlen(evp->str) + strlen(str) + 1;
382 s = (char *) h_malloc(len);
384 he_seterrev(ev, _HE_MALLOC_FAILED);
387 (void) strlcpy(s, h->cursor->ev.str, len);
388 (void) strlcat(s, str, len);
389 h_free((ptr_t)evp->str);
397 history_deldata_nth(history_t *h, HistEvent *ev,
398 int num, void **data)
400 if (history_set_nth(h, ev, num) != 0)
402 /* magic value to skip delete (just set to n-th history) */
403 if (data == (void **)-1)
405 ev->str = strdup(h->cursor->ev.str);
406 ev->num = h->cursor->ev.num;
408 *data = h->cursor->data;
409 history_def_delete(h, ev, h->cursor);
414 /* history_def_del():
415 * Delete element hp of the h list
419 history_def_del(ptr_t p, HistEvent *ev __unused,
422 history_t *h = (history_t *) p;
423 if (history_def_set(h, ev, num) != 0)
425 ev->str = strdup(h->cursor->ev.str);
426 ev->num = h->cursor->ev.num;
427 history_def_delete(h, ev, h->cursor);
432 /* history_def_delete():
433 * Delete element hp of the h list
437 history_def_delete(history_t *h,
438 HistEvent *ev __unused, hentry_t *hp)
440 HistEventPrivate *evp = (void *)&hp->ev;
443 if (h->cursor == hp) {
444 h->cursor = hp->prev;
445 if (h->cursor == &h->list)
446 h->cursor = hp->next;
448 hp->prev->next = hp->next;
449 hp->next->prev = hp->prev;
450 h_free((ptr_t) evp->str);
456 /* history_def_insert():
457 * Insert element with string str in the h list
460 history_def_insert(history_t *h, HistEvent *ev, const char *str)
463 h->cursor = (hentry_t *) h_malloc(sizeof(hentry_t));
464 if (h->cursor == NULL)
466 if ((h->cursor->ev.str = h_strdup(str)) == NULL) {
467 h_free((ptr_t)h->cursor);
470 h->cursor->data = NULL;
471 h->cursor->ev.num = ++h->eventid;
472 h->cursor->next = h->list.next;
473 h->cursor->prev = &h->list;
474 h->list.next->prev = h->cursor;
475 h->list.next = h->cursor;
481 he_seterrev(ev, _HE_MALLOC_FAILED);
486 /* history_def_enter():
487 * Default function to enter an item in the history
490 history_def_enter(ptr_t p, HistEvent *ev, const char *str)
492 history_t *h = (history_t *) p;
494 if ((h->flags & H_UNIQUE) != 0 && h->list.next != &h->list &&
495 strcmp(h->list.next->ev.str, str) == 0)
498 if (history_def_insert(h, ev, str) == -1)
499 return (-1); /* error, keep error message */
502 * Always keep at least one entry.
503 * This way we don't have to check for the empty list.
505 while (h->cur > h->max && h->cur > 0)
506 history_def_delete(h, ev, h->list.prev);
512 /* history_def_init():
513 * Default history initialization function
517 history_def_init(ptr_t *p, HistEvent *ev __unused, int n)
519 history_t *h = (history_t *) h_malloc(sizeof(history_t));
528 h->list.next = h->list.prev = &h->list;
529 h->list.ev.str = NULL;
531 h->cursor = &h->list;
538 /* history_def_clear():
539 * Default history cleanup function
542 history_def_clear(ptr_t p, HistEvent *ev)
544 history_t *h = (history_t *) p;
546 while (h->list.prev != &h->list)
547 history_def_delete(h, ev, h->list.prev);
555 /************************************************************************/
558 * Initialization function.
564 History *h = (History *) h_malloc(sizeof(History));
568 if (history_def_init(&h->h_ref, &ev, 0) == -1) {
573 h->h_next = history_def_next;
574 h->h_first = history_def_first;
575 h->h_last = history_def_last;
576 h->h_prev = history_def_prev;
577 h->h_curr = history_def_curr;
578 h->h_set = history_def_set;
579 h->h_clear = history_def_clear;
580 h->h_enter = history_def_enter;
581 h->h_add = history_def_add;
582 h->h_del = history_def_del;
592 history_end(History *h)
596 if (h->h_next == history_def_next)
597 history_def_clear(h->h_ref, &ev);
604 /* history_setsize():
605 * Set history number of events
608 history_setsize(History *h, HistEvent *ev, int num)
611 if (h->h_next != history_def_next) {
612 he_seterrev(ev, _HE_NOT_ALLOWED);
616 he_seterrev(ev, _HE_BAD_PARAM);
619 history_def_setsize(h->h_ref, num);
624 /* history_getsize():
625 * Get number of events currently in history
628 history_getsize(History *h, HistEvent *ev)
630 if (h->h_next != history_def_next) {
631 he_seterrev(ev, _HE_NOT_ALLOWED);
634 ev->num = history_def_getsize(h->h_ref);
636 he_seterrev(ev, _HE_SIZE_NEGATIVE);
643 /* history_setunique():
644 * Set if adjacent equal events should not be entered in history.
647 history_setunique(History *h, HistEvent *ev, int uni)
650 if (h->h_next != history_def_next) {
651 he_seterrev(ev, _HE_NOT_ALLOWED);
654 history_def_setunique(h->h_ref, uni);
659 /* history_getunique():
660 * Get if adjacent equal events should not be entered in history.
663 history_getunique(History *h, HistEvent *ev)
665 if (h->h_next != history_def_next) {
666 he_seterrev(ev, _HE_NOT_ALLOWED);
669 ev->num = history_def_getunique(h->h_ref);
674 /* history_set_fun():
675 * Set history functions
678 history_set_fun(History *h, History *nh)
682 if (nh->h_first == NULL || nh->h_next == NULL || nh->h_last == NULL ||
683 nh->h_prev == NULL || nh->h_curr == NULL || nh->h_set == NULL ||
684 nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL ||
685 nh->h_del == NULL || nh->h_ref == NULL) {
686 if (h->h_next != history_def_next) {
687 history_def_init(&h->h_ref, &ev, 0);
688 h->h_first = history_def_first;
689 h->h_next = history_def_next;
690 h->h_last = history_def_last;
691 h->h_prev = history_def_prev;
692 h->h_curr = history_def_curr;
693 h->h_set = history_def_set;
694 h->h_clear = history_def_clear;
695 h->h_enter = history_def_enter;
696 h->h_add = history_def_add;
697 h->h_del = history_def_del;
701 if (h->h_next == history_def_next)
702 history_def_clear(h->h_ref, &ev);
705 h->h_first = nh->h_first;
706 h->h_next = nh->h_next;
707 h->h_last = nh->h_last;
708 h->h_prev = nh->h_prev;
709 h->h_curr = nh->h_curr;
710 h->h_set = nh->h_set;
711 h->h_clear = nh->h_clear;
712 h->h_enter = nh->h_enter;
713 h->h_add = nh->h_add;
714 h->h_del = nh->h_del;
721 * History load function
724 history_load(History *h, const char *fname)
733 if ((fp = fopen(fname, "r")) == NULL)
736 if ((line = fgetln(fp, &sz)) == NULL)
739 if (strncmp(line, hist_cookie, sz) != 0)
742 ptr = h_malloc(max_size = 1024);
745 for (i = 0; (line = fgetln(fp, &sz)) != NULL; i++) {
748 if (sz != 0 && line[sz - 1] == '\n')
755 max_size = (sz + 1024) & ~1023;
756 nptr = h_realloc(ptr, max_size);
763 (void) strunvis(ptr, line);
765 if (HENTER(h, &ev, ptr) == -1) {
777 /* history_save_fp():
778 * History save with open FILE*
780 private int history_save_fp(History *h, FILE* fp)
784 size_t len, max_size;
787 if (fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1)
789 if (fputs(hist_cookie, fp) == EOF)
791 ptr = h_malloc(max_size = 1024);
794 for (i = 0, retval = HLAST(h, &ev);
796 retval = HPREV(h, &ev), i++) {
797 len = strlen(ev.str) * 4;
798 if (len >= max_size) {
800 max_size = (len + 1024) & ~1023;
801 nptr = h_realloc(ptr, max_size);
808 (void) strvis(ptr, ev.str, VIS_WHITE);
809 (void) fprintf(fp, "%s\n", ptr);
820 * History save function
823 history_save(History *h, const char *fname)
828 if ((fp = fopen(fname, "w")) == NULL)
831 i = history_save_fp(h, fp);
839 /* history_prev_event():
840 * Find the previous event, with number given
843 history_prev_event(History *h, HistEvent *ev, int num)
847 for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
851 he_seterrev(ev, _HE_NOT_FOUND);
857 history_next_evdata(History *h, HistEvent *ev, int num, void **d)
861 for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
864 *d = ((history_t *)h->h_ref)->cursor->data;
868 he_seterrev(ev, _HE_NOT_FOUND);
873 /* history_next_event():
874 * Find the next event, with number given
877 history_next_event(History *h, HistEvent *ev, int num)
881 for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
885 he_seterrev(ev, _HE_NOT_FOUND);
890 /* history_prev_string():
891 * Find the previous event beginning with string
894 history_prev_string(History *h, HistEvent *ev, const char *str)
896 size_t len = strlen(str);
899 for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
900 if (strncmp(str, ev->str, len) == 0)
903 he_seterrev(ev, _HE_NOT_FOUND);
908 /* history_next_string():
909 * Find the next event beginning with string
912 history_next_string(History *h, HistEvent *ev, const char *str)
914 size_t len = strlen(str);
917 for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
918 if (strncmp(str, ev->str, len) == 0)
921 he_seterrev(ev, _HE_NOT_FOUND);
927 * User interface to history functions.
930 history(History *h, HistEvent *ev, int fun, ...)
938 he_seterrev(ev, _HE_OK);
942 retval = history_getsize(h, ev);
946 retval = history_setsize(h, ev, va_arg(va, int));
950 retval = history_getunique(h, ev);
954 retval = history_setunique(h, ev, va_arg(va, int));
958 str = va_arg(va, const char *);
959 retval = HADD(h, ev, str);
963 retval = HDEL(h, ev, va_arg(va, const int));
967 str = va_arg(va, const char *);
968 if ((retval = HENTER(h, ev, str)) != -1)
973 str = va_arg(va, const char *);
974 if ((retval = HSET(h, ev, h->h_ent)) != -1)
975 retval = HADD(h, ev, str);
979 retval = HFIRST(h, ev);
983 retval = HNEXT(h, ev);
987 retval = HLAST(h, ev);
991 retval = HPREV(h, ev);
995 retval = HCURR(h, ev);
999 retval = HSET(h, ev, va_arg(va, const int));
1008 retval = history_load(h, va_arg(va, const char *));
1010 he_seterrev(ev, _HE_HIST_READ);
1014 retval = history_save(h, va_arg(va, const char *));
1016 he_seterrev(ev, _HE_HIST_WRITE);
1020 retval = history_save_fp(h, va_arg(va, FILE*));
1022 he_seterrev(ev, _HE_HIST_WRITE);
1026 retval = history_prev_event(h, ev, va_arg(va, int));
1030 retval = history_next_event(h, ev, va_arg(va, int));
1034 retval = history_prev_string(h, ev, va_arg(va, const char *));
1038 retval = history_next_string(h, ev, va_arg(va, const char *));
1045 hf.h_ref = va_arg(va, ptr_t);
1047 hf.h_first = va_arg(va, history_gfun_t);
1048 hf.h_next = va_arg(va, history_gfun_t);
1049 hf.h_last = va_arg(va, history_gfun_t);
1050 hf.h_prev = va_arg(va, history_gfun_t);
1051 hf.h_curr = va_arg(va, history_gfun_t);
1052 hf.h_set = va_arg(va, history_sfun_t);
1053 hf.h_clear = va_arg(va, history_vfun_t);
1054 hf.h_enter = va_arg(va, history_efun_t);
1055 hf.h_add = va_arg(va, history_efun_t);
1056 hf.h_del = va_arg(va, history_sfun_t);
1058 if ((retval = history_set_fun(h, &hf)) == -1)
1059 he_seterrev(ev, _HE_PARAM_MISSING);
1070 int num = va_arg(va, int);
1071 void **d = va_arg(va, void **);
1072 retval = history_next_evdata(h, ev, num, d);
1078 int num = va_arg(va, int);
1079 void **d = va_arg(va, void **);
1080 retval = history_deldata_nth((history_t *)h->h_ref, ev, num, d);
1084 case H_REPLACE: /* only use after H_NEXT_EVDATA */
1086 const char *line = va_arg(va, const char *);
1087 void *d = va_arg(va, void *);
1089 if(!line || !(s = strdup(line))) {
1093 ((history_t *)h->h_ref)->cursor->ev.str = s;
1094 ((history_t *)h->h_ref)->cursor->data = d;
1101 he_seterrev(ev, _HE_UNKNOWN);