diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
commit | d6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch) | |
tree | ece253b876159b39c620e62b6c9b1174642e070e /lib/libedit/history.c |
initial import of NetBSD tree
Diffstat (limited to 'lib/libedit/history.c')
-rw-r--r-- | lib/libedit/history.c | 602 |
1 files changed, 602 insertions, 0 deletions
diff --git a/lib/libedit/history.c b/lib/libedit/history.c new file mode 100644 index 00000000000..e8665481977 --- /dev/null +++ b/lib/libedit/history.c @@ -0,0 +1,602 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Christos Zoulas of Cornell University. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if !defined(lint) && !defined(SCCSID) +static char sccsid[] = "@(#)history.c 8.1 (Berkeley) 6/4/93"; +#endif /* not lint && not SCCSID */ + +/* + * hist.c: History access functions + */ +#include "sys.h" + +#include <string.h> +#include <stdlib.h> +#if __STDC__ +#include <stdarg.h> +#else +#include <varargs.h> +#endif + +#include "histedit.h" + +typedef const HistEvent * (*history_gfun_t) __P((ptr_t)); +typedef const HistEvent * (*history_efun_t) __P((ptr_t, const char *)); + +struct history { + ptr_t h_ref; /* Argument for history fcns */ + history_gfun_t h_first; /* Get the first element */ + history_gfun_t h_next; /* Get the next element */ + history_gfun_t h_last; /* Get the last element */ + history_gfun_t h_prev; /* Get the previous element */ + history_gfun_t h_curr; /* Get the current element */ + history_efun_t h_enter; /* Add an element */ + history_efun_t h_add; /* Append to an element */ +}; + +#define HNEXT(h) (*(h)->h_next)((h)->h_ref) +#define HFIRST(h) (*(h)->h_first)((h)->h_ref) +#define HPREV(h) (*(h)->h_prev)((h)->h_ref) +#define HLAST(h) (*(h)->h_last)((h)->h_ref) +#define HCURR(h) (*(h)->h_curr)((h)->h_ref) +#define HENTER(h, str) (*(h)->h_enter)((h)->h_ref, str) +#define HADD(h, str) (*(h)->h_add)((h)->h_ref, str) + +#define h_malloc(a) malloc(a) +#define h_free(a) free(a) + + +private int history_set_num __P((History *, int)); +private int history_set_fun __P((History *, history_gfun_t, + history_gfun_t, + history_gfun_t, + history_gfun_t, + history_gfun_t, + history_efun_t, + history_efun_t, ptr_t)); +private const HistEvent *history_prev_event __P((History *, int)); +private const HistEvent *history_next_event __P((History *, int)); +private const HistEvent *history_next_string __P((History *, const char *)); +private const HistEvent *history_prev_string __P((History *, const char *)); + + +/***********************************************************************/ + +/* + * Builtin- history implementation + */ +typedef struct hentry_t { + HistEvent ev; /* What we return */ + struct hentry_t *next; /* Next entry */ + struct hentry_t *prev; /* Previous entry */ +} hentry_t; + +typedef struct history_t { + hentry_t list; /* Fake list header element */ + hentry_t *cursor; /* Current element in the list */ + int max; /* Maximum number of events */ + int cur; /* Current number of events */ + int eventno; /* Current event number */ +} history_t; + +private const HistEvent *history_def_first __P((ptr_t)); +private const HistEvent *history_def_last __P((ptr_t)); +private const HistEvent *history_def_next __P((ptr_t)); +private const HistEvent *history_def_prev __P((ptr_t)); +private const HistEvent *history_def_curr __P((ptr_t)); +private const HistEvent *history_def_enter __P((ptr_t, const char *)); +private const HistEvent *history_def_add __P((ptr_t, const char *)); +private void history_def_init __P((ptr_t *, int)); +private void history_def_end __P((ptr_t)); +private const HistEvent *history_def_insert __P((history_t *, const char *)); +private void history_def_delete __P((history_t *, hentry_t *)); + +#define history_def_set(p, num) (void) (((history_t *) p)->max = (num)) + + +/* history_def_first(): + * Default function to return the first event in the history. + */ +private const HistEvent * +history_def_first(p) + ptr_t p; +{ + history_t *h = (history_t *) p; + h->cursor = h->list.next; + if (h->cursor != &h->list) + return &h->cursor->ev; + else + return NULL; +} + +/* history_def_last(): + * Default function to return the last event in the history. + */ +private const HistEvent * +history_def_last(p) + ptr_t p; +{ + history_t *h = (history_t *) p; + h->cursor = h->list.prev; + if (h->cursor != &h->list) + return &h->cursor->ev; + else + return NULL; +} + +/* history_def_next(): + * Default function to return the next event in the history. + */ +private const HistEvent * +history_def_next(p) + ptr_t p; +{ + history_t *h = (history_t *) p; + + if (h->cursor != &h->list) + h->cursor = h->cursor->next; + else + return NULL; + + if (h->cursor != &h->list) + return &h->cursor->ev; + else + return NULL; +} + + +/* history_def_prev(): + * Default function to return the previous event in the history. + */ +private const HistEvent * +history_def_prev(p) + ptr_t p; +{ + history_t *h = (history_t *) p; + + if (h->cursor != &h->list) + h->cursor = h->cursor->prev; + else + return NULL; + + if (h->cursor != &h->list) + return &h->cursor->ev; + else + return NULL; +} + + +/* history_def_curr(): + * Default function to return the current event in the history. + */ +private const HistEvent * +history_def_curr(p) + ptr_t p; +{ + history_t *h = (history_t *) p; + + if (h->cursor != &h->list) + return &h->cursor->ev; + else + return NULL; +} + + +/* history_def_add(): + * Append string to element + */ +private const HistEvent * +history_def_add(p, str) + ptr_t p; + const char *str; +{ + history_t *h = (history_t *) p; + size_t len; + char *s; + + if (h->cursor == &h->list) + return (history_def_enter(p, str)); + len = strlen(h->cursor->ev.str) + strlen(str) + 1; + s = (char *) h_malloc(len); + (void) strcpy(s, h->cursor->ev.str); + (void) strcat(s, str); + h_free((ptr_t) h->cursor->ev.str); + h->cursor->ev.str = s; + return &h->cursor->ev; +} + + +/* history_def_delete(): + * Delete element hp of the h list + */ +private void +history_def_delete(h, hp) + history_t *h; + hentry_t *hp; +{ + if (hp == &h->list) + abort(); + hp->prev->next = hp->next; + hp->next->prev = hp->prev; + h_free((ptr_t) hp->ev.str); + h_free(hp); + h->cur--; +} + + +/* history_def_insert(): + * Insert element with string str in the h list + */ +private const HistEvent * +history_def_insert(h, str) + history_t *h; + const char *str; +{ + h->cursor = (hentry_t *) h_malloc(sizeof(hentry_t)); + h->cursor->ev.str = strdup(str); + h->cursor->next = h->list.next; + h->cursor->prev = &h->list; + h->list.next->prev = h->cursor; + h->list.next = h->cursor; + h->cur++; + + return &h->cursor->ev; +} + + +/* history_def_enter(): + * Default function to enter an item in the history + */ +private const HistEvent * +history_def_enter(p, str) + ptr_t p; + const char *str; +{ + history_t *h = (history_t *) p; + const HistEvent *ev; + + + ev = history_def_insert(h, str); + ((HistEvent*) ev)->num = ++h->eventno; + + /* + * Always keep at least one entry. + * This way we don't have to check for the empty list. + */ + while (h->cur > h->max + 1) + history_def_delete(h, h->list.prev); + return ev; +} + + +/* history_def_init(): + * Default history initialization function + */ +private void +history_def_init(p, n) + ptr_t *p; + int n; +{ + history_t *h = (history_t *) h_malloc(sizeof(history_t)); + if (n <= 0) + n = 0; + h->eventno = 0; + h->cur = 0; + h->max = n; + h->list.next = h->list.prev = &h->list; + h->list.ev.str = NULL; + h->list.ev.num = 0; + h->cursor = &h->list; + *p = (ptr_t) h; +} + + +/* history_def_end(): + * Default history cleanup function + */ +private void +history_def_end(p) + ptr_t p; +{ + history_t *h = (history_t *) p; + + while (h->list.prev != &h->list) + history_def_delete(h, h->list.prev); +} + +/************************************************************************/ + +/* history_init(): + * Initialization function. + */ +public History * +history_init() +{ + History *h = (History *) h_malloc(sizeof(History)); + + history_def_init(&h->h_ref, 0); + + h->h_next = history_def_next; + h->h_first = history_def_first; + h->h_last = history_def_last; + h->h_prev = history_def_prev; + h->h_curr = history_def_curr; + h->h_enter = history_def_enter; + h->h_add = history_def_add; + + return h; +} + + +/* history_end(): + * clean up history; + */ +public void +history_end(h) + History *h; +{ + if (h->h_next == history_def_next) + history_def_end(h->h_ref); +} + + + +/* history_set_num(): + * Set history number of events + */ +private int +history_set_num(h, num) + History *h; + int num; +{ + if (h->h_next != history_def_next || num < 0) + return -1; + history_def_set(h->h_ref, num); + return 0; +} + + +/* history_set_fun(): + * Set history functions + */ +private int +history_set_fun(h, first, next, last, prev, curr, enter, add, ptr) + History *h; + history_gfun_t first, next, last, prev, curr; + history_efun_t enter, add; + ptr_t ptr; +{ + if (first == NULL || next == NULL || + last == NULL || prev == NULL || curr == NULL || + enter == NULL || add == NULL || + ptr == NULL ) { + if (h->h_next != history_def_next) { + history_def_init(&h->h_ref, 0); + h->h_first = history_def_first; + h->h_next = history_def_next; + h->h_last = history_def_last; + h->h_prev = history_def_prev; + h->h_curr = history_def_curr; + h->h_enter = history_def_enter; + h->h_add = history_def_add; + } + return -1; + } + + if (h->h_next == history_def_next) + history_def_end(h->h_ref); + + h->h_next = next; + h->h_first = first; + h->h_enter = enter; + h->h_add = add; + return 0; +} + + +/* history_prev_event(): + * Find the previous event, with number given + */ +private const HistEvent * +history_prev_event(h, num) + History *h; + int num; +{ + const HistEvent *ev; + for (ev = HCURR(h); ev != NULL; ev = HPREV(h)) + if (ev->num == num) + return ev; + return NULL; +} + + +/* history_next_event(): + * Find the next event, with number given + */ +private const HistEvent * +history_next_event(h, num) + History *h; + int num; +{ + const HistEvent *ev; + for (ev = HCURR(h); ev != NULL; ev = HNEXT(h)) + if (ev->num == num) + return ev; + return NULL; +} + + +/* history_prev_string(): + * Find the previous event beginning with string + */ +private const HistEvent * +history_prev_string(h, str) + History *h; + const char* str; +{ + const HistEvent *ev; + size_t len = strlen(str); + + for (ev = HCURR(h); ev != NULL; ev = HNEXT(h)) + if (strncmp(str, ev->str, len) == 0) + return ev; + return NULL; +} + + +/* history_next_string(): + * Find the next event beginning with string + */ +private const HistEvent * +history_next_string(h, str) + History *h; + const char* str; +{ + const HistEvent *ev; + size_t len = strlen(str); + + for (ev = HCURR(h); ev != NULL; ev = HPREV(h)) + if (strncmp(str, ev->str, len) == 0) + return ev; + return NULL; +} + + +/* history(): + * User interface to history functions. + */ +const HistEvent * +#if __STDC__ +history(History *h, int fun, ...) +#else +history(va_alist) + va_dcl +#endif +{ + va_list va; + const HistEvent *ev = NULL; + const char *str; + static const HistEvent sev = { 0, "" }; + +#if __STDC__ + va_start(va, fun); +#else + History *h; + int fun; + va_start(va); + h = va_arg(va, History *); + fun = va_arg(va, int); +#endif + + switch (fun) { + case H_ADD: + str = va_arg(va, const char *); + ev = HADD(h, str); + break; + + case H_ENTER: + str = va_arg(va, const char *); + ev = HENTER(h, str); + break; + + case H_FIRST: + ev = HFIRST(h); + break; + + case H_NEXT: + ev = HNEXT(h); + break; + + case H_LAST: + ev = HLAST(h); + break; + + case H_PREV: + ev = HPREV(h); + break; + + case H_CURR: + ev = HCURR(h); + break; + + case H_PREV_EVENT: + ev = history_prev_event(h, va_arg(va, int)); + break; + + case H_NEXT_EVENT: + ev = history_next_event(h, va_arg(va, int)); + break; + + case H_PREV_STR: + ev = history_prev_string(h, va_arg(va, const char*)); + break; + + case H_NEXT_STR: + ev = history_next_string(h, va_arg(va, const char*)); + break; + + case H_EVENT: + if (history_set_num(h, va_arg(va, int)) == 0) + ev = &sev; + break; + + case H_FUNC: + { + history_gfun_t first = va_arg(va, history_gfun_t); + history_gfun_t next = va_arg(va, history_gfun_t); + history_gfun_t last = va_arg(va, history_gfun_t); + history_gfun_t prev = va_arg(va, history_gfun_t); + history_gfun_t curr = va_arg(va, history_gfun_t); + history_efun_t enter = va_arg(va, history_efun_t); + history_efun_t add = va_arg(va, history_efun_t); + ptr_t ptr = va_arg(va, ptr_t); + + if (history_set_fun(h, first, next, last, prev, + curr, enter, add, ptr) == 0) + ev = &sev; + } + break; + + case H_END: + history_end(h); + break; + + default: + break; + } + va_end(va); + return ev; +} |