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

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

CVSweb <webmaster@jp.NetBSD.org>