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

1.17    ! christos    1: /*     $NetBSD: history.c,v 1.16 2000/09/04 22:06:30 lukem 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.
                     18:  * 3. All advertising materials mentioning features or use of this software
                     19:  *    must display the following acknowledgement:
                     20:  *     This product includes software developed by the University of
                     21:  *     California, Berkeley and its contributors.
                     22:  * 4. Neither the name of the University nor the names of its contributors
                     23:  *    may be used to endorse or promote products derived from this software
                     24:  *    without specific prior written permission.
                     25:  *
                     26:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     27:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     28:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     29:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     30:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     31:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     32:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     33:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     34:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     35:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     36:  * SUCH DAMAGE.
                     37:  */
                     38:
1.6       christos   39: #include <sys/cdefs.h>
1.1       cgd        40: #if !defined(lint) && !defined(SCCSID)
1.6       christos   41: #if 0
1.1       cgd        42: static char sccsid[] = "@(#)history.c  8.1 (Berkeley) 6/4/93";
1.6       christos   43: #else
1.17    ! christos   44: __RCSID("$NetBSD: history.c,v 1.16 2000/09/04 22:06:30 lukem Exp $");
1.6       christos   45: #endif
1.1       cgd        46: #endif /* not lint && not SCCSID */
                     47:
                     48: /*
                     49:  * hist.c: History access functions
                     50:  */
                     51: #include "sys.h"
                     52:
                     53: #include <string.h>
                     54: #include <stdlib.h>
                     55: #include <stdarg.h>
1.12      christos   56: #include <vis.h>
1.17    ! christos   57: #include <sys/stat.h>
1.1       cgd        58:
1.12      christos   59: static const char hist_cookie[] = "_HiStOrY_V2_\n";
1.2       christos   60:
1.1       cgd        61: #include "histedit.h"
                     62:
1.16      lukem      63: typedef int (*history_gfun_t)(ptr_t, HistEvent *);
                     64: typedef int (*history_efun_t)(ptr_t, HistEvent *, const char *);
                     65: typedef void (*history_vfun_t)(ptr_t, HistEvent *);
                     66: typedef int (*history_sfun_t)(ptr_t, HistEvent *, const int);
