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