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