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