]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/libedit/history.c
MFC r352136, r352204, r352275, r352341
[FreeBSD/FreeBSD.git] / contrib / libedit / 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 #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.62 2018/09/13 09:03:40 kre Exp $");
41 #endif
42 #endif /* not lint && not SCCSID */
43
44 /*
45  * hist.c: TYPE(History) access functions
46  */
47 #include <sys/stat.h>
48 #include <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;
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         len = Strlen(evp->str) + Strlen(str) + 1;
421         s = h_malloc(len * sizeof(*s));
422         if (s == NULL) {
423                 he_seterrev(ev, _HE_MALLOC_FAILED);
424                 return -1;
425         }
426         (void) Strncpy(s, h->cursor->ev.str, len);
427         s[len - 1] = '\0';
428         (void) Strncat(s, str, len - Strlen(s) - 1);
429         h_free(evp->str);
430         evp->str = s;
431         *ev = h->cursor->ev;
432         return 0;
433 }
434
435
436 static int
437 history_deldata_nth(history_t *h, TYPE(HistEvent) *ev,
438     int num, void **data)
439 {
440         if (history_set_nth(h, ev, num) != 0)
441                 return -1;
442         /* magic value to skip delete (just set to n-th history) */
443         if (data == (void **)-1)
444                 return 0;
445         ev->str = Strdup(h->cursor->ev.str);
446         ev->num = h->cursor->ev.num;
447         if (data)
448                 *data = h->cursor->data;
449         history_def_delete(h, ev, h->cursor);
450         return 0;
451 }
452
453
454 /* history_def_del():
455  *      Delete element hp of the h list
456  */
457 /* ARGSUSED */
458 static int
459 history_def_del(void *p, TYPE(HistEvent) *ev __attribute__((__unused__)),
460     const int num)
461 {
462         history_t *h = (history_t *) p;
463         if (history_def_set(h, ev, num) != 0)
464                 return -1;
465         ev->str = Strdup(h->cursor->ev.str);
466         ev->num = h->cursor->ev.num;
467         history_def_delete(h, ev, h->cursor);
468         return 0;
469 }
470
471
472 /* history_def_delete():
473  *      Delete element hp of the h list
474  */
475 /* ARGSUSED */
476 static void
477 history_def_delete(history_t *h,
478                    TYPE(HistEvent) *ev __attribute__((__unused__)), hentry_t *hp)
479 {
480         HistEventPrivate *evp = (void *)&hp->ev;
481         if (hp == &h->list)
482                 abort();
483         if (h->cursor == hp) {
484                 h->cursor = hp->prev;
485                 if (h->cursor == &h->list)
486                         h->cursor = hp->next;
487         }
488         hp->prev->next = hp->next;
489         hp->next->prev = hp->prev;
490         h_free(evp->str);
491         h_free(hp);
492         h->cur--;
493 }
494
495
496 /* history_def_insert():
497  *      Insert element with string str in the h list
498  */
499 static int
500 history_def_insert(history_t *h, TYPE(HistEvent) *ev, const Char *str)
501 {
502         hentry_t *c;
503
504         c = h_malloc(sizeof(*c));
505         if (c == NULL)
506                 goto oomem;
507         if ((c->ev.str = h_strdup(str)) == NULL) {
508                 h_free(c);
509                 goto oomem;
510         }
511         c->data = NULL;
512         c->ev.num = ++h->eventid;
513         c->next = h->list.next;
514         c->prev = &h->list;
515         h->list.next->prev = c;
516         h->list.next = c;
517         h->cur++;
518         h->cursor = c;
519
520         *ev = c->ev;
521         return 0;
522 oomem:
523         he_seterrev(ev, _HE_MALLOC_FAILED);
524         return -1;
525 }
526
527
528 /* history_def_enter():
529  *      Default function to enter an item in the history
530  */
531 static int
532 history_def_enter(void *p, TYPE(HistEvent) *ev, const Char *str)
533 {
534         history_t *h = (history_t *) p;
535
536         if ((h->flags & H_UNIQUE) != 0 && h->list.next != &h->list &&
537             Strcmp(h->list.next->ev.str, str) == 0)
538             return 0;
539
540         if (history_def_insert(h, ev, str) == -1)
541                 return -1;      /* error, keep error message */
542
543         /*
544          * Always keep at least one entry.
545          * This way we don't have to check for the empty list.
546          */
547         while (h->cur > h->max && h->cur > 0)
548                 history_def_delete(h, ev, h->list.prev);
549
550         return 1;
551 }
552
553
554 /* history_def_init():
555  *      Default history initialization function
556  */
557 /* ARGSUSED */
558 static int
559 history_def_init(void **p, TYPE(HistEvent) *ev __attribute__((__unused__)), int n)
560 {
561         history_t *h = (history_t *) h_malloc(sizeof(*h));
562         if (h == NULL)
563                 return -1;
564
565         if (n <= 0)
566                 n = 0;
567         h->eventid = 0;
568         h->cur = 0;
569         h->max = n;
570         h->list.next = h->list.prev = &h->list;
571         h->list.ev.str = NULL;
572         h->list.ev.num = 0;
573         h->cursor = &h->list;
574         h->flags = 0;
575         *p = h;
576         return 0;
577 }
578
579
580 /* history_def_clear():
581  *      Default history cleanup function
582  */
583 static void
584 history_def_clear(void *p, TYPE(HistEvent) *ev)
585 {
586         history_t *h = (history_t *) p;
587
588         while (h->list.prev != &h->list)
589                 history_def_delete(h, ev, h->list.prev);
590         h->cursor = &h->list;
591         h->eventid = 0;
592         h->cur = 0;
593 }
594
595
596
597
598 /************************************************************************/
599
600 /* history_init():
601  *      Initialization function.
602  */
603 TYPE(History) *
604 FUN(history,init)(void)
605 {
606         TYPE(HistEvent) ev;
607         TYPE(History) *h = (TYPE(History) *) h_malloc(sizeof(*h));
608         if (h == NULL)
609                 return NULL;
610
611         if (history_def_init(&h->h_ref, &ev, 0) == -1) {
612                 h_free(h);
613                 return NULL;
614         }
615         h->h_ent = -1;
616         h->h_next = history_def_next;
617         h->h_first = history_def_first;
618         h->h_last = history_def_last;
619         h->h_prev = history_def_prev;
620         h->h_curr = history_def_curr;
621         h->h_set = history_def_set;
622         h->h_clear = history_def_clear;
623         h->h_enter = history_def_enter;
624         h->h_add = history_def_add;
625         h->h_del = history_def_del;
626
627         return h;
628 }
629
630
631 /* history_end():
632  *      clean up history;
633  */
634 void
635 FUN(history,end)(TYPE(History) *h)
636 {
637         TYPE(HistEvent) ev;
638
639         if (h->h_next == history_def_next)
640                 history_def_clear(h->h_ref, &ev);
641         h_free(h->h_ref);
642         h_free(h);
643 }
644
645
646
647 /* history_setsize():
648  *      Set history number of events
649  */
650 static int
651 history_setsize(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
652 {
653
654         if (h->h_next != history_def_next) {
655                 he_seterrev(ev, _HE_NOT_ALLOWED);
656                 return -1;
657         }
658         if (num < 0) {
659                 he_seterrev(ev, _HE_BAD_PARAM);
660                 return -1;
661         }
662         history_def_setsize(h->h_ref, num);
663         return 0;
664 }
665
666
667 /* history_getsize():
668  *      Get number of events currently in history
669  */
670 static int
671 history_getsize(TYPE(History) *h, TYPE(HistEvent) *ev)
672 {
673         if (h->h_next != history_def_next) {
674                 he_seterrev(ev, _HE_NOT_ALLOWED);
675                 return -1;
676         }
677         ev->num = history_def_getsize(h->h_ref);
678         if (ev->num < -1) {
679                 he_seterrev(ev, _HE_SIZE_NEGATIVE);
680                 return -1;
681         }
682         return 0;
683 }
684
685
686 /* history_setunique():
687  *      Set if adjacent equal events should not be entered in history.
688  */
689 static int
690 history_setunique(TYPE(History) *h, TYPE(HistEvent) *ev, int uni)
691 {
692
693         if (h->h_next != history_def_next) {
694                 he_seterrev(ev, _HE_NOT_ALLOWED);
695                 return -1;
696         }
697         history_def_setunique(h->h_ref, uni);
698         return 0;
699 }
700
701
702 /* history_getunique():
703  *      Get if adjacent equal events should not be entered in history.
704  */
705 static int
706 history_getunique(TYPE(History) *h, TYPE(HistEvent) *ev)
707 {
708         if (h->h_next != history_def_next) {
709                 he_seterrev(ev, _HE_NOT_ALLOWED);
710                 return -1;
711         }
712         ev->num = history_def_getunique(h->h_ref);
713         return 0;
714 }
715
716
717 /* history_set_fun():
718  *      Set history functions
719  */
720 static int
721 history_set_fun(TYPE(History) *h, TYPE(History) *nh)
722 {
723         TYPE(HistEvent) ev;
724
725         if (nh->h_first == NULL || nh->h_next == NULL || nh->h_last == NULL ||
726             nh->h_prev == NULL || nh->h_curr == NULL || nh->h_set == NULL ||
727             nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL ||
728             nh->h_del == NULL || nh->h_ref == NULL) {
729                 if (h->h_next != history_def_next) {
730                         if (history_def_init(&h->h_ref, &ev, 0) == -1)
731                                 return -1;
732                         h->h_first = history_def_first;
733                         h->h_next = history_def_next;
734                         h->h_last = history_def_last;
735                         h->h_prev = history_def_prev;
736                         h->h_curr = history_def_curr;
737                         h->h_set = history_def_set;
738                         h->h_clear = history_def_clear;
739                         h->h_enter = history_def_enter;
740                         h->h_add = history_def_add;
741                         h->h_del = history_def_del;
742                 }
743                 return -1;
744         }
745         if (h->h_next == history_def_next)
746                 history_def_clear(h->h_ref, &ev);
747
748         h->h_ent = -1;
749         h->h_first = nh->h_first;
750         h->h_next = nh->h_next;
751         h->h_last = nh->h_last;
752         h->h_prev = nh->h_prev;
753         h->h_curr = nh->h_curr;
754         h->h_set = nh->h_set;
755         h->h_clear = nh->h_clear;
756         h->h_enter = nh->h_enter;
757         h->h_add = nh->h_add;
758         h->h_del = nh->h_del;
759
760         return 0;
761 }
762
763
764 /* history_load():
765  *      TYPE(History) load function
766  */
767 static int
768 history_load(TYPE(History) *h, const char *fname)
769 {
770         FILE *fp;
771         char *line;
772         size_t llen;
773         ssize_t sz;
774         size_t max_size;
775         char *ptr;
776         int i = -1;
777         TYPE(HistEvent) ev;
778         Char *decode_result;
779 #ifndef NARROWCHAR
780         static ct_buffer_t conv;
781 #endif
782
783         if ((fp = fopen(fname, "r")) == NULL)
784                 return i;
785
786         line = NULL;
787         llen = 0;
788         if ((sz = getline(&line, &llen, fp)) == -1)
789                 goto done;
790
791         if (strncmp(line, hist_cookie, (size_t)sz) != 0)
792                 goto done;
793
794         ptr = h_malloc((max_size = 1024) * sizeof(*ptr));
795         if (ptr == NULL)
796                 goto done;
797         for (i = 0; (sz = getline(&line, &llen, fp)) != -1; i++) {
798                 if (sz > 0 && line[sz - 1] == '\n')
799                         line[--sz] = '\0';
800                 if (max_size < (size_t)sz) {
801                         char *nptr;
802                         max_size = ((size_t)sz + 1024) & (size_t)~1023;
803                         nptr = h_realloc(ptr, max_size * sizeof(*ptr));
804                         if (nptr == NULL) {
805                                 i = -1;
806                                 goto oomem;
807                         }
808                         ptr = nptr;
809                 }
810                 (void) strunvis(ptr, line);
811                 decode_result = ct_decode_string(ptr, &conv);
812                 if (decode_result == NULL)
813                         continue;
814                 if (HENTER(h, &ev, decode_result) == -1) {
815                         i = -1;
816                         goto oomem;
817                 }
818         }
819 oomem:
820         h_free(ptr);
821 done:
822         free(line);
823         (void) fclose(fp);
824         return i;
825 }
826
827
828 /* history_save_fp():
829  *      TYPE(History) save function
830  */
831 static int
832 history_save_fp(TYPE(History) *h, size_t nelem, FILE *fp)
833 {
834         TYPE(HistEvent) ev;
835         int i = -1, retval;
836         size_t len, max_size;
837         char *ptr;
838         const char *str;
839 #ifndef NARROWCHAR
840         static ct_buffer_t conv;
841 #endif
842
843         if (fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1)
844                 goto done;
845         if (ftell(fp) == 0 && fputs(hist_cookie, fp) == EOF)
846                 goto done;
847         ptr = h_malloc((max_size = 1024) * sizeof(*ptr));
848         if (ptr == NULL)
849                 goto done;
850         if (nelem != (size_t)-1) {
851                 for (retval = HFIRST(h, &ev); retval != -1 && nelem-- > 0;
852                     retval = HNEXT(h, &ev))
853                         continue;
854         } else
855                 retval = -1;
856
857         if (retval == -1)
858                 retval = HLAST(h, &ev);
859
860         for (i = 0; retval != -1; retval = HPREV(h, &ev), i++) {
861                 str = ct_encode_string(ev.str, &conv);
862                 len = strlen(str) * 4 + 1;
863                 if (len > max_size) {
864                         char *nptr;
865                         max_size = (len + 1024) & (size_t)~1023;
866                         nptr = h_realloc(ptr, max_size * sizeof(*ptr));
867                         if (nptr == NULL) {
868                                 i = -1;
869                                 goto oomem;
870                         }
871                         ptr = nptr;
872                 }
873                 (void) strvis(ptr, str, VIS_WHITE);
874                 (void) fprintf(fp, "%s\n", ptr);
875         }
876 oomem:
877         h_free(ptr);
878 done:
879         return i;
880 }
881
882
883 /* history_save():
884  *    History save function
885  */
886 static int
887 history_save(TYPE(History) *h, const char *fname)
888 {
889     FILE *fp;
890     int i;
891
892     if ((fp = fopen(fname, "w")) == NULL)
893         return -1;
894
895     i = history_save_fp(h, (size_t)-1, fp);
896
897     (void) fclose(fp);
898     return i;
899 }
900
901
902 /* history_prev_event():
903  *      Find the previous event, with number given
904  */
905 static int
906 history_prev_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
907 {
908         int retval;
909
910         for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
911                 if (ev->num == num)
912                         return 0;
913
914         he_seterrev(ev, _HE_NOT_FOUND);
915         return -1;
916 }
917
918
919 static int
920 history_next_evdata(TYPE(History) *h, TYPE(HistEvent) *ev, int num, void **d)
921 {
922         int retval;
923
924         for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
925                 if (ev->num == num) {
926                         if (d)
927                                 *d = ((history_t *)h->h_ref)->cursor->data;
928                         return 0;
929                 }
930
931         he_seterrev(ev, _HE_NOT_FOUND);
932         return -1;
933 }
934
935
936 /* history_next_event():
937  *      Find the next event, with number given
938  */
939 static int
940 history_next_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
941 {
942         int retval;
943
944         for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
945                 if (ev->num == num)
946                         return 0;
947
948         he_seterrev(ev, _HE_NOT_FOUND);
949         return -1;
950 }
951
952
953 /* history_prev_string():
954  *      Find the previous event beginning with string
955  */
956 static int
957 history_prev_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str)
958 {
959         size_t len = Strlen(str);
960         int retval;
961
962         for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
963                 if (Strncmp(str, ev->str, len) == 0)
964                         return 0;
965
966         he_seterrev(ev, _HE_NOT_FOUND);
967         return -1;
968 }
969
970
971 /* history_next_string():
972  *      Find the next event beginning with string
973  */
974 static int
975 history_next_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str)
976 {
977         size_t len = Strlen(str);
978         int retval;
979
980         for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
981                 if (Strncmp(str, ev->str, len) == 0)
982                         return 0;
983
984         he_seterrev(ev, _HE_NOT_FOUND);
985         return -1;
986 }
987
988
989 /* history():
990  *      User interface to history functions.
991  */
992 int
993 FUNW(history)(TYPE(History) *h, TYPE(HistEvent) *ev, int fun, ...)
994 {
995         va_list va;
996         const Char *str;
997         int retval;
998
999         va_start(va, fun);
1000
1001         he_seterrev(ev, _HE_OK);
1002
1003         switch (fun) {
1004         case H_GETSIZE:
1005                 retval = history_getsize(h, ev);
1006                 break;
1007
1008         case H_SETSIZE:
1009                 retval = history_setsize(h, ev, va_arg(va, int));
1010                 break;
1011
1012         case H_GETUNIQUE:
1013                 retval = history_getunique(h, ev);
1014                 break;
1015
1016         case H_SETUNIQUE:
1017                 retval = history_setunique(h, ev, va_arg(va, int));
1018                 break;
1019
1020         case H_ADD:
1021                 str = va_arg(va, const Char *);
1022                 retval = HADD(h, ev, str);
1023                 break;
1024
1025         case H_DEL:
1026                 retval = HDEL(h, ev, va_arg(va, const int));
1027                 break;
1028
1029         case H_ENTER:
1030                 str = va_arg(va, const Char *);
1031                 if ((retval = HENTER(h, ev, str)) != -1)
1032                         h->h_ent = ev->num;
1033                 break;
1034
1035         case H_APPEND:
1036                 str = va_arg(va, const Char *);
1037                 if ((retval = HSET(h, ev, h->h_ent)) != -1)
1038                         retval = HADD(h, ev, str);
1039                 break;
1040
1041         case H_FIRST:
1042                 retval = HFIRST(h, ev);
1043                 break;
1044
1045         case H_NEXT:
1046                 retval = HNEXT(h, ev);
1047                 break;
1048
1049         case H_LAST:
1050                 retval = HLAST(h, ev);
1051                 break;
1052
1053         case H_PREV:
1054                 retval = HPREV(h, ev);
1055                 break;
1056
1057         case H_CURR:
1058                 retval = HCURR(h, ev);
1059                 break;
1060
1061         case H_SET:
1062                 retval = HSET(h, ev, va_arg(va, const int));
1063                 break;
1064
1065         case H_CLEAR:
1066                 HCLEAR(h, ev);
1067                 retval = 0;
1068                 break;
1069
1070         case H_LOAD:
1071                 retval = history_load(h, va_arg(va, const char *));
1072                 if (retval == -1)
1073                         he_seterrev(ev, _HE_HIST_READ);
1074                 break;
1075
1076         case H_SAVE:
1077                 retval = history_save(h, va_arg(va, const char *));
1078                 if (retval == -1)
1079                         he_seterrev(ev, _HE_HIST_WRITE);
1080                 break;
1081
1082         case H_SAVE_FP:
1083                 retval = history_save_fp(h, (size_t)-1, va_arg(va, FILE *));
1084                 if (retval == -1)
1085                     he_seterrev(ev, _HE_HIST_WRITE);
1086                 break;
1087
1088         case H_NSAVE_FP:
1089         {
1090                 size_t sz = va_arg(va, size_t);
1091                 retval = history_save_fp(h, sz, va_arg(va, FILE *));
1092                 if (retval == -1)
1093                     he_seterrev(ev, _HE_HIST_WRITE);
1094                 break;
1095         }
1096
1097         case H_PREV_EVENT:
1098                 retval = history_prev_event(h, ev, va_arg(va, int));
1099                 break;
1100
1101         case H_NEXT_EVENT:
1102                 retval = history_next_event(h, ev, va_arg(va, int));
1103                 break;
1104
1105         case H_PREV_STR:
1106                 retval = history_prev_string(h, ev, va_arg(va, const Char *));
1107                 break;
1108
1109         case H_NEXT_STR:
1110                 retval = history_next_string(h, ev, va_arg(va, const Char *));
1111                 break;
1112
1113         case H_FUNC:
1114         {
1115                 TYPE(History) hf;
1116
1117                 hf.h_ref = va_arg(va, void *);
1118                 h->h_ent = -1;
1119                 hf.h_first = va_arg(va, history_gfun_t);
1120                 hf.h_next = va_arg(va, history_gfun_t);
1121                 hf.h_last = va_arg(va, history_gfun_t);
1122                 hf.h_prev = va_arg(va, history_gfun_t);
1123                 hf.h_curr = va_arg(va, history_gfun_t);
1124                 hf.h_set = va_arg(va, history_sfun_t);
1125                 hf.h_clear = va_arg(va, history_vfun_t);
1126                 hf.h_enter = va_arg(va, history_efun_t);
1127                 hf.h_add = va_arg(va, history_efun_t);
1128                 hf.h_del = va_arg(va, history_sfun_t);
1129
1130                 if ((retval = history_set_fun(h, &hf)) == -1)
1131                         he_seterrev(ev, _HE_PARAM_MISSING);
1132                 break;
1133         }
1134
1135         case H_END:
1136                 FUN(history,end)(h);
1137                 retval = 0;
1138                 break;
1139
1140         case H_NEXT_EVDATA:
1141         {
1142                 int num = va_arg(va, int);
1143                 void **d = va_arg(va, void **);
1144                 retval = history_next_evdata(h, ev, num, d);
1145                 break;
1146         }
1147
1148         case H_DELDATA:
1149         {
1150                 int num = va_arg(va, int);
1151                 void **d = va_arg(va, void **);
1152                 retval = history_deldata_nth((history_t *)h->h_ref, ev, num, d);
1153                 break;
1154         }
1155
1156         case H_REPLACE: /* only use after H_NEXT_EVDATA */
1157         {
1158                 const Char *line = va_arg(va, const Char *);
1159                 void *d = va_arg(va, void *);
1160                 const Char *s;
1161                 if(!line || !(s = Strdup(line))) {
1162                         retval = -1;
1163                         break;
1164                 }
1165                 ((history_t *)h->h_ref)->cursor->ev.str = s;
1166                 ((history_t *)h->h_ref)->cursor->data = d;
1167                 retval = 0;
1168                 break;
1169         }
1170
1171         default:
1172                 retval = -1;
1173                 he_seterrev(ev, _HE_UNKNOWN);
1174                 break;
1175         }
1176         va_end(va);
1177         return retval;
1178 }