1.1       cgd        67:
                     68: struct history {
1.16      lukem      69:        ptr_t h_ref;            /* Argument for history fcns     */
                     70:        int h_ent;              /* Last entry point for history  */
                     71:        history_gfun_t h_first; /* Get the first element         */
                     72:        history_gfun_t h_next;  /* Get the next element          */
                     73:        history_gfun_t h_last;  /* Get the last element          */
                     74:        history_gfun_t h_prev;  /* Get the previous element      */
                     75:        history_gfun_t h_curr;  /* Get the current element       */
                     76:        history_sfun_t h_set;   /* Set the current element       */
                     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.16      lukem      81: #define        HNEXT(h, ev)            (*(h)->h_next)((h)->h_ref, ev)
                     82: #define        HFIRST(h, ev)           (*(h)->h_first)((h)->h_ref, ev)
                     83: #define        HPREV(h, ev)            (*(h)->h_prev)((h)->h_ref, ev)
                     84: #define        HLAST(h, ev)            (*(h)->h_last)((h)->h_ref, ev)
                     85: #define        HCURR(h, ev)            (*(h)->h_curr)((h)->h_ref, ev)
                     86: #define        HSET(h, ev, n)          (*(h)->h_set)((h)->h_ref, ev, n)
                     87: #define        HCLEAR(h, ev)           (*(h)->h_clear)((h)->h_ref, ev)
1.7       christos   88: #define        HENTER(h, ev, str)      (*(h)->h_enter)((h)->h_ref, ev, str)
                     89: #define        HADD(h, ev, str)        (*(h)->h_add)((h)->h_ref, ev, str)
1.1       cgd        90:
1.16      lukem      91: #define        h_malloc(a)     malloc(a)
                     92: #define        h_realloc(a, b) realloc((a), (b))
                     93: #define        h_free(a)       free(a)
1.1       cgd        94:
                     95:
1.16      lukem      96: private int history_setsize(History *, HistEvent *, int);
                     97: private int history_getsize(History *, HistEvent *);
                     98: private int history_set_fun(History *, History *);
                     99: private int history_load(History *, const char *);
                    100: private int history_save(History *, const char *);
                    101: private int history_prev_event(History *, HistEvent *, int);
                    102: private int history_next_event(History *, HistEvent *, int);
                    103: private int history_next_string(History *, HistEvent *, const char *);
                    104: private int history_prev_string(History *, HistEvent *, const char *);
1.1       cgd       105:
                    106:
                    107: /***********************************************************************/
                    108:
                    109: /*
                    110:  * Builtin- history implementation
                    111:  */
                    112: typedef struct hentry_t {
1.16      lukem     113:        HistEvent ev;           /* What we return                */
                    114:        struct hentry_t *next;  /* Next entry                    */
                    115:        struct hentry_t *prev;  /* Previous entry                */
                    116: }        hentry_t;
1.1       cgd       117:
                    118: typedef struct history_t {
1.16      lukem     119:        hentry_t list;          /* Fake list header element      */
                    120:        hentry_t *cursor;       /* Current element in the list   */
                    121:        int max;                /* Maximum number of events      */
                    122:        int cur;                /* Current number of events      */
                    123:        int eventid;            /* For generation of unique event id     */
                    124: }         history_t;
                    125:
                    126: private int history_def_first(ptr_t, HistEvent *);
                    127: private int history_def_last(ptr_t, HistEvent *);
                    128: private int history_def_next(ptr_t, HistEvent *);
                    129: private int history_def_prev(ptr_t, HistEvent *);
                    130: private int history_def_curr(ptr_t, HistEvent *);
                    131: private int history_def_set(ptr_t, HistEvent *, const int n);
                    132: private int history_def_enter(ptr_t, HistEvent *, const char *);
                    133: private int history_def_add(ptr_t, HistEvent *, const char *);
                    134: private void history_def_init(ptr_t *, HistEvent *, int);
                    135: private void history_def_clear(ptr_t, HistEvent *);
                    136: private int history_def_insert(history_t *, HistEvent *, const char *);
                    137: private void history_def_delete(history_t *, HistEvent *, hentry_t *);
1.1       cgd       138:
1.16      lukem     139: #define        history_def_setsize(p, num)(void) (((history_t *) p)->max = (num))
                    140: #define        history_def_getsize(p)  (((history_t *) p)->cur)
1.1       cgd       141:
1.16      lukem     142: #define        he_strerror(code)       he_errlist[code]
                    143: #define        he_seterrev(evp, code)  {\
1.7       christos  144:                                    evp->num = code;\
                    145:                                    evp->str = he_strerror(code);\
                    146:                                }
1.14      simonb    147:
1.7       christos  148: /* error messages */
                    149: static const char *const he_errlist[] = {
1.16      lukem     150:        "OK",
                    151:        "unknown error",
                    152:        "malloc() failed",
                    153:        "first event not found",
                    154:        "last event not found",
                    155:        "empty list",
                    156:        "no next event",
                    157:        "no previous event",
                    158:        "current event is invalid",
                    159:        "event not found",
                    160:        "can't read history from file",
                    161:        "can't write history",
                    162:        "required parameter(s) not supplied",
                    163:        "history size negative",
                    164:        "function not allowed with other history-functions-set the default",
                    165:        "bad parameters"
1.7       christos  166: };
                    167: /* error codes */
1.16      lukem     168: #define        _HE_OK                   0
                    169: #define        _HE_UNKNOWN              1
                    170: #define        _HE_MALLOC_FAILED        2
                    171: #define        _HE_FIRST_NOTFOUND       3
                    172: #define        _HE_LAST_NOTFOUND        4
                    173: #define        _HE_EMPTY_LIST           5
                    174: #define        _HE_END_REACHED          6
                    175: #define        _HE_START_REACHED        7
                    176: #define        _HE_CURR_INVALID         8
                    177: #define        _HE_NOT_FOUND            9
                    178: #define        _HE_HIST_READ           10
                    179: #define        _HE_HIST_WRITE          11
                    180: #define        _HE_PARAM_MISSING       12
                    181: #define        _HE_SIZE_NEGATIVE       13
                    182: #define        _HE_NOT_ALLOWED         14
                    183: #define        _HE_BAD_PARAM           15
1.1       cgd       184:
                    185: /* history_def_first():
                    186:  *     Default function to return the first event in the history.
                    187:  */
