36 #if !defined(lint) && !defined(SCCSID)
38 static char sccsid[] =
"@(#)history.c 8.1 (Berkeley) 6/4/93";
56 static const char hist_cookie[] =
"_HiStOrY_V2_\n";
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);
66 struct TYPE(history) {
69 history_gfun_t h_first;
70 history_gfun_t h_next;
71 history_gfun_t h_last;
72 history_gfun_t h_prev;
73 history_gfun_t h_curr;
76 history_vfun_t h_clear;
77 history_efun_t h_enter;
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)
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)
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 *);
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);
150 private int history_def_init(
void **, TYPE(
HistEvent) *,
int);
155 private int history_set_nth(
void *, TYPE(
HistEvent) *,
int);
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) \
162 (((history_t *)p)->flags) |= H_UNIQUE; \
164 (((history_t *)p)->flags) &= ~H_UNIQUE
166 #define he_strerror(code) he_errlist[code]
167 #define he_seterrev(evp, code) {\
169 evp->str = he_strerror(code);\
173 static const Char *
const he_errlist[] = {
175 STR(
"unknown error"),
176 STR(
"malloc() failed"),
177 STR(
"first event not found"),
178 STR(
"last event not found"),
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")
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
213 history_def_first(
void *p, TYPE(
HistEvent) *ev)
217 h->cursor = h->list.next;
218 if (h->cursor != &h->list)
221 he_seterrev(ev, _HE_FIRST_NOTFOUND);
233 history_def_last(
void *p, TYPE(
HistEvent) *ev)
237 h->cursor = h->list.prev;
238 if (h->cursor != &h->list)
241 he_seterrev(ev, _HE_LAST_NOTFOUND);
253 history_def_next(
void *p, TYPE(
HistEvent) *ev)
257 if (h->cursor == &h->list) {
258 he_seterrev(ev, _HE_EMPTY_LIST);
262 if (h->cursor->next == &h->list) {
263 he_seterrev(ev, _HE_END_REACHED);
267 h->cursor = h->cursor->next;
278 history_def_prev(
void *p, TYPE(
HistEvent) *ev)
282 if (h->cursor == &h->list) {
284 (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST);
288 if (h->cursor->prev == &h->list) {
289 he_seterrev(ev, _HE_START_REACHED);
293 h->cursor = h->cursor->prev;
304 history_def_curr(
void *p, TYPE(
HistEvent) *ev)
308 if (h->cursor != &h->list)
312 (h->cur > 0) ? _HE_CURR_INVALID : _HE_EMPTY_LIST);
325 history_def_set(
void *p, TYPE(
HistEvent) *ev,
const int n)
330 he_seterrev(ev, _HE_EMPTY_LIST);
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)
339 if (h->cursor == &h->list) {
340 he_seterrev(ev, _HE_NOT_FOUND);
352 history_set_nth(
void *p, TYPE(
HistEvent) *ev,
int n)
357 he_seterrev(ev, _HE_EMPTY_LIST);
360 for (h->cursor = h->list.prev; h->cursor != &h->list;
361 h->cursor = h->cursor->prev)
364 if (h->cursor == &h->list) {
365 he_seterrev(ev, _HE_NOT_FOUND);
376 history_def_add(
void *p, TYPE(
HistEvent) *ev,
const Char *str)
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));
388 he_seterrev(ev, _HE_MALLOC_FAILED);
391 (void) Strncpy(s, h->cursor->ev.str, len);
393 (void) Strncat(s, str, len - Strlen(s) - 1);
403 int num,
void **data)
405 if (history_set_nth(h, ev, num) != 0)
408 if (data == (
void **)-1)
410 ev->str = Strdup(h->cursor->ev.str);
411 ev->num = h->cursor->ev.num;
413 *data = h->cursor->data;
414 history_def_delete(h, ev, h->cursor);
424 history_def_del(
void *p, TYPE(
HistEvent) *ev __attribute__((__unused__)),
428 if (history_def_set(h, ev, num) != 0)
430 ev->str = Strdup(h->cursor->ev.str);
431 ev->num = h->cursor->ev.num;
432 history_def_delete(h, ev, h->cursor);
448 if (h->cursor == hp) {
449 h->cursor = hp->prev;
450 if (h->cursor == &h->list)
451 h->cursor = hp->next;
453 hp->prev->next = hp->next;
454 hp->next->prev = hp->prev;
469 c = h_malloc(
sizeof(*c));
472 if ((c->ev.str = h_strdup(str)) == NULL) {
477 c->ev.num = ++h->eventid;
478 c->next = h->list.next;
480 h->list.next->prev = c;
488 he_seterrev(ev, _HE_MALLOC_FAILED);
497 history_def_enter(
void *p, TYPE(
HistEvent) *ev,
const Char *str)
501 if ((h->flags & H_UNIQUE) != 0 && h->list.next != &h->list &&
502 Strcmp(h->list.next->ev.str, str) == 0)
505 if (history_def_insert(h, ev, str) == -1)
512 while (h->cur > h->max && h->cur > 0)
513 history_def_delete(h, ev, h->list.prev);
524 history_def_init(
void **p, TYPE(
HistEvent) *ev __attribute__((__unused__)),
int n)
535 h->list.next = h->list.prev = &h->list;
536 h->list.ev.str = NULL;
538 h->cursor = &h->list;
549 history_def_clear(
void *p, TYPE(
HistEvent) *ev)
553 while (h->list.prev != &h->list)
554 history_def_delete(h, ev, h->list.prev);
555 h->cursor = &h->list;
568 public TYPE(History) *
569 FUN(history,init)(void)
572 TYPE(History) *h = (TYPE(History) *) h_malloc(sizeof(*h));
576 if (history_def_init(&h->h_ref, &ev, 0) == -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;
600 FUN(history,end)(TYPE(History) *h)
604 if (h->h_next == history_def_next)
605 history_def_clear(h->h_ref, &ev);
616 history_setsize(TYPE(History) *h, TYPE(
HistEvent) *ev,
int num)
619 if (h->h_next != history_def_next) {
620 he_seterrev(ev, _HE_NOT_ALLOWED);
624 he_seterrev(ev, _HE_BAD_PARAM);
627 history_def_setsize(h->h_ref, num);
636 history_getsize(TYPE(History) *h, TYPE(
HistEvent) *ev)
638 if (h->h_next != history_def_next) {
639 he_seterrev(ev, _HE_NOT_ALLOWED);
642 ev->num = history_def_getsize(h->h_ref);
644 he_seterrev(ev, _HE_SIZE_NEGATIVE);
655 history_setunique(TYPE(History) *h, TYPE(
HistEvent) *ev,
int uni)
658 if (h->h_next != history_def_next) {
659 he_seterrev(ev, _HE_NOT_ALLOWED);
662 history_def_setunique(h->h_ref, uni);
671 history_getunique(TYPE(History) *h, TYPE(
HistEvent) *ev)
673 if (h->h_next != history_def_next) {
674 he_seterrev(ev, _HE_NOT_ALLOWED);
677 ev->num = history_def_getunique(h->h_ref);
686 history_set_fun(TYPE(History) *h, TYPE(History) *nh)
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;
709 if (h->h_next == history_def_next)
710 history_def_clear(h->h_ref, &ev);
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;
732 history_load(TYPE(History) *h,
const char *fname)
741 static ct_buffer_t conv;
744 if ((fp = fopen(fname,
"r")) == NULL)
747 if ((line = fgetln(fp, &sz)) == NULL)
750 if (strncmp(line, hist_cookie, sz) != 0)
753 ptr = h_malloc((max_size = 1024) *
sizeof(*ptr));
756 for (i = 0; (line = fgetln(fp, &sz)) != NULL; i++) {
759 if (sz != 0 && line[sz - 1] ==
'\n')
766 max_size = (sz + 1024) & (
size_t)~1023;
767 nptr = h_realloc(ptr, max_size *
sizeof(*ptr));
774 (void) strunvis(ptr, line);
776 if (HENTER(h, &ev, ct_decode_string(ptr, &conv)) == -1) {
793 history_save(TYPE(History) *h,
const char *fname)
798 size_t len, max_size;
802 static ct_buffer_t conv;
805 if ((fp = fopen(fname,
"w")) == NULL)
808 if (fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1)
810 if (fputs(hist_cookie, fp) == EOF)
812 ptr = h_malloc((max_size = 1024) *
sizeof(*ptr));
815 for (i = 0, retval = HLAST(h, &ev);
817 retval = HPREV(h, &ev), i++) {
818 str = ct_encode_string(ev.str, &conv);
819 len = strlen(str) * 4;
820 if (len >= max_size) {
822 max_size = (len + 1024) & (
size_t)~1023;
823 nptr = h_realloc(ptr, max_size *
sizeof(*ptr));
830 (void) strvis(ptr, str, VIS_WHITE);
831 (void) fprintf(fp,
"%s\n", ptr);
845 history_prev_event(TYPE(History) *h, TYPE(
HistEvent) *ev,
int num)
849 for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
853 he_seterrev(ev, _HE_NOT_FOUND);
859 history_next_evdata(TYPE(History) *h, TYPE(
HistEvent) *ev,
int num,
void **d)
863 for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
864 if (ev->num == num) {
866 *d = ((
history_t *)h->h_ref)->cursor->data;
870 he_seterrev(ev, _HE_NOT_FOUND);
879 history_next_event(TYPE(History) *h, TYPE(
HistEvent) *ev,
int num)
883 for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
887 he_seterrev(ev, _HE_NOT_FOUND);
896 history_prev_string(TYPE(History) *h, TYPE(
HistEvent) *ev,
const Char *str)
898 size_t len = Strlen(str);
901 for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
902 if (Strncmp(str, ev->str, len) == 0)
905 he_seterrev(ev, _HE_NOT_FOUND);
914 history_next_string(TYPE(History) *h, TYPE(
HistEvent) *ev,
const Char *str)
916 size_t len = Strlen(str);
919 for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
920 if (Strncmp(str, ev->str, len) == 0)
923 he_seterrev(ev, _HE_NOT_FOUND);
932 FUNW(history)(TYPE(History) *h, TYPE(
HistEvent) *ev,
int fun, ...)
940 he_seterrev(ev, _HE_OK);
944 retval = history_getsize(h, ev);
948 retval = history_setsize(h, ev, va_arg(va,
int));
952 retval = history_getunique(h, ev);
956 retval = history_setunique(h, ev, va_arg(va,
int));
960 str = va_arg(va,
const Char *);
961 retval = HADD(h, ev, str);
965 retval = HDEL(h, ev, va_arg(va,
const int));
969 str = va_arg(va,
const Char *);
970 if ((retval = HENTER(h, ev, str)) != -1)
975 str = va_arg(va,
const Char *);
976 if ((retval = HSET(h, ev, h->h_ent)) != -1)
977 retval = HADD(h, ev, str);
981 retval = HFIRST(h, ev);
985 retval = HNEXT(h, ev);
989 retval = HLAST(h, ev);
993 retval = HPREV(h, ev);
997 retval = HCURR(h, ev);
1001 retval = HSET(h, ev, va_arg(va,
const int));
1010 retval = history_load(h, va_arg(va,
const char *));
1012 he_seterrev(ev, _HE_HIST_READ);
1016 retval = history_save(h, va_arg(va,
const char *));
1018 he_seterrev(ev, _HE_HIST_WRITE);
1022 retval = history_prev_event(h, ev, va_arg(va,
int));
1026 retval = history_next_event(h, ev, va_arg(va,
int));
1030 retval = history_prev_string(h, ev, va_arg(va,
const Char *));
1034 retval = history_next_string(h, ev, va_arg(va,
const Char *));
1041 hf.h_ref = va_arg(va,
void *);
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);
1054 if ((retval = history_set_fun(h, &hf)) == -1)
1055 he_seterrev(ev, _HE_PARAM_MISSING);
1060 FUN(history,end)(h);
1066 int num = va_arg(va,
int);
1067 void **d = va_arg(va,
void **);
1068 retval = history_next_evdata(h, ev, num, d);
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);
1082 const Char *line = va_arg(va,
const Char *);
1083 void *d = va_arg(va,
void *);
1085 if(!line || !(s = Strdup(line))) {
1089 ((
history_t *)h->h_ref)->cursor->ev.str = s;
1090 ((
history_t *)h->h_ref)->cursor->data = d;
1097 he_seterrev(ev, _HE_UNKNOWN);