[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.44

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

CVSweb <webmaster@jp.NetBSD.org>