1 /*-
2 * Copyright (c) 1992, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Christos Zoulas of Cornell University.
7 *
8 * %sccs.include.redist.c%
9 */
10
11 #if !defined(lint) && !defined(SCCSID)
12 static char sccsid[] = "@(#)history.c 8.1 (Berkeley) 06/04/93";
13 #endif /* not lint && not SCCSID */
14
15 /*
16 * hist.c: History access functions
17 */
18 #include "sys.h"
19
20 #include <string.h>
21 #include <stdlib.h>
22 #if __STDC__
23 #include <stdarg.h>
24 #else
25 #include <varargs.h>
26 #endif
27
28 #include "histedit.h"
29
30 typedef const HistEvent * (*history_gfun_t) __P((ptr_t));
31 typedef const HistEvent * (*history_efun_t) __P((ptr_t, const char *));
32
33 struct history {
34 ptr_t h_ref; /* Argument for history fcns */
35 history_gfun_t h_first; /* Get the first element */
36 history_gfun_t h_next; /* Get the next element */
37 history_gfun_t h_last; /* Get the last element */
38 history_gfun_t h_prev; /* Get the previous element */
39 history_gfun_t h_curr; /* Get the current element */
40 history_efun_t h_enter; /* Add an element */
41 history_efun_t h_add; /* Append to an element */
42 };
43
44 #define HNEXT(h) (*(h)->h_next)((h)->h_ref)
45 #define HFIRST(h) (*(h)->h_first)((h)->h_ref)
46 #define HPREV(h) (*(h)->h_prev)((h)->h_ref)
47 #define HLAST(h) (*(h)->h_last)((h)->h_ref)
48 #define HCURR(h) (*(h)->h_curr)((h)->h_ref)
49 #define HENTER(h, str) (*(h)->h_enter)((h)->h_ref, str)
50 #define HADD(h, str) (*(h)->h_add)((h)->h_ref, str)
51
52 #define h_malloc(a) malloc(a)
53 #define h_free(a) free(a)
54
55
56 private int history_set_num __P((History *, int));
57 private int history_set_fun __P((History *, history_gfun_t,
58 history_gfun_t,
59 history_gfun_t,
60 history_gfun_t,
61 history_gfun_t,
62 history_efun_t,
63 history_efun_t, ptr_t));
64 private const HistEvent *history_prev_event __P((History *, int));
65 private const HistEvent *history_next_event __P((History *, int));
66 private const HistEvent *history_next_string __P((History *, const char *));
67 private const HistEvent *history_prev_string __P((History *, const char *));
68
69
70 /***********************************************************************/
71
72 /*
73 * Builtin- history implementation
74 */
75 typedef struct hentry_t {
76 HistEvent ev; /* What we return */
77 struct hentry_t *next; /* Next entry */
78 struct hentry_t *prev; /* Previous entry */
79 } hentry_t;
80
81 typedef struct history_t {
82 hentry_t list; /* Fake list header element */
83 hentry_t *cursor; /* Current element in the list */
84 int max; /* Maximum number of events */
85 int cur; /* Current number of events */
86 int eventno; /* Current event number */
87 } history_t;
88
89 private const HistEvent *history_def_first __P((ptr_t));
90 private const HistEvent *history_def_last __P((ptr_t));
91 private const HistEvent *history_def_next __P((ptr_t));
92 private const HistEvent *history_def_prev __P((ptr_t));
93 private const HistEvent *history_def_curr __P((ptr_t));
94 private const HistEvent *history_def_enter __P((ptr_t, const char *));
95 private const HistEvent *history_def_add __P((ptr_t, const char *));
96 private void history_def_init __P((ptr_t *, int));
97 private void history_def_end __P((ptr_t));
98 private const HistEvent *history_def_insert __P((history_t *, const char *));
99 private void history_def_delete __P((history_t *, hentry_t *));
100
101 #define history_def_set(p, num) (void) (((history_t *) p)->max = (num))
102
103
104 /* history_def_first():
105 * Default function to return the first event in the history.
106 */
107 private const HistEvent *
history_def_first(p)108 history_def_first(p)
109 ptr_t p;
110 {
111 history_t *h = (history_t *) p;
112 h->cursor = h->list.next;
113 if (h->cursor != &h->list)
114 return &h->cursor->ev;
115 else
116 return NULL;
117 }
118
119 /* history_def_last():
120 * Default function to return the last event in the history.
121 */
122 private const HistEvent *
history_def_last(p)123 history_def_last(p)
124 ptr_t p;
125 {
126 history_t *h = (history_t *) p;
127 h->cursor = h->list.prev;
128 if (h->cursor != &h->list)
129 return &h->cursor->ev;
130 else
131 return NULL;
132 }
133
134 /* history_def_next():
135 * Default function to return the next event in the history.
136 */
137 private const HistEvent *
history_def_next(p)138 history_def_next(p)
139 ptr_t p;
140 {
141 history_t *h = (history_t *) p;
142
143 if (h->cursor != &h->list)
144 h->cursor = h->cursor->next;
145 else
146 return NULL;
147
148 if (h->cursor != &h->list)
149 return &h->cursor->ev;
150 else
151 return NULL;
152 }
153
154
155 /* history_def_prev():
156 * Default function to return the previous event in the history.
157 */
158 private const HistEvent *
history_def_prev(p)159 history_def_prev(p)
160 ptr_t p;
161 {
162 history_t *h = (history_t *) p;
163
164 if (h->cursor != &h->list)
165 h->cursor = h->cursor->prev;
166 else
167 return NULL;
168
169 if (h->cursor != &h->list)
170 return &h->cursor->ev;
171 else
172 return NULL;
173 }
174
175
176 /* history_def_curr():
177 * Default function to return the current event in the history.
178 */
179 private const HistEvent *
history_def_curr(p)180 history_def_curr(p)
181 ptr_t p;
182 {
183 history_t *h = (history_t *) p;
184
185 if (h->cursor != &h->list)
186 return &h->cursor->ev;
187 else
188 return NULL;
189 }
190
191
192 /* history_def_add():
193 * Append string to element
194 */
195 private const HistEvent *
history_def_add(p,str)196 history_def_add(p, str)
197 ptr_t p;
198 const char *str;
199 {
200 history_t *h = (history_t *) p;
201 size_t len;
202 char *s;
203
204 if (h->cursor == &h->list)
205 return (history_def_enter(p, str));
206 len = strlen(h->cursor->ev.str) + strlen(str) + 1;
207 s = (char *) h_malloc(len);
208 (void) strcpy(s, h->cursor->ev.str);
209 (void) strcat(s, str);
210 h_free((ptr_t) h->cursor->ev.str);
211 h->cursor->ev.str = s;
212 return &h->cursor->ev;
213 }
214
215
216 /* history_def_delete():
217 * Delete element hp of the h list
218 */
219 private void
history_def_delete(h,hp)220 history_def_delete(h, hp)
221 history_t *h;
222 hentry_t *hp;
223 {
224 if (hp == &h->list)
225 abort();
226 hp->prev->next = hp->next;
227 hp->next->prev = hp->prev;
228 h_free((ptr_t) hp->ev.str);
229 h_free(hp);
230 h->cur--;
231 }
232
233
234 /* history_def_insert():
235 * Insert element with string str in the h list
236 */
237 private const HistEvent *
history_def_insert(h,str)238 history_def_insert(h, str)
239 history_t *h;
240 const char *str;
241 {
242 h->cursor = (hentry_t *) h_malloc(sizeof(hentry_t));
243 h->cursor->ev.str = strdup(str);
244 h->cursor->next = h->list.next;
245 h->cursor->prev = &h->list;
246 h->list.next->prev = h->cursor;
247 h->list.next = h->cursor;
248 h->cur++;
249
250 return &h->cursor->ev;
251 }
252
253
254 /* history_def_enter():
255 * Default function to enter an item in the history
256 */
257 private const HistEvent *
history_def_enter(p,str)258 history_def_enter(p, str)
259 ptr_t p;
260 const char *str;
261 {
262 history_t *h = (history_t *) p;
263 const HistEvent *ev;
264
265
266 ev = history_def_insert(h, str);
267 ((HistEvent*) ev)->num = ++h->eventno;
268
269 /*
270 * Always keep at least one entry.
271 * This way we don't have to check for the empty list.
272 */
273 while (h->cur > h->max + 1)
274 history_def_delete(h, h->list.prev);
275 return ev;
276 }
277
278
279 /* history_def_init():
280 * Default history initialization function
281 */
282 private void
history_def_init(p,n)283 history_def_init(p, n)
284 ptr_t *p;
285 int n;
286 {
287 history_t *h = (history_t *) h_malloc(sizeof(history_t));
288 if (n <= 0)
289 n = 0;
290 h->eventno = 0;
291 h->cur = 0;
292 h->max = n;
293 h->list.next = h->list.prev = &h->list;
294 h->list.ev.str = NULL;
295 h->list.ev.num = 0;
296 h->cursor = &h->list;
297 *p = (ptr_t) h;
298 }
299
300
301 /* history_def_end():
302 * Default history cleanup function
303 */
304 private void
history_def_end(p)305 history_def_end(p)
306 ptr_t p;
307 {
308 history_t *h = (history_t *) p;
309
310 while (h->list.prev != &h->list)
311 history_def_delete(h, h->list.prev);
312 }
313
314 /************************************************************************/
315
316 /* history_init():
317 * Initialization function.
318 */
319 public History *
history_init()320 history_init()
321 {
322 History *h = (History *) h_malloc(sizeof(History));
323
324 history_def_init(&h->h_ref, 0);
325
326 h->h_next = history_def_next;
327 h->h_first = history_def_first;
328 h->h_last = history_def_last;
329 h->h_prev = history_def_prev;
330 h->h_curr = history_def_curr;
331 h->h_enter = history_def_enter;
332 h->h_add = history_def_add;
333
334 return h;
335 }
336
337
338 /* history_end():
339 * clean up history;
340 */
341 public void
history_end(h)342 history_end(h)
343 History *h;
344 {
345 if (h->h_next == history_def_next)
346 history_def_end(h->h_ref);
347 }
348
349
350
351 /* history_set_num():
352 * Set history number of events
353 */
354 private int
history_set_num(h,num)355 history_set_num(h, num)
356 History *h;
357 int num;
358 {
359 if (h->h_next != history_def_next || num < 0)
360 return -1;
361 history_def_set(h->h_ref, num);
362 return 0;
363 }
364
365
366 /* history_set_fun():
367 * Set history functions
368 */
369 private int
history_set_fun(h,first,next,last,prev,curr,enter,add,ptr)370 history_set_fun(h, first, next, last, prev, curr, enter, add, ptr)
371 History *h;
372 history_gfun_t first, next, last, prev, curr;
373 history_efun_t enter, add;
374 ptr_t ptr;
375 {
376 if (first == NULL || next == NULL ||
377 last == NULL || prev == NULL || curr == NULL ||
378 enter == NULL || add == NULL ||
379 ptr == NULL ) {
380 if (h->h_next != history_def_next) {
381 history_def_init(&h->h_ref, 0);
382 h->h_first = history_def_first;
383 h->h_next = history_def_next;
384 h->h_last = history_def_last;
385 h->h_prev = history_def_prev;
386 h->h_curr = history_def_curr;
387 h->h_enter = history_def_enter;
388 h->h_add = history_def_add;
389 }
390 return -1;
391 }
392
393 if (h->h_next == history_def_next)
394 history_def_end(h->h_ref);
395
396 h->h_next = next;
397 h->h_first = first;
398 h->h_enter = enter;
399 h->h_add = add;
400 return 0;
401 }
402
403
404 /* history_prev_event():
405 * Find the previous event, with number given
406 */
407 private const HistEvent *
history_prev_event(h,num)408 history_prev_event(h, num)
409 History *h;
410 int num;
411 {
412 const HistEvent *ev;
413 for (ev = HCURR(h); ev != NULL; ev = HPREV(h))
414 if (ev->num == num)
415 return ev;
416 return NULL;
417 }
418
419
420 /* history_next_event():
421 * Find the next event, with number given
422 */
423 private const HistEvent *
history_next_event(h,num)424 history_next_event(h, num)
425 History *h;
426 int num;
427 {
428 const HistEvent *ev;
429 for (ev = HCURR(h); ev != NULL; ev = HNEXT(h))
430 if (ev->num == num)
431 return ev;
432 return NULL;
433 }
434
435
436 /* history_prev_string():
437 * Find the previous event beginning with string
438 */
439 private const HistEvent *
history_prev_string(h,str)440 history_prev_string(h, str)
441 History *h;
442 const char* str;
443 {
444 const HistEvent *ev;
445 size_t len = strlen(str);
446
447 for (ev = HCURR(h); ev != NULL; ev = HNEXT(h))
448 if (strncmp(str, ev->str, len) == 0)
449 return ev;
450 return NULL;
451 }
452
453
454 /* history_next_string():
455 * Find the next event beginning with string
456 */
457 private const HistEvent *
history_next_string(h,str)458 history_next_string(h, str)
459 History *h;
460 const char* str;
461 {
462 const HistEvent *ev;
463 size_t len = strlen(str);
464
465 for (ev = HCURR(h); ev != NULL; ev = HPREV(h))
466 if (strncmp(str, ev->str, len) == 0)
467 return ev;
468 return NULL;
469 }
470
471
472 /* history():
473 * User interface to history functions.
474 */
475 const HistEvent *
476 #if __STDC__
history(History * h,int fun,...)477 history(History *h, int fun, ...)
478 #else
479 history(va_alist)
480 va_dcl
481 #endif
482 {
483 va_list va;
484 const HistEvent *ev = NULL;
485 const char *str;
486 static const HistEvent sev = { 0, "" };
487
488 #if __STDC__
489 va_start(va, fun);
490 #else
491 History *h;
492 int fun;
493 va_start(va);
494 h = va_arg(va, History *);
495 fun = va_arg(va, int);
496 #endif
497
498 switch (fun) {
499 case H_ADD:
500 str = va_arg(va, const char *);
501 ev = HADD(h, str);
502 break;
503
504 case H_ENTER:
505 str = va_arg(va, const char *);
506 ev = HENTER(h, str);
507 break;
508
509 case H_FIRST:
510 ev = HFIRST(h);
511 break;
512
513 case H_NEXT:
514 ev = HNEXT(h);
515 break;
516
517 case H_LAST:
518 ev = HLAST(h);
519 break;
520
521 case H_PREV:
522 ev = HPREV(h);
523 break;
524
525 case H_CURR:
526 ev = HCURR(h);
527 break;
528
529 case H_PREV_EVENT:
530 ev = history_prev_event(h, va_arg(va, int));
531 break;
532
533 case H_NEXT_EVENT:
534 ev = history_next_event(h, va_arg(va, int));
535 break;
536
537 case H_PREV_STR:
538 ev = history_prev_string(h, va_arg(va, const char*));
539 break;
540
541 case H_NEXT_STR:
542 ev = history_next_string(h, va_arg(va, const char*));
543 break;
544
545 case H_EVENT:
546 if (history_set_num(h, va_arg(va, int)) == 0)
547 ev = &sev;
548 break;
549
550 case H_FUNC:
551 {
552 history_gfun_t first = va_arg(va, history_gfun_t);
553 history_gfun_t next = va_arg(va, history_gfun_t);
554 history_gfun_t last = va_arg(va, history_gfun_t);
555 history_gfun_t prev = va_arg(va, history_gfun_t);
556 history_gfun_t curr = va_arg(va, history_gfun_t);
557 history_efun_t enter = va_arg(va, history_efun_t);
558 history_efun_t add = va_arg(va, history_efun_t);
559 ptr_t ptr = va_arg(va, ptr_t);
560
561 if (history_set_fun(h, first, next, last, prev,
562 curr, enter, add, ptr) == 0)
563 ev = &sev;
564 }
565 break;
566
567 case H_END:
568 history_end(h);
569 break;
570
571 default:
572 break;
573 }
574 va_end(va);
575 return ev;
576 }
577