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);