[BACK]Return to history.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libedit

Annotation of src/lib/libedit/history.c, Revision 1.57

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

CVSweb <webmaster@jp.NetBSD.org>