File: | src/lib/libedit/history.c |
Warning: | line 579, column 3 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: history.c,v 1.29 2023/03/08 04:43:05 guenther Exp $ */ | |||
2 | /* $NetBSD: history.c,v 1.37 2010/01/03 18:27:10 christos Exp $ */ | |||
3 | ||||
4 | /*- | |||
5 | * Copyright (c) 1992, 1993 | |||
6 | * The Regents of the University of California. All rights reserved. | |||
7 | * | |||
8 | * This code is derived from software contributed to Berkeley by | |||
9 | * Christos Zoulas of Cornell University. | |||
10 | * | |||
11 | * Redistribution and use in source and binary forms, with or without | |||
12 | * modification, are permitted provided that the following conditions | |||
13 | * are met: | |||
14 | * 1. Redistributions of source code must retain the above copyright | |||
15 | * notice, this list of conditions and the following disclaimer. | |||
16 | * 2. Redistributions in binary form must reproduce the above copyright | |||
17 | * notice, this list of conditions and the following disclaimer in the | |||
18 | * documentation and/or other materials provided with the distribution. | |||
19 | * 3. Neither the name of the University nor the names of its contributors | |||
20 | * may be used to endorse or promote products derived from this software | |||
21 | * without specific prior written permission. | |||
22 | * | |||
23 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |||
24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |||
27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||
28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||
29 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
30 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||
31 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||
32 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
33 | * SUCH DAMAGE. | |||
34 | */ | |||
35 | ||||
36 | #include "config.h" | |||
37 | ||||
38 | /* | |||
39 | * hist.c: TYPE(History) access functions | |||
40 | */ | |||
41 | #include <sys/stat.h> | |||
42 | #include <stdarg.h> | |||
43 | #include <stdlib.h> | |||
44 | #include <string.h> | |||
45 | #ifdef HAVE_VIS_H1 | |||
46 | #include <vis.h> | |||
47 | #else | |||
48 | #include "np/vis.h" | |||
49 | #endif | |||
50 | ||||
51 | static const char hist_cookie[] = "_HiStOrY_V2_\n"; | |||
52 | ||||
53 | #include "histedit.h" | |||
54 | ||||
55 | ||||
56 | #ifdef NARROWCHAR | |||
57 | ||||
58 | #define Charwchar_t char | |||
59 | #define FUN(prefix, rest)prefix_wrest prefix ## _ ## rest | |||
60 | #define FUNW(type)type_w type | |||
61 | #define TYPE(type)typeW type | |||
62 | #define STR(x)Lx x | |||
63 | ||||
64 | #define Strlen(s)wcslen(s) strlen(s) | |||
65 | #define Strdup(s)wcsdup(s) strdup(s) | |||
66 | #define Strcmp(d, s)wcscmp(d, s) strcmp(d, s) | |||
67 | #define Strncmp(d, s, n)wcsncmp(d, s, n) strncmp(d, s, n) | |||
68 | #define Strncpy(d, s, n)wcsncpy(d, s, n) strncpy(d, s, n) | |||
69 | #define Strncat(d, s, n)wcsncat(d, s, n) strncat(d, s, n) | |||
70 | #define ct_decode_string(s, b) (s) | |||
71 | #define ct_encode_string(s, b) (s) | |||
72 | ||||
73 | #else | |||
74 | #include "chartype.h" | |||
75 | ||||
76 | #define Charwchar_t wchar_t | |||
77 | #define FUN(prefix, rest)prefix_wrest prefix ## _w ## rest | |||
78 | #define FUNW(type)type_w type ## _w | |||
79 | #define TYPE(type)typeW type ## W | |||
80 | #define STR(x)Lx L ## x | |||
81 | ||||
82 | #define Strlen(s)wcslen(s) wcslen(s) | |||
83 | #define Strdup(s)wcsdup(s) wcsdup(s) | |||
84 | #define Strcmp(d, s)wcscmp(d, s) wcscmp(d, s) | |||
85 | #define Strncmp(d, s, n)wcsncmp(d, s, n) wcsncmp(d, s, n) | |||
86 | #define Strncpy(d, s, n)wcsncpy(d, s, n) wcsncpy(d, s, n) | |||
87 | #define Strncat(d, s, n)wcsncat(d, s, n) wcsncat(d, s, n) | |||
88 | ||||
89 | #endif | |||
90 | ||||
91 | ||||
92 | typedef int (*history_gfun_t)(void *, TYPE(HistEvent)HistEventW *); | |||
93 | typedef int (*history_efun_t)(void *, TYPE(HistEvent)HistEventW *, const Charwchar_t *); | |||
94 | typedef void (*history_vfun_t)(void *, TYPE(HistEvent)HistEventW *); | |||
95 | typedef int (*history_sfun_t)(void *, TYPE(HistEvent)HistEventW *, const int); | |||
96 | ||||
97 | struct TYPE(history)historyW { | |||
98 | void *h_ref; /* Argument for history fcns */ | |||
99 | int h_ent; /* Last entry point for history */ | |||
100 | history_gfun_t h_first; /* Get the first element */ | |||
101 | history_gfun_t h_next; /* Get the next element */ | |||
102 | history_gfun_t h_last; /* Get the last element */ | |||
103 | history_gfun_t h_prev; /* Get the previous element */ | |||
104 | history_gfun_t h_curr; /* Get the current element */ | |||
105 | history_sfun_t h_set; /* Set the current element */ | |||
106 | history_sfun_t h_del; /* Set the given element */ | |||
107 | history_vfun_t h_clear; /* Clear the history list */ | |||
108 | history_efun_t h_enter; /* Add an element */ | |||
109 | history_efun_t h_add; /* Append to an element */ | |||
110 | }; | |||
111 | ||||
112 | #define HNEXT(h, ev)(*(h)->h_next)((h)->h_ref, ev) (*(h)->h_next)((h)->h_ref, ev) | |||
113 | #define HFIRST(h, ev)(*(h)->h_first)((h)->h_ref, ev) (*(h)->h_first)((h)->h_ref, ev) | |||
114 | #define HPREV(h, ev)(*(h)->h_prev)((h)->h_ref, ev) (*(h)->h_prev)((h)->h_ref, ev) | |||
115 | #define HLAST(h, ev)(*(h)->h_last)((h)->h_ref, ev) (*(h)->h_last)((h)->h_ref, ev) | |||
116 | #define HCURR(h, ev)(*(h)->h_curr)((h)->h_ref, ev) (*(h)->h_curr)((h)->h_ref, ev) | |||
117 | #define HSET(h, ev, n)(*(h)->h_set)((h)->h_ref, ev, n) (*(h)->h_set)((h)->h_ref, ev, n) | |||
118 | #define HCLEAR(h, ev)(*(h)->h_clear)((h)->h_ref, ev) (*(h)->h_clear)((h)->h_ref, ev) | |||
119 | #define HENTER(h, ev, str)(*(h)->h_enter)((h)->h_ref, ev, str) (*(h)->h_enter)((h)->h_ref, ev, str) | |||
120 | #define HADD(h, ev, str)(*(h)->h_add)((h)->h_ref, ev, str) (*(h)->h_add)((h)->h_ref, ev, str) | |||
121 | #define HDEL(h, ev, n)(*(h)->h_del)((h)->h_ref, ev, n) (*(h)->h_del)((h)->h_ref, ev, n) | |||
122 | ||||
123 | #define h_strdup(a)wcsdup(a) Strdup(a)wcsdup(a) | |||
124 | ||||
125 | typedef struct { | |||
126 | int num; | |||
127 | Charwchar_t *str; | |||
128 | } HistEventPrivate; | |||
129 | ||||
130 | ||||
131 | static int history_setsize(TYPE(History)HistoryW *, TYPE(HistEvent)HistEventW *, int); | |||
132 | static int history_getsize(TYPE(History)HistoryW *, TYPE(HistEvent)HistEventW *); | |||
133 | static int history_setunique(TYPE(History)HistoryW *, TYPE(HistEvent)HistEventW *, int); | |||
134 | static int history_getunique(TYPE(History)HistoryW *, TYPE(HistEvent)HistEventW *); | |||
135 | static int history_set_fun(TYPE(History)HistoryW *, TYPE(History)HistoryW *); | |||
136 | static int history_load(TYPE(History)HistoryW *, const char *); | |||
137 | static int history_save(TYPE(History)HistoryW *, const char *); | |||
138 | static int history_save_fp(TYPE(History)HistoryW *, FILE *); | |||
139 | static int history_prev_event(TYPE(History)HistoryW *, TYPE(HistEvent)HistEventW *, int); | |||
140 | static int history_next_event(TYPE(History)HistoryW *, TYPE(HistEvent)HistEventW *, int); | |||
141 | static int history_next_string(TYPE(History)HistoryW *, TYPE(HistEvent)HistEventW *, | |||
142 | const Charwchar_t *); | |||
143 | static int history_prev_string(TYPE(History)HistoryW *, TYPE(HistEvent)HistEventW *, | |||
144 | const Charwchar_t *); | |||
145 | ||||
146 | ||||
147 | /***********************************************************************/ | |||
148 | ||||
149 | /* | |||
150 | * Builtin- history implementation | |||
151 | */ | |||
152 | typedef struct hentry_t { | |||
153 | TYPE(HistEvent)HistEventW ev; /* What we return */ | |||
154 | void *data; /* data */ | |||
155 | struct hentry_t *next; /* Next entry */ | |||
156 | struct hentry_t *prev; /* Previous entry */ | |||
157 | } hentry_t; | |||
158 | ||||
159 | typedef struct history_t { | |||
160 | hentry_t list; /* Fake list header element */ | |||
161 | hentry_t *cursor; /* Current element in the list */ | |||
162 | int max; /* Maximum number of events */ | |||
163 | int cur; /* Current number of events */ | |||
164 | int eventid; /* For generation of unique event id */ | |||
165 | int flags; /* TYPE(History) flags */ | |||
166 | #define H_UNIQUE1 1 /* Store only unique elements */ | |||
167 | } history_t; | |||
168 | ||||
169 | static int history_def_next(void *, TYPE(HistEvent)HistEventW *); | |||
170 | static int history_def_first(void *, TYPE(HistEvent)HistEventW *); | |||
171 | static int history_def_prev(void *, TYPE(HistEvent)HistEventW *); | |||
172 | static int history_def_last(void *, TYPE(HistEvent)HistEventW *); | |||
173 | static int history_def_curr(void *, TYPE(HistEvent)HistEventW *); | |||
174 | static int history_def_set(void *, TYPE(HistEvent)HistEventW *, const int); | |||
175 | static void history_def_clear(void *, TYPE(HistEvent)HistEventW *); | |||
176 | static int history_def_enter(void *, TYPE(HistEvent)HistEventW *, const Charwchar_t *); | |||
177 | static int history_def_add(void *, TYPE(HistEvent)HistEventW *, const Charwchar_t *); | |||
178 | static int history_def_del(void *, TYPE(HistEvent)HistEventW *, const int); | |||
179 | ||||
180 | static int history_def_init(void **, TYPE(HistEvent)HistEventW *, int); | |||
181 | static int history_def_insert(history_t *, TYPE(HistEvent)HistEventW *, const Charwchar_t *); | |||
182 | static void history_def_delete(history_t *, TYPE(HistEvent)HistEventW *, hentry_t *); | |||
183 | ||||
184 | static int history_deldata_nth(history_t *, TYPE(HistEvent)HistEventW *, int, void **); | |||
185 | static int history_set_nth(void *, TYPE(HistEvent)HistEventW *, int); | |||
186 | ||||
187 | #define history_def_setsize(p, num)(void) (((history_t *)p)->max = (num))(void) (((history_t *)p)->max = (num)) | |||
188 | #define history_def_getsize(p)(((history_t *)p)->cur) (((history_t *)p)->cur) | |||
189 | #define history_def_getunique(p)(((((history_t *)p)->flags) & 1) != 0) (((((history_t *)p)->flags) & H_UNIQUE1) != 0) | |||
190 | #define history_def_setunique(p, uni)if (uni) (((history_t *)p)->flags) |= 1; else (((history_t *)p)->flags) &= ~1 \ | |||
191 | if (uni) \ | |||
192 | (((history_t *)p)->flags) |= H_UNIQUE1; \ | |||
193 | else \ | |||
194 | (((history_t *)p)->flags) &= ~H_UNIQUE1 | |||
195 | ||||
196 | #define he_strerror(code)he_errlist[code] he_errlist[code] | |||
197 | #define he_seterrev(evp, code){ evp->num = code; evp->str = he_errlist[code]; } {\ | |||
198 | evp->num = code;\ | |||
199 | evp->str = he_strerror(code)he_errlist[code];\ | |||
200 | } | |||
201 | ||||
202 | /* error messages */ | |||
203 | static const Charwchar_t *const he_errlist[] = { | |||
204 | STR("OK")L"OK", | |||
205 | STR("unknown error")L"unknown error", | |||
206 | STR("malloc() failed")L"malloc() failed", | |||
207 | STR("first event not found")L"first event not found", | |||
208 | STR("last event not found")L"last event not found", | |||
209 | STR("empty list")L"empty list", | |||
210 | STR("no next event")L"no next event", | |||
211 | STR("no previous event")L"no previous event", | |||
212 | STR("current event is invalid")L"current event is invalid", | |||
213 | STR("event not found")L"event not found", | |||
214 | STR("can't read history from file")L"can't read history from file", | |||
215 | STR("can't write history")L"can't write history", | |||
216 | STR("required parameter(s) not supplied")L"required parameter(s) not supplied", | |||
217 | STR("history size negative")L"history size negative", | |||
218 | STR("function not allowed with other history-functions-set the default")L"function not allowed with other history-functions-set the default", | |||
219 | STR("bad parameters")L"bad parameters" | |||
220 | }; | |||
221 | /* error codes */ | |||
222 | #define _HE_OK0 0 | |||
223 | #define _HE_UNKNOWN1 1 | |||
224 | #define _HE_MALLOC_FAILED2 2 | |||
225 | #define _HE_FIRST_NOTFOUND3 3 | |||
226 | #define _HE_LAST_NOTFOUND4 4 | |||
227 | #define _HE_EMPTY_LIST5 5 | |||
228 | #define _HE_END_REACHED6 6 | |||
229 | #define _HE_START_REACHED7 7 | |||
230 | #define _HE_CURR_INVALID8 8 | |||
231 | #define _HE_NOT_FOUND9 9 | |||
232 | #define _HE_HIST_READ10 10 | |||
233 | #define _HE_HIST_WRITE11 11 | |||
234 | #define _HE_PARAM_MISSING12 12 | |||
235 | #define _HE_SIZE_NEGATIVE13 13 | |||
236 | #define _HE_NOT_ALLOWED14 14 | |||
237 | #define _HE_BAD_PARAM15 15 | |||
238 | ||||
239 | /* history_def_first(): | |||
240 | * Default function to return the first event in the history. | |||
241 | */ | |||
242 | static int | |||
243 | history_def_first(void *p, TYPE(HistEvent)HistEventW *ev) | |||
244 | { | |||
245 | history_t *h = (history_t *) p; | |||
246 | ||||
247 | h->cursor = h->list.next; | |||
248 | if (h->cursor != &h->list) | |||
249 | *ev = h->cursor->ev; | |||
250 | else { | |||
251 | he_seterrev(ev, _HE_FIRST_NOTFOUND){ ev->num = 3; ev->str = he_errlist[3]; }; | |||
252 | return -1; | |||
253 | } | |||
254 | ||||
255 | return 0; | |||
256 | } | |||
257 | ||||
258 | ||||
259 | /* history_def_last(): | |||
260 | * Default function to return the last event in the history. | |||
261 | */ | |||
262 | static int | |||
263 | history_def_last(void *p, TYPE(HistEvent)HistEventW *ev) | |||
264 | { | |||
265 | history_t *h = (history_t *) p; | |||
266 | ||||
267 | h->cursor = h->list.prev; | |||
268 | if (h->cursor != &h->list) | |||
269 | *ev = h->cursor->ev; | |||
270 | else { | |||
271 | he_seterrev(ev, _HE_LAST_NOTFOUND){ ev->num = 4; ev->str = he_errlist[4]; }; | |||
272 | return -1; | |||
273 | } | |||
274 | ||||
275 | return 0; | |||
276 | } | |||
277 | ||||
278 | ||||
279 | /* history_def_next(): | |||
280 | * Default function to return the next event in the history. | |||
281 | */ | |||
282 | static int | |||
283 | history_def_next(void *p, TYPE(HistEvent)HistEventW *ev) | |||
284 | { | |||
285 | history_t *h = (history_t *) p; | |||
286 | ||||
287 | if (h->cursor == &h->list) { | |||
288 | he_seterrev(ev, _HE_EMPTY_LIST){ ev->num = 5; ev->str = he_errlist[5]; }; | |||
289 | return -1; | |||
290 | } | |||
291 | ||||
292 | if (h->cursor->next == &h->list) { | |||
293 | he_seterrev(ev, _HE_END_REACHED){ ev->num = 6; ev->str = he_errlist[6]; }; | |||
294 | return -1; | |||
295 | } | |||
296 | ||||
297 | h->cursor = h->cursor->next; | |||
298 | *ev = h->cursor->ev; | |||
299 | ||||
300 | return 0; | |||
301 | } | |||
302 | ||||
303 | ||||
304 | /* history_def_prev(): | |||
305 | * Default function to return the previous event in the history. | |||
306 | */ | |||
307 | static int | |||
308 | history_def_prev(void *p, TYPE(HistEvent)HistEventW *ev) | |||
309 | { | |||
310 | history_t *h = (history_t *) p; | |||
311 | ||||
312 | if (h->cursor == &h->list) { | |||
313 | he_seterrev(ev,{ ev->num = (h->cur > 0) ? 6 : 5; ev->str = he_errlist [(h->cur > 0) ? 6 : 5]; } | |||
314 | (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST){ ev->num = (h->cur > 0) ? 6 : 5; ev->str = he_errlist [(h->cur > 0) ? 6 : 5]; }; | |||
315 | return -1; | |||
316 | } | |||
317 | ||||
318 | if (h->cursor->prev == &h->list) { | |||
319 | he_seterrev(ev, _HE_START_REACHED){ ev->num = 7; ev->str = he_errlist[7]; }; | |||
320 | return -1; | |||
321 | } | |||
322 | ||||
323 | h->cursor = h->cursor->prev; | |||
324 | *ev = h->cursor->ev; | |||
325 | ||||
326 | return 0; | |||
327 | } | |||
328 | ||||
329 | ||||
330 | /* history_def_curr(): | |||
331 | * Default function to return the current event in the history. | |||
332 | */ | |||
333 | static int | |||
334 | history_def_curr(void *p, TYPE(HistEvent)HistEventW *ev) | |||
335 | { | |||
336 | history_t *h = (history_t *) p; | |||
337 | ||||
338 | if (h->cursor != &h->list) | |||
339 | *ev = h->cursor->ev; | |||
340 | else { | |||
341 | he_seterrev(ev,{ ev->num = (h->cur > 0) ? 8 : 5; ev->str = he_errlist [(h->cur > 0) ? 8 : 5]; } | |||
342 | (h->cur > 0) ? _HE_CURR_INVALID : _HE_EMPTY_LIST){ ev->num = (h->cur > 0) ? 8 : 5; ev->str = he_errlist [(h->cur > 0) ? 8 : 5]; }; | |||
343 | return -1; | |||
344 | } | |||
345 | ||||
346 | return 0; | |||
347 | } | |||
348 | ||||
349 | ||||
350 | /* history_def_set(): | |||
351 | * Default function to set the current event in the history to the | |||
352 | * given one. | |||
353 | */ | |||
354 | static int | |||
355 | history_def_set(void *p, TYPE(HistEvent)HistEventW *ev, const int n) | |||
356 | { | |||
357 | history_t *h = (history_t *) p; | |||
358 | ||||
359 | if (h->cur == 0) { | |||
360 | he_seterrev(ev, _HE_EMPTY_LIST){ ev->num = 5; ev->str = he_errlist[5]; }; | |||
361 | return -1; | |||
362 | } | |||
363 | if (h->cursor == &h->list || h->cursor->ev.num != n) { | |||
364 | for (h->cursor = h->list.next; h->cursor != &h->list; | |||
365 | h->cursor = h->cursor->next) | |||
366 | if (h->cursor->ev.num == n) | |||
367 | break; | |||
368 | } | |||
369 | if (h->cursor == &h->list) { | |||
370 | he_seterrev(ev, _HE_NOT_FOUND){ ev->num = 9; ev->str = he_errlist[9]; }; | |||
371 | return -1; | |||
372 | } | |||
373 | return 0; | |||
374 | } | |||
375 | ||||
376 | ||||
377 | /* history_set_nth(): | |||
378 | * Default function to set the current event in the history to the | |||
379 | * n-th one. | |||
380 | */ | |||
381 | static int | |||
382 | history_set_nth(void *p, TYPE(HistEvent)HistEventW *ev, int n) | |||
383 | { | |||
384 | history_t *h = (history_t *) p; | |||
385 | ||||
386 | if (h->cur == 0) { | |||
387 | he_seterrev(ev, _HE_EMPTY_LIST){ ev->num = 5; ev->str = he_errlist[5]; }; | |||
388 | return -1; | |||
389 | } | |||
390 | for (h->cursor = h->list.prev; h->cursor != &h->list; | |||
391 | h->cursor = h->cursor->prev) | |||
392 | if (n-- <= 0) | |||
393 | break; | |||
394 | if (h->cursor == &h->list) { | |||
395 | he_seterrev(ev, _HE_NOT_FOUND){ ev->num = 9; ev->str = he_errlist[9]; }; | |||
396 | return -1; | |||
397 | } | |||
398 | return 0; | |||
399 | } | |||
400 | ||||
401 | ||||
402 | /* history_def_add(): | |||
403 | * Append string to element | |||
404 | */ | |||
405 | static int | |||
406 | history_def_add(void *p, TYPE(HistEvent)HistEventW *ev, const Charwchar_t *str) | |||
407 | { | |||
408 | history_t *h = (history_t *) p; | |||
409 | size_t len; | |||
410 | Charwchar_t *s; | |||
411 | HistEventPrivate *evp = (void *)&h->cursor->ev; | |||
412 | ||||
413 | if (h->cursor == &h->list) | |||
414 | return history_def_enter(p, ev, str); | |||
415 | len = Strlen(evp->str)wcslen(evp->str) + Strlen(str)wcslen(str) + 1; | |||
416 | s = reallocarray(NULL((void *)0), len, sizeof(*s)); | |||
417 | if (s == NULL((void *)0)) { | |||
418 | he_seterrev(ev, _HE_MALLOC_FAILED){ ev->num = 2; ev->str = he_errlist[2]; }; | |||
419 | return -1; | |||
420 | } | |||
421 | (void) Strncpy(s, h->cursor->ev.str, len)wcsncpy(s, h->cursor->ev.str, len); | |||
422 | s[len - 1] = '\0'; | |||
423 | (void) Strncat(s, str, len - Strlen(s) - 1)wcsncat(s, str, len - wcslen(s) - 1); | |||
424 | free(evp->str); | |||
425 | evp->str = s; | |||
426 | *ev = h->cursor->ev; | |||
427 | return 0; | |||
428 | } | |||
429 | ||||
430 | ||||
431 | static int | |||
432 | history_deldata_nth(history_t *h, TYPE(HistEvent)HistEventW *ev, | |||
433 | int num, void **data) | |||
434 | { | |||
435 | if (history_set_nth(h, ev, num) != 0) | |||
436 | return -1; | |||
437 | /* magic value to skip delete (just set to n-th history) */ | |||
438 | if (data == (void **)-1) | |||
439 | return 0; | |||
440 | ev->str = Strdup(h->cursor->ev.str)wcsdup(h->cursor->ev.str); | |||
441 | ev->num = h->cursor->ev.num; | |||
442 | if (data) | |||
443 | *data = h->cursor->data; | |||
444 | history_def_delete(h, ev, h->cursor); | |||
445 | return 0; | |||
446 | } | |||
447 | ||||
448 | ||||
449 | /* history_def_del(): | |||
450 | * Delete element hp of the h list | |||
451 | */ | |||
452 | static int | |||
453 | history_def_del(void *p, TYPE(HistEvent)HistEventW *ev __attribute__((__unused__)), | |||
454 | const int num) | |||
455 | { | |||
456 | history_t *h = (history_t *) p; | |||
457 | if (history_def_set(h, ev, num) != 0) | |||
458 | return -1; | |||
459 | ev->str = Strdup(h->cursor->ev.str)wcsdup(h->cursor->ev.str); | |||
460 | ev->num = h->cursor->ev.num; | |||
461 | history_def_delete(h, ev, h->cursor); | |||
462 | return 0; | |||
463 | } | |||
464 | ||||
465 | ||||
466 | /* history_def_delete(): | |||
467 | * Delete element hp of the h list | |||
468 | */ | |||
469 | static void | |||
470 | history_def_delete(history_t *h, | |||
471 | TYPE(HistEvent)HistEventW *ev __attribute__((__unused__)), hentry_t *hp) | |||
472 | { | |||
473 | HistEventPrivate *evp = (void *)&hp->ev; | |||
474 | if (hp == &h->list) | |||
475 | abort(); | |||
476 | if (h->cursor == hp) { | |||
477 | h->cursor = hp->prev; | |||
478 | if (h->cursor == &h->list) | |||
479 | h->cursor = hp->next; | |||
480 | } | |||
481 | hp->prev->next = hp->next; | |||
482 | hp->next->prev = hp->prev; | |||
483 | free(evp->str); | |||
484 | free(hp); | |||
485 | h->cur--; | |||
486 | } | |||
487 | ||||
488 | ||||
489 | /* history_def_insert(): | |||
490 | * Insert element with string str in the h list | |||
491 | */ | |||
492 | static int | |||
493 | history_def_insert(history_t *h, TYPE(HistEvent)HistEventW *ev, const Charwchar_t *str) | |||
494 | { | |||
495 | ||||
496 | h->cursor = (hentry_t *) malloc(sizeof(hentry_t)); | |||
497 | if (h->cursor == NULL((void *)0)) | |||
498 | goto oomem; | |||
499 | if ((h->cursor->ev.str = h_strdup(str)wcsdup(str)) == NULL((void *)0)) { | |||
500 | free(h->cursor); | |||
501 | goto oomem; | |||
502 | } | |||
503 | h->cursor->data = NULL((void *)0); | |||
504 | h->cursor->ev.num = ++h->eventid; | |||
505 | h->cursor->next = h->list.next; | |||
506 | h->cursor->prev = &h->list; | |||
507 | h->list.next->prev = h->cursor; | |||
508 | h->list.next = h->cursor; | |||
509 | h->cur++; | |||
510 | ||||
511 | *ev = h->cursor->ev; | |||
512 | return 0; | |||
513 | oomem: | |||
514 | he_seterrev(ev, _HE_MALLOC_FAILED){ ev->num = 2; ev->str = he_errlist[2]; }; | |||
515 | return -1; | |||
516 | } | |||
517 | ||||
518 | ||||
519 | /* history_def_enter(): | |||
520 | * Default function to enter an item in the history | |||
521 | */ | |||
522 | static int | |||
523 | history_def_enter(void *p, TYPE(HistEvent)HistEventW *ev, const Charwchar_t *str) | |||
524 | { | |||
525 | history_t *h = (history_t *) p; | |||
526 | ||||
527 | if ((h->flags & H_UNIQUE1) != 0 && h->list.next != &h->list && | |||
528 | Strcmp(h->list.next->ev.str, str)wcscmp(h->list.next->ev.str, str) == 0) | |||
529 | return 0; | |||
530 | ||||
531 | if (history_def_insert(h, ev, str) == -1) | |||
532 | return -1; /* error, keep error message */ | |||
533 | ||||
534 | /* | |||
535 | * Always keep at least one entry. | |||
536 | * This way we don't have to check for the empty list. | |||
537 | */ | |||
538 | while (h->cur > h->max && h->cur > 0) | |||
539 | history_def_delete(h, ev, h->list.prev); | |||
540 | ||||
541 | return 1; | |||
542 | } | |||
543 | ||||
544 | ||||
545 | /* history_def_init(): | |||
546 | * Default history initialization function | |||
547 | */ | |||
548 | static int | |||
549 | history_def_init(void **p, TYPE(HistEvent)HistEventW *ev __attribute__((__unused__)), int n) | |||
550 | { | |||
551 | history_t *h = (history_t *) malloc(sizeof(history_t)); | |||
552 | if (h == NULL((void *)0)) | |||
553 | return -1; | |||
554 | ||||
555 | if (n <= 0) | |||
556 | n = 0; | |||
557 | h->eventid = 0; | |||
558 | h->cur = 0; | |||
559 | h->max = n; | |||
560 | h->list.next = h->list.prev = &h->list; | |||
561 | h->list.ev.str = NULL((void *)0); | |||
562 | h->list.ev.num = 0; | |||
563 | h->cursor = &h->list; | |||
564 | h->flags = 0; | |||
565 | *p = h; | |||
566 | return 0; | |||
567 | } | |||
568 | ||||
569 | ||||
570 | /* history_def_clear(): | |||
571 | * Default history cleanup function | |||
572 | */ | |||
573 | static void | |||
574 | history_def_clear(void *p, TYPE(HistEvent)HistEventW *ev) | |||
575 | { | |||
576 | history_t *h = (history_t *) p; | |||
577 | ||||
578 | while (h->list.prev != &h->list) | |||
579 | history_def_delete(h, ev, h->list.prev); | |||
| ||||
580 | h->eventid = 0; | |||
581 | h->cur = 0; | |||
582 | } | |||
583 | ||||
584 | ||||
585 | ||||
586 | ||||
587 | /************************************************************************/ | |||
588 | ||||
589 | /* history_init(): | |||
590 | * Initialization function. | |||
591 | */ | |||
592 | TYPE(History)HistoryW * | |||
593 | FUN(history,init)history_winit(void) | |||
594 | { | |||
595 | TYPE(HistEvent)HistEventW ev; | |||
596 | TYPE(History)HistoryW *h = (TYPE(History)HistoryW *) malloc(sizeof(TYPE(History)HistoryW)); | |||
597 | if (h == NULL((void *)0)) | |||
598 | return NULL((void *)0); | |||
599 | ||||
600 | if (history_def_init(&h->h_ref, &ev, 0) == -1) { | |||
601 | free(h); | |||
602 | return NULL((void *)0); | |||
603 | } | |||
604 | h->h_ent = -1; | |||
605 | h->h_next = history_def_next; | |||
606 | h->h_first = history_def_first; | |||
607 | h->h_last = history_def_last; | |||
608 | h->h_prev = history_def_prev; | |||
609 | h->h_curr = history_def_curr; | |||
610 | h->h_set = history_def_set; | |||
611 | h->h_clear = history_def_clear; | |||
612 | h->h_enter = history_def_enter; | |||
613 | h->h_add = history_def_add; | |||
614 | h->h_del = history_def_del; | |||
615 | ||||
616 | return h; | |||
617 | } | |||
618 | ||||
619 | ||||
620 | /* history_end(): | |||
621 | * clean up history; | |||
622 | */ | |||
623 | void | |||
624 | FUN(history,end)history_wend(TYPE(History)HistoryW *h) | |||
625 | { | |||
626 | TYPE(HistEvent)HistEventW ev; | |||
627 | ||||
628 | if (h->h_next == history_def_next) | |||
629 | history_def_clear(h->h_ref, &ev); | |||
630 | free(h->h_ref); | |||
631 | free(h); | |||
632 | } | |||
633 | ||||
634 | ||||
635 | ||||
636 | /* history_setsize(): | |||
637 | * Set history number of events | |||
638 | */ | |||
639 | static int | |||
640 | history_setsize(TYPE(History)HistoryW *h, TYPE(HistEvent)HistEventW *ev, int num) | |||
641 | { | |||
642 | ||||
643 | if (h->h_next != history_def_next) { | |||
644 | he_seterrev(ev, _HE_NOT_ALLOWED){ ev->num = 14; ev->str = he_errlist[14]; }; | |||
645 | return -1; | |||
646 | } | |||
647 | if (num < 0) { | |||
648 | he_seterrev(ev, _HE_BAD_PARAM){ ev->num = 15; ev->str = he_errlist[15]; }; | |||
649 | return -1; | |||
650 | } | |||
651 | history_def_setsize(h->h_ref, num)(void) (((history_t *)h->h_ref)->max = (num)); | |||
652 | return 0; | |||
653 | } | |||
654 | ||||
655 | ||||
656 | /* history_getsize(): | |||
657 | * Get number of events currently in history | |||
658 | */ | |||
659 | static int | |||
660 | history_getsize(TYPE(History)HistoryW *h, TYPE(HistEvent)HistEventW *ev) | |||
661 | { | |||
662 | if (h->h_next != history_def_next) { | |||
663 | he_seterrev(ev, _HE_NOT_ALLOWED){ ev->num = 14; ev->str = he_errlist[14]; }; | |||
664 | return -1; | |||
665 | } | |||
666 | ev->num = history_def_getsize(h->h_ref)(((history_t *)h->h_ref)->cur); | |||
667 | if (ev->num < -1) { | |||
668 | he_seterrev(ev, _HE_SIZE_NEGATIVE){ ev->num = 13; ev->str = he_errlist[13]; }; | |||
669 | return -1; | |||
670 | } | |||
671 | return 0; | |||
672 | } | |||
673 | ||||
674 | ||||
675 | /* history_setunique(): | |||
676 | * Set if adjacent equal events should not be entered in history. | |||
677 | */ | |||
678 | static int | |||
679 | history_setunique(TYPE(History)HistoryW *h, TYPE(HistEvent)HistEventW *ev, int uni) | |||
680 | { | |||
681 | ||||
682 | if (h->h_next != history_def_next) { | |||
683 | he_seterrev(ev, _HE_NOT_ALLOWED){ ev->num = 14; ev->str = he_errlist[14]; }; | |||
684 | return -1; | |||
685 | } | |||
686 | history_def_setunique(h->h_ref, uni)if (uni) (((history_t *)h->h_ref)->flags) |= 1; else (( (history_t *)h->h_ref)->flags) &= ~1; | |||
687 | return 0; | |||
688 | } | |||
689 | ||||
690 | ||||
691 | /* history_getunique(): | |||
692 | * Get if adjacent equal events should not be entered in history. | |||
693 | */ | |||
694 | static int | |||
695 | history_getunique(TYPE(History)HistoryW *h, TYPE(HistEvent)HistEventW *ev) | |||
696 | { | |||
697 | if (h->h_next != history_def_next) { | |||
698 | he_seterrev(ev, _HE_NOT_ALLOWED){ ev->num = 14; ev->str = he_errlist[14]; }; | |||
699 | return -1; | |||
700 | } | |||
701 | ev->num = history_def_getunique(h->h_ref)(((((history_t *)h->h_ref)->flags) & 1) != 0); | |||
702 | return 0; | |||
703 | } | |||
704 | ||||
705 | ||||
706 | /* history_set_fun(): | |||
707 | * Set history functions | |||
708 | */ | |||
709 | static int | |||
710 | history_set_fun(TYPE(History)HistoryW *h, TYPE(History)HistoryW *nh) | |||
711 | { | |||
712 | TYPE(HistEvent)HistEventW ev; | |||
713 | ||||
714 | if (nh->h_first == NULL((void *)0) || nh->h_next == NULL((void *)0) || nh->h_last == NULL((void *)0) || | |||
715 | nh->h_prev == NULL((void *)0) || nh->h_curr == NULL((void *)0) || nh->h_set == NULL((void *)0) || | |||
716 | nh->h_enter == NULL((void *)0) || nh->h_add == NULL((void *)0) || nh->h_clear == NULL((void *)0) || | |||
717 | nh->h_del == NULL((void *)0) || nh->h_ref == NULL((void *)0)) { | |||
718 | if (h->h_next != history_def_next) { | |||
719 | history_def_init(&h->h_ref, &ev, 0); | |||
720 | h->h_first = history_def_first; | |||
721 | h->h_next = history_def_next; | |||
722 | h->h_last = history_def_last; | |||
723 | h->h_prev = history_def_prev; | |||
724 | h->h_curr = history_def_curr; | |||
725 | h->h_set = history_def_set; | |||
726 | h->h_clear = history_def_clear; | |||
727 | h->h_enter = history_def_enter; | |||
728 | h->h_add = history_def_add; | |||
729 | h->h_del = history_def_del; | |||
730 | } | |||
731 | return -1; | |||
732 | } | |||
733 | if (h->h_next == history_def_next) | |||
734 | history_def_clear(h->h_ref, &ev); | |||
735 | ||||
736 | h->h_ent = -1; | |||
737 | h->h_first = nh->h_first; | |||
738 | h->h_next = nh->h_next; | |||
739 | h->h_last = nh->h_last; | |||
740 | h->h_prev = nh->h_prev; | |||
741 | h->h_curr = nh->h_curr; | |||
742 | h->h_set = nh->h_set; | |||
743 | h->h_clear = nh->h_clear; | |||
744 | h->h_enter = nh->h_enter; | |||
745 | h->h_add = nh->h_add; | |||
746 | h->h_del = nh->h_del; | |||
747 | ||||
748 | return 0; | |||
749 | } | |||
750 | ||||
751 | ||||
752 | /* history_load(): | |||
753 | * TYPE(History) load function | |||
754 | */ | |||
755 | static int | |||
756 | history_load(TYPE(History)HistoryW *h, const char *fname) | |||
757 | { | |||
758 | FILE *fp; | |||
759 | char *line; | |||
760 | size_t llen; | |||
761 | ssize_t sz; | |||
762 | size_t max_size; | |||
763 | char *ptr; | |||
764 | int i = -1; | |||
765 | TYPE(HistEvent)HistEventW ev; | |||
766 | #ifndef NARROWCHAR | |||
767 | static ct_buffer_t conv; | |||
768 | #endif | |||
769 | ||||
770 | if ((fp = fopen(fname, "r")) == NULL((void *)0)) | |||
771 | return i; | |||
772 | ||||
773 | line = NULL((void *)0); | |||
774 | llen = 0; | |||
775 | if ((sz = getline(&line, &llen, fp)) == -1) | |||
776 | goto done; | |||
777 | ||||
778 | if (strncmp(line, hist_cookie, sz) != 0) | |||
779 | goto done; | |||
780 | ||||
781 | ptr = malloc(max_size = 1024); | |||
782 | if (ptr == NULL((void *)0)) | |||
783 | goto done; | |||
784 | for (i = 0; (sz = getline(&line, &llen, fp)) != -1; i++) { | |||
785 | if (sz > 0 && line[sz - 1] == '\n') | |||
786 | line[--sz] = '\0'; | |||
787 | if (max_size < sz) { | |||
788 | char *nptr; | |||
789 | max_size = (sz + 1024) & ~1023; | |||
790 | nptr = realloc(ptr, max_size); | |||
791 | if (nptr == NULL((void *)0)) { | |||
792 | i = -1; | |||
793 | goto oomem; | |||
794 | } | |||
795 | ptr = nptr; | |||
796 | } | |||
797 | (void) strunvis(ptr, line); | |||
798 | if (HENTER(h, &ev, ct_decode_string(ptr, &conv))(*(h)->h_enter)((h)->h_ref, &ev, ct_decode_string(ptr , &conv)) == -1) { | |||
799 | i = -1; | |||
800 | goto oomem; | |||
801 | } | |||
802 | } | |||
803 | oomem: | |||
804 | free(ptr); | |||
805 | done: | |||
806 | free(line); | |||
807 | (void) fclose(fp); | |||
808 | return i; | |||
809 | } | |||
810 | ||||
811 | ||||
812 | /* history_save_fp(): | |||
813 | * TYPE(History) save function | |||
814 | */ | |||
815 | static int | |||
816 | history_save_fp(TYPE(History)HistoryW *h, FILE *fp) | |||
817 | { | |||
818 | TYPE(HistEvent)HistEventW ev; | |||
819 | int i = -1, retval; | |||
820 | size_t len, max_size; | |||
821 | char *ptr; | |||
822 | #ifndef NARROWCHAR | |||
823 | static ct_buffer_t conv; | |||
824 | #endif | |||
825 | ||||
826 | if (fchmod(fileno(fp)(!__isthreaded ? ((fp)->_file) : (fileno)(fp)), S_IRUSR0000400|S_IWUSR0000200) == -1) | |||
827 | goto done; | |||
828 | if (fputs(hist_cookie, fp) == EOF(-1)) | |||
829 | goto done; | |||
830 | ptr = malloc(max_size = 1024); | |||
831 | if (ptr == NULL((void *)0)) | |||
832 | goto done; | |||
833 | for (i = 0, retval = HLAST(h, &ev)(*(h)->h_last)((h)->h_ref, &ev); | |||
834 | retval != -1; | |||
835 | retval = HPREV(h, &ev)(*(h)->h_prev)((h)->h_ref, &ev), i++) { | |||
836 | len = Strlen(ev.str)wcslen(ev.str) * 4 + 1; | |||
837 | if (len > max_size) { | |||
838 | char *nptr; | |||
839 | max_size = (len + 1024) & ~1023; | |||
840 | nptr = realloc(ptr, max_size); | |||
841 | if (nptr == NULL((void *)0)) { | |||
842 | i = -1; | |||
843 | goto oomem; | |||
844 | } | |||
845 | ptr = nptr; | |||
846 | } | |||
847 | (void) strnvis(ptr, ct_encode_string(ev.str, &conv), max_size, | |||
848 | VIS_WHITE(0x04 | 0x08 | 0x10)); | |||
849 | (void) fprintf(fp, "%s\n", ptr); | |||
850 | } | |||
851 | oomem: | |||
852 | free(ptr); | |||
853 | done: | |||
854 | return i; | |||
855 | } | |||
856 | ||||
857 | ||||
858 | /* history_save(): | |||
859 | * History save function | |||
860 | */ | |||
861 | static int | |||
862 | history_save(TYPE(History)HistoryW *h, const char *fname) | |||
863 | { | |||
864 | FILE *fp; | |||
865 | int i; | |||
866 | ||||
867 | if ((fp = fopen(fname, "w")) == NULL((void *)0)) | |||
868 | return -1; | |||
869 | ||||
870 | i = history_save_fp(h, fp); | |||
871 | ||||
872 | (void) fclose(fp); | |||
873 | return i; | |||
874 | } | |||
875 | ||||
876 | ||||
877 | /* history_prev_event(): | |||
878 | * Find the previous event, with number given | |||
879 | */ | |||
880 | static int | |||
881 | history_prev_event(TYPE(History)HistoryW *h, TYPE(HistEvent)HistEventW *ev, int num) | |||
882 | { | |||
883 | int retval; | |||
884 | ||||
885 | for (retval = HCURR(h, ev)(*(h)->h_curr)((h)->h_ref, ev); retval != -1; retval = HPREV(h, ev)(*(h)->h_prev)((h)->h_ref, ev)) | |||
886 | if (ev->num == num) | |||
887 | return 0; | |||
888 | ||||
889 | he_seterrev(ev, _HE_NOT_FOUND){ ev->num = 9; ev->str = he_errlist[9]; }; | |||
890 | return -1; | |||
891 | } | |||
892 | ||||
893 | ||||
894 | static int | |||
895 | history_next_evdata(TYPE(History)HistoryW *h, TYPE(HistEvent)HistEventW *ev, int num, void **d) | |||
896 | { | |||
897 | int retval; | |||
898 | ||||
899 | for (retval = HCURR(h, ev)(*(h)->h_curr)((h)->h_ref, ev); retval != -1; retval = HPREV(h, ev)(*(h)->h_prev)((h)->h_ref, ev)) | |||
900 | if (ev->num == num) { | |||
901 | if (d) | |||
902 | *d = ((history_t *)h->h_ref)->cursor->data; | |||
903 | return 0; | |||
904 | } | |||
905 | ||||
906 | he_seterrev(ev, _HE_NOT_FOUND){ ev->num = 9; ev->str = he_errlist[9]; }; | |||
907 | return -1; | |||
908 | } | |||
909 | ||||
910 | ||||
911 | /* history_next_event(): | |||
912 | * Find the next event, with number given | |||
913 | */ | |||
914 | static int | |||
915 | history_next_event(TYPE(History)HistoryW *h, TYPE(HistEvent)HistEventW *ev, int num) | |||
916 | { | |||
917 | int retval; | |||
918 | ||||
919 | for (retval = HCURR(h, ev)(*(h)->h_curr)((h)->h_ref, ev); retval != -1; retval = HNEXT(h, ev)(*(h)->h_next)((h)->h_ref, ev)) | |||
920 | if (ev->num == num) | |||
921 | return 0; | |||
922 | ||||
923 | he_seterrev(ev, _HE_NOT_FOUND){ ev->num = 9; ev->str = he_errlist[9]; }; | |||
924 | return -1; | |||
925 | } | |||
926 | ||||
927 | ||||
928 | /* history_prev_string(): | |||
929 | * Find the previous event beginning with string | |||
930 | */ | |||
931 | static int | |||
932 | history_prev_string(TYPE(History)HistoryW *h, TYPE(HistEvent)HistEventW *ev, const Charwchar_t *str) | |||
933 | { | |||
934 | size_t len = Strlen(str)wcslen(str); | |||
935 | int retval; | |||
936 | ||||
937 | for (retval = HCURR(h, ev)(*(h)->h_curr)((h)->h_ref, ev); retval != -1; retval = HNEXT(h, ev)(*(h)->h_next)((h)->h_ref, ev)) | |||
938 | if (Strncmp(str, ev->str, len)wcsncmp(str, ev->str, len) == 0) | |||
939 | return 0; | |||
940 | ||||
941 | he_seterrev(ev, _HE_NOT_FOUND){ ev->num = 9; ev->str = he_errlist[9]; }; | |||
942 | return -1; | |||
943 | } | |||
944 | ||||
945 | ||||
946 | /* history_next_string(): | |||
947 | * Find the next event beginning with string | |||
948 | */ | |||
949 | static int | |||
950 | history_next_string(TYPE(History)HistoryW *h, TYPE(HistEvent)HistEventW *ev, const Charwchar_t *str) | |||
951 | { | |||
952 | size_t len = Strlen(str)wcslen(str); | |||
953 | int retval; | |||
954 | ||||
955 | for (retval = HCURR(h, ev)(*(h)->h_curr)((h)->h_ref, ev); retval != -1; retval = HPREV(h, ev)(*(h)->h_prev)((h)->h_ref, ev)) | |||
956 | if (Strncmp(str, ev->str, len)wcsncmp(str, ev->str, len) == 0) | |||
957 | return 0; | |||
958 | ||||
959 | he_seterrev(ev, _HE_NOT_FOUND){ ev->num = 9; ev->str = he_errlist[9]; }; | |||
960 | return -1; | |||
961 | } | |||
962 | ||||
963 | ||||
964 | /* history(): | |||
965 | * User interface to history functions. | |||
966 | */ | |||
967 | int | |||
968 | FUNW(history)history_w(TYPE(History)HistoryW *h, TYPE(HistEvent)HistEventW *ev, int fun, ...) | |||
969 | { | |||
970 | va_list va; | |||
971 | const Charwchar_t *str; | |||
972 | int retval; | |||
973 | ||||
974 | va_start(va, fun)__builtin_va_start((va), fun); | |||
975 | ||||
976 | he_seterrev(ev, _HE_OK){ ev->num = 0; ev->str = he_errlist[0]; }; | |||
977 | ||||
978 | switch (fun) { | |||
| ||||
979 | case H_GETSIZE2: | |||
980 | retval = history_getsize(h, ev); | |||
981 | break; | |||
982 | ||||
983 | case H_SETSIZE1: | |||
984 | retval = history_setsize(h, ev, va_arg(va, int)__builtin_va_arg((va), int)); | |||
985 | break; | |||
986 | ||||
987 | case H_GETUNIQUE21: | |||
988 | retval = history_getunique(h, ev); | |||
989 | break; | |||
990 | ||||
991 | case H_SETUNIQUE20: | |||
992 | retval = history_setunique(h, ev, va_arg(va, int)__builtin_va_arg((va), int)); | |||
993 | break; | |||
994 | ||||
995 | case H_ADD9: | |||
996 | str = va_arg(va, const Char *)__builtin_va_arg((va), const wchar_t *); | |||
997 | retval = HADD(h, ev, str)(*(h)->h_add)((h)->h_ref, ev, str); | |||
998 | break; | |||
999 | ||||
1000 | case H_DEL22: | |||
1001 | retval = HDEL(h, ev, va_arg(va, const int))(*(h)->h_del)((h)->h_ref, ev, __builtin_va_arg((va), const int)); | |||
1002 | break; | |||
1003 | ||||
1004 | case H_ENTER10: | |||
1005 | str = va_arg(va, const Char *)__builtin_va_arg((va), const wchar_t *); | |||
1006 | if ((retval = HENTER(h, ev, str)(*(h)->h_enter)((h)->h_ref, ev, str)) != -1) | |||
1007 | h->h_ent = ev->num; | |||
1008 | break; | |||
1009 | ||||
1010 | case H_APPEND11: | |||
1011 | str = va_arg(va, const Char *)__builtin_va_arg((va), const wchar_t *); | |||
1012 | if ((retval = HSET(h, ev, h->h_ent)(*(h)->h_set)((h)->h_ref, ev, h->h_ent)) != -1) | |||
1013 | retval = HADD(h, ev, str)(*(h)->h_add)((h)->h_ref, ev, str); | |||
1014 | break; | |||
1015 | ||||
1016 | case H_FIRST3: | |||
1017 | retval = HFIRST(h, ev)(*(h)->h_first)((h)->h_ref, ev); | |||
1018 | break; | |||
1019 | ||||
1020 | case H_NEXT6: | |||
1021 | retval = HNEXT(h, ev)(*(h)->h_next)((h)->h_ref, ev); | |||
1022 | break; | |||
1023 | ||||
1024 | case H_LAST4: | |||
1025 | retval = HLAST(h, ev)(*(h)->h_last)((h)->h_ref, ev); | |||
1026 | break; | |||
1027 | ||||
1028 | case H_PREV5: | |||
1029 | retval = HPREV(h, ev)(*(h)->h_prev)((h)->h_ref, ev); | |||
1030 | break; | |||
1031 | ||||
1032 | case H_CURR8: | |||
1033 | retval = HCURR(h, ev)(*(h)->h_curr)((h)->h_ref, ev); | |||
1034 | break; | |||
1035 | ||||
1036 | case H_SET7: | |||
1037 | retval = HSET(h, ev, va_arg(va, const int))(*(h)->h_set)((h)->h_ref, ev, __builtin_va_arg((va), const int)); | |||
1038 | break; | |||
1039 | ||||
1040 | case H_CLEAR19: | |||
1041 | HCLEAR(h, ev)(*(h)->h_clear)((h)->h_ref, ev); | |||
1042 | retval = 0; | |||
1043 | break; | |||
1044 | ||||
1045 | case H_LOAD17: | |||
1046 | retval = history_load(h, va_arg(va, const char *)__builtin_va_arg((va), const char *)); | |||
1047 | if (retval == -1) | |||
1048 | he_seterrev(ev, _HE_HIST_READ){ ev->num = 10; ev->str = he_errlist[10]; }; | |||
1049 | break; | |||
1050 | ||||
1051 | case H_SAVE18: | |||
1052 | retval = history_save(h, va_arg(va, const char *)__builtin_va_arg((va), const char *)); | |||
1053 | if (retval == -1) | |||
1054 | he_seterrev(ev, _HE_HIST_WRITE){ ev->num = 11; ev->str = he_errlist[11]; }; | |||
1055 | break; | |||
1056 | ||||
1057 | case H_SAVE_FP26: | |||
1058 | retval = history_save_fp(h, va_arg(va, FILE *)__builtin_va_arg((va), FILE *)); | |||
1059 | if (retval == -1) | |||
1060 | he_seterrev(ev, _HE_HIST_WRITE){ ev->num = 11; ev->str = he_errlist[11]; }; | |||
1061 | break; | |||
1062 | ||||
1063 | case H_PREV_EVENT16: | |||
1064 | retval = history_prev_event(h, ev, va_arg(va, int)__builtin_va_arg((va), int)); | |||
1065 | break; | |||
1066 | ||||
1067 | case H_NEXT_EVENT15: | |||
1068 | retval = history_next_event(h, ev, va_arg(va, int)__builtin_va_arg((va), int)); | |||
1069 | break; | |||
1070 | ||||
1071 | case H_PREV_STR14: | |||
1072 | retval = history_prev_string(h, ev, va_arg(va, const Char *)__builtin_va_arg((va), const wchar_t *)); | |||
1073 | break; | |||
1074 | ||||
1075 | case H_NEXT_STR13: | |||
1076 | retval = history_next_string(h, ev, va_arg(va, const Char *)__builtin_va_arg((va), const wchar_t *)); | |||
1077 | break; | |||
1078 | ||||
1079 | case H_FUNC0: | |||
1080 | { | |||
1081 | TYPE(History)HistoryW hf; | |||
1082 | ||||
1083 | hf.h_ref = va_arg(va, void *)__builtin_va_arg((va), void *); | |||
1084 | h->h_ent = -1; | |||
1085 | hf.h_first = va_arg(va, history_gfun_t)__builtin_va_arg((va), history_gfun_t); | |||
1086 | hf.h_next = va_arg(va, history_gfun_t)__builtin_va_arg((va), history_gfun_t); | |||
1087 | hf.h_last = va_arg(va, history_gfun_t)__builtin_va_arg((va), history_gfun_t); | |||
1088 | hf.h_prev = va_arg(va, history_gfun_t)__builtin_va_arg((va), history_gfun_t); | |||
1089 | hf.h_curr = va_arg(va, history_gfun_t)__builtin_va_arg((va), history_gfun_t); | |||
1090 | hf.h_set = va_arg(va, history_sfun_t)__builtin_va_arg((va), history_sfun_t); | |||
1091 | hf.h_clear = va_arg(va, history_vfun_t)__builtin_va_arg((va), history_vfun_t); | |||
1092 | hf.h_enter = va_arg(va, history_efun_t)__builtin_va_arg((va), history_efun_t); | |||
1093 | hf.h_add = va_arg(va, history_efun_t)__builtin_va_arg((va), history_efun_t); | |||
1094 | hf.h_del = va_arg(va, history_sfun_t)__builtin_va_arg((va), history_sfun_t); | |||
1095 | ||||
1096 | if ((retval = history_set_fun(h, &hf)) == -1) | |||
1097 | he_seterrev(ev, _HE_PARAM_MISSING){ ev->num = 12; ev->str = he_errlist[12]; }; | |||
1098 | break; | |||
1099 | } | |||
1100 | ||||
1101 | case H_END12: | |||
1102 | FUN(history,end)history_wend(h); | |||
1103 | retval = 0; | |||
1104 | break; | |||
1105 | ||||
1106 | case H_NEXT_EVDATA23: | |||
1107 | { | |||
1108 | int num = va_arg(va, int)__builtin_va_arg((va), int); | |||
1109 | void **d = va_arg(va, void **)__builtin_va_arg((va), void **); | |||
1110 | retval = history_next_evdata(h, ev, num, d); | |||
1111 | break; | |||
1112 | } | |||
1113 | ||||
1114 | case H_DELDATA24: | |||
1115 | { | |||
1116 | int num = va_arg(va, int)__builtin_va_arg((va), int); | |||
1117 | void **d = va_arg(va, void **)__builtin_va_arg((va), void **); | |||
1118 | retval = history_deldata_nth((history_t *)h->h_ref, ev, num, d); | |||
1119 | break; | |||
1120 | } | |||
1121 | ||||
1122 | case H_REPLACE25: /* only use after H_NEXT_EVDATA */ | |||
1123 | { | |||
1124 | const Charwchar_t *line = va_arg(va, const Char *)__builtin_va_arg((va), const wchar_t *); | |||
1125 | void *d = va_arg(va, void *)__builtin_va_arg((va), void *); | |||
1126 | const Charwchar_t *s; | |||
1127 | if(!line || !(s = Strdup(line)wcsdup(line))) { | |||
1128 | retval = -1; | |||
1129 | break; | |||
1130 | } | |||
1131 | ((history_t *)h->h_ref)->cursor->ev.str = s; | |||
1132 | ((history_t *)h->h_ref)->cursor->data = d; | |||
1133 | retval = 0; | |||
1134 | break; | |||
1135 | } | |||
1136 | ||||
1137 | default: | |||
1138 | retval = -1; | |||
1139 | he_seterrev(ev, _HE_UNKNOWN){ ev->num = 1; ev->str = he_errlist[1]; }; | |||
1140 | break; | |||
1141 | } | |||
1142 | va_end(va)__builtin_va_end((va)); | |||
1143 | return retval; | |||
1144 | } |