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

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

CVSweb <webmaster@jp.NetBSD.org>