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