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