154219Sbostic /*-
2*61275Sbostic * Copyright (c) 1992, 1993
3*61275Sbostic * The Regents of the University of California. All rights reserved.
454219Sbostic *
554219Sbostic * This code is derived from software contributed to Berkeley by
654219Sbostic * Christos Zoulas of Cornell University.
754219Sbostic *
854219Sbostic * %sccs.include.redist.c%
954219Sbostic */
1054219Sbostic
1154624Schristos #if !defined(lint) && !defined(SCCSID)
12*61275Sbostic static char sccsid[] = "@(#)history.c 8.1 (Berkeley) 06/04/93";
1354624Schristos #endif /* not lint && not SCCSID */
1454219Sbostic
1554219Sbostic /*
1654219Sbostic * hist.c: History access functions
1754219Sbostic */
1854219Sbostic #include "sys.h"
1954219Sbostic
2054219Sbostic #include <string.h>
2154219Sbostic #include <stdlib.h>
2254219Sbostic #if __STDC__
2354219Sbostic #include <stdarg.h>
2454219Sbostic #else
2554219Sbostic #include <varargs.h>
2654219Sbostic #endif
2754219Sbostic
2854249Smarc #include "histedit.h"
2954219Sbostic
3054219Sbostic typedef const HistEvent * (*history_gfun_t) __P((ptr_t));
3154219Sbostic typedef const HistEvent * (*history_efun_t) __P((ptr_t, const char *));
3254219Sbostic
3354219Sbostic struct history {
3454219Sbostic ptr_t h_ref; /* Argument for history fcns */
3554219Sbostic history_gfun_t h_first; /* Get the first element */
3654219Sbostic history_gfun_t h_next; /* Get the next element */
3754219Sbostic history_gfun_t h_last; /* Get the last element */
3854219Sbostic history_gfun_t h_prev; /* Get the previous element */
3954219Sbostic history_gfun_t h_curr; /* Get the current element */
4054219Sbostic history_efun_t h_enter; /* Add an element */
4154219Sbostic history_efun_t h_add; /* Append to an element */
4254219Sbostic };
4354219Sbostic
4454219Sbostic #define HNEXT(h) (*(h)->h_next)((h)->h_ref)
4554219Sbostic #define HFIRST(h) (*(h)->h_first)((h)->h_ref)
4654219Sbostic #define HPREV(h) (*(h)->h_prev)((h)->h_ref)
4754219Sbostic #define HLAST(h) (*(h)->h_last)((h)->h_ref)
4854219Sbostic #define HCURR(h) (*(h)->h_curr)((h)->h_ref)
4954219Sbostic #define HENTER(h, str) (*(h)->h_enter)((h)->h_ref, str)
5054219Sbostic #define HADD(h, str) (*(h)->h_add)((h)->h_ref, str)
5154219Sbostic
5254219Sbostic #define h_malloc(a) malloc(a)
5354219Sbostic #define h_free(a) free(a)
5454219Sbostic
5554219Sbostic
5654219Sbostic private int history_set_num __P((History *, int));
5754219Sbostic private int history_set_fun __P((History *, history_gfun_t,
5854219Sbostic history_gfun_t,
5954219Sbostic history_gfun_t,
6054219Sbostic history_gfun_t,
6154219Sbostic history_gfun_t,
6254219Sbostic history_efun_t,
6354219Sbostic history_efun_t, ptr_t));
6454219Sbostic private const HistEvent *history_prev_event __P((History *, int));
6554219Sbostic private const HistEvent *history_next_event __P((History *, int));
6654219Sbostic private const HistEvent *history_next_string __P((History *, const char *));
6754219Sbostic private const HistEvent *history_prev_string __P((History *, const char *));
6854219Sbostic
6954219Sbostic
7054219Sbostic /***********************************************************************/
7154219Sbostic
7254219Sbostic /*
7354219Sbostic * Builtin- history implementation
7454219Sbostic */
7554219Sbostic typedef struct hentry_t {
7654219Sbostic HistEvent ev; /* What we return */
7754219Sbostic struct hentry_t *next; /* Next entry */
7854219Sbostic struct hentry_t *prev; /* Previous entry */
7954219Sbostic } hentry_t;
8054219Sbostic
8154219Sbostic typedef struct history_t {
8254219Sbostic hentry_t list; /* Fake list header element */
8354219Sbostic hentry_t *cursor; /* Current element in the list */
8454219Sbostic int max; /* Maximum number of events */
8554219Sbostic int cur; /* Current number of events */
8654219Sbostic int eventno; /* Current event number */
8754219Sbostic } history_t;
8854219Sbostic
8954219Sbostic private const HistEvent *history_def_first __P((ptr_t));
9054219Sbostic private const HistEvent *history_def_last __P((ptr_t));
9154219Sbostic private const HistEvent *history_def_next __P((ptr_t));
9254219Sbostic private const HistEvent *history_def_prev __P((ptr_t));
9354219Sbostic private const HistEvent *history_def_curr __P((ptr_t));
9454219Sbostic private const HistEvent *history_def_enter __P((ptr_t, const char *));
9554219Sbostic private const HistEvent *history_def_add __P((ptr_t, const char *));
9654219Sbostic private void history_def_init __P((ptr_t *, int));
9754219Sbostic private void history_def_end __P((ptr_t));
9854219Sbostic private const HistEvent *history_def_insert __P((history_t *, const char *));
9954219Sbostic private void history_def_delete __P((history_t *, hentry_t *));
10054219Sbostic
10154219Sbostic #define history_def_set(p, num) (void) (((history_t *) p)->max = (num))
10254219Sbostic
10354219Sbostic
10454219Sbostic /* history_def_first():
10554219Sbostic * Default function to return the first event in the history.
10654219Sbostic */
10754219Sbostic private const HistEvent *
history_def_first(p)10854219Sbostic history_def_first(p)
10954219Sbostic ptr_t p;
11054219Sbostic {
11154219Sbostic history_t *h = (history_t *) p;
11254219Sbostic h->cursor = h->list.next;
11354219Sbostic if (h->cursor != &h->list)
11454219Sbostic return &h->cursor->ev;
11554219Sbostic else
11654219Sbostic return NULL;
11754219Sbostic }
11854219Sbostic
11954219Sbostic /* history_def_last():
12054219Sbostic * Default function to return the last event in the history.
12154219Sbostic */
12254219Sbostic private const HistEvent *
history_def_last(p)12354219Sbostic history_def_last(p)
12454219Sbostic ptr_t p;
12554219Sbostic {
12654219Sbostic history_t *h = (history_t *) p;
12754219Sbostic h->cursor = h->list.prev;
12854219Sbostic if (h->cursor != &h->list)
12954219Sbostic return &h->cursor->ev;
13054219Sbostic else
13154219Sbostic return NULL;
13254219Sbostic }
13354219Sbostic
13454219Sbostic /* history_def_next():
13554219Sbostic * Default function to return the next event in the history.
13654219Sbostic */
13754219Sbostic private const HistEvent *
history_def_next(p)13854219Sbostic history_def_next(p)
13954219Sbostic ptr_t p;
14054219Sbostic {
14154219Sbostic history_t *h = (history_t *) p;
14254219Sbostic
14354219Sbostic if (h->cursor != &h->list)
14454219Sbostic h->cursor = h->cursor->next;
14554219Sbostic else
14654219Sbostic return NULL;
14754219Sbostic
14854219Sbostic if (h->cursor != &h->list)
14954219Sbostic return &h->cursor->ev;
15054219Sbostic else
15154219Sbostic return NULL;
15254219Sbostic }
15354219Sbostic
15454219Sbostic
15554219Sbostic /* history_def_prev():
15654219Sbostic * Default function to return the previous event in the history.
15754219Sbostic */
15854219Sbostic private const HistEvent *
history_def_prev(p)15954219Sbostic history_def_prev(p)
16054219Sbostic ptr_t p;
16154219Sbostic {
16254219Sbostic history_t *h = (history_t *) p;
16354219Sbostic
16454219Sbostic if (h->cursor != &h->list)
16554219Sbostic h->cursor = h->cursor->prev;
16654219Sbostic else
16754219Sbostic return NULL;
16854219Sbostic
16954219Sbostic if (h->cursor != &h->list)
17054219Sbostic return &h->cursor->ev;
17154219Sbostic else
17254219Sbostic return NULL;
17354219Sbostic }
17454219Sbostic
17554219Sbostic
17654219Sbostic /* history_def_curr():
17754219Sbostic * Default function to return the current event in the history.
17854219Sbostic */
17954219Sbostic private const HistEvent *
history_def_curr(p)18054219Sbostic history_def_curr(p)
18154219Sbostic ptr_t p;
18254219Sbostic {
18354219Sbostic history_t *h = (history_t *) p;
18454219Sbostic
18554219Sbostic if (h->cursor != &h->list)
18654219Sbostic return &h->cursor->ev;
18754219Sbostic else
18854219Sbostic return NULL;
18954219Sbostic }
19054219Sbostic
19154219Sbostic
19254219Sbostic /* history_def_add():
19354219Sbostic * Append string to element
19454219Sbostic */
19554219Sbostic private const HistEvent *
history_def_add(p,str)19654219Sbostic history_def_add(p, str)
19754219Sbostic ptr_t p;
19854219Sbostic const char *str;
19954219Sbostic {
20054219Sbostic history_t *h = (history_t *) p;
20154219Sbostic size_t len;
20254219Sbostic char *s;
20354219Sbostic
20454219Sbostic if (h->cursor == &h->list)
20554219Sbostic return (history_def_enter(p, str));
20654219Sbostic len = strlen(h->cursor->ev.str) + strlen(str) + 1;
20754219Sbostic s = (char *) h_malloc(len);
20854219Sbostic (void) strcpy(s, h->cursor->ev.str);
20954219Sbostic (void) strcat(s, str);
21054219Sbostic h_free((ptr_t) h->cursor->ev.str);
21154219Sbostic h->cursor->ev.str = s;
21254219Sbostic return &h->cursor->ev;
21354219Sbostic }
21454219Sbostic
21554219Sbostic
21654219Sbostic /* history_def_delete():
21754219Sbostic * Delete element hp of the h list
21854219Sbostic */
21954219Sbostic private void
history_def_delete(h,hp)22054219Sbostic history_def_delete(h, hp)
22154219Sbostic history_t *h;
22254219Sbostic hentry_t *hp;
22354219Sbostic {
22454219Sbostic if (hp == &h->list)
22554219Sbostic abort();
22654219Sbostic hp->prev->next = hp->next;
22754219Sbostic hp->next->prev = hp->prev;
22854219Sbostic h_free((ptr_t) hp->ev.str);
22954219Sbostic h_free(hp);
23054219Sbostic h->cur--;
23154219Sbostic }
23254219Sbostic
23354219Sbostic
23454219Sbostic /* history_def_insert():
23554219Sbostic * Insert element with string str in the h list
23654219Sbostic */
23754219Sbostic private const HistEvent *
history_def_insert(h,str)23854219Sbostic history_def_insert(h, str)
23954219Sbostic history_t *h;
24054219Sbostic const char *str;
24154219Sbostic {
24254219Sbostic h->cursor = (hentry_t *) h_malloc(sizeof(hentry_t));
24354219Sbostic h->cursor->ev.str = strdup(str);
24454219Sbostic h->cursor->next = h->list.next;
24554219Sbostic h->cursor->prev = &h->list;
24654219Sbostic h->list.next->prev = h->cursor;
24754219Sbostic h->list.next = h->cursor;
24854219Sbostic h->cur++;
24954219Sbostic
25054219Sbostic return &h->cursor->ev;
25154219Sbostic }
25254219Sbostic
25354219Sbostic
25454219Sbostic /* history_def_enter():
25554219Sbostic * Default function to enter an item in the history
25654219Sbostic */
25754219Sbostic private const HistEvent *
history_def_enter(p,str)25854219Sbostic history_def_enter(p, str)
25954219Sbostic ptr_t p;
26054219Sbostic const char *str;
26154219Sbostic {
26254219Sbostic history_t *h = (history_t *) p;
26354219Sbostic const HistEvent *ev;
26454219Sbostic
26554219Sbostic
26654219Sbostic ev = history_def_insert(h, str);
26754219Sbostic ((HistEvent*) ev)->num = ++h->eventno;
26854219Sbostic
26954219Sbostic /*
27054219Sbostic * Always keep at least one entry.
27154219Sbostic * This way we don't have to check for the empty list.
27254219Sbostic */
27354219Sbostic while (h->cur > h->max + 1)
27454219Sbostic history_def_delete(h, h->list.prev);
27554219Sbostic return ev;
27654219Sbostic }
27754219Sbostic
27854219Sbostic
27954219Sbostic /* history_def_init():
28054219Sbostic * Default history initialization function
28154219Sbostic */
28254219Sbostic private void
history_def_init(p,n)28354219Sbostic history_def_init(p, n)
28454219Sbostic ptr_t *p;
28554219Sbostic int n;
28654219Sbostic {
28754219Sbostic history_t *h = (history_t *) h_malloc(sizeof(history_t));
28854219Sbostic if (n <= 0)
28954219Sbostic n = 0;
29054219Sbostic h->eventno = 0;
29154219Sbostic h->cur = 0;
29254219Sbostic h->max = n;
29354219Sbostic h->list.next = h->list.prev = &h->list;
29454219Sbostic h->list.ev.str = NULL;
29554219Sbostic h->list.ev.num = 0;
29654219Sbostic h->cursor = &h->list;
29754219Sbostic *p = (ptr_t) h;
29854219Sbostic }
29954219Sbostic
30054219Sbostic
30154219Sbostic /* history_def_end():
30254219Sbostic * Default history cleanup function
30354219Sbostic */
30454219Sbostic private void
history_def_end(p)30554219Sbostic history_def_end(p)
30654219Sbostic ptr_t p;
30754219Sbostic {
30854219Sbostic history_t *h = (history_t *) p;
30954219Sbostic
31054219Sbostic while (h->list.prev != &h->list)
31154219Sbostic history_def_delete(h, h->list.prev);
31254219Sbostic }
31354219Sbostic
31454219Sbostic /************************************************************************/
31554219Sbostic
31654219Sbostic /* history_init():
31754219Sbostic * Initialization function.
31854219Sbostic */
31954219Sbostic public History *
history_init()32054219Sbostic history_init()
32154219Sbostic {
32254219Sbostic History *h = (History *) h_malloc(sizeof(History));
32354219Sbostic
32454219Sbostic history_def_init(&h->h_ref, 0);
32554219Sbostic
32654219Sbostic h->h_next = history_def_next;
32754219Sbostic h->h_first = history_def_first;
32854219Sbostic h->h_last = history_def_last;
32954219Sbostic h->h_prev = history_def_prev;
33054219Sbostic h->h_curr = history_def_curr;
33154219Sbostic h->h_enter = history_def_enter;
33254219Sbostic h->h_add = history_def_add;
33354219Sbostic
33454219Sbostic return h;
33554219Sbostic }
33654219Sbostic
33754219Sbostic
33854219Sbostic /* history_end():
33954219Sbostic * clean up history;
34054219Sbostic */
34154219Sbostic public void
history_end(h)34254219Sbostic history_end(h)
34354219Sbostic History *h;
34454219Sbostic {
34554219Sbostic if (h->h_next == history_def_next)
34654219Sbostic history_def_end(h->h_ref);
34754219Sbostic }
34854219Sbostic
34954219Sbostic
35054219Sbostic
35154219Sbostic /* history_set_num():
35254219Sbostic * Set history number of events
35354219Sbostic */
35454219Sbostic private int
history_set_num(h,num)35554219Sbostic history_set_num(h, num)
35654219Sbostic History *h;
35754219Sbostic int num;
35854219Sbostic {
35954219Sbostic if (h->h_next != history_def_next || num < 0)
36054219Sbostic return -1;
36154219Sbostic history_def_set(h->h_ref, num);
36254219Sbostic return 0;
36354219Sbostic }
36454219Sbostic
36554219Sbostic
36654219Sbostic /* history_set_fun():
36754219Sbostic * Set history functions
36854219Sbostic */
36954219Sbostic private int
history_set_fun(h,first,next,last,prev,curr,enter,add,ptr)37054219Sbostic history_set_fun(h, first, next, last, prev, curr, enter, add, ptr)
37154219Sbostic History *h;
37254219Sbostic history_gfun_t first, next, last, prev, curr;
37354219Sbostic history_efun_t enter, add;
37454219Sbostic ptr_t ptr;
37554219Sbostic {
37654219Sbostic if (first == NULL || next == NULL ||
37754219Sbostic last == NULL || prev == NULL || curr == NULL ||
37854219Sbostic enter == NULL || add == NULL ||
37954219Sbostic ptr == NULL ) {
38054219Sbostic if (h->h_next != history_def_next) {
38154219Sbostic history_def_init(&h->h_ref, 0);
38254219Sbostic h->h_first = history_def_first;
38354219Sbostic h->h_next = history_def_next;
38454219Sbostic h->h_last = history_def_last;
38554219Sbostic h->h_prev = history_def_prev;
38654219Sbostic h->h_curr = history_def_curr;
38754219Sbostic h->h_enter = history_def_enter;
38854219Sbostic h->h_add = history_def_add;
38954219Sbostic }
39054219Sbostic return -1;
39154219Sbostic }
39254219Sbostic
39354219Sbostic if (h->h_next == history_def_next)
39454219Sbostic history_def_end(h->h_ref);
39554219Sbostic
39654219Sbostic h->h_next = next;
39754219Sbostic h->h_first = first;
39854219Sbostic h->h_enter = enter;
39954219Sbostic h->h_add = add;
40054219Sbostic return 0;
40154219Sbostic }
40254219Sbostic
40354219Sbostic
40454219Sbostic /* history_prev_event():
40554219Sbostic * Find the previous event, with number given
40654219Sbostic */
40754219Sbostic private const HistEvent *
history_prev_event(h,num)40854219Sbostic history_prev_event(h, num)
40954219Sbostic History *h;
41054219Sbostic int num;
41154219Sbostic {
41254219Sbostic const HistEvent *ev;
41354219Sbostic for (ev = HCURR(h); ev != NULL; ev = HPREV(h))
41454219Sbostic if (ev->num == num)
41554219Sbostic return ev;
41654219Sbostic return NULL;
41754219Sbostic }
41854219Sbostic
41954219Sbostic
42054219Sbostic /* history_next_event():
42154219Sbostic * Find the next event, with number given
42254219Sbostic */
42354219Sbostic private const HistEvent *
history_next_event(h,num)42454219Sbostic history_next_event(h, num)
42554219Sbostic History *h;
42654219Sbostic int num;
42754219Sbostic {
42854219Sbostic const HistEvent *ev;
42954219Sbostic for (ev = HCURR(h); ev != NULL; ev = HNEXT(h))
43054219Sbostic if (ev->num == num)
43154219Sbostic return ev;
43254219Sbostic return NULL;
43354219Sbostic }
43454219Sbostic
43554219Sbostic
43654219Sbostic /* history_prev_string():
43754219Sbostic * Find the previous event beginning with string
43854219Sbostic */
43954219Sbostic private const HistEvent *
history_prev_string(h,str)44054219Sbostic history_prev_string(h, str)
44154219Sbostic History *h;
44254219Sbostic const char* str;
44354219Sbostic {
44454219Sbostic const HistEvent *ev;
44554219Sbostic size_t len = strlen(str);
44654219Sbostic
44754219Sbostic for (ev = HCURR(h); ev != NULL; ev = HNEXT(h))
44854219Sbostic if (strncmp(str, ev->str, len) == 0)
44954219Sbostic return ev;
45054219Sbostic return NULL;
45154219Sbostic }
45254219Sbostic
45354219Sbostic
45454219Sbostic /* history_next_string():
45554219Sbostic * Find the next event beginning with string
45654219Sbostic */
45754219Sbostic private const HistEvent *
history_next_string(h,str)45854219Sbostic history_next_string(h, str)
45954219Sbostic History *h;
46054219Sbostic const char* str;
46154219Sbostic {
46254219Sbostic const HistEvent *ev;
46354219Sbostic size_t len = strlen(str);
46454219Sbostic
46554219Sbostic for (ev = HCURR(h); ev != NULL; ev = HPREV(h))
46654219Sbostic if (strncmp(str, ev->str, len) == 0)
46754219Sbostic return ev;
46854219Sbostic return NULL;
46954219Sbostic }
47054219Sbostic
47154219Sbostic
47254219Sbostic /* history():
47354219Sbostic * User interface to history functions.
47454219Sbostic */
47554219Sbostic const HistEvent *
47654219Sbostic #if __STDC__
history(History * h,int fun,...)47754219Sbostic history(History *h, int fun, ...)
47854219Sbostic #else
47954219Sbostic history(va_alist)
48054219Sbostic va_dcl
48154219Sbostic #endif
48254219Sbostic {
48354219Sbostic va_list va;
48455353Schristos const HistEvent *ev = NULL;
48554219Sbostic const char *str;
48654219Sbostic static const HistEvent sev = { 0, "" };
48754219Sbostic
48854219Sbostic #if __STDC__
48954219Sbostic va_start(va, fun);
49054219Sbostic #else
49154219Sbostic History *h;
49254219Sbostic int fun;
49354219Sbostic va_start(va);
49454219Sbostic h = va_arg(va, History *);
49554219Sbostic fun = va_arg(va, int);
49654219Sbostic #endif
49754219Sbostic
49854219Sbostic switch (fun) {
49954219Sbostic case H_ADD:
50054219Sbostic str = va_arg(va, const char *);
50154219Sbostic ev = HADD(h, str);
50254219Sbostic break;
50354219Sbostic
50454219Sbostic case H_ENTER:
50554219Sbostic str = va_arg(va, const char *);
50654219Sbostic ev = HENTER(h, str);
50754219Sbostic break;
50854219Sbostic
50954219Sbostic case H_FIRST:
51054219Sbostic ev = HFIRST(h);
51154219Sbostic break;
51254219Sbostic
51354219Sbostic case H_NEXT:
51454219Sbostic ev = HNEXT(h);
51554219Sbostic break;
51654219Sbostic
51754219Sbostic case H_LAST:
51854219Sbostic ev = HLAST(h);
51954219Sbostic break;
52054219Sbostic
52154219Sbostic case H_PREV:
52254219Sbostic ev = HPREV(h);
52354219Sbostic break;
52454219Sbostic
52554219Sbostic case H_CURR:
52654219Sbostic ev = HCURR(h);
52754219Sbostic break;
52854219Sbostic
52954219Sbostic case H_PREV_EVENT:
53054219Sbostic ev = history_prev_event(h, va_arg(va, int));
53154219Sbostic break;
53254219Sbostic
53354219Sbostic case H_NEXT_EVENT:
53454219Sbostic ev = history_next_event(h, va_arg(va, int));
53554219Sbostic break;
53654219Sbostic
53754219Sbostic case H_PREV_STR:
53854219Sbostic ev = history_prev_string(h, va_arg(va, const char*));
53954219Sbostic break;
54054219Sbostic
54154219Sbostic case H_NEXT_STR:
54254219Sbostic ev = history_next_string(h, va_arg(va, const char*));
54354219Sbostic break;
54454219Sbostic
54554219Sbostic case H_EVENT:
54654219Sbostic if (history_set_num(h, va_arg(va, int)) == 0)
54754219Sbostic ev = &sev;
54854219Sbostic break;
54954219Sbostic
55054219Sbostic case H_FUNC:
55154219Sbostic {
55254219Sbostic history_gfun_t first = va_arg(va, history_gfun_t);
55354219Sbostic history_gfun_t next = va_arg(va, history_gfun_t);
55454219Sbostic history_gfun_t last = va_arg(va, history_gfun_t);
55554219Sbostic history_gfun_t prev = va_arg(va, history_gfun_t);
55654219Sbostic history_gfun_t curr = va_arg(va, history_gfun_t);
55754219Sbostic history_efun_t enter = va_arg(va, history_efun_t);
55854219Sbostic history_efun_t add = va_arg(va, history_efun_t);
55954219Sbostic ptr_t ptr = va_arg(va, ptr_t);
56054219Sbostic
56154219Sbostic if (history_set_fun(h, first, next, last, prev,
56254219Sbostic curr, enter, add, ptr) == 0)
56354219Sbostic ev = &sev;
56454219Sbostic }
56554219Sbostic break;
56654219Sbostic
56754219Sbostic case H_END:
56854219Sbostic history_end(h);
56954219Sbostic break;
57054219Sbostic
57154219Sbostic default:
57254219Sbostic break;
57354219Sbostic }
57454219Sbostic va_end(va);
57554219Sbostic return ev;
57654219Sbostic }
577