2 * Copyright (c) 1992, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Christos Zoulas of Cornell University.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 #if !defined(lint) && !defined(SCCSID)
38 static char sccsid[] = "@(#)history.c 8.1 (Berkeley) 6/4/93";
39 #endif /* not lint && not SCCSID */
42 * hist.c: History access functions
54 static const char hist_cookie[] = "_HiStOrY_V1_\n";
58 typedef const HistEvent * (*history_gfun_t) __P((ptr_t));
59 typedef const HistEvent * (*history_efun_t) __P((ptr_t, const char *));
60 typedef void (*history_vfun_t) __P((ptr_t));
63 ptr_t h_ref; /* Argument for history fcns */
64 history_gfun_t h_first; /* Get the first element */
65 history_gfun_t h_next; /* Get the next element */
66 history_gfun_t h_last; /* Get the last element */
67 history_gfun_t h_prev; /* Get the previous element */
68 history_gfun_t h_curr; /* Get the current element */
69 history_vfun_t h_clear; /* Clear the history list */
70 history_efun_t h_enter; /* Add an element */
71 history_efun_t h_add; /* Append to an element */
74 #define HNEXT(h) (*(h)->h_next)((h)->h_ref)
75 #define HFIRST(h) (*(h)->h_first)((h)->h_ref)
76 #define HPREV(h) (*(h)->h_prev)((h)->h_ref)
77 #define HLAST(h) (*(h)->h_last)((h)->h_ref)
78 #define HCURR(h) (*(h)->h_curr)((h)->h_ref)
79 #define HCLEAR(h) (*(h)->h_clear)((h)->h_ref)
80 #define HENTER(h, str) (*(h)->h_enter)((h)->h_ref, str)
81 #define HADD(h, str) (*(h)->h_add)((h)->h_ref, str)
83 #define h_malloc(a) malloc(a)
84 #define h_free(a) free(a)
87 private int history_set_num __P((History *, int));
88 private int history_set_fun __P((History *, History *));
89 private int history_load __P((History *, const char *));
90 private int history_save __P((History *, const char *));
91 private const HistEvent *history_prev_event __P((History *, int));
92 private const HistEvent *history_next_event __P((History *, int));
93 private const HistEvent *history_next_string __P((History *, const char *));
94 private const HistEvent *history_prev_string __P((History *, const char *));
97 /***********************************************************************/
100 * Builtin- history implementation
102 typedef struct hentry_t {
103 HistEvent ev; /* What we return */
104 struct hentry_t *next; /* Next entry */
105 struct hentry_t *prev; /* Previous entry */
108 typedef struct history_t {
109 hentry_t list; /* Fake list header element */
110 hentry_t *cursor; /* Current element in the list */
111 int max; /* Maximum number of events */
112 int cur; /* Current number of events */
113 int eventno; /* Current event number */
116 private const HistEvent *history_def_first __P((ptr_t));
117 private const HistEvent *history_def_last __P((ptr_t));
118 private const HistEvent *history_def_next __P((ptr_t));
119 private const HistEvent *history_def_prev __P((ptr_t));
120 private const HistEvent *history_def_curr __P((ptr_t));
121 private const HistEvent *history_def_enter __P((ptr_t, const char *));
122 private const HistEvent *history_def_add __P((ptr_t, const char *));
123 private void history_def_init __P((ptr_t *, int));
124 private void history_def_clear __P((ptr_t));
125 private const HistEvent *history_def_insert __P((history_t *, const char *));
126 private void history_def_delete __P((history_t *, hentry_t *));
128 #define history_def_set(p, num) (void) (((history_t *) p)->max = (num))
131 /* history_def_first():
132 * Default function to return the first event in the history.
134 private const HistEvent *
138 history_t *h = (history_t *) p;
139 h->cursor = h->list.next;
140 if (h->cursor != &h->list)
141 return &h->cursor->ev;
146 /* history_def_last():
147 * Default function to return the last event in the history.
149 private const HistEvent *
153 history_t *h = (history_t *) p;
154 h->cursor = h->list.prev;
155 if (h->cursor != &h->list)
156 return &h->cursor->ev;
161 /* history_def_next():
162 * Default function to return the next event in the history.
164 private const HistEvent *
168 history_t *h = (history_t *) p;
170 if (h->cursor != &h->list)
171 h->cursor = h->cursor->next;
175 if (h->cursor != &h->list)
176 return &h->cursor->ev;
182 /* history_def_prev():
183 * Default function to return the previous event in the history.
185 private const HistEvent *
189 history_t *h = (history_t *) p;
191 if (h->cursor != &h->list)
192 h->cursor = h->cursor->prev;
196 if (h->cursor != &h->list)
197 return &h->cursor->ev;
203 /* history_def_curr():
204 * Default function to return the current event in the history.
206 private const HistEvent *
210 history_t *h = (history_t *) p;
212 if (h->cursor != &h->list)
213 return &h->cursor->ev;
219 /* history_def_add():
220 * Append string to element
222 private const HistEvent *
223 history_def_add(p, str)
227 history_t *h = (history_t *) p;
231 if (h->cursor == &h->list)
232 return (history_def_enter(p, str));
233 len = strlen(h->cursor->ev.str) + strlen(str) + 1;
234 s = (char *) h_malloc(len);
235 (void)strcpy(s, h->cursor->ev.str); /* XXX strcpy is safe */
236 (void)strcat(s, str); /* XXX strcat is safe */
237 h_free((ptr_t) h->cursor->ev.str);
238 h->cursor->ev.str = s;
239 return &h->cursor->ev;
243 /* history_def_delete():
244 * Delete element hp of the h list
247 history_def_delete(h, hp)
253 hp->prev->next = hp->next;
254 hp->next->prev = hp->prev;
255 h_free((ptr_t) hp->ev.str);
261 /* history_def_insert():
262 * Insert element with string str in the h list
264 private const HistEvent *
265 history_def_insert(h, str)
269 h->cursor = (hentry_t *) h_malloc(sizeof(hentry_t));
270 h->cursor->ev.str = strdup(str);
271 h->cursor->next = h->list.next;
272 h->cursor->prev = &h->list;
273 h->list.next->prev = h->cursor;
274 h->list.next = h->cursor;
277 return &h->cursor->ev;
281 /* history_def_enter():
282 * Default function to enter an item in the history
284 private const HistEvent *
285 history_def_enter(p, str)
289 history_t *h = (history_t *) p;
293 ev = history_def_insert(h, str);
294 ((HistEvent*) ev)->num = ++h->eventno;
297 * Always keep at least one entry.
298 * This way we don't have to check for the empty list.
300 while (h->cur > h->max + 1)
301 history_def_delete(h, h->list.prev);
306 /* history_def_init():
307 * Default history initialization function
310 history_def_init(p, n)
314 history_t *h = (history_t *) h_malloc(sizeof(history_t));
320 h->list.next = h->list.prev = &h->list;
321 h->list.ev.str = NULL;
323 h->cursor = &h->list;
328 /* history_def_clear():
329 * Default history cleanup function
335 history_t *h = (history_t *) p;
337 while (h->list.prev != &h->list)
338 history_def_delete(h, h->list.prev);
343 /************************************************************************/
346 * Initialization function.
351 History *h = (History *) h_malloc(sizeof(History));
353 history_def_init(&h->h_ref, 0);
355 h->h_next = history_def_next;
356 h->h_first = history_def_first;
357 h->h_last = history_def_last;
358 h->h_prev = history_def_prev;
359 h->h_curr = history_def_curr;
360 h->h_clear = history_def_clear;
361 h->h_enter = history_def_enter;
362 h->h_add = history_def_add;
375 if (h->h_next == history_def_next)
376 history_def_clear(h->h_ref);
381 /* history_set_num():
382 * Set history number of events
385 history_set_num(h, num)
389 if (h->h_next != history_def_next || num < 0)
391 history_def_set(h->h_ref, num);
396 /* history_set_fun():
397 * Set history functions
400 history_set_fun(h, nh)
403 if (nh->h_first == NULL || nh->h_next == NULL ||
404 nh->h_last == NULL || nh->h_prev == NULL || nh->h_curr == NULL ||
405 nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL ||
407 if (h->h_next != history_def_next) {
408 history_def_init(&h->h_ref, 0);
409 h->h_first = history_def_first;
410 h->h_next = history_def_next;
411 h->h_last = history_def_last;
412 h->h_prev = history_def_prev;
413 h->h_curr = history_def_curr;
414 h->h_clear = history_def_clear;
415 h->h_enter = history_def_enter;
416 h->h_add = history_def_add;
421 if (h->h_next == history_def_next)
422 history_def_clear(h->h_ref);
424 h->h_first = nh->h_first;
425 h->h_next = nh->h_next;
426 h->h_last = nh->h_last;
427 h->h_prev = nh->h_prev;
428 h->h_curr = nh->h_curr;
429 h->h_clear = nh->h_clear;
430 h->h_enter = nh->h_enter;
431 h->h_add = nh->h_add;
437 * History load function
440 history_load(h, fname)
449 if ((fp = fopen(fname, "r")) == NULL)
452 if ((line = fgetln(fp, &sz)) == NULL)
455 if (strncmp(line, hist_cookie, sz) != 0)
458 for (i = 0; (line = fgetln(fp, &sz)) != NULL; i++) {
472 * History save function
475 history_save(h, fname)
483 if ((fp = fopen(fname, "w")) == NULL)
486 (void) fputs(hist_cookie, fp);
487 for (ev = HLAST(h); ev != NULL; ev = HPREV(h), i++)
488 (void) fprintf(fp, "%s", ev->str);
494 /* history_prev_event():
495 * Find the previous event, with number given
497 private const HistEvent *
498 history_prev_event(h, num)
503 for (ev = HCURR(h); ev != NULL; ev = HPREV(h))
510 /* history_next_event():
511 * Find the next event, with number given
513 private const HistEvent *
514 history_next_event(h, num)
519 for (ev = HCURR(h); ev != NULL; ev = HNEXT(h))
526 /* history_prev_string():
527 * Find the previous event beginning with string
529 private const HistEvent *
530 history_prev_string(h, str)
535 size_t len = strlen(str);
537 for (ev = HCURR(h); ev != NULL; ev = HNEXT(h))
538 if (strncmp(str, ev->str, len) == 0)
544 /* history_next_string():
545 * Find the next event beginning with string
547 private const HistEvent *
548 history_next_string(h, str)
553 size_t len = strlen(str);
555 for (ev = HCURR(h); ev != NULL; ev = HPREV(h))
556 if (strncmp(str, ev->str, len) == 0)
563 * User interface to history functions.
567 history(History *h, int fun, ...)
574 const HistEvent *ev = NULL;
576 static HistEvent sev = { 0, "" };
584 h = va_arg(va, History *);
585 fun = va_arg(va, int);
590 str = va_arg(va, const char *);
595 str = va_arg(va, const char *);
624 sev.num = history_load(h, va_arg(va, const char *));
629 sev.num = history_save(h, va_arg(va, const char *));
634 ev = history_prev_event(h, va_arg(va, int));
638 ev = history_next_event(h, va_arg(va, int));
642 ev = history_prev_string(h, va_arg(va, const char*));
646 ev = history_next_string(h, va_arg(va, const char*));
650 if (history_set_num(h, va_arg(va, int)) == 0) {
659 hf.h_ref = va_arg(va, ptr_t);
660 hf.h_first = va_arg(va, history_gfun_t);
661 hf.h_next = va_arg(va, history_gfun_t);
662 hf.h_last = va_arg(va, history_gfun_t);
663 hf.h_prev = va_arg(va, history_gfun_t);
664 hf.h_curr = va_arg(va, history_gfun_t);
665 hf.h_clear = va_arg(va, history_vfun_t);
666 hf.h_enter = va_arg(va, history_efun_t);
667 hf.h_add = va_arg(va, history_efun_t);
669 if (history_set_fun(h, &hf) == 0) {