Update libedit from version 2017-03-29 to 2019-03-24 on vendor branch
[dragonfly.git] / contrib / libedit / src / history.c
1 /*      $NetBSD: history.c,v 1.62 2018/09/13 09:03:40 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.62 2018/09/13 09:03:40 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 <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
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
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
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
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
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
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
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
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
414 history_def_add(void *p, TYPE(HistEvent) *ev, const Char *str)
415 {
416         history_t *h = (history_t *) p;
417         size_t len;
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         len = Strlen(evp->str) + Strlen(str) + 1;
424         s = h_malloc(len * sizeof(*s));
425         if (s == NULL) {
426                 he_seterrev(ev, _HE_MALLOC_FAILED);
427                 return -1;
428         }
429         (void) Strncpy(s, h->cursor->ev.str, len);
430         s[len - 1] = '\0';
431         (void) Strncat(s, str, len - Strlen(s) - 1);
432         h_free(evp->str);
433         evp->str = s;
434         *ev = h->cursor->ev;
435         return 0;
436 }
437
438
439 static int
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
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
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
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
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
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
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  */
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
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
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
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
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
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
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
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
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 (fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1)
847                 goto done;
848         if (ftell(fp) == 0 && fputs(hist_cookie, fp) == EOF)
849                 goto done;
850         ptr = h_malloc((max_size = 1024) * sizeof(*ptr));
851         if (ptr == NULL)
852                 goto done;
853         if (nelem != (size_t)-1) {
854                 for (retval = HFIRST(h, &ev); retval != -1 && nelem-- > 0;
855                     retval = HNEXT(h, &ev))
856                         continue;
857         } else
858                 retval = -1;
859
860         if (retval == -1)
861                 retval = HLAST(h, &ev);
862
863         for (i = 0; retval != -1; retval = HPREV(h, &ev), i++) {
864                 str = ct_encode_string(ev.str, &conv);
865                 len = strlen(str) * 4 + 1;
866                 if (len > max_size) {
867                         char *nptr;
868                         max_size = (len + 1024) & (size_t)~1023;
869                         nptr = h_realloc(ptr, max_size * sizeof(*ptr));
870                         if (nptr == NULL) {
871                                 i = -1;
872                                 goto oomem;
873                         }
874                         ptr = nptr;
875                 }
876                 (void) strvis(ptr, str, VIS_WHITE);
877                 (void) fprintf(fp, "%s\n", ptr);
878         }
879 oomem:
880         h_free(ptr);
881 done:
882         return i;
883 }
884
885
886 /* history_save():
887  *    History save function
888  */
889 static int
890 history_save(TYPE(History) *h, const char *fname)
891 {
892     FILE *fp;
893     int i;
894
895     if ((fp = fopen(fname, "w")) == NULL)
896         return -1;
897
898     i = history_save_fp(h, (size_t)-1, fp);
899
900     (void) fclose(fp);
901     return i;
902 }
903
904
905 /* history_prev_event():
906  *      Find the previous event, with number given
907  */
908 static int
909 history_prev_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
910 {
911         int retval;
912
913         for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
914                 if (ev->num == num)
915                         return 0;
916
917         he_seterrev(ev, _HE_NOT_FOUND);
918         return -1;
919 }
920
921
922 static int
923 history_next_evdata(TYPE(History) *h, TYPE(HistEvent) *ev, int num, void **d)
924 {
925         int retval;
926
927         for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
928                 if (ev->num == num) {
929                         if (d)
930                                 *d = ((history_t *)h->h_ref)->cursor->data;
931                         return 0;
932                 }
933
934         he_seterrev(ev, _HE_NOT_FOUND);
935         return -1;
936 }
937
938
939 /* history_next_event():
940  *      Find the next event, with number given
941  */
942 static int
943 history_next_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
944 {
945         int retval;
946
947         for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
948                 if (ev->num == num)
949                         return 0;
950
951         he_seterrev(ev, _HE_NOT_FOUND);
952         return -1;
953 }
954
955
956 /* history_prev_string():
957  *      Find the previous event beginning with string
958  */
959 static int
960 history_prev_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str)
961 {
962         size_t len = Strlen(str);
963         int retval;
964
965         for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
966                 if (Strncmp(str, ev->str, len) == 0)
967                         return 0;
968
969         he_seterrev(ev, _HE_NOT_FOUND);
970         return -1;
971 }
972
973
974 /* history_next_string():
975  *      Find the next event beginning with string
976  */
977 static int
978 history_next_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str)
979 {
980         size_t len = Strlen(str);
981         int retval;
982
983         for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
984                 if (Strncmp(str, ev->str, len) == 0)
985                         return 0;
986
987         he_seterrev(ev, _HE_NOT_FOUND);
988         return -1;
989 }
990
991
992 /* history():
993  *      User interface to history functions.
994  */
995 int
996 FUNW(history)(TYPE(History) *h, TYPE(HistEvent) *ev, int fun, ...)
997 {
998         va_list va;
999         const Char *str;
1000         int retval;
1001
1002         va_start(va, fun);
1003
1004         he_seterrev(ev, _HE_OK);
1005
1006         switch (fun) {
1007         case H_GETSIZE:
1008                 retval = history_getsize(h, ev);
1009                 break;
1010
1011         case H_SETSIZE:
1012                 retval = history_setsize(h, ev, va_arg(va, int));
1013                 break;
1014
1015         case H_GETUNIQUE:
1016                 retval = history_getunique(h, ev);
1017                 break;
1018
1019         case H_SETUNIQUE:
1020                 retval = history_setunique(h, ev, va_arg(va, int));
1021                 break;
1022
1023         case H_ADD:
1024                 str = va_arg(va, const Char *);
1025                 retval = HADD(h, ev, str);
1026                 break;
1027
1028         case H_DEL:
1029                 retval = HDEL(h, ev, va_arg(va, const int));
1030                 break;
1031
1032         case H_ENTER:
1033                 str = va_arg(va, const Char *);
1034                 if ((retval = HENTER(h, ev, str)) != -1)
1035                         h->h_ent = ev->num;
1036                 break;
1037
1038         case H_APPEND:
1039                 str = va_arg(va, const Char *);
1040                 if ((retval = HSET(h, ev, h->h_ent)) != -1)
1041                         retval = HADD(h, ev, str);
1042                 break;
1043
1044         case H_FIRST:
1045                 retval = HFIRST(h, ev);
1046                 break;
1047
1048         case H_NEXT:
1049                 retval = HNEXT(h, ev);
1050                 break;
1051
1052         case H_LAST:
1053                 retval = HLAST(h, ev);
1054                 break;
1055
1056         case H_PREV:
1057                 retval = HPREV(h, ev);
1058                 break;
1059
1060         case H_CURR:
1061                 retval = HCURR(h, ev);
1062                 break;
1063
1064         case H_SET:
1065                 retval = HSET(h, ev, va_arg(va, const int));
1066                 break;
1067
1068         case H_CLEAR:
1069                 HCLEAR(h, ev);
1070                 retval = 0;
1071                 break;
1072
1073         case H_LOAD:
1074                 retval = history_load(h, va_arg(va, const char *));
1075                 if (retval == -1)
1076                         he_seterrev(ev, _HE_HIST_READ);
1077                 break;
1078
1079         case H_SAVE:
1080                 retval = history_save(h, va_arg(va, const char *));
1081                 if (retval == -1)
1082                         he_seterrev(ev, _HE_HIST_WRITE);
1083                 break;
1084
1085         case H_SAVE_FP:
1086                 retval = history_save_fp(h, (size_t)-1, va_arg(va, FILE *));
1087                 if (retval == -1)
1088                     he_seterrev(ev, _HE_HIST_WRITE);
1089                 break;
1090
1091         case H_NSAVE_FP:
1092         {
1093                 size_t sz = va_arg(va, size_t);
1094                 retval = history_save_fp(h, sz, va_arg(va, FILE *));
1095                 if (retval == -1)
1096                     he_seterrev(ev, _HE_HIST_WRITE);
1097                 break;
1098         }
1099
1100         case H_PREV_EVENT:
1101                 retval = history_prev_event(h, ev, va_arg(va, int));
1102                 break;
1103
1104         case H_NEXT_EVENT:
1105                 retval = history_next_event(h, ev, va_arg(va, int));
1106                 break;
1107
1108         case H_PREV_STR:
1109                 retval = history_prev_string(h, ev, va_arg(va, const Char *));
1110                 break;
1111
1112         case H_NEXT_STR:
1113                 retval = history_next_string(h, ev, va_arg(va, const Char *));
1114                 break;
1115
1116         case H_FUNC:
1117         {
1118                 TYPE(History) hf;
1119
1120                 hf.h_ref = va_arg(va, void *);
1121                 h->h_ent = -1;
1122                 hf.h_first = va_arg(va, history_gfun_t);
1123                 hf.h_next = va_arg(va, history_gfun_t);
1124                 hf.h_last = va_arg(va, history_gfun_t);
1125                 hf.h_prev = va_arg(va, history_gfun_t);
1126                 hf.h_curr = va_arg(va, history_gfun_t);
1127                 hf.h_set = va_arg(va, history_sfun_t);
1128                 hf.h_clear = va_arg(va, history_vfun_t);
1129                 hf.h_enter = va_arg(va, history_efun_t);
1130                 hf.h_add = va_arg(va, history_efun_t);
1131                 hf.h_del = va_arg(va, history_sfun_t);
1132
1133                 if ((retval = history_set_fun(h, &hf)) == -1)
1134                         he_seterrev(ev, _HE_PARAM_MISSING);
1135                 break;
1136         }
1137
1138         case H_END:
1139                 FUN(history,end)(h);
1140                 retval = 0;
1141                 break;
1142
1143         case H_NEXT_EVDATA:
1144         {
1145                 int num = va_arg(va, int);
1146                 void **d = va_arg(va, void **);
1147                 retval = history_next_evdata(h, ev, num, d);
1148                 break;
1149         }
1150
1151         case H_DELDATA:
1152         {
1153                 int num = va_arg(va, int);
1154                 void **d = va_arg(va, void **);
1155                 retval = history_deldata_nth((history_t *)h->h_ref, ev, num, d);
1156                 break;
1157         }
1158
1159         case H_REPLACE: /* only use after H_NEXT_EVDATA */
1160         {
1161                 const Char *line = va_arg(va, const Char *);
1162                 void *d = va_arg(va, void *);
1163                 const Char *s;
1164                 if(!line || !(s = Strdup(line))) {
1165                         retval = -1;
1166                         break;
1167                 }
1168                 ((history_t *)h->h_ref)->cursor->ev.str = s;
1169                 ((history_t *)h->h_ref)->cursor->data = d;
1170                 retval = 0;
1171                 break;
1172         }
1173
1174         default:
1175                 retval = -1;
1176                 he_seterrev(ev, _HE_UNKNOWN);
1177                 break;
1178         }
1179         va_end(va);
1180         return retval;
1181 }