history.c revision 1.22 1 /* $NetBSD: history.c,v 1.22 2003/01/21 18:40:24 christos Exp $ */
2
3 /*-
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Christos Zoulas of Cornell University.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 */
38
39 #include "config.h"
40 #if !defined(lint) && !defined(SCCSID)
41 #if 0
42 static char sccsid[] = "@(#)history.c 8.1 (Berkeley) 6/4/93";
43 #else
44 __RCSID("$NetBSD: history.c,v 1.22 2003/01/21 18:40:24 christos Exp $");
45 #endif
46 #endif /* not lint && not SCCSID */
47
48 /*
49 * hist.c: History access functions
50 */
51 #include <string.h>
52 #include <stdlib.h>
53 #include <stdarg.h>
54 #ifdef HAVE_VIS_H
55 #include <vis.h>
56 #else
57 #include "np/vis.h"
58 #endif
59 #include <sys/stat.h>
60
61 static const char hist_cookie[] = "_HiStOrY_V2_\n";
62
63 #include "histedit.h"
64
65 typedef int (*history_gfun_t)(ptr_t, HistEvent *);
66 typedef int (*history_efun_t)(ptr_t, HistEvent *, const char *);
67 typedef void (*history_vfun_t)(ptr_t, HistEvent *);
68 typedef int (*history_sfun_t)(ptr_t, HistEvent *, const int);
69
70 struct history {
71 ptr_t h_ref; /* Argument for history fcns */
72 int h_ent; /* Last entry point for history */
73 history_gfun_t h_first; /* Get the first element */
74 history_gfun_t h_next; /* Get the next element */
75 history_gfun_t h_last; /* Get the last element */
76 history_gfun_t h_prev; /* Get the previous element */
77 history_gfun_t h_curr; /* Get the current element */
78 history_sfun_t h_set; /* Set the current element */
79 history_vfun_t h_clear; /* Clear the history list */
80 history_efun_t h_enter; /* Add an element */
81 history_efun_t h_add; /* Append to an element */
82 };
83
84 #define HNEXT(h, ev) (*(h)->h_next)((h)->h_ref, ev)
85 #define HFIRST(h, ev) (*(h)->h_first)((h)->h_ref, ev)
86 #define HPREV(h, ev) (*(h)->h_prev)((h)->h_ref, ev)
87 #define HLAST(h, ev) (*(h)->h_last)((h)->h_ref, ev)
88 #define HCURR(h, ev) (*(h)->h_curr)((h)->h_ref, ev)
89 #define HSET(h, ev, n) (*(h)->h_set)((h)->h_ref, ev, n)
90 #define HCLEAR(h, ev) (*(h)->h_clear)((h)->h_ref, ev)
91 #define HENTER(h, ev, str) (*(h)->h_enter)((h)->h_ref, ev, str)
92 #define HADD(h, ev, str) (*(h)->h_add)((h)->h_ref, ev, str)
93
94 #define h_malloc(a) malloc(a)
95 #define h_realloc(a, b) realloc((a), (b))
96 #define h_free(a) free(a)
97
98 typedef struct {
99 int num;
100 char *str;
101 } HistEventPrivate;
102
103
104
105 private int history_setsize(History *, HistEvent *, int);
106 private int history_getsize(History *, HistEvent *);
107 private int history_setunique(History *, HistEvent *, int);
108 private int history_getunique(History *, HistEvent *);
109 private int history_set_fun(History *, History *);
110 private int history_load(History *, const char *);
111 private int history_save(History *, const char *);
112 private int history_prev_event(History *, HistEvent *, int);
113 private int history_next_event(History *, HistEvent *, int);
114 private int history_next_string(History *, HistEvent *, const char *);
115 private int history_prev_string(History *, HistEvent *, const char *);
116
117
118 /***********************************************************************/
119
120 /*
121 * Builtin- history implementation
122 */
123 typedef struct hentry_t {
124 HistEvent ev; /* What we return */
125 struct hentry_t *next; /* Next entry */
126 struct hentry_t *prev; /* Previous entry */
127 } hentry_t;
128
129 typedef struct history_t {
130 hentry_t list; /* Fake list header element */
131 hentry_t *cursor; /* Current element in the list */
132 int max; /* Maximum number of events */
133 int cur; /* Current number of events */
134 int eventid; /* For generation of unique event id */
135 int flags; /* History flags */
136 #define H_UNIQUE 1 /* Store only unique elements */
137 } history_t;
138
139 private int history_def_first(ptr_t, HistEvent *);
140 private int history_def_last(ptr_t, HistEvent *);
141 private int history_def_next(ptr_t, HistEvent *);
142 private int history_def_prev(ptr_t, HistEvent *);
143 private int history_def_curr(ptr_t, HistEvent *);
144 private int history_def_set(ptr_t, HistEvent *, const int n);
145 private int history_def_enter(ptr_t, HistEvent *, const char *);
146 private int history_def_add(ptr_t, HistEvent *, const char *);
147 private int history_def_init(ptr_t *, HistEvent *, int);
148 private void history_def_clear(ptr_t, HistEvent *);
149 private int history_def_insert(history_t *, HistEvent *, const char *);
150 private void history_def_delete(history_t *, HistEvent *, hentry_t *);
151
152 #define history_def_setsize(p, num)(void) (((history_t *)p)->max = (num))
153 #define history_def_getsize(p) (((history_t *)p)->cur)
154 #define history_def_getunique(p) (((((history_t *)p)->flags) & H_UNIQUE) != 0)
155 #define history_def_setunique(p, uni) \
156 if (uni) \
157 (((history_t *)p)->flags) |= H_UNIQUE; \
158 else \
159 (((history_t *)p)->flags) &= ~H_UNIQUE
160
161 #define he_strerror(code) he_errlist[code]
162 #define he_seterrev(evp, code) {\
163 evp->num = code;\
164 evp->str = he_strerror(code);\
165 }
166
167 /* error messages */
168 static const char *const he_errlist[] = {
169 "OK",
170 "unknown error",
171 "malloc() failed",
172 "first event not found",
173 "last event not found",
174 "empty list",
175 "no next event",
176 "no previous event",
177 "current event is invalid",
178 "event not found",
179 "can't read history from file",
180 "can't write history",
181 "required parameter(s) not supplied",
182 "history size negative",
183 "function not allowed with other history-functions-set the default",
184 "bad parameters"
185 };
186 /* error codes */
187 #define _HE_OK 0
188 #define _HE_UNKNOWN 1
189 #define _HE_MALLOC_FAILED 2
190 #define _HE_FIRST_NOTFOUND 3
191 #define _HE_LAST_NOTFOUND 4
192 #define _HE_EMPTY_LIST 5
193 #define _HE_END_REACHED 6
194 #define _HE_START_REACHED 7
195 #define _HE_CURR_INVALID 8
196 #define _HE_NOT_FOUND 9
197 #define _HE_HIST_READ 10
198 #define _HE_HIST_WRITE 11
199 #define _HE_PARAM_MISSING 12
200 #define _HE_SIZE_NEGATIVE 13
201 #define _HE_NOT_ALLOWED 14
202 #define _HE_BAD_PARAM 15
203
204 /* history_def_first():
205 * Default function to return the first event in the history.
206 */
207 private int
208 history_def_first(ptr_t p, HistEvent *ev)
209 {
210 history_t *h = (history_t *) p;
211
212 h->cursor = h->list.next;
213 if (h->cursor != &h->list)
214 *ev = h->cursor->ev;
215 else {
216 he_seterrev(ev, _HE_FIRST_NOTFOUND);
217 return (-1);
218 }
219
220 return (0);
221 }
222
223
224 /* history_def_last():
225 * Default function to return the last event in the history.
226 */
227 private int
228 history_def_last(ptr_t p, HistEvent *ev)
229 {
230 history_t *h = (history_t *) p;
231
232 h->cursor = h->list.prev;
233 if (h->cursor != &h->list)
234 *ev = h->cursor->ev;
235 else {
236 he_seterrev(ev, _HE_LAST_NOTFOUND);
237 return (-1);
238 }
239
240 return (0);
241 }
242
243
244 /* history_def_next():
245 * Default function to return the next event in the history.
246 */
247 private int
248 history_def_next(ptr_t p, HistEvent *ev)
249 {
250 history_t *h = (history_t *) p;
251
252 if (h->cursor != &h->list)
253 h->cursor = h->cursor->next;
254 else {
255 he_seterrev(ev, _HE_EMPTY_LIST);
256 return (-1);
257 }
258
259 if (h->cursor != &h->list)
260 *ev = h->cursor->ev;
261 else {
262 he_seterrev(ev, _HE_END_REACHED);
263 return (-1);
264 }
265
266 return (0);
267 }
268
269
270 /* history_def_prev():
271 * Default function to return the previous event in the history.
272 */
273 private int
274 history_def_prev(ptr_t p, HistEvent *ev)
275 {
276 history_t *h = (history_t *) p;
277
278 if (h->cursor != &h->list)
279 h->cursor = h->cursor->prev;
280 else {
281 he_seterrev(ev,
282 (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST);
283 return (-1);
284 }
285
286 if (h->cursor != &h->list)
287 *ev = h->cursor->ev;
288 else {
289 he_seterrev(ev, _HE_START_REACHED);
290 return (-1);
291 }
292
293 return (0);
294 }
295
296
297 /* history_def_curr():
298 * Default function to return the current event in the history.
299 */
300 private int
301 history_def_curr(ptr_t p, HistEvent *ev)
302 {
303 history_t *h = (history_t *) p;
304
305 if (h->cursor != &h->list)
306 *ev = h->cursor->ev;
307 else {
308 he_seterrev(ev,
309 (h->cur > 0) ? _HE_CURR_INVALID : _HE_EMPTY_LIST);
310 return (-1);
311 }
312
313 return (0);
314 }
315
316
317 /* history_def_set():
318 * Default function to set the current event in the history to the
319 * given one.
320 */
321 private int
322 history_def_set(ptr_t p, HistEvent *ev, const int n)
323 {
324 history_t *h = (history_t *) p;
325
326 if (h->cur == 0) {
327 he_seterrev(ev, _HE_EMPTY_LIST);
328 return (-1);
329 }
330 if (h->cursor == &h->list || h->cursor->ev.num != n) {
331 for (h->cursor = h->list.next; h->cursor != &h->list;
332 h->cursor = h->cursor->next)
333 if (h->cursor->ev.num == n)
334 break;
335 }
336 if (h->cursor == &h->list) {
337 he_seterrev(ev, _HE_NOT_FOUND);
338 return (-1);
339 }
340 return (0);
341 }
342
343
344 /* history_def_add():
345 * Append string to element
346 */
347 private int
348 history_def_add(ptr_t p, HistEvent *ev, const char *str)
349 {
350 history_t *h = (history_t *) p;
351 size_t len;
352 char *s;
353 HistEventPrivate *evp = (void *)&h->cursor->ev;
354
355 if (h->cursor == &h->list)
356 return (history_def_enter(p, ev, str));
357 len = strlen(evp->str) + strlen(str) + 1;
358 s = (char *) h_malloc(len);
359 if (s == NULL) {
360 he_seterrev(ev, _HE_MALLOC_FAILED);
361 return (-1);
362 }
363 (void) strlcpy(s, h->cursor->ev.str, len);
364 (void) strlcat(s, str, len);
365 h_free((ptr_t)evp->str);
366 evp->str = s;
367 *ev = h->cursor->ev;
368 return (0);
369 }
370
371
372 /* history_def_delete():
373 * Delete element hp of the h list
374 */
375 /* ARGSUSED */
376 private void
377 history_def_delete(history_t *h, HistEvent *ev, hentry_t *hp)
378 {
379 HistEventPrivate *evp = (void *)&hp->ev;
380 if (hp == &h->list)
381 abort();
382 hp->prev->next = hp->next;
383 hp->next->prev = hp->prev;
384 h_free((ptr_t) evp->str);
385 h_free(hp);
386 h->cur--;
387 }
388
389
390 /* history_def_insert():
391 * Insert element with string str in the h list
392 */
393 private int
394 history_def_insert(history_t *h, HistEvent *ev, const char *str)
395 {
396
397 h->cursor = (hentry_t *) h_malloc(sizeof(hentry_t));
398 if (h->cursor == NULL)
399 goto oomem;
400 if ((h->cursor->ev.str = strdup(str)) == NULL) {
401 h_free((ptr_t)h->cursor);
402 goto oomem;
403 }
404 h->cursor->ev.num = ++h->eventid;
405 h->cursor->next = h->list.next;
406 h->cursor->prev = &h->list;
407 h->list.next->prev = h->cursor;
408 h->list.next = h->cursor;
409 h->cur++;
410
411 *ev = h->cursor->ev;
412 return (0);
413 oomem:
414 he_seterrev(ev, _HE_MALLOC_FAILED);
415 return (-1);
416 }
417
418
419 /* history_def_enter():
420 * Default function to enter an item in the history
421 */
422 private int
423 history_def_enter(ptr_t p, HistEvent *ev, const char *str)
424 {
425 history_t *h = (history_t *) p;
426
427 if ((h->flags & H_UNIQUE) != 0 && h->list.next != &h->list &&
428 strcmp(h->list.next->ev.str, str) == 0)
429 return (0);
430
431 if (history_def_insert(h, ev, str) == -1)
432 return (-1); /* error, keep error message */
433
434 /*
435 * Always keep at least one entry.
436 * This way we don't have to check for the empty list.
437 */
438 while (h->cur > h->max && h->cur > 0)
439 history_def_delete(h, ev, h->list.prev);
440
441 return (1);
442 }
443
444
445 /* history_def_init():
446 * Default history initialization function
447 */
448 /* ARGSUSED */
449 private int
450 history_def_init(ptr_t *p, HistEvent *ev, int n)
451 {
452 history_t *h = (history_t *) h_malloc(sizeof(history_t));
453 if (h == NULL)
454 return -1;
455
456 if (n <= 0)
457 n = 0;
458 h->eventid = 0;
459 h->cur = 0;
460 h->max = n;
461 h->list.next = h->list.prev = &h->list;
462 h->list.ev.str = NULL;
463 h->list.ev.num = 0;
464 h->cursor = &h->list;
465 h->flags = 0;
466 *p = (ptr_t) h;
467 return 0;
468 }
469
470
471 /* history_def_clear():
472 * Default history cleanup function
473 */
474 private void
475 history_def_clear(ptr_t p, HistEvent *ev)
476 {
477 history_t *h = (history_t *) p;
478
479 while (h->list.prev != &h->list)
480 history_def_delete(h, ev, h->list.prev);
481 h->eventid = 0;
482 h->cur = 0;
483 }
484
485
486
487
488 /************************************************************************/
489
490 /* history_init():
491 * Initialization function.
492 */
493 public History *
494 history_init(void)
495 {
496 HistEvent ev;
497 History *h = (History *) h_malloc(sizeof(History));
498 if (h == NULL)
499 return NULL;
500
501 if (history_def_init(&h->h_ref, &ev, 0) == -1) {
502 h_free((ptr_t)h);
503 return NULL;
504 }
505 h->h_ent = -1;
506 h->h_next = history_def_next;
507 h->h_first = history_def_first;
508 h->h_last = history_def_last;
509 h->h_prev = history_def_prev;
510 h->h_curr = history_def_curr;
511 h->h_set = history_def_set;
512 h->h_clear = history_def_clear;
513 h->h_enter = history_def_enter;
514 h->h_add = history_def_add;
515
516 return (h);
517 }
518
519
520 /* history_end():
521 * clean up history;
522 */
523 public void
524 history_end(History *h)
525 {
526 HistEvent ev;
527
528 if (h->h_next == history_def_next)
529 history_def_clear(h->h_ref, &ev);
530 }
531
532
533
534 /* history_setsize():
535 * Set history number of events
536 */
537 private int
538 history_setsize(History *h, HistEvent *ev, int num)
539 {
540
541 if (h->h_next != history_def_next) {
542 he_seterrev(ev, _HE_NOT_ALLOWED);
543 return (-1);
544 }
545 if (num < 0) {
546 he_seterrev(ev, _HE_BAD_PARAM);
547 return (-1);
548 }
549 history_def_setsize(h->h_ref, num);
550 return (0);
551 }
552
553
554 /* history_getsize():
555 * Get number of events currently in history
556 */
557 private int
558 history_getsize(History *h, HistEvent *ev)
559 {
560 if (h->h_next != history_def_next) {
561 he_seterrev(ev, _HE_NOT_ALLOWED);
562 return (-1);
563 }
564 ev->num = history_def_getsize(h->h_ref);
565 if (ev->num < -1) {
566 he_seterrev(ev, _HE_SIZE_NEGATIVE);
567 return (-1);
568 }
569 return (0);
570 }
571
572
573 /* history_setunique():
574 * Set if adjacent equal events should not be entered in history.
575 */
576 private int
577 history_setunique(History *h, HistEvent *ev, int uni)
578 {
579
580 if (h->h_next != history_def_next) {
581 he_seterrev(ev, _HE_NOT_ALLOWED);
582 return (-1);
583 }
584 history_def_setunique(h->h_ref, uni);
585 return (0);
586 }
587
588
589 /* history_getunique():
590 * Get if adjacent equal events should not be entered in history.
591 */
592 private int
593 history_getunique(History *h, HistEvent *ev)
594 {
595 if (h->h_next != history_def_next) {
596 he_seterrev(ev, _HE_NOT_ALLOWED);
597 return (-1);
598 }
599 ev->num = history_def_getunique(h->h_ref);
600 return (0);
601 }
602
603
604 /* history_set_fun():
605 * Set history functions
606 */
607 private int
608 history_set_fun(History *h, History *nh)
609 {
610 HistEvent ev;
611
612 if (nh->h_first == NULL || nh->h_next == NULL || nh->h_last == NULL ||
613 nh->h_prev == NULL || nh->h_curr == NULL || nh->h_set == NULL ||
614 nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL ||
615 nh->h_ref == NULL) {
616 if (h->h_next != history_def_next) {
617 history_def_init(&h->h_ref, &ev, 0);
618 h->h_first = history_def_first;
619 h->h_next = history_def_next;
620 h->h_last = history_def_last;
621 h->h_prev = history_def_prev;
622 h->h_curr = history_def_curr;
623 h->h_set = history_def_set;
624 h->h_clear = history_def_clear;
625 h->h_enter = history_def_enter;
626 h->h_add = history_def_add;
627 }
628 return (-1);
629 }
630 if (h->h_next == history_def_next)
631 history_def_clear(h->h_ref, &ev);
632
633 h->h_ent = -1;
634 h->h_first = nh->h_first;
635 h->h_next = nh->h_next;
636 h->h_last = nh->h_last;
637 h->h_prev = nh->h_prev;
638 h->h_curr = nh->h_curr;
639 h->h_set = nh->h_set;
640 h->h_clear = nh->h_clear;
641 h->h_enter = nh->h_enter;
642 h->h_add = nh->h_add;
643
644 return (0);
645 }
646
647
648 /* history_load():
649 * History load function
650 */
651 private int
652 history_load(History *h, const char *fname)
653 {
654 FILE *fp;
655 char *line;
656 size_t sz, max_size;
657 char *ptr;
658 int i = -1;
659 HistEvent ev;
660
661 if ((fp = fopen(fname, "r")) == NULL)
662 return (i);
663
664 if ((line = fgetln(fp, &sz)) == NULL)
665 goto done;
666
667 if (strncmp(line, hist_cookie, sz) != 0)
668 goto done;
669
670 ptr = h_malloc(max_size = 1024);
671 if (ptr == NULL)
672 goto done;
673 for (i = 0; (line = fgetln(fp, &sz)) != NULL; i++) {
674 char c = line[sz];
675
676 if (sz != 0 && line[sz - 1] == '\n')
677 line[--sz] = '\0';
678 else
679 line[sz] = '\0';
680
681 if (max_size < sz) {
682 char *nptr;
683 max_size = (sz + 1023) & ~1023;
684 nptr = h_realloc(ptr, max_size);
685 if (nptr == NULL) {
686 i = -1;
687 goto oomem;
688 }
689 ptr = nptr;
690 }
691 (void) strunvis(ptr, line);
692 line[sz] = c;
693 if (HENTER(h, &ev, ptr) == -1) {
694 h_free((ptr_t)ptr);
695 return -1;
696 }
697 }
698 oomem:
699 h_free((ptr_t)ptr);
700 done:
701 (void) fclose(fp);
702 return (i);
703 }
704
705
706 /* history_save():
707 * History save function
708 */
709 private int
710 history_save(History *h, const char *fname)
711 {
712 FILE *fp;
713 HistEvent ev;
714 int i = -1, retval;
715 size_t len, max_size;
716 char *ptr;
717
718 if ((fp = fopen(fname, "w")) == NULL)
719 return (-1);
720
721 if (fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1)
722 goto done;
723 if (fputs(hist_cookie, fp) == EOF)
724 goto done;
725 ptr = h_malloc(max_size = 1024);
726 if (ptr == NULL)
727 goto done;
728 for (i = 0, retval = HLAST(h, &ev);
729 retval != -1;
730 retval = HPREV(h, &ev), i++) {
731 len = strlen(ev.str) * 4;
732 if (len >= max_size) {
733 char *nptr;
734 max_size = (len + 1023) & 1023;
735 nptr = h_realloc(ptr, max_size);
736 if (nptr == NULL) {
737 i = -1;
738 goto oomem;
739 }
740 ptr = nptr;
741 }
742 (void) strvis(ptr, ev.str, VIS_WHITE);
743 (void) fprintf(fp, "%s\n", ptr);
744 }
745 oomem:
746 h_free((ptr_t)ptr);
747 done:
748 (void) fclose(fp);
749 return (i);
750 }
751
752
753 /* history_prev_event():
754 * Find the previous event, with number given
755 */
756 private int
757 history_prev_event(History *h, HistEvent *ev, int num)
758 {
759 int retval;
760
761 for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
762 if (ev->num == num)
763 return (0);
764
765 he_seterrev(ev, _HE_NOT_FOUND);
766 return (-1);
767 }
768
769
770 /* history_next_event():
771 * Find the next event, with number given
772 */
773 private int
774 history_next_event(History *h, HistEvent *ev, int num)
775 {
776 int retval;
777
778 for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
779 if (ev->num == num)
780 return (0);
781
782 he_seterrev(ev, _HE_NOT_FOUND);
783 return (-1);
784 }
785
786
787 /* history_prev_string():
788 * Find the previous event beginning with string
789 */
790 private int
791 history_prev_string(History *h, HistEvent *ev, const char *str)
792 {
793 size_t len = strlen(str);
794 int retval;
795
796 for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
797 if (strncmp(str, ev->str, len) == 0)
798 return (0);
799
800 he_seterrev(ev, _HE_NOT_FOUND);
801 return (-1);
802 }
803
804
805 /* history_next_string():
806 * Find the next event beginning with string
807 */
808 private int
809 history_next_string(History *h, HistEvent *ev, const char *str)
810 {
811 size_t len = strlen(str);
812 int retval;
813
814 for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
815 if (strncmp(str, ev->str, len) == 0)
816 return (0);
817
818 he_seterrev(ev, _HE_NOT_FOUND);
819 return (-1);
820 }
821
822
823 /* history():
824 * User interface to history functions.
825 */
826 int
827 history(History *h, HistEvent *ev, int fun, ...)
828 {
829 va_list va;
830 const char *str;
831 int retval;
832
833 va_start(va, fun);
834
835 he_seterrev(ev, _HE_OK);
836
837 switch (fun) {
838 case H_GETSIZE:
839 retval = history_getsize(h, ev);
840 break;
841
842 case H_SETSIZE:
843 retval = history_setsize(h, ev, va_arg(va, int));
844 break;
845
846 case H_GETUNIQUE:
847 retval = history_getunique(h, ev);
848 break;
849
850 case H_SETUNIQUE:
851 retval = history_setunique(h, ev, va_arg(va, int));
852 break;
853
854 case H_ADD:
855 str = va_arg(va, const char *);
856 retval = HADD(h, ev, str);
857 break;
858
859 case H_ENTER:
860 str = va_arg(va, const char *);
861 if ((retval = HENTER(h, ev, str)) != -1)
862 h->h_ent = ev->num;
863 break;
864
865 case H_APPEND:
866 str = va_arg(va, const char *);
867 if ((retval = HSET(h, ev, h->h_ent)) != -1)
868 retval = HADD(h, ev, str);
869 break;
870
871 case H_FIRST:
872 retval = HFIRST(h, ev);
873 break;
874
875 case H_NEXT:
876 retval = HNEXT(h, ev);
877 break;
878
879 case H_LAST:
880 retval = HLAST(h, ev);
881 break;
882
883 case H_PREV:
884 retval = HPREV(h, ev);
885 break;
886
887 case H_CURR:
888 retval = HCURR(h, ev);
889 break;
890
891 case H_SET:
892 retval = HSET(h, ev, va_arg(va, const int));
893 break;
894
895 case H_CLEAR:
896 HCLEAR(h, ev);
897 retval = 0;
898 break;
899
900 case H_LOAD:
901 retval = history_load(h, va_arg(va, const char *));
902 if (retval == -1)
903 he_seterrev(ev, _HE_HIST_READ);
904 break;
905
906 case H_SAVE:
907 retval = history_save(h, va_arg(va, const char *));
908 if (retval == -1)
909 he_seterrev(ev, _HE_HIST_WRITE);
910 break;
911
912 case H_PREV_EVENT:
913 retval = history_prev_event(h, ev, va_arg(va, int));
914 break;
915
916 case H_NEXT_EVENT:
917 retval = history_next_event(h, ev, va_arg(va, int));
918 break;
919
920 case H_PREV_STR:
921 retval = history_prev_string(h, ev, va_arg(va, const char *));
922 break;
923
924 case H_NEXT_STR:
925 retval = history_next_string(h, ev, va_arg(va, const char *));
926 break;
927
928 case H_FUNC:
929 {
930 History hf;
931
932 hf.h_ref = va_arg(va, ptr_t);
933 h->h_ent = -1;
934 hf.h_first = va_arg(va, history_gfun_t);
935 hf.h_next = va_arg(va, history_gfun_t);
936 hf.h_last = va_arg(va, history_gfun_t);
937 hf.h_prev = va_arg(va, history_gfun_t);
938 hf.h_curr = va_arg(va, history_gfun_t);
939 hf.h_set = va_arg(va, history_sfun_t);
940 hf.h_clear = va_arg(va, history_vfun_t);
941 hf.h_enter = va_arg(va, history_efun_t);
942 hf.h_add = va_arg(va, history_efun_t);
943
944 if ((retval = history_set_fun(h, &hf)) == -1)
945 he_seterrev(ev, _HE_PARAM_MISSING);
946 break;
947 }
948
949 case H_END:
950 history_end(h);
951 retval = 0;
952 break;
953
954 default:
955 retval = -1;
956 he_seterrev(ev, _HE_UNKNOWN);
957 break;
958 }
959 va_end(va);
960 return (retval);
961 }
962