1 /* $NetBSD: history.c,v 1.47 2014/05/11 01:05:17 christos Exp $ */
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * Christos Zoulas of Cornell University.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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
36 #if !defined(lint) && !defined(SCCSID)
38 static char sccsid
[] = "@(#)history.c 8.1 (Berkeley) 6/4/93";
40 __RCSID("$NetBSD: history.c,v 1.47 2014/05/11 01:05:17 christos Exp $");
42 #endif /* not lint && not SCCSID */
45 * hist.c: TYPE(History) access functions
53 static const char hist_cookie
[] = "_HiStOrY_V2_\n";
58 typedef int (*history_gfun_t
)(void *, TYPE(HistEvent
) *);
59 typedef int (*history_efun_t
)(void *, TYPE(HistEvent
) *, const Char
*);
60 typedef void (*history_vfun_t
)(void *, TYPE(HistEvent
) *);
61 typedef int (*history_sfun_t
)(void *, TYPE(HistEvent
) *, const int);
63 struct TYPE(history
) {
64 void *h_ref
; /* Argument for history fcns */
65 int h_ent
; /* Last entry point for history */
66 history_gfun_t h_first
; /* Get the first element */
67 history_gfun_t h_next
; /* Get the next element */
68 history_gfun_t h_last
; /* Get the last element */
69 history_gfun_t h_prev
; /* Get the previous element */
70 history_gfun_t h_curr
; /* Get the current element */
71 history_sfun_t h_set
; /* Set the current element */
72 history_sfun_t h_del
; /* Set the given element */
73 history_vfun_t h_clear
; /* Clear the history list */
74 history_efun_t h_enter
; /* Add an element */
75 history_efun_t h_add
; /* Append to an element */
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 #define HDEL(h, ev, n) (*(h)->h_del)((h)->h_ref, ev, n)
89 #define h_strdup(a) Strdup(a)
90 #define h_malloc(a) malloc(a)
91 #define h_realloc(a, b) realloc((a), (b))
92 #define h_free(a) free(a)
101 private int history_setsize(TYPE(History
) *, TYPE(HistEvent
) *, int);
102 private int history_getsize(TYPE(History
) *, TYPE(HistEvent
) *);
103 private int history_setunique(TYPE(History
) *, TYPE(HistEvent
) *, int);
104 private int history_getunique(TYPE(History
) *, TYPE(HistEvent
) *);
105 private int history_set_fun(TYPE(History
) *, TYPE(History
) *);
106 private int history_load(TYPE(History
) *, const char *);
107 private int history_save(TYPE(History
) *, const char *);
108 private int history_save_fp(TYPE(History
) *, FILE *);
109 private int history_prev_event(TYPE(History
) *, TYPE(HistEvent
) *, int);
110 private int history_next_event(TYPE(History
) *, TYPE(HistEvent
) *, int);
111 private int history_next_string(TYPE(History
) *, TYPE(HistEvent
) *, const Char
*);
112 private int history_prev_string(TYPE(History
) *, TYPE(HistEvent
) *, const Char
*);
115 /***********************************************************************/
118 * Builtin- history implementation
120 typedef struct hentry_t
{
121 TYPE(HistEvent
) ev
; /* What we return */
122 void *data
; /* data */
123 struct hentry_t
*next
; /* Next entry */
124 struct hentry_t
*prev
; /* Previous entry */
127 typedef struct history_t
{
128 hentry_t list
; /* Fake list header element */
129 hentry_t
*cursor
; /* Current element in the list */
130 int max
; /* Maximum number of events */
131 int cur
; /* Current number of events */
132 int eventid
; /* For generation of unique event id */
133 int flags
; /* TYPE(History) flags */
134 #define H_UNIQUE 1 /* Store only unique elements */
137 private int history_def_next(void *, TYPE(HistEvent
) *);
138 private int history_def_first(void *, TYPE(HistEvent
) *);
139 private int history_def_prev(void *, TYPE(HistEvent
) *);
140 private int history_def_last(void *, TYPE(HistEvent
) *);
141 private int history_def_curr(void *, TYPE(HistEvent
) *);
142 private int history_def_set(void *, TYPE(HistEvent
) *, const int);
143 private void history_def_clear(void *, TYPE(HistEvent
) *);
144 private int history_def_enter(void *, TYPE(HistEvent
) *, const Char
*);
145 private int history_def_add(void *, TYPE(HistEvent
) *, const Char
*);
146 private int history_def_del(void *, TYPE(HistEvent
) *, const int);
148 private int history_def_init(void **, TYPE(HistEvent
) *, int);
149 private int history_def_insert(history_t
*, TYPE(HistEvent
) *, const Char
*);
150 private void history_def_delete(history_t
*, TYPE(HistEvent
) *, hentry_t
*);
152 private int history_deldata_nth(history_t
*, TYPE(HistEvent
) *, int, void **);
153 private int history_set_nth(void *, TYPE(HistEvent
) *, int);
155 #define history_def_setsize(p, num)(void) (((history_t *)p)->max = (num))
156 #define history_def_getsize(p) (((history_t *)p)->cur)
157 #define history_def_getunique(p) (((((history_t *)p)->flags) & H_UNIQUE) != 0)
158 #define history_def_setunique(p, uni) \
160 (((history_t *)p)->flags) |= H_UNIQUE; \
162 (((history_t *)p)->flags) &= ~H_UNIQUE
164 #define he_strerror(code) he_errlist[code]
165 #define he_seterrev(evp, code) {\
167 evp->str = he_strerror(code);\
171 static const Char
*const he_errlist
[] = {
173 STR("unknown error"),
174 STR("malloc() failed"),
175 STR("first event not found"),
176 STR("last event not found"),
178 STR("no next event"),
179 STR("no previous event"),
180 STR("current event is invalid"),
181 STR("event not found"),
182 STR("can't read history from file"),
183 STR("can't write history"),
184 STR("required parameter(s) not supplied"),
185 STR("history size negative"),
186 STR("function not allowed with other history-functions-set the default"),
187 STR("bad parameters")
191 #define _HE_UNKNOWN 1
192 #define _HE_MALLOC_FAILED 2
193 #define _HE_FIRST_NOTFOUND 3
194 #define _HE_LAST_NOTFOUND 4
195 #define _HE_EMPTY_LIST 5
196 #define _HE_END_REACHED 6
197 #define _HE_START_REACHED 7
198 #define _HE_CURR_INVALID 8
199 #define _HE_NOT_FOUND 9
200 #define _HE_HIST_READ 10
201 #define _HE_HIST_WRITE 11
202 #define _HE_PARAM_MISSING 12
203 #define _HE_SIZE_NEGATIVE 13
204 #define _HE_NOT_ALLOWED 14
205 #define _HE_BAD_PARAM 15
207 /* history_def_first():
208 * Default function to return the first event in the history.
211 history_def_first(void *p
, TYPE(HistEvent
) *ev
)
213 history_t
*h
= (history_t
*) p
;
215 h
->cursor
= h
->list
.next
;
216 if (h
->cursor
!= &h
->list
)
219 he_seterrev(ev
, _HE_FIRST_NOTFOUND
);
227 /* history_def_last():
228 * Default function to return the last event in the history.
231 history_def_last(void *p
, TYPE(HistEvent
) *ev
)
233 history_t
*h
= (history_t
*) p
;
235 h
->cursor
= h
->list
.prev
;
236 if (h
->cursor
!= &h
->list
)
239 he_seterrev(ev
, _HE_LAST_NOTFOUND
);
247 /* history_def_next():
248 * Default function to return the next event in the history.
251 history_def_next(void *p
, TYPE(HistEvent
) *ev
)
253 history_t
*h
= (history_t
*) p
;
255 if (h
->cursor
== &h
->list
) {
256 he_seterrev(ev
, _HE_EMPTY_LIST
);
260 if (h
->cursor
->next
== &h
->list
) {
261 he_seterrev(ev
, _HE_END_REACHED
);
265 h
->cursor
= h
->cursor
->next
;
272 /* history_def_prev():
273 * Default function to return the previous event in the history.
276 history_def_prev(void *p
, TYPE(HistEvent
) *ev
)
278 history_t
*h
= (history_t
*) p
;
280 if (h
->cursor
== &h
->list
) {
282 (h
->cur
> 0) ? _HE_END_REACHED
: _HE_EMPTY_LIST
);
286 if (h
->cursor
->prev
== &h
->list
) {
287 he_seterrev(ev
, _HE_START_REACHED
);
291 h
->cursor
= h
->cursor
->prev
;
298 /* history_def_curr():
299 * Default function to return the current event in the history.
302 history_def_curr(void *p
, TYPE(HistEvent
) *ev
)
304 history_t
*h
= (history_t
*) p
;
306 if (h
->cursor
!= &h
->list
)
310 (h
->cur
> 0) ? _HE_CURR_INVALID
: _HE_EMPTY_LIST
);
318 /* history_def_set():
319 * Default function to set the current event in the history to the
323 history_def_set(void *p
, TYPE(HistEvent
) *ev
, const int n
)
325 history_t
*h
= (history_t
*) p
;
328 he_seterrev(ev
, _HE_EMPTY_LIST
);
331 if (h
->cursor
== &h
->list
|| h
->cursor
->ev
.num
!= n
) {
332 for (h
->cursor
= h
->list
.next
; h
->cursor
!= &h
->list
;
333 h
->cursor
= h
->cursor
->next
)
334 if (h
->cursor
->ev
.num
== n
)
337 if (h
->cursor
== &h
->list
) {
338 he_seterrev(ev
, _HE_NOT_FOUND
);
345 /* history_set_nth():
346 * Default function to set the current event in the history to the
350 history_set_nth(void *p
, TYPE(HistEvent
) *ev
, int n
)
352 history_t
*h
= (history_t
*) p
;
355 he_seterrev(ev
, _HE_EMPTY_LIST
);
358 for (h
->cursor
= h
->list
.prev
; h
->cursor
!= &h
->list
;
359 h
->cursor
= h
->cursor
->prev
)
362 if (h
->cursor
== &h
->list
) {
363 he_seterrev(ev
, _HE_NOT_FOUND
);
370 /* history_def_add():
371 * Append string to element
374 history_def_add(void *p
, TYPE(HistEvent
) *ev
, const Char
*str
)
376 history_t
*h
= (history_t
*) p
;
379 HistEventPrivate
*evp
= (void *)&h
->cursor
->ev
;
381 if (h
->cursor
== &h
->list
)
382 return history_def_enter(p
, ev
, str
);
383 len
= Strlen(evp
->str
) + Strlen(str
) + 1;
384 s
= h_malloc(len
* sizeof(*s
));
386 he_seterrev(ev
, _HE_MALLOC_FAILED
);
389 (void) Strncpy(s
, h
->cursor
->ev
.str
, len
);
391 (void) Strncat(s
, str
, len
- Strlen(s
) - 1);
400 history_deldata_nth(history_t
*h
, TYPE(HistEvent
) *ev
,
401 int num
, void **data
)
403 if (history_set_nth(h
, ev
, num
) != 0)
405 /* magic value to skip delete (just set to n-th history) */
406 if (data
== (void **)-1)
408 ev
->str
= Strdup(h
->cursor
->ev
.str
);
409 ev
->num
= h
->cursor
->ev
.num
;
411 *data
= h
->cursor
->data
;
412 history_def_delete(h
, ev
, h
->cursor
);
417 /* history_def_del():
418 * Delete element hp of the h list
422 history_def_del(void *p
, TYPE(HistEvent
) *ev
__attribute__((__unused__
)),
425 history_t
*h
= (history_t
*) p
;
426 if (history_def_set(h
, ev
, num
) != 0)
428 ev
->str
= Strdup(h
->cursor
->ev
.str
);
429 ev
->num
= h
->cursor
->ev
.num
;
430 history_def_delete(h
, ev
, h
->cursor
);
435 /* history_def_delete():
436 * Delete element hp of the h list
440 history_def_delete(history_t
*h
,
441 TYPE(HistEvent
) *ev
__attribute__((__unused__
)), hentry_t
*hp
)
443 HistEventPrivate
*evp
= (void *)&hp
->ev
;
446 if (h
->cursor
== hp
) {
447 h
->cursor
= hp
->prev
;
448 if (h
->cursor
== &h
->list
)
449 h
->cursor
= hp
->next
;
451 hp
->prev
->next
= hp
->next
;
452 hp
->next
->prev
= hp
->prev
;
459 /* history_def_insert():
460 * Insert element with string str in the h list
463 history_def_insert(history_t
*h
, TYPE(HistEvent
) *ev
, const Char
*str
)
467 c
= h_malloc(sizeof(*c
));
470 if ((c
->ev
.str
= h_strdup(str
)) == NULL
) {
475 c
->ev
.num
= ++h
->eventid
;
476 c
->next
= h
->list
.next
;
478 h
->list
.next
->prev
= c
;
486 he_seterrev(ev
, _HE_MALLOC_FAILED
);
491 /* history_def_enter():
492 * Default function to enter an item in the history
495 history_def_enter(void *p
, TYPE(HistEvent
) *ev
, const Char
*str
)
497 history_t
*h
= (history_t
*) p
;
499 if ((h
->flags
& H_UNIQUE
) != 0 && h
->list
.next
!= &h
->list
&&
500 Strcmp(h
->list
.next
->ev
.str
, str
) == 0)
503 if (history_def_insert(h
, ev
, str
) == -1)
504 return -1; /* error, keep error message */
507 * Always keep at least one entry.
508 * This way we don't have to check for the empty list.
510 while (h
->cur
> h
->max
&& h
->cur
> 0)
511 history_def_delete(h
, ev
, h
->list
.prev
);
517 /* history_def_init():
518 * Default history initialization function
522 history_def_init(void **p
, TYPE(HistEvent
) *ev
__attribute__((__unused__
)), int n
)
524 history_t
*h
= (history_t
*) h_malloc(sizeof(*h
));
533 h
->list
.next
= h
->list
.prev
= &h
->list
;
534 h
->list
.ev
.str
= NULL
;
536 h
->cursor
= &h
->list
;
543 /* history_def_clear():
544 * Default history cleanup function
547 history_def_clear(void *p
, TYPE(HistEvent
) *ev
)
549 history_t
*h
= (history_t
*) p
;
551 while (h
->list
.prev
!= &h
->list
)
552 history_def_delete(h
, ev
, h
->list
.prev
);
553 h
->cursor
= &h
->list
;
561 /************************************************************************/
564 * Initialization function.
566 public TYPE(History
) *
567 FUN(history
,init
)(void)
570 TYPE(History
) *h
= (TYPE(History
) *) h_malloc(sizeof(*h
));
574 if (history_def_init(&h
->h_ref
, &ev
, 0) == -1) {
579 h
->h_next
= history_def_next
;
580 h
->h_first
= history_def_first
;
581 h
->h_last
= history_def_last
;
582 h
->h_prev
= history_def_prev
;
583 h
->h_curr
= history_def_curr
;
584 h
->h_set
= history_def_set
;
585 h
->h_clear
= history_def_clear
;
586 h
->h_enter
= history_def_enter
;
587 h
->h_add
= history_def_add
;
588 h
->h_del
= history_def_del
;
598 FUN(history
,end
)(TYPE(History
) *h
)
602 if (h
->h_next
== history_def_next
)
603 history_def_clear(h
->h_ref
, &ev
);
610 /* history_setsize():
611 * Set history number of events
614 history_setsize(TYPE(History
) *h
, TYPE(HistEvent
) *ev
, int num
)
617 if (h
->h_next
!= history_def_next
) {
618 he_seterrev(ev
, _HE_NOT_ALLOWED
);
622 he_seterrev(ev
, _HE_BAD_PARAM
);
625 history_def_setsize(h
->h_ref
, num
);
630 /* history_getsize():
631 * Get number of events currently in history
634 history_getsize(TYPE(History
) *h
, TYPE(HistEvent
) *ev
)
636 if (h
->h_next
!= history_def_next
) {
637 he_seterrev(ev
, _HE_NOT_ALLOWED
);
640 ev
->num
= history_def_getsize(h
->h_ref
);
642 he_seterrev(ev
, _HE_SIZE_NEGATIVE
);
649 /* history_setunique():
650 * Set if adjacent equal events should not be entered in history.
653 history_setunique(TYPE(History
) *h
, TYPE(HistEvent
) *ev
, int uni
)
656 if (h
->h_next
!= history_def_next
) {
657 he_seterrev(ev
, _HE_NOT_ALLOWED
);
660 history_def_setunique(h
->h_ref
, uni
);
665 /* history_getunique():
666 * Get if adjacent equal events should not be entered in history.
669 history_getunique(TYPE(History
) *h
, TYPE(HistEvent
) *ev
)
671 if (h
->h_next
!= history_def_next
) {
672 he_seterrev(ev
, _HE_NOT_ALLOWED
);
675 ev
->num
= history_def_getunique(h
->h_ref
);
680 /* history_set_fun():
681 * Set history functions
684 history_set_fun(TYPE(History
) *h
, TYPE(History
) *nh
)
688 if (nh
->h_first
== NULL
|| nh
->h_next
== NULL
|| nh
->h_last
== NULL
||
689 nh
->h_prev
== NULL
|| nh
->h_curr
== NULL
|| nh
->h_set
== NULL
||
690 nh
->h_enter
== NULL
|| nh
->h_add
== NULL
|| nh
->h_clear
== NULL
||
691 nh
->h_del
== NULL
|| nh
->h_ref
== NULL
) {
692 if (h
->h_next
!= history_def_next
) {
693 if (history_def_init(&h
->h_ref
, &ev
, 0) == -1)
695 h
->h_first
= history_def_first
;
696 h
->h_next
= history_def_next
;
697 h
->h_last
= history_def_last
;
698 h
->h_prev
= history_def_prev
;
699 h
->h_curr
= history_def_curr
;
700 h
->h_set
= history_def_set
;
701 h
->h_clear
= history_def_clear
;
702 h
->h_enter
= history_def_enter
;
703 h
->h_add
= history_def_add
;
704 h
->h_del
= history_def_del
;
708 if (h
->h_next
== history_def_next
)
709 history_def_clear(h
->h_ref
, &ev
);
712 h
->h_first
= nh
->h_first
;
713 h
->h_next
= nh
->h_next
;
714 h
->h_last
= nh
->h_last
;
715 h
->h_prev
= nh
->h_prev
;
716 h
->h_curr
= nh
->h_curr
;
717 h
->h_set
= nh
->h_set
;
718 h
->h_clear
= nh
->h_clear
;
719 h
->h_enter
= nh
->h_enter
;
720 h
->h_add
= nh
->h_add
;
721 h
->h_del
= nh
->h_del
;
728 * TYPE(History) load function
731 history_load(TYPE(History
) *h
, const char *fname
)
740 static ct_buffer_t conv
;
743 if ((fp
= fopen(fname
, "r")) == NULL
)
746 if ((line
= fgetln(fp
, &sz
)) == NULL
)
749 if (strncmp(line
, hist_cookie
, sz
) != 0)
752 ptr
= h_malloc((max_size
= 1024) * sizeof(*ptr
));
755 for (i
= 0; (line
= fgetln(fp
, &sz
)) != NULL
; i
++) {
758 if (sz
!= 0 && line
[sz
- 1] == '\n')
765 max_size
= (sz
+ 1024) & (size_t)~1023;
766 nptr
= h_realloc(ptr
, max_size
* sizeof(*ptr
));
773 (void) strunvis(ptr
, line
);
775 if (HENTER(h
, &ev
, ct_decode_string(ptr
, &conv
)) == -1) {
788 /* history_save_fp():
789 * TYPE(History) save function
792 history_save_fp(TYPE(History
) *h
, FILE *fp
)
796 size_t len
, max_size
;
800 static ct_buffer_t conv
;
803 if (fchmod(fileno(fp
), S_IRUSR
|S_IWUSR
) == -1)
805 if (fputs(hist_cookie
, fp
) == EOF
)
807 ptr
= h_malloc((max_size
= 1024) * sizeof(*ptr
));
810 for (i
= 0, retval
= HLAST(h
, &ev
);
812 retval
= HPREV(h
, &ev
), i
++) {
813 str
= ct_encode_string(ev
.str
, &conv
);
814 len
= strlen(str
) * 4;
815 if (len
>= max_size
) {
817 max_size
= (len
+ 1024) & (size_t)~1023;
818 nptr
= h_realloc(ptr
, max_size
* sizeof(*ptr
));
825 (void) strvis(ptr
, str
, VIS_WHITE
);
826 (void) fprintf(fp
, "%s\n", ptr
);
836 * History save function
839 history_save(TYPE(History
) *h
, const char *fname
)
844 if ((fp
= fopen(fname
, "w")) == NULL
)
847 i
= history_save_fp(h
, fp
);
854 /* history_prev_event():
855 * Find the previous event, with number given
858 history_prev_event(TYPE(History
) *h
, TYPE(HistEvent
) *ev
, int num
)
862 for (retval
= HCURR(h
, ev
); retval
!= -1; retval
= HPREV(h
, ev
))
866 he_seterrev(ev
, _HE_NOT_FOUND
);
872 history_next_evdata(TYPE(History
) *h
, TYPE(HistEvent
) *ev
, int num
, void **d
)
876 for (retval
= HCURR(h
, ev
); retval
!= -1; retval
= HPREV(h
, ev
))
877 if (ev
->num
== num
) {
879 *d
= ((history_t
*)h
->h_ref
)->cursor
->data
;
883 he_seterrev(ev
, _HE_NOT_FOUND
);
888 /* history_next_event():
889 * Find the next event, with number given
892 history_next_event(TYPE(History
) *h
, TYPE(HistEvent
) *ev
, int num
)
896 for (retval
= HCURR(h
, ev
); retval
!= -1; retval
= HNEXT(h
, ev
))
900 he_seterrev(ev
, _HE_NOT_FOUND
);
905 /* history_prev_string():
906 * Find the previous event beginning with string
909 history_prev_string(TYPE(History
) *h
, TYPE(HistEvent
) *ev
, const Char
*str
)
911 size_t len
= Strlen(str
);
914 for (retval
= HCURR(h
, ev
); retval
!= -1; retval
= HNEXT(h
, ev
))
915 if (Strncmp(str
, ev
->str
, len
) == 0)
918 he_seterrev(ev
, _HE_NOT_FOUND
);
923 /* history_next_string():
924 * Find the next event beginning with string
927 history_next_string(TYPE(History
) *h
, TYPE(HistEvent
) *ev
, const Char
*str
)
929 size_t len
= Strlen(str
);
932 for (retval
= HCURR(h
, ev
); retval
!= -1; retval
= HPREV(h
, ev
))
933 if (Strncmp(str
, ev
->str
, len
) == 0)
936 he_seterrev(ev
, _HE_NOT_FOUND
);
942 * User interface to history functions.
945 FUNW(history
)(TYPE(History
) *h
, TYPE(HistEvent
) *ev
, int fun
, ...)
953 he_seterrev(ev
, _HE_OK
);
957 retval
= history_getsize(h
, ev
);
961 retval
= history_setsize(h
, ev
, va_arg(va
, int));
965 retval
= history_getunique(h
, ev
);
969 retval
= history_setunique(h
, ev
, va_arg(va
, int));
973 str
= va_arg(va
, const Char
*);
974 retval
= HADD(h
, ev
, str
);
978 retval
= HDEL(h
, ev
, va_arg(va
, const int));
982 str
= va_arg(va
, const Char
*);
983 if ((retval
= HENTER(h
, ev
, str
)) != -1)
988 str
= va_arg(va
, const Char
*);
989 if ((retval
= HSET(h
, ev
, h
->h_ent
)) != -1)
990 retval
= HADD(h
, ev
, str
);
994 retval
= HFIRST(h
, ev
);
998 retval
= HNEXT(h
, ev
);
1002 retval
= HLAST(h
, ev
);
1006 retval
= HPREV(h
, ev
);
1010 retval
= HCURR(h
, ev
);
1014 retval
= HSET(h
, ev
, va_arg(va
, const int));
1023 retval
= history_load(h
, va_arg(va
, const char *));
1025 he_seterrev(ev
, _HE_HIST_READ
);
1029 retval
= history_save(h
, va_arg(va
, const char *));
1031 he_seterrev(ev
, _HE_HIST_WRITE
);
1035 retval
= history_save_fp(h
, va_arg(va
, FILE *));
1037 he_seterrev(ev
, _HE_HIST_WRITE
);
1041 retval
= history_prev_event(h
, ev
, va_arg(va
, int));
1045 retval
= history_next_event(h
, ev
, va_arg(va
, int));
1049 retval
= history_prev_string(h
, ev
, va_arg(va
, const Char
*));
1053 retval
= history_next_string(h
, ev
, va_arg(va
, const Char
*));
1060 hf
.h_ref
= va_arg(va
, void *);
1062 hf
.h_first
= va_arg(va
, history_gfun_t
);
1063 hf
.h_next
= va_arg(va
, history_gfun_t
);
1064 hf
.h_last
= va_arg(va
, history_gfun_t
);
1065 hf
.h_prev
= va_arg(va
, history_gfun_t
);
1066 hf
.h_curr
= va_arg(va
, history_gfun_t
);
1067 hf
.h_set
= va_arg(va
, history_sfun_t
);
1068 hf
.h_clear
= va_arg(va
, history_vfun_t
);
1069 hf
.h_enter
= va_arg(va
, history_efun_t
);
1070 hf
.h_add
= va_arg(va
, history_efun_t
);
1071 hf
.h_del
= va_arg(va
, history_sfun_t
);
1073 if ((retval
= history_set_fun(h
, &hf
)) == -1)
1074 he_seterrev(ev
, _HE_PARAM_MISSING
);
1079 FUN(history
,end
)(h
);
1085 int num
= va_arg(va
, int);
1086 void **d
= va_arg(va
, void **);
1087 retval
= history_next_evdata(h
, ev
, num
, d
);
1093 int num
= va_arg(va
, int);
1094 void **d
= va_arg(va
, void **);
1095 retval
= history_deldata_nth((history_t
*)h
->h_ref
, ev
, num
, d
);
1099 case H_REPLACE
: /* only use after H_NEXT_EVDATA */
1101 const Char
*line
= va_arg(va
, const Char
*);
1102 void *d
= va_arg(va
, void *);
1104 if(!line
|| !(s
= Strdup(line
))) {
1108 ((history_t
*)h
->h_ref
)->cursor
->ev
.str
= s
;
1109 ((history_t
*)h
->h_ref
)->cursor
->data
= d
;
1116 he_seterrev(ev
, _HE_UNKNOWN
);