1 /* $NetBSD: history.c,v 1.63 2019/10/08 19:17:57 christos Exp $ */
2
3 /*-
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Christos Zoulas of Cornell University.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #ifndef NARROWCHAR
36 #include "config.h"
37 #endif
38
39 #if !defined(lint) && !defined(SCCSID)
40 #if 0
41 static char sccsid[] = "@(#)history.c 8.1 (Berkeley) 6/4/93";
42 #else
43 __RCSID("$NetBSD: history.c,v 1.63 2019/10/08 19:17:57 christos 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 <stdarg.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <vis.h>
55
56 static const char hist_cookie[] = "_HiStOrY_V2_\n";
57
58 #include "histedit.h"
59
60
61 #ifdef NARROWCHAR
62
63 #define Char char
64 #define FUN(prefix, rest) prefix ## _ ## rest
65 #define FUNW(type) type
66 #define TYPE(type) type
67 #define STR(x) x
68
69 #define Strlen(s) strlen(s)
70 #define Strdup(s) strdup(s)
71 #define Strcmp(d, s) strcmp(d, s)
72 #define Strncmp(d, s, n) strncmp(d, s, n)
73 #define Strncpy(d, s, n) strncpy(d, s, n)
74 #define Strncat(d, s, n) strncat(d, s, n)
75 #define ct_decode_string(s, b) (s)
76 #define ct_encode_string(s, b) (s)
77
78 #else
79 #include "chartype.h"
80
81 #define Char wchar_t
82 #define FUN(prefix, rest) prefix ## _w ## rest
83 #define FUNW(type) type ## _w
84 #define TYPE(type) type ## W
85 #define STR(x) L ## x
86
87 #define Strlen(s) wcslen(s)
88 #define Strdup(s) wcsdup(s)
89 #define Strcmp(d, s) wcscmp(d, s)
90 #define Strncmp(d, s, n) wcsncmp(d, s, n)
91 #define Strncpy(d, s, n) wcsncpy(d, s, n)
92 #define Strncat(d, s, n) wcsncat(d, s, n)
93
94 #endif
95
96
97 typedef int (*history_gfun_t)(void *, TYPE(HistEvent) *);
98 typedef int (*history_efun_t)(void *, TYPE(HistEvent) *, const Char *);
99 typedef void (*history_vfun_t)(void *, TYPE(HistEvent) *);
100 typedef int (*history_sfun_t)(void *, TYPE(HistEvent) *, const int);
101
TYPE(history)102 struct TYPE(history) {
103 void *h_ref; /* Argument for history fcns */
104 int h_ent; /* Last entry point for history */
105 history_gfun_t h_first; /* Get the first element */
106 history_gfun_t h_next; /* Get the next element */
107 history_gfun_t h_last; /* Get the last element */
108 history_gfun_t h_prev; /* Get the previous element */
109 history_gfun_t h_curr; /* Get the current element */
110 history_sfun_t h_set; /* Set the current element */
111 history_sfun_t h_del; /* Set the given element */
112 history_vfun_t h_clear; /* Clear the history list */
113 history_efun_t h_enter; /* Add an element */
114 history_efun_t h_add; /* Append to an element */
115 };
116
117 #define HNEXT(h, ev) (*(h)->h_next)((h)->h_ref, ev)
118 #define HFIRST(h, ev) (*(h)->h_first)((h)->h_ref, ev)
119 #define HPREV(h, ev) (*(h)->h_prev)((h)->h_ref, ev)
120 #define HLAST(h, ev) (*(h)->h_last)((h)->h_ref, ev)
121 #define HCURR(h, ev) (*(h)->h_curr)((h)->h_ref, ev)
122 #define HSET(h, ev, n) (*(h)->h_set)((h)->h_ref, ev, n)
123 #define HCLEAR(h, ev) (*(h)->h_clear)((h)->h_ref, ev)
124 #define HENTER(h, ev, str) (*(h)->h_enter)((h)->h_ref, ev, str)
125 #define HADD(h, ev, str) (*(h)->h_add)((h)->h_ref, ev, str)
126 #define HDEL(h, ev, n) (*(h)->h_del)((h)->h_ref, ev, n)
127
128 #define h_strdup(a) Strdup(a)
129 #define h_malloc(a) malloc(a)
130 #define h_realloc(a, b) realloc((a), (b))
131 #define h_free(a) free(a)
132
133 typedef struct {
134 int num;
135 Char *str;
136 } HistEventPrivate;
137
138
139 static int history_setsize(TYPE(History) *, TYPE(HistEvent) *, int);
140 static int history_getsize(TYPE(History) *, TYPE(HistEvent) *);
141 static int history_setunique(TYPE(History) *, TYPE(HistEvent) *, int);
142 static int history_getunique(TYPE(History) *, TYPE(HistEvent) *);
143 static int history_set_fun(TYPE(History) *, TYPE(History) *);
144 static int history_load(TYPE(History) *, const char *);
145 static int history_save(TYPE(History) *, const char *);
146 static int history_save_fp(TYPE(History) *, size_t, FILE *);
147 static int history_prev_event(TYPE(History) *, TYPE(HistEvent) *, int);
148 static int history_next_event(TYPE(History) *, TYPE(HistEvent) *, int);
149 static int history_next_string(TYPE(History) *, TYPE(HistEvent) *,
150 const Char *);
151 static int history_prev_string(TYPE(History) *, TYPE(HistEvent) *,
152 const Char *);
153
154
155 /***********************************************************************/
156
157 /*
158 * Builtin- history implementation
159 */
160 typedef struct hentry_t {
161 TYPE(HistEvent) ev; /* What we return */
162 void *data; /* data */
163 struct hentry_t *next; /* Next entry */
164 struct hentry_t *prev; /* Previous entry */
165 } hentry_t;
166
167 typedef struct history_t {
168 hentry_t list; /* Fake list header element */
169 hentry_t *cursor; /* Current element in the list */
170 int max; /* Maximum number of events */
171 int cur; /* Current number of events */
172 int eventid; /* For generation of unique event id */
173 int flags; /* TYPE(History) flags */
174 #define H_UNIQUE 1 /* Store only unique elements */
175 } history_t;
176
177 static int history_def_next(void *, TYPE(HistEvent) *);
178 static int history_def_first(void *, TYPE(HistEvent) *);
179 static int history_def_prev(void *, TYPE(HistEvent) *);
180 static int history_def_last(void *, TYPE(HistEvent) *);
181 static int history_def_curr(void *, TYPE(HistEvent) *);
182 static int history_def_set(void *, TYPE(HistEvent) *, const int);
183 static void history_def_clear(void *, TYPE(HistEvent) *);
184 static int history_def_enter(void *, TYPE(HistEvent) *, const Char *);
185 static int history_def_add(void *, TYPE(HistEvent) *, const Char *);
186 static int history_def_del(void *, TYPE(HistEvent) *, const int);
187
188 static int history_def_init(void **, TYPE(HistEvent) *, int);
189 static int history_def_insert(history_t *, TYPE(HistEvent) *, const Char *);
190 static void history_def_delete(history_t *, TYPE(HistEvent) *, hentry_t *);
191
192 static int history_deldata_nth(history_t *, TYPE(HistEvent) *, int, void **);
193 static int history_set_nth(void *, TYPE(HistEvent) *, int);
194
195 #define history_def_setsize(p, num)(void) (((history_t *)p)->max = (num))
196 #define history_def_getsize(p) (((history_t *)p)->cur)
197 #define history_def_getunique(p) (((((history_t *)p)->flags) & H_UNIQUE) != 0)
198 #define history_def_setunique(p, uni) \
199 if (uni) \
200 (((history_t *)p)->flags) |= H_UNIQUE; \
201 else \
202 (((history_t *)p)->flags) &= ~H_UNIQUE
203
204 #define he_strerror(code) he_errlist[code]
205 #define he_seterrev(evp, code) {\
206 evp->num = code;\
207 evp->str = he_strerror(code);\
208 }
209
210 /* error messages */
211 static const Char *const he_errlist[] = {
212 STR("OK"),
213 STR("unknown error"),
214 STR("malloc() failed"),
215 STR("first event not found"),
216 STR("last event not found"),
217 STR("empty list"),
218 STR("no next event"),
219 STR("no previous event"),
220 STR("current event is invalid"),
221 STR("event not found"),
222 STR("can't read history from file"),
223 STR("can't write history"),
224 STR("required parameter(s) not supplied"),
225 STR("history size negative"),
226 STR("function not allowed with other history-functions-set the default"),
227 STR("bad parameters")
228 };
229 /* error codes */
230 #define _HE_OK 0
231 #define _HE_UNKNOWN 1
232 #define _HE_MALLOC_FAILED 2
233 #define _HE_FIRST_NOTFOUND 3
234 #define _HE_LAST_NOTFOUND 4
235 #define _HE_EMPTY_LIST 5
236 #define _HE_END_REACHED 6
237 #define _HE_START_REACHED 7
238 #define _HE_CURR_INVALID 8
239 #define _HE_NOT_FOUND 9
240 #define _HE_HIST_READ 10
241 #define _HE_HIST_WRITE 11
242 #define _HE_PARAM_MISSING 12
243 #define _HE_SIZE_NEGATIVE 13
244 #define _HE_NOT_ALLOWED 14
245 #define _HE_BAD_PARAM 15
246
247 /* history_def_first():
248 * Default function to return the first event in the history.
249 */
250 static int
history_def_first(void * p,TYPE (HistEvent)* ev)251 history_def_first(void *p, TYPE(HistEvent) *ev)
252 {
253 history_t *h = (history_t *) p;
254
255 h->cursor = h->list.next;
256 if (h->cursor != &h->list)
257 *ev = h->cursor->ev;
258 else {
259 he_seterrev(ev, _HE_FIRST_NOTFOUND);
260 return -1;
261 }
262
263 return 0;
264 }
265
266
267 /* history_def_last():
268 * Default function to return the last event in the history.
269 */
270 static int
history_def_last(void * p,TYPE (HistEvent)* ev)271 history_def_last(void *p, TYPE(HistEvent) *ev)
272 {
273 history_t *h = (history_t *) p;
274
275 h->cursor = h->list.prev;
276 if (h->cursor != &h->list)
277 *ev = h->cursor->ev;
278 else {
279 he_seterrev(ev, _HE_LAST_NOTFOUND);
280 return -1;
281 }
282
283 return 0;
284 }
285
286
287 /* history_def_next():
288 * Default function to return the next event in the history.
289 */
290 static int
history_def_next(void * p,TYPE (HistEvent)* ev)291 history_def_next(void *p, TYPE(HistEvent) *ev)
292 {
293 history_t *h = (history_t *) p;
294
295 if (h->cursor == &h->list) {
296 he_seterrev(ev, _HE_EMPTY_LIST);
297 return -1;
298 }
299
300 if (h->cursor->next == &h->list) {
301 he_seterrev(ev, _HE_END_REACHED);
302 return -1;
303 }
304
305 h->cursor = h->cursor->next;
306 *ev = h->cursor->ev;
307
308 return 0;
309 }
310
311
312 /* history_def_prev():
313 * Default function to return the previous event in the history.
314 */
315 static int
history_def_prev(void * p,TYPE (HistEvent)* ev)316 history_def_prev(void *p, TYPE(HistEvent) *ev)
317 {
318 history_t *h = (history_t *) p;
319
320 if (h->cursor == &h->list) {
321 he_seterrev(ev,
322 (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST);
323 return -1;
324 }
325
326 if (h->cursor->prev == &h->list) {
327 he_seterrev(ev, _HE_START_REACHED);
328 return -1;
329 }
330
331 h->cursor = h->cursor->prev;
332 *ev = h->cursor->ev;
333
334 return 0;
335 }
336
337
338 /* history_def_curr():
339 * Default function to return the current event in the history.
340 */
341 static int
history_def_curr(void * p,TYPE (HistEvent)* ev)342 history_def_curr(void *p, TYPE(HistEvent) *ev)
343 {
344 history_t *h = (history_t *) p;
345
346 if (h->cursor != &h->list)
347 *ev = h->cursor->ev;
348 else {
349 he_seterrev(ev,
350 (h->cur > 0) ? _HE_CURR_INVALID : _HE_EMPTY_LIST);
351 return -1;
352 }
353
354 return 0;
355 }
356
357
358 /* history_def_set():
359 * Default function to set the current event in the history to the
360 * given one.
361 */
362 static int
history_def_set(void * p,TYPE (HistEvent)* ev,const int n)363 history_def_set(void *p, TYPE(HistEvent) *ev, const int n)
364 {
365 history_t *h = (history_t *) p;
366
367 if (h->cur == 0) {
368 he_seterrev(ev, _HE_EMPTY_LIST);
369 return -1;
370 }
371 if (h->cursor == &h->list || h->cursor->ev.num != n) {
372 for (h->cursor = h->list.next; h->cursor != &h->list;
373 h->cursor = h->cursor->next)
374 if (h->cursor->ev.num == n)
375 break;
376 }
377 if (h->cursor == &h->list) {
378 he_seterrev(ev, _HE_NOT_FOUND);
379 return -1;
380 }
381 return 0;
382 }
383
384
385 /* history_set_nth():
386 * Default function to set the current event in the history to the
387 * n-th one.
388 */
389 static int
history_set_nth(void * p,TYPE (HistEvent)* ev,int n)390 history_set_nth(void *p, TYPE(HistEvent) *ev, int n)
391 {
392 history_t *h = (history_t *) p;
393
394 if (h->cur == 0) {
395 he_seterrev(ev, _HE_EMPTY_LIST);
396 return -1;
397 }
398 for (h->cursor = h->list.prev; h->cursor != &h->list;
399 h->cursor = h->cursor->prev)
400 if (n-- <= 0)
401 break;
402 if (h->cursor == &h->list) {
403 he_seterrev(ev, _HE_NOT_FOUND);
404 return -1;
405 }
406 return 0;
407 }
408
409
410 /* history_def_add():
411 * Append string to element
412 */
413 static int
history_def_add(void * p,TYPE (HistEvent)* ev,const Char * str)414 history_def_add(void *p, TYPE(HistEvent) *ev, const Char *str)
415 {
416 history_t *h = (history_t *) p;
417 size_t len, elen, slen;
418 Char *s;
419 HistEventPrivate *evp = (void *)&h->cursor->ev;
420
421 if (h->cursor == &h->list)
422 return history_def_enter(p, ev, str);
423 elen = Strlen(evp->str);
424 slen = Strlen(str);
425 len = elen + slen + 1;
426 s = h_malloc(len * sizeof(*s));
427 if (s == NULL) {
428 he_seterrev(ev, _HE_MALLOC_FAILED);
429 return -1;
430 }
431 memcpy(s, evp->str, elen * sizeof(*s));
432 memcpy(s + elen, str, slen * sizeof(*s));
433 s[len - 1] = '\0';
434 h_free(evp->str);
435 evp->str = s;
436 *ev = h->cursor->ev;
437 return 0;
438 }
439
440
441 static int
history_deldata_nth(history_t * h,TYPE (HistEvent)* ev,int num,void ** data)442 history_deldata_nth(history_t *h, TYPE(HistEvent) *ev,
443 int num, void **data)
444 {
445 if (history_set_nth(h, ev, num) != 0)
446 return -1;
447 /* magic value to skip delete (just set to n-th history) */
448 if (data == (void **)-1)
449 return 0;
450 ev->str = Strdup(h->cursor->ev.str);
451 ev->num = h->cursor->ev.num;
452 if (data)
453 *data = h->cursor->data;
454 history_def_delete(h, ev, h->cursor);
455 return 0;
456 }
457
458
459 /* history_def_del():
460 * Delete element hp of the h list
461 */
462 /* ARGSUSED */
463 static int
history_def_del(void * p,TYPE (HistEvent)* ev,const int num)464 history_def_del(void *p, TYPE(HistEvent) *ev __attribute__((__unused__)),
465 const int num)
466 {
467 history_t *h = (history_t *) p;
468 if (history_def_set(h, ev, num) != 0)
469 return -1;
470 ev->str = Strdup(h->cursor->ev.str);
471 ev->num = h->cursor->ev.num;
472 history_def_delete(h, ev, h->cursor);
473 return 0;
474 }
475
476
477 /* history_def_delete():
478 * Delete element hp of the h list
479 */
480 /* ARGSUSED */
481 static void
history_def_delete(history_t * h,TYPE (HistEvent)* ev,hentry_t * hp)482 history_def_delete(history_t *h,
483 TYPE(HistEvent) *ev __attribute__((__unused__)), hentry_t *hp)
484 {
485 HistEventPrivate *evp = (void *)&hp->ev;
486 if (hp == &h->list)
487 abort();
488 if (h->cursor == hp) {
489 h->cursor = hp->prev;
490 if (h->cursor == &h->list)
491 h->cursor = hp->next;
492 }
493 hp->prev->next = hp->next;
494 hp->next->prev = hp->prev;
495 h_free(evp->str);
496 h_free(hp);
497 h->cur--;
498 }
499
500
501 /* history_def_insert():
502 * Insert element with string str in the h list
503 */
504 static int
history_def_insert(history_t * h,TYPE (HistEvent)* ev,const Char * str)505 history_def_insert(history_t *h, TYPE(HistEvent) *ev, const Char *str)
506 {
507 hentry_t *c;
508
509 c = h_malloc(sizeof(*c));
510 if (c == NULL)
511 goto oomem;
512 if ((c->ev.str = h_strdup(str)) == NULL) {
513 h_free(c);
514 goto oomem;
515 }
516 c->data = NULL;
517 c->ev.num = ++h->eventid;
518 c->next = h->list.next;
519 c->prev = &h->list;
520 h->list.next->prev = c;
521 h->list.next = c;
522 h->cur++;
523 h->cursor = c;
524
525 *ev = c->ev;
526 return 0;
527 oomem:
528 he_seterrev(ev, _HE_MALLOC_FAILED);
529 return -1;
530 }
531
532
533 /* history_def_enter():
534 * Default function to enter an item in the history
535 */
536 static int
history_def_enter(void * p,TYPE (HistEvent)* ev,const Char * str)537 history_def_enter(void *p, TYPE(HistEvent) *ev, const Char *str)
538 {
539 history_t *h = (history_t *) p;
540
541 if ((h->flags & H_UNIQUE) != 0 && h->list.next != &h->list &&
542 Strcmp(h->list.next->ev.str, str) == 0)
543 return 0;
544
545 if (history_def_insert(h, ev, str) == -1)
546 return -1; /* error, keep error message */
547
548 /*
549 * Always keep at least one entry.
550 * This way we don't have to check for the empty list.
551 */
552 while (h->cur > h->max && h->cur > 0)
553 history_def_delete(h, ev, h->list.prev);
554
555 return 1;
556 }
557
558
559 /* history_def_init():
560 * Default history initialization function
561 */
562 /* ARGSUSED */
563 static int
history_def_init(void ** p,TYPE (HistEvent)* ev,int n)564 history_def_init(void **p, TYPE(HistEvent) *ev __attribute__((__unused__)), int n)
565 {
566 history_t *h = (history_t *) h_malloc(sizeof(*h));
567 if (h == NULL)
568 return -1;
569
570 if (n <= 0)
571 n = 0;
572 h->eventid = 0;
573 h->cur = 0;
574 h->max = n;
575 h->list.next = h->list.prev = &h->list;
576 h->list.ev.str = NULL;
577 h->list.ev.num = 0;
578 h->cursor = &h->list;
579 h->flags = 0;
580 *p = h;
581 return 0;
582 }
583
584
585 /* history_def_clear():
586 * Default history cleanup function
587 */
588 static void
history_def_clear(void * p,TYPE (HistEvent)* ev)589 history_def_clear(void *p, TYPE(HistEvent) *ev)
590 {
591 history_t *h = (history_t *) p;
592
593 while (h->list.prev != &h->list)
594 history_def_delete(h, ev, h->list.prev);
595 h->cursor = &h->list;
596 h->eventid = 0;
597 h->cur = 0;
598 }
599
600
601
602
603 /************************************************************************/
604
605 /* history_init():
606 * Initialization function.
607 */
TYPE(History)608 TYPE(History) *
609 FUN(history,init)(void)
610 {
611 TYPE(HistEvent) ev;
612 TYPE(History) *h = (TYPE(History) *) h_malloc(sizeof(*h));
613 if (h == NULL)
614 return NULL;
615
616 if (history_def_init(&h->h_ref, &ev, 0) == -1) {
617 h_free(h);
618 return NULL;
619 }
620 h->h_ent = -1;
621 h->h_next = history_def_next;
622 h->h_first = history_def_first;
623 h->h_last = history_def_last;
624 h->h_prev = history_def_prev;
625 h->h_curr = history_def_curr;
626 h->h_set = history_def_set;
627 h->h_clear = history_def_clear;
628 h->h_enter = history_def_enter;
629 h->h_add = history_def_add;
630 h->h_del = history_def_del;
631
632 return h;
633 }
634
635
636 /* history_end():
637 * clean up history;
638 */
639 void
FUN(history,end)640 FUN(history,end)(TYPE(History) *h)
641 {
642 TYPE(HistEvent) ev;
643
644 if (h->h_next == history_def_next)
645 history_def_clear(h->h_ref, &ev);
646 h_free(h->h_ref);
647 h_free(h);
648 }
649
650
651
652 /* history_setsize():
653 * Set history number of events
654 */
655 static int
history_setsize(TYPE (History)* h,TYPE (HistEvent)* ev,int num)656 history_setsize(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
657 {
658
659 if (h->h_next != history_def_next) {
660 he_seterrev(ev, _HE_NOT_ALLOWED);
661 return -1;
662 }
663 if (num < 0) {
664 he_seterrev(ev, _HE_BAD_PARAM);
665 return -1;
666 }
667 history_def_setsize(h->h_ref, num);
668 return 0;
669 }
670
671
672 /* history_getsize():
673 * Get number of events currently in history
674 */
675 static int
history_getsize(TYPE (History)* h,TYPE (HistEvent)* ev)676 history_getsize(TYPE(History) *h, TYPE(HistEvent) *ev)
677 {
678 if (h->h_next != history_def_next) {
679 he_seterrev(ev, _HE_NOT_ALLOWED);
680 return -1;
681 }
682 ev->num = history_def_getsize(h->h_ref);
683 if (ev->num < -1) {
684 he_seterrev(ev, _HE_SIZE_NEGATIVE);
685 return -1;
686 }
687 return 0;
688 }
689
690
691 /* history_setunique():
692 * Set if adjacent equal events should not be entered in history.
693 */
694 static int
history_setunique(TYPE (History)* h,TYPE (HistEvent)* ev,int uni)695 history_setunique(TYPE(History) *h, TYPE(HistEvent) *ev, int uni)
696 {
697
698 if (h->h_next != history_def_next) {
699 he_seterrev(ev, _HE_NOT_ALLOWED);
700 return -1;
701 }
702 history_def_setunique(h->h_ref, uni);
703 return 0;
704 }
705
706
707 /* history_getunique():
708 * Get if adjacent equal events should not be entered in history.
709 */
710 static int
history_getunique(TYPE (History)* h,TYPE (HistEvent)* ev)711 history_getunique(TYPE(History) *h, TYPE(HistEvent) *ev)
712 {
713 if (h->h_next != history_def_next) {
714 he_seterrev(ev, _HE_NOT_ALLOWED);
715 return -1;
716 }
717 ev->num = history_def_getunique(h->h_ref);
718 return 0;
719 }
720
721
722 /* history_set_fun():
723 * Set history functions
724 */
725 static int
history_set_fun(TYPE (History)* h,TYPE (History)* nh)726 history_set_fun(TYPE(History) *h, TYPE(History) *nh)
727 {
728 TYPE(HistEvent) ev;
729
730 if (nh->h_first == NULL || nh->h_next == NULL || nh->h_last == NULL ||
731 nh->h_prev == NULL || nh->h_curr == NULL || nh->h_set == NULL ||
732 nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL ||
733 nh->h_del == NULL || nh->h_ref == NULL) {
734 if (h->h_next != history_def_next) {
735 if (history_def_init(&h->h_ref, &ev, 0) == -1)
736 return -1;
737 h->h_first = history_def_first;
738 h->h_next = history_def_next;
739 h->h_last = history_def_last;
740 h->h_prev = history_def_prev;
741 h->h_curr = history_def_curr;
742 h->h_set = history_def_set;
743 h->h_clear = history_def_clear;
744 h->h_enter = history_def_enter;
745 h->h_add = history_def_add;
746 h->h_del = history_def_del;
747 }
748 return -1;
749 }
750 if (h->h_next == history_def_next)
751 history_def_clear(h->h_ref, &ev);
752
753 h->h_ent = -1;
754 h->h_first = nh->h_first;
755 h->h_next = nh->h_next;
756 h->h_last = nh->h_last;
757 h->h_prev = nh->h_prev;
758 h->h_curr = nh->h_curr;
759 h->h_set = nh->h_set;
760 h->h_clear = nh->h_clear;
761 h->h_enter = nh->h_enter;
762 h->h_add = nh->h_add;
763 h->h_del = nh->h_del;
764
765 return 0;
766 }
767
768
769 /* history_load():
770 * TYPE(History) load function
771 */
772 static int
history_load(TYPE (History)* h,const char * fname)773 history_load(TYPE(History) *h, const char *fname)
774 {
775 FILE *fp;
776 char *line;
777 size_t llen;
778 ssize_t sz;
779 size_t max_size;
780 char *ptr;
781 int i = -1;
782 TYPE(HistEvent) ev;
783 Char *decode_result;
784 #ifndef NARROWCHAR
785 static ct_buffer_t conv;
786 #endif
787
788 if ((fp = fopen(fname, "r")) == NULL)
789 return i;
790
791 line = NULL;
792 llen = 0;
793 if ((sz = getline(&line, &llen, fp)) == -1)
794 goto done;
795
796 if (strncmp(line, hist_cookie, (size_t)sz) != 0)
797 goto done;
798
799 ptr = h_malloc((max_size = 1024) * sizeof(*ptr));
800 if (ptr == NULL)
801 goto done;
802 for (i = 0; (sz = getline(&line, &llen, fp)) != -1; i++) {
803 if (sz > 0 && line[sz - 1] == '\n')
804 line[--sz] = '\0';
805 if (max_size < (size_t)sz) {
806 char *nptr;
807 max_size = ((size_t)sz + 1024) & (size_t)~1023;
808 nptr = h_realloc(ptr, max_size * sizeof(*ptr));
809 if (nptr == NULL) {
810 i = -1;
811 goto oomem;
812 }
813 ptr = nptr;
814 }
815 (void) strunvis(ptr, line);
816 decode_result = ct_decode_string(ptr, &conv);
817 if (decode_result == NULL)
818 continue;
819 if (HENTER(h, &ev, decode_result) == -1) {
820 i = -1;
821 goto oomem;
822 }
823 }
824 oomem:
825 h_free(ptr);
826 done:
827 free(line);
828 (void) fclose(fp);
829 return i;
830 }
831
832
833 /* history_save_fp():
834 * TYPE(History) save function
835 */
836 static int
history_save_fp(TYPE (History)* h,size_t nelem,FILE * fp)837 history_save_fp(TYPE(History) *h, size_t nelem, FILE *fp)
838 {
839 TYPE(HistEvent) ev;
840 int i = -1, retval;
841 size_t len, max_size;
842 char *ptr;
843 const char *str;
844 #ifndef NARROWCHAR
845 static ct_buffer_t conv;
846 #endif
847
848 if (fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1)
849 goto done;
850 if (ftell(fp) == 0 && fputs(hist_cookie, fp) == EOF)
851 goto done;
852 ptr = h_malloc((max_size = 1024) * sizeof(*ptr));
853 if (ptr == NULL)
854 goto done;
855 if (nelem != (size_t)-1) {
856 for (retval = HFIRST(h, &ev); retval != -1 && nelem-- > 0;
857 retval = HNEXT(h, &ev))
858 continue;
859 } else
860 retval = -1;
861
862 if (retval == -1)
863 retval = HLAST(h, &ev);
864
865 for (i = 0; retval != -1; retval = HPREV(h, &ev), i++) {
866 str = ct_encode_string(ev.str, &conv);
867 len = strlen(str) * 4 + 1;
868 if (len > max_size) {
869 char *nptr;
870 max_size = (len + 1024) & (size_t)~1023;
871 nptr = h_realloc(ptr, max_size * sizeof(*ptr));
872 if (nptr == NULL) {
873 i = -1;
874 goto oomem;
875 }
876 ptr = nptr;
877 }
878 (void) strvis(ptr, str, VIS_WHITE);
879 (void) fprintf(fp, "%s\n", ptr);
880 }
881 oomem:
882 h_free(ptr);
883 done:
884 return i;
885 }
886
887
888 /* history_save():
889 * History save function
890 */
891 static int
history_save(TYPE (History)* h,const char * fname)892 history_save(TYPE(History) *h, const char *fname)
893 {
894 FILE *fp;
895 int i;
896
897 if ((fp = fopen(fname, "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