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