1.7       christos  188: private int
1.16      lukem     189: history_def_first(ptr_t p, HistEvent *ev)
1.1       cgd       190: {
1.16      lukem     191:        history_t *h = (history_t *) p;
1.7       christos  192:
1.16      lukem     193:        h->cursor = h->list.next;
                    194:        if (h->cursor != &h->list)
                    195:                *ev = h->cursor->ev;
                    196:        else {
                    197:                he_seterrev(ev, _HE_FIRST_NOTFOUND);
                    198:                return (-1);
                    199:        }
1.7       christos  200:
1.16      lukem     201:        return (0);
1.1       cgd       202: }
                    203:
1.8       christos  204:
1.1       cgd       205: /* history_def_last():
                    206:  *     Default function to return the last event in the history.
                    207:  */
1.7       christos  208: private int
1.16      lukem     209: history_def_last(ptr_t p, HistEvent *ev)
                    210: {
                    211:        history_t *h = (history_t *) p;
                    212:
                    213:        h->cursor = h->list.prev;
                    214:        if (h->cursor != &h->list)
                    215:                *ev = h->cursor->ev;
                    216:        else {
                    217:                he_seterrev(ev, _HE_LAST_NOTFOUND);
                    218:                return (-1);
                    219:        }
1.7       christos  220:
1.16      lukem     221:        return (0);
1.1       cgd       222: }
                    223:
1.8       christos  224:
1.1       cgd       225: /* history_def_next():
                    226:  *     Default function to return the next event in the history.
                    227:  */
1.7       christos  228: private int
1.16      lukem     229: history_def_next(ptr_t p, HistEvent *ev)
                    230: {
                    231:        history_t *h = (history_t *) p;
                    232:
                    233:        if (h->cursor != &h->list)
                    234:                h->cursor = h->cursor->next;
                    235:        else {
                    236:                he_seterrev(ev, _HE_EMPTY_LIST);
                    237:                return (-1);
                    238:        }
1.1       cgd       239:
1.16      lukem     240:        if (h->cursor != &h->list)
                    241:                *ev = h->cursor->ev;
                    242:        else {
                    243:                he_seterrev(ev, _HE_END_REACHED);
                    244:                return (-1);
                    245:        }
1.7       christos  246:
1.16      lukem     247:        return (0);
1.1       cgd       248: }
                    249:
                    250:
                    251: /* history_def_prev():
                    252:  *     Default function to return the previous event in the history.
                    253:  */
