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