Import NetBSD's LibEdit version 2012-03-11 on vendor branch
[dragonfly.git] / contrib / libedit / src / history.c
1 /*      $NetBSD: history.c,v 1.46 2011/11/18 20:39:18 christos Exp $    */
2
3 /*-
4  * Copyright (c) 1992, 1993
5  *      The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Christos Zoulas of Cornell University.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34
35 #ifndef NARROWCHAR
36 #include "config.h"
37 #endif
38
39 #if !defined(lint) && !defined(SCCSID)
40 #if 0
41 static char sccsid[] = "@(#)history.c   8.1 (Berkeley) 6/4/93";
42 #else
43 __RCSID("$NetBSD: history.c,v 1.46 2011/11/18 20:39:18 christos Exp $");
44 #endif
45 #endif /* not lint && not SCCSID */
46
47 /*
48  * hist.c: TYPE(History) access functions
49  */
50 #include <string.h>
51 #include <stdlib.h>
52 #include <stdarg.h>
53 #include <vis.h>
54 #include <sys/stat.h>
55
56 static const char hist_cookie[] = "_HiStOrY_V2_\n";
57
58 #include "histedit.h"
59 #include "chartype.h"
60
61 typedef int (*history_gfun_t)(void *, TYPE(HistEvent) *);
62 typedef int (*history_efun_t)(void *, TYPE(HistEvent) *, const Char *);
63 typedef void (*history_vfun_t)(void *, TYPE(HistEvent) *);
64 typedef int (*history_sfun_t)(void *, TYPE(HistEvent) *, const int);
65
66 struct TYPE(history) {
67         void *h_ref;            /* Argument for history fcns     */
68         int h_ent;              /* Last entry point for history  */
69         history_gfun_t h_first; /* Get the first element         */
70         history_gfun_t h_next;  /* Get the next element          */
71         history_gfun_t h_last;  /* Get the last element          */
72         history_gfun_t h_prev;  /* Get the previous element      */
73         history_gfun_t h_curr;  /* Get the current element       */
74         history_sfun_t h_set;   /* Set the current element       */
75         history_sfun_t h_del;   /* Set the given element         */
76         history_vfun_t h_clear; /* Clear the history list        */
77         history_efun_t h_enter; /* Add an element                */
78         history_efun_t h_add;   /* Append to an element          */
79 };
80
81 #define HNEXT(h, ev)            (*(h)->h_next)((h)->h_ref, ev)
82 #define HFIRST(h, ev)           (*(h)->h_first)((h)->h_ref, ev)
83 #define HPREV(h, ev)            (*(h)->h_prev)((h)->h_ref, ev)
84 #define HLAST(h, ev)            (*(h)->h_last)((h)->h_ref, ev)
85 #define HCURR(h, ev)            (*(h)->h_curr)((h)->h_ref, ev)
86 #define HSET(h, ev, n)          (*(h)->h_set)((h)->h_ref, ev, n)
87 #define HCLEAR(h, ev)           (*(h)->h_clear)((h)->h_ref, ev)
88 #define HENTER(h, ev, str)      (*(h)->h_enter)((h)->h_ref, ev, str)
89 #define HADD(h, ev, str)        (*(h)->h_add)((h)->h_ref, ev, str)
90 #define HDEL(h, ev, n)          (*(h)->h_del)((h)->h_ref, ev, n)
91
92 #define h_strdup(a)     Strdup(a)
93 #define h_malloc(a)     malloc(a)
94 #define h_realloc(a, b) realloc((a), (b))
95 #define h_free(a)       free(a)
96
97 typedef struct {
98     int         num;
99     Char        *str;
100 } HistEventPrivate;
101
102
103
104 private int history_setsize(TYPE(History) *, TYPE(HistEvent) *, int);
105 private int history_getsize(TYPE(History) *, TYPE(HistEvent) *);
106 private int history_setunique(TYPE(History) *, TYPE(HistEvent) *, int);
107 private int history_getunique(TYPE(History) *, TYPE(HistEvent) *);
108 private int history_set_fun(TYPE(History) *, TYPE(History) *);
109 private int history_load(TYPE(History) *, const char *);
110 private int history_save(TYPE(History) *, const char *);
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 sz, max_size;
738         char *ptr;
739         int i = -1;
740         TYPE(HistEvent) ev;
741 #ifdef WIDECHAR
742         static ct_buffer_t conv;
743 #endif
744
745         if ((fp = fopen(fname, "r")) == NULL)
746                 return i;
747
748         if ((line = fgetln(fp, &sz)) == NULL)
749                 goto done;
750
751         if (strncmp(line, hist_cookie, sz) != 0)
752                 goto done;
753
754         ptr = h_malloc((max_size = 1024) * sizeof(*ptr));
755         if (ptr == NULL)
756                 goto done;
757         for (i = 0; (line = fgetln(fp, &sz)) != NULL; i++) {
758                 char c = line[sz];
759
760                 if (sz != 0 && line[sz - 1] == '\n')
761                         line[--sz] = '\0';
762                 else
763                         line[sz] = '\0';
764
765                 if (max_size < sz) {
766                         char *nptr;
767                         max_size = (sz + 1024) & (size_t)~1023;
768                         nptr = h_realloc(ptr, max_size * sizeof(*ptr));
769                         if (nptr == NULL) {
770                                 i = -1;
771                                 goto oomem;
772                         }
773                         ptr = nptr;
774                 }
775                 (void) strunvis(ptr, line);
776                 line[sz] = c;
777                 if (HENTER(h, &ev, ct_decode_string(ptr, &conv)) == -1) {
778                         i = -1;
779                         goto oomem;
780                 }
781         }
782 oomem:
783         h_free(ptr);
784 done:
785         (void) fclose(fp);
786         return i;
787 }
788
789
790 /* history_save():
791  *      TYPE(History) save function
792  */
793 private int
794 history_save(TYPE(History) *h, const char *fname)
795 {
796         FILE *fp;
797         TYPE(HistEvent) ev;
798         int i = -1, retval;
799         size_t len, max_size;
800         char *ptr;
801         const char *str;
802 #ifdef WIDECHAR
803         static ct_buffer_t conv;
804 #endif
805
806         if ((fp = fopen(fname, "w")) == NULL)
807                 return -1;
808
809         if (fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1)
810                 goto done;
811         if (fputs(hist_cookie, fp) == EOF)
812                 goto done;
813         ptr = h_malloc((max_size = 1024) * sizeof(*ptr));
814         if (ptr == NULL)
815                 goto done;
816         for (i = 0, retval = HLAST(h, &ev);
817             retval != -1;
818             retval = HPREV(h, &ev), i++) {
819                 str = ct_encode_string(ev.str, &conv);
820                 len = strlen(str) * 4;
821                 if (len >= max_size) {
822                         char *nptr;
823                         max_size = (len + 1024) & (size_t)~1023;
824                         nptr = h_realloc(ptr, max_size * sizeof(*ptr));
825                         if (nptr == NULL) {
826                                 i = -1;
827                                 goto oomem;
828                         }
829                         ptr = nptr;
830                 }
831                 (void) strvis(ptr, str, VIS_WHITE);
832                 (void) fprintf(fp, "%s\n", ptr);
833         }
834 oomem:
835         h_free(ptr);
836 done:
837         (void) fclose(fp);
838         return i;
839 }
840
841
842 /* history_prev_event():
843  *      Find the previous event, with number given
844  */
845 private int
846 history_prev_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
847 {
848         int retval;
849
850         for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
851                 if (ev->num == num)
852                         return 0;
853
854         he_seterrev(ev, _HE_NOT_FOUND);
855         return -1;
856 }
857
858
859 private int
860 history_next_evdata(TYPE(History) *h, TYPE(HistEvent) *ev, int num, void **d)
861 {
862         int retval;
863
864         for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
865                 if (ev->num == num) {
866                         if (d)
867                                 *d = ((history_t *)h->h_ref)->cursor->data;
868                         return 0;
869                 }
870
871         he_seterrev(ev, _HE_NOT_FOUND);
872         return -1;
873 }
874
875
876 /* history_next_event():
877  *      Find the next event, with number given
878  */
879 private int
880 history_next_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
881 {
882         int retval;
883
884         for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
885                 if (ev->num == num)
886                         return 0;
887
888         he_seterrev(ev, _HE_NOT_FOUND);
889         return -1;
890 }
891
892
893 /* history_prev_string():
894  *      Find the previous event beginning with string
895  */
896 private int
897 history_prev_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str)
898 {
899         size_t len = Strlen(str);
900         int retval;
901
902         for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
903                 if (Strncmp(str, ev->str, len) == 0)
904                         return 0;
905
906         he_seterrev(ev, _HE_NOT_FOUND);
907         return -1;
908 }
909
910
911 /* history_next_string():
912  *      Find the next event beginning with string
913  */
914 private int
915 history_next_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str)
916 {
917         size_t len = Strlen(str);
918         int retval;
919
920         for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
921                 if (Strncmp(str, ev->str, len) == 0)
922                         return 0;
923
924         he_seterrev(ev, _HE_NOT_FOUND);
925         return -1;
926 }
927
928
929 /* history():
930  *      User interface to history functions.
931  */
932 int
933 FUNW(history)(TYPE(History) *h, TYPE(HistEvent) *ev, int fun, ...)
934 {
935         va_list va;
936         const Char *str;
937         int retval;
938
939         va_start(va, fun);
940
941         he_seterrev(ev, _HE_OK);
942
943         switch (fun) {
944         case H_GETSIZE:
945                 retval = history_getsize(h, ev);
946                 break;
947
948         case H_SETSIZE:
949                 retval = history_setsize(h, ev, va_arg(va, int));
950                 break;
951
952         case H_GETUNIQUE:
953                 retval = history_getunique(h, ev);
954                 break;
955
956         case H_SETUNIQUE:
957                 retval = history_setunique(h, ev, va_arg(va, int));
958                 break;
959
960         case H_ADD:
961                 str = va_arg(va, const Char *);
962                 retval = HADD(h, ev, str);
963                 break;
964
965         case H_DEL:
966                 retval = HDEL(h, ev, va_arg(va, const int));
967                 break;
968
969         case H_ENTER:
970                 str = va_arg(va, const Char *);
971                 if ((retval = HENTER(h, ev, str)) != -1)
972                         h->h_ent = ev->num;
973                 break;
974
975         case H_APPEND:
976                 str = va_arg(va, const Char *);
977                 if ((retval = HSET(h, ev, h->h_ent)) != -1)
978                         retval = HADD(h, ev, str);
979                 break;
980
981         case H_FIRST:
982                 retval = HFIRST(h, ev);
983                 break;
984
985         case H_NEXT:
986                 retval = HNEXT(h, ev);
987                 break;
988
989         case H_LAST:
990                 retval = HLAST(h, ev);
991                 break;
992
993         case H_PREV:
994                 retval = HPREV(h, ev);
995                 break;
996
997         case H_CURR:
998                 retval = HCURR(h, ev);
999                 break;
1000
1001         case H_SET:
1002                 retval = HSET(h, ev, va_arg(va, const int));
1003                 break;
1004
1005         case H_CLEAR:
1006                 HCLEAR(h, ev);
1007                 retval = 0;
1008                 break;
1009
1010         case H_LOAD:
1011                 retval = history_load(h, va_arg(va, const char *));
1012                 if (retval == -1)
1013                         he_seterrev(ev, _HE_HIST_READ);
1014                 break;
1015
1016         case H_SAVE:
1017                 retval = history_save(h, va_arg(va, const char *));
1018                 if (retval == -1)
1019                         he_seterrev(ev, _HE_HIST_WRITE);
1020                 break;
1021
1022         case H_PREV_EVENT:
1023                 retval = history_prev_event(h, ev, va_arg(va, int));
1024                 break;
1025
1026         case H_NEXT_EVENT:
1027                 retval = history_next_event(h, ev, va_arg(va, int));
1028                 break;
1029
1030         case H_PREV_STR:
1031                 retval = history_prev_string(h, ev, va_arg(va, const Char *));
1032                 break;
1033
1034         case H_NEXT_STR:
1035                 retval = history_next_string(h, ev, va_arg(va, const Char *));
1036                 break;
1037
1038         case H_FUNC:
1039         {
1040                 TYPE(History) hf;
1041
1042                 hf.h_ref = va_arg(va, void *);
1043                 h->h_ent = -1;
1044                 hf.h_first = va_arg(va, history_gfun_t);
1045                 hf.h_next = va_arg(va, history_gfun_t);
1046                 hf.h_last = va_arg(va, history_gfun_t);
1047                 hf.h_prev = va_arg(va, history_gfun_t);
1048                 hf.h_curr = va_arg(va, history_gfun_t);
1049                 hf.h_set = va_arg(va, history_sfun_t);
1050                 hf.h_clear = va_arg(va, history_vfun_t);
1051                 hf.h_enter = va_arg(va, history_efun_t);
1052                 hf.h_add = va_arg(va, history_efun_t);
1053                 hf.h_del = va_arg(va, history_sfun_t);
1054
1055                 if ((retval = history_set_fun(h, &hf)) == -1)
1056                         he_seterrev(ev, _HE_PARAM_MISSING);
1057                 break;
1058         }
1059
1060         case H_END:
1061                 FUN(history,end)(h);
1062                 retval = 0;
1063                 break;
1064
1065         case H_NEXT_EVDATA:
1066         {
1067                 int num = va_arg(va, int);
1068                 void **d = va_arg(va, void **);
1069                 retval = history_next_evdata(h, ev, num, d);
1070                 break;
1071         }
1072
1073         case H_DELDATA:
1074         {
1075                 int num = va_arg(va, int);
1076                 void **d = va_arg(va, void **);
1077                 retval = history_deldata_nth((history_t *)h->h_ref, ev, num, d);
1078                 break;
1079         }
1080
1081         case H_REPLACE: /* only use after H_NEXT_EVDATA */
1082         {
1083                 const Char *line = va_arg(va, const Char *);
1084                 void *d = va_arg(va, void *);
1085                 const Char *s;
1086                 if(!line || !(s = Strdup(line))) {
1087                         retval = -1;
1088                         break;
1089                 }
1090                 ((history_t *)h->h_ref)->cursor->ev.str = s;
1091                 ((history_t *)h->h_ref)->cursor->data = d;
1092                 retval = 0;
1093                 break;
1094         }
1095
1096         default:
1097                 retval = -1;
1098                 he_seterrev(ev, _HE_UNKNOWN);
1099                 break;
1100         }
1101         va_end(va);
1102         return retval;
1103 }