1.7       christos  254: private int
1.16      lukem     255: history_def_prev(ptr_t p, HistEvent *ev)
                    256: {
                    257:        history_t *h = (history_t *) p;
                    258:
                    259:        if (h->cursor != &h->list)
                    260:                h->cursor = h->cursor->prev;
                    261:        else {
                    262:                he_seterrev(ev,
                    263:                    (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST);
                    264:                return (-1);
                    265:        }
1.1       cgd       266:
1.16      lukem     267:        if (h->cursor != &h->list)
                    268:                *ev = h->cursor->ev;
                    269:        else {
                    270:                he_seterrev(ev, _HE_START_REACHED);
                    271:                return (-1);
                    272:        }
1.7       christos  273:
1.16      lukem     274:        return (0);
1.1       cgd       275: }
                    276:
                    277:
                    278: /* history_def_curr():
                    279:  *     Default function to return the current event in the history.
                    280:  */
1.7       christos  281: private int
1.16      lukem     282: history_def_curr(ptr_t p, HistEvent *ev)
1.1       cgd       283: {
1.16      lukem     284:        history_t *h = (history_t *) p;
1.1       cgd       285:
1.16      lukem     286:        if (h->cursor != &h->list)
                    287:                *ev = h->cursor->ev;
                    288:        else {
                    289:                he_seterrev(ev,
                    290:                    (h->cur > 0) ? _HE_CURR_INVALID : _HE_EMPTY_LIST);
                    291:                return (-1);
                    292:        }
1.7       christos  293:
1.16      lukem     294:        return (0);
1.1       cgd       295: }
                    296:
1.8       christos  297:
                    298: /* history_def_set():
                    299:  *     Default function to set the current event in the history to the
                    300:  *     given one.
                    301:  */
                    302: private int
1.16      lukem     303: history_def_set(ptr_t p, HistEvent *ev, const int n)
                    304: {
                    305:        history_t *h = (history_t *) p;
1.8       christos  306:
1.16      lukem     307:        if (h->cur == 0) {
                    308:                he_seterrev(ev, _HE_EMPTY_LIST);
                    309:                return (-1);
                    310:        }
                    311:        if (h->cursor == &h->list || h->cursor->ev.num != n) {
                    312:                for (h->cursor = h->list.next; h->cursor != &h->list;
                    313:                    h->cursor = h->cursor->next)
                    314:                        if (h->cursor->ev.num == n)
                    315:                                break;
                    316:        }
                    317:        if (h->cursor == &h->list) {
                    318:                he_seterrev(ev, _HE_NOT_FOUND);
                    319:                return (-1);
                    320:        }
                    321:        return (0);
1.8       christos  322: }
                    323:
                    324:
1.1       cgd       325: /* history_def_add():
                    326:  *     Append string to element
                    327:  */
1.7       christos  328: private int
1.16      lukem     329: history_def_add(ptr_t p, HistEvent *ev, const char *str)
                    330: {
                    331:        history_t *h = (history_t *) p;
                    332:        size_t len;
                    333:        char *s;
                    334:
                    335:        if (h->cursor == &h->list)
                    336:                return (history_def_enter(p, ev, str));
                    337:        len = strlen(h->cursor->ev.str) + strlen(str) + 1;
                    338:        s = (char *) h_malloc(len);
                    339:        if (!s) {
                    340:                he_seterrev(ev, _HE_MALLOC_FAILED);
                    341:                return (-1);
                    342:        }
                    343:        (void) strlcpy(s, h->cursor->ev.str, len);
                    344:        (void) strlcat(s, str, len);
                    345:        /* LINTED const cast */
                    346:        h_free((ptr_t) h->cursor->ev.str);
                    347:        h->cursor->ev.str = s;
                    348:        *ev = h->cursor->ev;
                    349:        return (0);
1.1       cgd       350: }
                    351:
                    352:
                    353: /* history_def_delete():
                    354:  *     Delete element hp of the h list
                    355:  */
1.11      christos  356: /* ARGSUSED */
1.1       cgd       357: private void
1.16      lukem     358: history_def_delete(history_t *h, HistEvent *ev, hentry_t *hp)
                    359: {
                    360:
                    361:        if (hp == &h->list)
                    362:                abort();
                    363:        hp->prev->next = hp->next;
                    364:        hp->next->prev = hp->prev;
                    365:        /* LINTED const cast */
                    366:        h_free((ptr_t) hp->ev.str);
                    367:        h_free(hp);
                    368:        h->cur--;
1.1       cgd       369: }
                    370:
                    371:
                    372: /* history_def_insert():
                    373:  *     Insert element with string str in the h list
                    374:  */
1.7       christos  375: private int
1.16      lukem     376: history_def_insert(history_t *h, HistEvent *ev, const char *str)
                    377: {
                    378:
                    379:        h->cursor = (hentry_t *) h_malloc(sizeof(hentry_t));
                    380:        if (h->cursor)
                    381:                h->cursor->ev.str = strdup(str);
                    382:        if (!h->cursor || !h->cursor->ev.str) {
                    383:                he_seterrev(ev, _HE_MALLOC_FAILED);
                    384:                return (-1);
                    385:        }
                    386:        h->cursor->ev.num = ++h->eventid;
                    387:        h->cursor->next = h->list.next;
                    388:        h->cursor->prev = &h->list;
                    389:        h->list.next->prev = h->cursor;
                    390:        h->list.next = h->cursor;
                    391:        h->cur++;
1.1       cgd       392:
1.16      lukem     393:        *ev = h->cursor->ev;
                    394:        return (0);
1.1       cgd       395: }
                    396:
                    397:
                    398: /* history_def_enter():
                    399:  *     Default function to enter an item in the history
                    400:  */
1.7       christos  401: private int
1.16      lukem     402: history_def_enter(ptr_t p, HistEvent *ev, const char *str)
                    403: {
                    404:        history_t *h = (history_t *) p;
                    405:
                    406:        if (history_def_insert(h, ev, str) == -1)
                    407:                return (-1);    /* error, keep error message */
                    408:
                    409:        /*
                    410:          * Always keep at least one entry.
                    411:          * This way we don't have to check for the empty list.
                    412:          */
                    413:        while (h->cur - 1 > h->max)
                    414:                history_def_delete(h, ev, h->list.prev);
1.7       christos  415:
1.16      lukem     416:        return (0);
1.1       cgd       417: }
                    418:
                    419:
                    420: /* history_def_init():
                    421:  *     Default history initialization function
                    422:  */
1.11      christos  423: /* ARGSUSED */
1.1       cgd       424: private void
1.16      lukem     425: history_def_init(ptr_t *p, HistEvent *ev, int n)
                    426: {
                    427:        history_t *h = (history_t *) h_malloc(sizeof(history_t));
                    428:
                    429:        if (n <= 0)
                    430:                n = 0;
                    431:        h->eventid = 0;
                    432:        h->cur = 0;
                    433:        h->max = n;
                    434:        h->list.next = h->list.prev = &h->list;
                    435:        h->list.ev.str = NULL;
                    436:        h->list.ev.num = 0;
                    437:        h->cursor = &h->list;
                    438:        *p = (ptr_t) h;
1.1       cgd       439: }
                    440:
                    441:
1.2       christos  442: /* history_def_clear():
1.1       cgd       443:  *     Default history cleanup function
                    444:  */
                    445: private void
1.16      lukem     446: history_def_clear(ptr_t p, HistEvent *ev)
                    447: {
                    448:        history_t *h = (history_t *) p;
                    449:
                    450:        while (h->list.prev != &h->list)
                    451:                history_def_delete(h, ev, h->list.prev);
                    452:        h->eventid = 0;
                    453:        h->cur = 0;
1.1       cgd       454: }
                    455:
1.2       christos  456:
                    457:
                    458:
1.1       cgd       459: /************************************************************************/
                    460:
                    461: /* history_init():
                    462:  *     Initialization function.
                    463:  */
                    464: public History *
1.16      lukem     465: history_init(void)
1.1       cgd       466: {
1.16      lukem     467:        History *h = (History *) h_malloc(sizeof(History));
                    468:        HistEvent ev;
1.1       cgd       469:
1.16      lukem     470:        history_def_init(&h->h_ref, &ev, 0);
                    471:        h->h_ent = -1;
                    472:        h->h_next = history_def_next;
                    473:        h->h_first = history_def_first;
                    474:        h->h_last = history_def_last;
                    475:        h->h_prev = history_def_prev;
                    476:        h->h_curr = history_def_curr;
                    477:        h->h_set = history_def_set;
                    478:        h->h_clear = history_def_clear;
                    479:        h->h_enter = history_def_enter;
                    480:        h->h_add = history_def_add;
1.1       cgd       481:
1.16      lukem     482:        return (h);
1.1       cgd       483: }
                    484:
                    485:
                    486: /* history_end():
                    487:  *     clean up history;
                    488:  */
                    489: public void
1.16      lukem     490: history_end(History *h)
1.1       cgd       491: {
1.16      lukem     492:        HistEvent ev;
                    493:
                    494:        if (h->h_next == history_def_next)
                    495:                history_def_clear(h->h_ref, &ev);
1.1       cgd       496: }
                    497:
                    498:
                    499:
1.12      christos  500: /* history_setsize():
1.1       cgd       501:  *     Set history number of events
                    502:  */
                    503: private int
1.16      lukem     504: history_setsize(History *h, HistEvent *ev, int num)
                    505: {
1.7       christos  506:
1.16      lukem     507:        if (h->h_next != history_def_next) {
                    508:                he_seterrev(ev, _HE_NOT_ALLOWED);
                    509:                return (-1);
                    510:        }
                    511:        if (num < 0) {
                    512:                he_seterrev(ev, _HE_BAD_PARAM);
                    513:                return (-1);
                    514:        }
                    515:        history_def_setsize(h->h_ref, num);
                    516:        return (0);
1.1       cgd       517: }
                    518:
1.16      lukem     519:
1.12      christos  520: /* history_getsize():
1.7       christos  521:  *      Get number of events currently in history
                    522:  */
                    523: private int
1.16      lukem     524: history_getsize(History *h, HistEvent *ev)
                    525: {
                    526:        int retval = 0;
1.7       christos  527:
1.16      lukem     528:        if (h->h_next != history_def_next) {
                    529:                he_seterrev(ev, _HE_NOT_ALLOWED);
                    530:                return (-1);
                    531:        }
                    532:        retval = history_def_getsize(h->h_ref);
                    533:        if (retval < -1) {
                    534:                he_seterrev(ev, _HE_SIZE_NEGATIVE);
                    535:                return (-1);
                    536:        }
                    537:        ev->num = retval;
                    538:        return (0);
1.7       christos  539: }
1.1       cgd       540:
1.16      lukem     541:
1.1       cgd       542: /* history_set_fun():
                    543:  *     Set history functions
                    544:  */
                    545: private int
1.16      lukem     546: history_set_fun(History *h, History *nh)
                    547: {
                    548:        HistEvent ev;
                    549:
                    550:        if (nh->h_first == NULL || nh->h_next == NULL || nh->h_last == NULL ||
                    551:            nh->h_prev == NULL || nh->h_curr == NULL || nh->h_set == NULL ||
                    552:            nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL ||
                    553:            nh->h_ref == NULL) {
                    554:                if (h->h_next != history_def_next) {
                    555:                        history_def_init(&h->h_ref, &ev, 0);
                    556:                        h->h_first = history_def_first;
                    557:                        h->h_next = history_def_next;
                    558:                        h->h_last = history_def_last;
                    559:                        h->h_prev = history_def_prev;
                    560:                        h->h_curr = history_def_curr;
                    561:                        h->h_set = history_def_set;
                    562:                        h->h_clear = history_def_clear;
                    563:                        h->h_enter = history_def_enter;
                    564:                        h->h_add = history_def_add;
                    565:                }
                    566:                return (-1);
                    567:        }
                    568:        if (h->h_next == history_def_next)
                    569:                history_def_clear(h->h_ref, &ev);
                    570:
                    571:        h->h_ent = -1;
                    572:        h->h_first = nh->h_first;
                    573:        h->h_next = nh->h_next;
                    574:        h->h_last = nh->h_last;
                    575:        h->h_prev = nh->h_prev;
                    576:        h->h_curr = nh->h_curr;
                    577:        h->h_set = nh->h_set;
                    578:        h->h_clear = nh->h_clear;
                    579:        h->h_enter = nh->h_enter;
                    580:        h->h_add = nh->h_add;
1.1       cgd       581:
1.16      lukem     582:        return (0);
1.1       cgd       583: }
                    584:
                    585:
1.2       christos  586: /* history_load():
                    587:  *     History load function
                    588:  */
                    589: private int
1.16      lukem     590: history_load(History *h, const char *fname)
                    591: {
                    592:        FILE *fp;
                    593:        char *line;
                    594:        size_t sz, max_size;
                    595:        char *ptr;
                    596:        int i = -1;
                    597:        HistEvent ev;
                    598:
                    599:        if ((fp = fopen(fname, "r")) == NULL)
                    600:                return (i);
                    601:
                    602:        if ((line = fgetln(fp, &sz)) == NULL)
                    603:                goto done;
                    604:
                    605:        if (strncmp(line, hist_cookie, sz) != 0)
                    606:                goto done;
                    607:
                    608:        ptr = h_malloc(max_size = 1024);
                    609:        for (i = 0; (line = fgetln(fp, &sz)) != NULL; i++) {
                    610:                char c = line[sz];
                    611:
                    612:                if (sz != 0 && line[sz - 1] == '\n')
                    613:                        line[--sz] = '\0';
                    614:                else
                    615:                        line[sz] = '\0';
                    616:
                    617:                if (max_size < sz) {
                    618:                        max_size = (sz + 1023) & ~1023;
                    619:                        ptr = h_realloc(ptr, max_size);
                    620:                }
                    621:                (void) strunvis(ptr, line);
                    622:                line[sz] = c;
                    623:                HENTER(h, &ev, ptr);
                    624:        }
                    625:        h_free(ptr);
1.2       christos  626:
                    627: done:
1.16      lukem     628:        (void) fclose(fp);
                    629:        return (i);
1.2       christos  630: }
                    631:
                    632:
                    633: /* history_save():
                    634:  *     History save function
                    635:  */
                    636: private int
1.16      lukem     637: history_save(History *h, const char *fname)
                    638: {
                    639:        FILE *fp;
                    640:        HistEvent ev;
                    641:        int i = 0, retval;
                    642:        size_t len, max_size;
                    643:        char *ptr;
                    644:
                    645:        if ((fp = fopen(fname, "w")) == NULL)
                    646:                return (-1);
                    647:
1.17    ! christos  648:        (void) fchmod(fileno(fp), S_IRUSR|S_IWUSR);
1.16      lukem     649:        (void) fputs(hist_cookie, fp);
                    650:        ptr = h_malloc(max_size = 1024);
                    651:        for (retval = HLAST(h, &ev);
                    652:            retval != -1;
                    653:            retval = HPREV(h, &ev), i++) {
                    654:                len = strlen(ev.str) * 4;
                    655:                if (len >= max_size) {
                    656:                        max_size = (len + 1023) & 1023;
                    657:                        ptr = h_realloc(ptr, max_size);
                    658:                }
                    659:                (void) strvis(ptr, ev.str, VIS_WHITE);
                    660:                (void) fprintf(fp, "%s\n", ev.str);
                    661:        }
                    662:        h_free(ptr);
                    663:        (void) fclose(fp);
                    664:        return (i);
1.2       christos  665: }
                    666:
                    667:
1.1       cgd       668: /* history_prev_event():
                    669:  *     Find the previous event, with number given
                    670:  */
1.7       christos  671: private int
1.16      lukem     672: history_prev_event(History *h, HistEvent *ev, int num)
                    673: {
                    674:        int retval;
1.7       christos  675:
1.16      lukem     676:        for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
                    677:                if (ev->num == num)
                    678:                        return (0);
                    679:
                    680:        he_seterrev(ev, _HE_NOT_FOUND);
                    681:        return (-1);
1.1       cgd       682: }
                    683:
                    684:
                    685: /* history_next_event():
                    686:  *     Find the next event, with number given
                    687:  */
1.7       christos  688: private int
1.16      lukem     689: history_next_event(History *h, HistEvent *ev, int num)
                    690: {
                    691:        int retval;
                    692:
                    693:        for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
                    694:                if (ev->num == num)
                    695:                        return (0);
1.7       christos  696:
1.16      lukem     697:        he_seterrev(ev, _HE_NOT_FOUND);
                    698:        return (-1);
1.1       cgd       699: }
                    700:
                    701:
                    702: /* history_prev_string():
                    703:  *     Find the previous event beginning with string
                    704:  */
1.7       christos  705: private int
1.16      lukem     706: history_prev_string(History *h, HistEvent *ev, const char *str)
                    707: {
                    708:        size_t len = strlen(str);
                    709:        int retval;
1.7       christos  710:
1.16      lukem     711:        for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
                    712:                if (strncmp(str, ev->str, len) == 0)
                    713:                        return (0);
                    714:
                    715:        he_seterrev(ev, _HE_NOT_FOUND);
                    716:        return (-1);
1.1       cgd       717: }
                    718:
                    719:
                    720: /* history_next_string():
                    721:  *     Find the next event beginning with string
                    722:  */
1.7       christos  723: private int
1.16      lukem     724: history_next_string(History *h, HistEvent *ev, const char *str)
                    725: {
                    726:        size_t len = strlen(str);
                    727:        int retval;
                    728:
                    729:        for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
                    730:                if (strncmp(str, ev->str, len) == 0)
                    731:                        return (0);
1.7       christos  732:
1.16      lukem     733:        he_seterrev(ev, _HE_NOT_FOUND);
                    734:        return (-1);
1.1       cgd       735: }
                    736:
                    737:
                    738: /* history():
                    739:  *     User interface to history functions.
                    740:  */
1.7       christos  741: int
                    742: history(History *h, HistEvent *ev, int fun, ...)
1.1       cgd       743: {
1.16      lukem     744:        va_list va;
                    745:        const char *str;
                    746:        int retval;
                    747:
                    748:        va_start(va, fun);
                    749:
                    750:        he_seterrev(ev, _HE_OK);
                    751:
                    752:        switch (fun) {
                    753:        case H_GETSIZE:
                    754:                retval = history_getsize(h, ev);
                    755:                break;
                    756:
                    757:        case H_SETSIZE:
                    758:                retval = history_setsize(h, ev, va_arg(va, int));
                    759:                break;
                    760:
                    761:        case H_ADD:
                    762:                str = va_arg(va, const char *);
                    763:                retval = HADD(h, ev, str);
                    764:                break;
                    765:
                    766:        case H_ENTER:
                    767:                str = va_arg(va, const char *);
                    768:                if ((retval = HENTER(h, ev, str)) != -1)
                    769:                        h->h_ent = ev->num;
                    770:                break;
                    771:
                    772:        case H_APPEND:
                    773:                str = va_arg(va, const char *);
                    774:                if ((retval = HSET(h, ev, h->h_ent)) != -1)
                    775:                        retval = HADD(h, ev, str);
                    776:                break;
                    777:
                    778:        case H_FIRST:
                    779:                retval = HFIRST(h, ev);
                    780:                break;
1.1       cgd       781:
1.16      lukem     782:        case H_NEXT:
                    783:                retval = HNEXT(h, ev);
                    784:                break;
                    785:
                    786:        case H_LAST:
                    787:                retval = HLAST(h, ev);
                    788:                break;
                    789:
                    790:        case H_PREV:
                    791:                retval = HPREV(h, ev);
                    792:                break;
                    793:
                    794:        case H_CURR:
                    795:                retval = HCURR(h, ev);
                    796:                break;
                    797:
                    798:        case H_SET:
                    799:                retval = HSET(h, ev, va_arg(va, const int));
                    800:                break;
                    801:
                    802:        case H_CLEAR:
                    803:                HCLEAR(h, ev);
                    804:                retval = 0;
                    805:                break;
                    806:
                    807:        case H_LOAD:
                    808:                retval = history_load(h, va_arg(va, const char *));
                    809:                if (retval == -1)
                    810:                        he_seterrev(ev, _HE_HIST_READ);
                    811:                break;
                    812:
                    813:        case H_SAVE:
                    814:                retval = history_save(h, va_arg(va, const char *));
                    815:                if (retval == -1)
                    816:                        he_seterrev(ev, _HE_HIST_WRITE);
                    817:                break;
                    818:
                    819:        case H_PREV_EVENT:
                    820:                retval = history_prev_event(h, ev, va_arg(va, int));
                    821:                break;
                    822:
                    823:        case H_NEXT_EVENT:
                    824:                retval = history_next_event(h, ev, va_arg(va, int));
                    825:                break;
1.1       cgd       826:
1.16      lukem     827:        case H_PREV_STR:
                    828:                retval = history_prev_string(h, ev, va_arg(va, const char *));
                    829:                break;
1.7       christos  830:
1.16      lukem     831:        case H_NEXT_STR:
                    832:                retval = history_next_string(h, ev, va_arg(va, const char *));
                    833:                break;
1.1       cgd       834:
1.16      lukem     835:        case H_FUNC:
1.1       cgd       836:        {
1.16      lukem     837:                History hf;
                    838:
                    839:                hf.h_ref = va_arg(va, ptr_t);
                    840:                h->h_ent = -1;
                    841:                hf.h_first = va_arg(va, history_gfun_t);
                    842:                hf.h_next = va_arg(va, history_gfun_t);
                    843:                hf.h_last = va_arg(va, history_gfun_t);
                    844:                hf.h_prev = va_arg(va, history_gfun_t);
                    845:                hf.h_curr = va_arg(va, history_gfun_t);
                    846:                hf.h_set = va_arg(va, history_sfun_t);
                    847:                hf.h_clear = va_arg(va, history_vfun_t);
                    848:                hf.h_enter = va_arg(va, history_efun_t);
                    849:                hf.h_add = va_arg(va, history_efun_t);
1.8       christos  850:
1.16      lukem     851:                if ((retval = history_set_fun(h, &hf)) == -1)
                    852:                        he_seterrev(ev, _HE_PARAM_MISSING);
                    853:                break;
                    854:        }
                    855:
                    856:        case H_END:
                    857:                history_end(h);
                    858:                retval = 0;
                    859:                break;
                    860:
                    861:        default:
                    862:                retval = -1;
                    863:                he_seterrev(ev, _HE_UNKNOWN);
                    864:                break;
                    865:        }
                    866:        va_end(va);
                    867:        return (retval);
1.1       cgd       868: }

CVSweb <webmaster@jp.NetBSD.org>