"Fossies" - the Fresh Open Source Software Archive

Member "tnftp-20200705/libedit/history.c" (4 Jul 2020, 27366 Bytes) of package /linux/privat/tnftp-20200705.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "history.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 20151004_vs_20200705.

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