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