summaryrefslogtreecommitdiff
path: root/lib/libedit/history.c
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
commitd6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch)
treeece253b876159b39c620e62b6c9b1174642e070e /lib/libedit/history.c
initial import of NetBSD tree
Diffstat (limited to 'lib/libedit/history.c')
-rw-r--r--lib/libedit/history.c602
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;
+}