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