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