Home | History | Annotate | Line # | Download | only in libedit
history.c revision 1.5
      1  1.5  christos /*	$NetBSD: history.c,v 1.5 1997/04/11 17:52:46 christos Exp $	*/
      2  1.3     lukem 
      3  1.1       cgd /*-
      4  1.1       cgd  * Copyright (c) 1992, 1993
      5  1.1       cgd  *	The Regents of the University of California.  All rights reserved.
      6  1.1       cgd  *
      7  1.1       cgd  * This code is derived from software contributed to Berkeley by
      8  1.1       cgd  * Christos Zoulas of Cornell University.
      9  1.1       cgd  *
     10  1.1       cgd  * Redistribution and use in source and binary forms, with or without
     11  1.1       cgd  * modification, are permitted provided that the following conditions
     12  1.1       cgd  * are met:
     13  1.1       cgd  * 1. Redistributions of source code must retain the above copyright
     14  1.1       cgd  *    notice, this list of conditions and the following disclaimer.
     15  1.1       cgd  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.1       cgd  *    notice, this list of conditions and the following disclaimer in the
     17  1.1       cgd  *    documentation and/or other materials provided with the distribution.
     18  1.1       cgd  * 3. All advertising materials mentioning features or use of this software
     19  1.1       cgd  *    must display the following acknowledgement:
     20  1.1       cgd  *	This product includes software developed by the University of
     21  1.1       cgd  *	California, Berkeley and its contributors.
     22  1.1       cgd  * 4. Neither the name of the University nor the names of its contributors
     23  1.1       cgd  *    may be used to endorse or promote products derived from this software
     24  1.1       cgd  *    without specific prior written permission.
     25  1.1       cgd  *
     26  1.1       cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     27  1.1       cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     28  1.1       cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     29  1.1       cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     30  1.1       cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     31  1.1       cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     32  1.1       cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     33  1.1       cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     34  1.1       cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     35  1.1       cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     36  1.1       cgd  * SUCH DAMAGE.
     37  1.1       cgd  */
     38  1.1       cgd 
     39  1.1       cgd #if !defined(lint) && !defined(SCCSID)
     40  1.1       cgd static char sccsid[] = "@(#)history.c	8.1 (Berkeley) 6/4/93";
     41  1.1       cgd #endif /* not lint && not SCCSID */
     42  1.1       cgd 
     43  1.1       cgd /*
     44  1.1       cgd  * hist.c: History access functions
     45  1.1       cgd  */
     46  1.1       cgd #include "sys.h"
     47  1.1       cgd 
     48  1.1       cgd #include <string.h>
     49  1.1       cgd #include <stdlib.h>
     50  1.5  christos #ifdef __STDC__
     51  1.1       cgd #include <stdarg.h>
     52  1.1       cgd #else
     53  1.1       cgd #include <varargs.h>
     54  1.1       cgd #endif
     55  1.1       cgd 
     56  1.2  christos static const char hist_cookie[] = "_HiStOrY_V1_\n";
     57  1.2  christos 
     58  1.1       cgd #include "histedit.h"
     59  1.1       cgd 
     60  1.1       cgd typedef const HistEvent *	(*history_gfun_t) __P((ptr_t));
     61  1.1       cgd typedef const HistEvent *	(*history_efun_t) __P((ptr_t, const char *));
     62  1.2  christos typedef void 			(*history_vfun_t) __P((ptr_t));
     63  1.1       cgd 
     64  1.1       cgd struct history {
     65  1.1       cgd     ptr_t	   h_ref;		/* Argument for history fcns	*/
     66  1.1       cgd     history_gfun_t h_first;		/* Get the first element	*/
     67  1.1       cgd     history_gfun_t h_next;		/* Get the next element		*/
     68  1.1       cgd     history_gfun_t h_last;		/* Get the last element		*/
     69  1.1       cgd     history_gfun_t h_prev;		/* Get the previous element	*/
     70  1.1       cgd     history_gfun_t h_curr;		/* Get the current element	*/
     71  1.2  christos     history_vfun_t h_clear;		/* Clear the history list	*/
     72  1.1       cgd     history_efun_t h_enter;		/* Add an element		*/
     73  1.1       cgd     history_efun_t h_add;		/* Append to an element		*/
     74  1.1       cgd };
     75  1.1       cgd 
     76  1.1       cgd #define	HNEXT(h)  	(*(h)->h_next)((h)->h_ref)
     77  1.1       cgd #define	HFIRST(h) 	(*(h)->h_first)((h)->h_ref)
     78  1.1       cgd #define	HPREV(h)  	(*(h)->h_prev)((h)->h_ref)
     79  1.1       cgd #define	HLAST(h) 	(*(h)->h_last)((h)->h_ref)
     80  1.1       cgd #define	HCURR(h) 	(*(h)->h_curr)((h)->h_ref)
     81  1.2  christos #define	HCLEAR(h) 	(*(h)->h_clear)((h)->h_ref)
     82  1.1       cgd #define	HENTER(h, str)	(*(h)->h_enter)((h)->h_ref, str)
     83  1.1       cgd #define	HADD(h, str)	(*(h)->h_add)((h)->h_ref, str)
     84  1.1       cgd 
     85  1.1       cgd #define h_malloc(a)	malloc(a)
     86  1.1       cgd #define h_free(a)	free(a)
     87  1.1       cgd 
     88  1.1       cgd 
     89  1.1       cgd private int		 history_set_num	__P((History *, int));
     90  1.2  christos private int		 history_set_fun	__P((History *, History *));
     91  1.2  christos private int 		 history_load		__P((History *, const char *));
     92  1.2  christos private int 		 history_save		__P((History *, const char *));
     93  1.1       cgd private const HistEvent *history_prev_event	__P((History *, int));
     94  1.1       cgd private const HistEvent *history_next_event	__P((History *, int));
     95  1.1       cgd private const HistEvent *history_next_string	__P((History *, const char *));
     96  1.1       cgd private const HistEvent *history_prev_string	__P((History *, const char *));
     97  1.1       cgd 
     98  1.1       cgd 
     99  1.1       cgd /***********************************************************************/
    100  1.1       cgd 
    101  1.1       cgd /*
    102  1.1       cgd  * Builtin- history implementation
    103  1.1       cgd  */
    104  1.1       cgd typedef struct hentry_t {
    105  1.1       cgd     HistEvent ev;		/* What we return		*/
    106  1.1       cgd     struct hentry_t *next;	/* Next entry			*/
    107  1.1       cgd     struct hentry_t *prev;	/* Previous entry		*/
    108  1.1       cgd } hentry_t;
    109  1.1       cgd 
    110  1.1       cgd typedef struct history_t {
    111  1.1       cgd     hentry_t  list;		/* Fake list header element	*/
    112  1.1       cgd     hentry_t *cursor;		/* Current element in the list	*/
    113  1.1       cgd     int	max;			/* Maximum number of events	*/
    114  1.1       cgd     int cur;			/* Current number of events	*/
    115  1.1       cgd     int	eventno;		/* Current event number		*/
    116  1.1       cgd } history_t;
    117  1.1       cgd 
    118  1.1       cgd private const HistEvent *history_def_first  __P((ptr_t));
    119  1.1       cgd private const HistEvent *history_def_last   __P((ptr_t));
    120  1.1       cgd private const HistEvent *history_def_next   __P((ptr_t));
    121  1.1       cgd private const HistEvent *history_def_prev   __P((ptr_t));
    122  1.1       cgd private const HistEvent *history_def_curr   __P((ptr_t));
    123  1.1       cgd private const HistEvent *history_def_enter  __P((ptr_t, const char *));
    124  1.1       cgd private const HistEvent *history_def_add    __P((ptr_t, const char *));
    125  1.1       cgd private void             history_def_init   __P((ptr_t *, int));
    126  1.2  christos private void             history_def_clear  __P((ptr_t));
    127  1.1       cgd private const HistEvent *history_def_insert __P((history_t *, const char *));
    128  1.1       cgd private void             history_def_delete __P((history_t *, hentry_t *));
    129  1.1       cgd 
    130  1.1       cgd #define history_def_set(p, num)	(void) (((history_t *) p)->max = (num))
    131  1.1       cgd 
    132  1.1       cgd 
    133  1.1       cgd /* history_def_first():
    134  1.1       cgd  *	Default function to return the first event in the history.
    135  1.1       cgd  */
    136  1.1       cgd private const HistEvent *
    137  1.1       cgd history_def_first(p)
    138  1.1       cgd     ptr_t p;
    139  1.1       cgd {
    140  1.1       cgd     history_t *h = (history_t *) p;
    141  1.1       cgd     h->cursor = h->list.next;
    142  1.1       cgd     if (h->cursor != &h->list)
    143  1.1       cgd 	return &h->cursor->ev;
    144  1.1       cgd     else
    145  1.1       cgd 	return NULL;
    146  1.1       cgd }
    147  1.1       cgd 
    148  1.1       cgd /* history_def_last():
    149  1.1       cgd  *	Default function to return the last event in the history.
    150  1.1       cgd  */
    151  1.1       cgd private const HistEvent *
    152  1.1       cgd history_def_last(p)
    153  1.1       cgd     ptr_t p;
    154  1.1       cgd {
    155  1.1       cgd     history_t *h = (history_t *) p;
    156  1.1       cgd     h->cursor = h->list.prev;
    157  1.1       cgd     if (h->cursor != &h->list)
    158  1.1       cgd 	return &h->cursor->ev;
    159  1.1       cgd     else
    160  1.1       cgd 	return NULL;
    161  1.1       cgd }
    162  1.1       cgd 
    163  1.1       cgd /* history_def_next():
    164  1.1       cgd  *	Default function to return the next event in the history.
    165  1.1       cgd  */
    166  1.1       cgd private const HistEvent *
    167  1.1       cgd history_def_next(p)
    168  1.1       cgd     ptr_t p;
    169  1.1       cgd {
    170  1.1       cgd     history_t *h = (history_t *) p;
    171  1.1       cgd 
    172  1.1       cgd     if (h->cursor != &h->list)
    173  1.1       cgd 	h->cursor = h->cursor->next;
    174  1.1       cgd     else
    175  1.1       cgd 	return NULL;
    176  1.1       cgd 
    177  1.1       cgd     if (h->cursor != &h->list)
    178  1.1       cgd 	return &h->cursor->ev;
    179  1.1       cgd     else
    180  1.1       cgd 	return NULL;
    181  1.1       cgd }
    182  1.1       cgd 
    183  1.1       cgd 
    184  1.1       cgd /* history_def_prev():
    185  1.1       cgd  *	Default function to return the previous event in the history.
    186  1.1       cgd  */
    187  1.1       cgd private const HistEvent *
    188  1.1       cgd history_def_prev(p)
    189  1.1       cgd     ptr_t p;
    190  1.1       cgd {
    191  1.1       cgd     history_t *h = (history_t *) p;
    192  1.1       cgd 
    193  1.1       cgd     if (h->cursor != &h->list)
    194  1.1       cgd 	h->cursor = h->cursor->prev;
    195  1.1       cgd     else
    196  1.1       cgd 	return NULL;
    197  1.1       cgd 
    198  1.1       cgd     if (h->cursor != &h->list)
    199  1.1       cgd 	return &h->cursor->ev;
    200  1.1       cgd     else
    201  1.1       cgd 	return NULL;
    202  1.1       cgd }
    203  1.1       cgd 
    204  1.1       cgd 
    205  1.1       cgd /* history_def_curr():
    206  1.1       cgd  *	Default function to return the current event in the history.
    207  1.1       cgd  */
    208  1.1       cgd private const HistEvent *
    209  1.1       cgd history_def_curr(p)
    210  1.1       cgd     ptr_t p;
    211  1.1       cgd {
    212  1.1       cgd     history_t *h = (history_t *) p;
    213  1.1       cgd 
    214  1.1       cgd     if (h->cursor != &h->list)
    215  1.1       cgd 	return &h->cursor->ev;
    216  1.1       cgd     else
    217  1.1       cgd 	return NULL;
    218  1.1       cgd }
    219  1.1       cgd 
    220  1.1       cgd /* history_def_add():
    221  1.1       cgd  *	Append string to element
    222  1.1       cgd  */
    223  1.1       cgd private const HistEvent *
    224  1.1       cgd history_def_add(p, str)
    225  1.1       cgd     ptr_t p;
    226  1.1       cgd     const char *str;
    227  1.1       cgd {
    228  1.1       cgd     history_t *h = (history_t *) p;
    229  1.1       cgd     size_t len;
    230  1.1       cgd     char *s;
    231  1.1       cgd 
    232  1.1       cgd     if (h->cursor == &h->list)
    233  1.1       cgd 	return (history_def_enter(p, str));
    234  1.1       cgd     len = strlen(h->cursor->ev.str) + strlen(str) + 1;
    235  1.1       cgd     s = (char *) h_malloc(len);
    236  1.4       mrg     (void)strcpy(s, h->cursor->ev.str);	/* XXX strcpy is safe */
    237  1.4       mrg     (void)strcat(s, str);			/* XXX strcat is safe */
    238  1.1       cgd     h_free((ptr_t) h->cursor->ev.str);
    239  1.1       cgd     h->cursor->ev.str = s;
    240  1.1       cgd     return &h->cursor->ev;
    241  1.1       cgd }
    242  1.1       cgd 
    243  1.1       cgd 
    244  1.1       cgd /* history_def_delete():
    245  1.1       cgd  *	Delete element hp of the h list
    246  1.1       cgd  */
    247  1.1       cgd private void
    248  1.1       cgd history_def_delete(h, hp)
    249  1.1       cgd     history_t *h;
    250  1.1       cgd     hentry_t *hp;
    251  1.1       cgd {
    252  1.1       cgd     if (hp == &h->list)
    253  1.1       cgd 	abort();
    254  1.1       cgd     hp->prev->next = hp->next;
    255  1.1       cgd     hp->next->prev = hp->prev;
    256  1.1       cgd     h_free((ptr_t) hp->ev.str);
    257  1.1       cgd     h_free(hp);
    258  1.1       cgd     h->cur--;
    259  1.1       cgd }
    260  1.1       cgd 
    261  1.1       cgd 
    262  1.1       cgd /* history_def_insert():
    263  1.1       cgd  *	Insert element with string str in the h list
    264  1.1       cgd  */
    265  1.1       cgd private const HistEvent *
    266  1.1       cgd history_def_insert(h, str)
    267  1.1       cgd     history_t *h;
    268  1.1       cgd     const char *str;
    269  1.1       cgd {
    270  1.1       cgd     h->cursor = (hentry_t *) h_malloc(sizeof(hentry_t));
    271  1.1       cgd     h->cursor->ev.str = strdup(str);
    272  1.1       cgd     h->cursor->next = h->list.next;
    273  1.1       cgd     h->cursor->prev = &h->list;
    274  1.1       cgd     h->list.next->prev = h->cursor;
    275  1.1       cgd     h->list.next = h->cursor;
    276  1.1       cgd     h->cur++;
    277  1.1       cgd 
    278  1.1       cgd     return &h->cursor->ev;
    279  1.1       cgd }
    280  1.1       cgd 
    281  1.1       cgd 
    282  1.1       cgd /* history_def_enter():
    283  1.1       cgd  *	Default function to enter an item in the history
    284  1.1       cgd  */
    285  1.1       cgd private const HistEvent *
    286  1.1       cgd history_def_enter(p, str)
    287  1.1       cgd     ptr_t p;
    288  1.1       cgd     const char *str;
    289  1.1       cgd {
    290  1.1       cgd     history_t *h = (history_t *) p;
    291  1.1       cgd     const HistEvent *ev;
    292  1.1       cgd 
    293  1.1       cgd 
    294  1.1       cgd     ev = history_def_insert(h, str);
    295  1.1       cgd     ((HistEvent*) ev)->num = ++h->eventno;
    296  1.1       cgd 
    297  1.1       cgd     /*
    298  1.1       cgd      * Always keep at least one entry.
    299  1.1       cgd      * This way we don't have to check for the empty list.
    300  1.1       cgd      */
    301  1.1       cgd     while (h->cur > h->max + 1)
    302  1.1       cgd 	history_def_delete(h, h->list.prev);
    303  1.1       cgd     return ev;
    304  1.1       cgd }
    305  1.1       cgd 
    306  1.1       cgd 
    307  1.1       cgd /* history_def_init():
    308  1.1       cgd  *	Default history initialization function
    309  1.1       cgd  */
    310  1.1       cgd private void
    311  1.1       cgd history_def_init(p, n)
    312  1.1       cgd     ptr_t *p;
    313  1.1       cgd     int n;
    314  1.1       cgd {
    315  1.1       cgd     history_t *h = (history_t *) h_malloc(sizeof(history_t));
    316  1.1       cgd     if (n <= 0)
    317  1.1       cgd 	n = 0;
    318  1.1       cgd     h->eventno = 0;
    319  1.1       cgd     h->cur = 0;
    320  1.1       cgd     h->max = n;
    321  1.1       cgd     h->list.next = h->list.prev = &h->list;
    322  1.1       cgd     h->list.ev.str = NULL;
    323  1.1       cgd     h->list.ev.num = 0;
    324  1.1       cgd     h->cursor = &h->list;
    325  1.1       cgd     *p = (ptr_t) h;
    326  1.1       cgd }
    327  1.1       cgd 
    328  1.1       cgd 
    329  1.2  christos /* history_def_clear():
    330  1.1       cgd  *	Default history cleanup function
    331  1.1       cgd  */
    332  1.1       cgd private void
    333  1.2  christos history_def_clear(p)
    334  1.1       cgd     ptr_t p;
    335  1.1       cgd {
    336  1.1       cgd     history_t *h = (history_t *) p;
    337  1.1       cgd 
    338  1.1       cgd     while (h->list.prev != &h->list)
    339  1.1       cgd 	history_def_delete(h, h->list.prev);
    340  1.2  christos     h->eventno = 0;
    341  1.2  christos     h->cur = 0;
    342  1.1       cgd }
    343  1.1       cgd 
    344  1.2  christos 
    345  1.2  christos 
    346  1.2  christos 
    347  1.1       cgd /************************************************************************/
    348  1.1       cgd 
    349  1.1       cgd /* history_init():
    350  1.1       cgd  *	Initialization function.
    351  1.1       cgd  */
    352  1.1       cgd public History *
    353  1.1       cgd history_init()
    354  1.1       cgd {
    355  1.1       cgd     History *h = (History *) h_malloc(sizeof(History));
    356  1.1       cgd 
    357  1.1       cgd     history_def_init(&h->h_ref, 0);
    358  1.1       cgd 
    359  1.1       cgd     h->h_next  = history_def_next;
    360  1.1       cgd     h->h_first = history_def_first;
    361  1.1       cgd     h->h_last  = history_def_last;
    362  1.1       cgd     h->h_prev  = history_def_prev;
    363  1.1       cgd     h->h_curr  = history_def_curr;
    364  1.2  christos     h->h_clear = history_def_clear;
    365  1.1       cgd     h->h_enter = history_def_enter;
    366  1.1       cgd     h->h_add   = history_def_add;
    367  1.1       cgd 
    368  1.1       cgd     return h;
    369  1.1       cgd }
    370  1.1       cgd 
    371  1.1       cgd 
    372  1.1       cgd /* history_end():
    373  1.1       cgd  *	clean up history;
    374  1.1       cgd  */
    375  1.1       cgd public void
    376  1.1       cgd history_end(h)
    377  1.1       cgd     History *h;
    378  1.1       cgd {
    379  1.1       cgd     if (h->h_next == history_def_next)
    380  1.2  christos 	history_def_clear(h->h_ref);
    381  1.1       cgd }
    382  1.1       cgd 
    383  1.1       cgd 
    384  1.1       cgd 
    385  1.1       cgd /* history_set_num():
    386  1.1       cgd  *	Set history number of events
    387  1.1       cgd  */
    388  1.1       cgd private int
    389  1.1       cgd history_set_num(h, num)
    390  1.1       cgd     History *h;
    391  1.1       cgd     int num;
    392  1.1       cgd {
    393  1.1       cgd     if (h->h_next != history_def_next || num < 0)
    394  1.1       cgd 	return -1;
    395  1.1       cgd     history_def_set(h->h_ref, num);
    396  1.1       cgd     return 0;
    397  1.1       cgd }
    398  1.1       cgd 
    399  1.1       cgd 
    400  1.1       cgd /* history_set_fun():
    401  1.1       cgd  *	Set history functions
    402  1.1       cgd  */
    403  1.1       cgd private int
    404  1.2  christos history_set_fun(h, nh)
    405  1.2  christos     History *h, *nh;
    406  1.2  christos {
    407  1.2  christos     if (nh->h_first == NULL || nh->h_next == NULL ||
    408  1.2  christos         nh->h_last == NULL  || nh->h_prev == NULL || nh->h_curr == NULL ||
    409  1.2  christos 	nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL ||
    410  1.2  christos 	nh->h_ref == NULL) {
    411  1.1       cgd 	if (h->h_next != history_def_next) {
    412  1.1       cgd 	    history_def_init(&h->h_ref, 0);
    413  1.1       cgd 	    h->h_first = history_def_first;
    414  1.1       cgd 	    h->h_next  = history_def_next;
    415  1.1       cgd 	    h->h_last  = history_def_last;
    416  1.1       cgd 	    h->h_prev  = history_def_prev;
    417  1.1       cgd 	    h->h_curr  = history_def_curr;
    418  1.2  christos 	    h->h_clear = history_def_clear;
    419  1.1       cgd 	    h->h_enter = history_def_enter;
    420  1.1       cgd 	    h->h_add   = history_def_add;
    421  1.1       cgd 	}
    422  1.1       cgd 	return -1;
    423  1.1       cgd     }
    424  1.1       cgd 
    425  1.1       cgd     if (h->h_next == history_def_next)
    426  1.2  christos 	history_def_clear(h->h_ref);
    427  1.2  christos 
    428  1.2  christos     h->h_first = nh->h_first;
    429  1.2  christos     h->h_next  = nh->h_next;
    430  1.2  christos     h->h_last  = nh->h_last;
    431  1.2  christos     h->h_prev  = nh->h_prev;
    432  1.2  christos     h->h_curr  = nh->h_curr;
    433  1.2  christos     h->h_clear = nh->h_clear;
    434  1.2  christos     h->h_enter = nh->h_enter;
    435  1.2  christos     h->h_add   = nh->h_add;
    436  1.1       cgd 
    437  1.1       cgd     return 0;
    438  1.1       cgd }
    439  1.1       cgd 
    440  1.1       cgd 
    441  1.2  christos /* history_load():
    442  1.2  christos  *	History load function
    443  1.2  christos  */
    444  1.2  christos private int
    445  1.2  christos history_load(h, fname)
    446  1.2  christos     History *h;
    447  1.2  christos     const char *fname;
    448  1.2  christos {
    449  1.2  christos     FILE *fp;
    450  1.2  christos     char *line;
    451  1.2  christos     size_t sz;
    452  1.2  christos     int i = -1;
    453  1.2  christos 
    454  1.2  christos     if ((fp = fopen(fname, "r")) == NULL)
    455  1.2  christos 	return i;
    456  1.2  christos 
    457  1.2  christos     if ((line = fgetln(fp, &sz)) == NULL)
    458  1.2  christos 	goto done;
    459  1.2  christos 
    460  1.2  christos     if (strncmp(line, hist_cookie, sz) != 0)
    461  1.2  christos 	goto done;
    462  1.2  christos 
    463  1.2  christos     for (i = 0; (line = fgetln(fp, &sz)) != NULL; i++) {
    464  1.2  christos 	char c = line[sz];
    465  1.2  christos 	line[sz] = '\0';
    466  1.2  christos 	HENTER(h, line);
    467  1.2  christos 	line[sz] = c;
    468  1.2  christos     }
    469  1.2  christos 
    470  1.2  christos done:
    471  1.2  christos     (void) fclose(fp);
    472  1.2  christos     return i;
    473  1.2  christos }
    474  1.2  christos 
    475  1.2  christos 
    476  1.2  christos /* history_save():
    477  1.2  christos  *	History save function
    478  1.2  christos  */
    479  1.2  christos private int
    480  1.2  christos history_save(h, fname)
    481  1.2  christos     History *h;
    482  1.2  christos     const char *fname;
    483  1.2  christos {
    484  1.2  christos     FILE *fp;
    485  1.2  christos     const HistEvent *ev;
    486  1.2  christos     int i = 0;
    487  1.2  christos 
    488  1.2  christos     if ((fp = fopen(fname, "w")) == NULL)
    489  1.2  christos 	return -1;
    490  1.2  christos 
    491  1.2  christos     (void) fputs(hist_cookie, fp);
    492  1.2  christos     for (ev = HLAST(h); ev != NULL; ev = HPREV(h), i++)
    493  1.2  christos 	(void) fprintf(fp, "%s", ev->str);
    494  1.2  christos     (void) fclose(fp);
    495  1.2  christos     return i;
    496  1.2  christos }
    497  1.2  christos 
    498  1.2  christos 
    499  1.1       cgd /* history_prev_event():
    500  1.1       cgd  *	Find the previous event, with number given
    501  1.1       cgd  */
    502  1.1       cgd private const HistEvent *
    503  1.1       cgd history_prev_event(h, num)
    504  1.1       cgd     History *h;
    505  1.1       cgd     int num;
    506  1.1       cgd {
    507  1.1       cgd     const HistEvent *ev;
    508  1.1       cgd     for (ev = HCURR(h); ev != NULL; ev = HPREV(h))
    509  1.1       cgd 	if (ev->num == num)
    510  1.1       cgd 	    return ev;
    511  1.1       cgd     return NULL;
    512  1.1       cgd }
    513  1.1       cgd 
    514  1.1       cgd 
    515  1.1       cgd /* history_next_event():
    516  1.1       cgd  *	Find the next event, with number given
    517  1.1       cgd  */
    518  1.1       cgd private const HistEvent *
    519  1.1       cgd history_next_event(h, num)
    520  1.1       cgd     History *h;
    521  1.1       cgd     int num;
    522  1.1       cgd {
    523  1.1       cgd     const HistEvent *ev;
    524  1.1       cgd     for (ev = HCURR(h); ev != NULL; ev = HNEXT(h))
    525  1.1       cgd 	if (ev->num == num)
    526  1.1       cgd 	    return ev;
    527  1.1       cgd     return NULL;
    528  1.1       cgd }
    529  1.1       cgd 
    530  1.1       cgd 
    531  1.1       cgd /* history_prev_string():
    532  1.1       cgd  *	Find the previous event beginning with string
    533  1.1       cgd  */
    534  1.1       cgd private const HistEvent *
    535  1.1       cgd history_prev_string(h, str)
    536  1.1       cgd     History *h;
    537  1.1       cgd     const char* str;
    538  1.1       cgd {
    539  1.1       cgd     const HistEvent *ev;
    540  1.1       cgd     size_t len = strlen(str);
    541  1.1       cgd 
    542  1.1       cgd     for (ev = HCURR(h); ev != NULL; ev = HNEXT(h))
    543  1.1       cgd 	if (strncmp(str, ev->str, len) == 0)
    544  1.1       cgd 	    return ev;
    545  1.1       cgd     return NULL;
    546  1.1       cgd }
    547  1.1       cgd 
    548  1.1       cgd 
    549  1.2  christos 
    550  1.2  christos 
    551  1.1       cgd /* history_next_string():
    552  1.1       cgd  *	Find the next event beginning with string
    553  1.1       cgd  */
    554  1.1       cgd private const HistEvent *
    555  1.1       cgd history_next_string(h, str)
    556  1.1       cgd     History *h;
    557  1.1       cgd     const char* str;
    558  1.1       cgd {
    559  1.1       cgd     const HistEvent *ev;
    560  1.1       cgd     size_t len = strlen(str);
    561  1.1       cgd 
    562  1.1       cgd     for (ev = HCURR(h); ev != NULL; ev = HPREV(h))
    563  1.1       cgd 	if (strncmp(str, ev->str, len) == 0)
    564  1.1       cgd 	    return ev;
    565  1.1       cgd     return NULL;
    566  1.1       cgd }
    567  1.1       cgd 
    568  1.1       cgd 
    569  1.1       cgd /* history():
    570  1.1       cgd  *	User interface to history functions.
    571  1.1       cgd  */
    572  1.1       cgd const HistEvent *
    573  1.5  christos #ifdef __STDC__
    574  1.1       cgd history(History *h, int fun, ...)
    575  1.1       cgd #else
    576  1.1       cgd history(va_alist)
    577  1.1       cgd     va_dcl
    578  1.1       cgd #endif
    579  1.1       cgd {
    580  1.1       cgd     va_list va;
    581  1.1       cgd     const HistEvent *ev = NULL;
    582  1.1       cgd     const char *str;
    583  1.2  christos     static HistEvent sev = { 0, "" };
    584  1.1       cgd 
    585  1.5  christos #ifdef __STDC__
    586  1.1       cgd     va_start(va, fun);
    587  1.1       cgd #else
    588  1.1       cgd     History *h;
    589  1.1       cgd     int fun;
    590  1.1       cgd     va_start(va);
    591  1.1       cgd     h = va_arg(va, History *);
    592  1.1       cgd     fun = va_arg(va, int);
    593  1.1       cgd #endif
    594  1.1       cgd 
    595  1.1       cgd     switch (fun) {
    596  1.1       cgd     case H_ADD:
    597  1.1       cgd 	str = va_arg(va, const char *);
    598  1.1       cgd 	ev = HADD(h, str);
    599  1.1       cgd 	break;
    600  1.1       cgd 
    601  1.1       cgd     case H_ENTER:
    602  1.1       cgd 	str = va_arg(va, const char *);
    603  1.1       cgd 	ev = HENTER(h, str);
    604  1.1       cgd 	break;
    605  1.1       cgd 
    606  1.1       cgd     case H_FIRST:
    607  1.1       cgd 	ev = HFIRST(h);
    608  1.1       cgd 	break;
    609  1.1       cgd 
    610  1.1       cgd     case H_NEXT:
    611  1.1       cgd 	ev = HNEXT(h);
    612  1.1       cgd 	break;
    613  1.1       cgd 
    614  1.1       cgd     case H_LAST:
    615  1.1       cgd 	ev = HLAST(h);
    616  1.1       cgd 	break;
    617  1.1       cgd 
    618  1.1       cgd     case H_PREV:
    619  1.1       cgd 	ev = HPREV(h);
    620  1.1       cgd 	break;
    621  1.1       cgd 
    622  1.1       cgd     case H_CURR:
    623  1.1       cgd 	ev = HCURR(h);
    624  1.1       cgd 	break;
    625  1.1       cgd 
    626  1.2  christos     case H_CLEAR:
    627  1.2  christos 	HCLEAR(h);
    628  1.2  christos 	break;
    629  1.2  christos 
    630  1.2  christos     case H_LOAD:
    631  1.2  christos 	sev.num = history_load(h, va_arg(va, const char *));
    632  1.2  christos 	ev = &sev;
    633  1.2  christos 	break;
    634  1.2  christos 
    635  1.2  christos     case H_SAVE:
    636  1.2  christos 	sev.num = history_save(h, va_arg(va, const char *));
    637  1.2  christos 	ev = &sev;
    638  1.2  christos 	break;
    639  1.2  christos 
    640  1.1       cgd     case H_PREV_EVENT:
    641  1.1       cgd 	ev = history_prev_event(h, va_arg(va, int));
    642  1.1       cgd 	break;
    643  1.1       cgd 
    644  1.1       cgd     case H_NEXT_EVENT:
    645  1.1       cgd 	ev = history_next_event(h, va_arg(va, int));
    646  1.1       cgd 	break;
    647  1.1       cgd 
    648  1.1       cgd     case H_PREV_STR:
    649  1.1       cgd 	ev = history_prev_string(h, va_arg(va, const char*));
    650  1.1       cgd 	break;
    651  1.1       cgd 
    652  1.1       cgd     case H_NEXT_STR:
    653  1.1       cgd 	ev = history_next_string(h, va_arg(va, const char*));
    654  1.1       cgd 	break;
    655  1.1       cgd 
    656  1.1       cgd     case H_EVENT:
    657  1.2  christos 	if (history_set_num(h, va_arg(va, int)) == 0) {
    658  1.2  christos 	    sev.num = -1;
    659  1.1       cgd 	    ev = &sev;
    660  1.2  christos 	}
    661  1.1       cgd 	break;
    662  1.1       cgd 
    663  1.1       cgd     case H_FUNC:
    664  1.1       cgd 	{
    665  1.2  christos 	    History hf;
    666  1.2  christos 	    hf.h_ref   = va_arg(va, ptr_t);
    667  1.2  christos 	    hf.h_first = va_arg(va, history_gfun_t);
    668  1.2  christos 	    hf.h_next  = va_arg(va, history_gfun_t);
    669  1.2  christos 	    hf.h_last  = va_arg(va, history_gfun_t);
    670  1.2  christos 	    hf.h_prev  = va_arg(va, history_gfun_t);
    671  1.2  christos 	    hf.h_curr  = va_arg(va, history_gfun_t);
    672  1.2  christos 	    hf.h_clear = va_arg(va, history_vfun_t);
    673  1.2  christos 	    hf.h_enter = va_arg(va, history_efun_t);
    674  1.2  christos 	    hf.h_add   = va_arg(va, history_efun_t);
    675  1.1       cgd 
    676  1.2  christos 	    if (history_set_fun(h, &hf) == 0) {
    677  1.2  christos 		sev.num = -1;
    678  1.1       cgd 		ev = &sev;
    679  1.2  christos 	    }
    680  1.1       cgd 	}
    681  1.1       cgd 	break;
    682  1.1       cgd 
    683  1.1       cgd     case H_END:
    684  1.1       cgd 	history_end(h);
    685  1.1       cgd 	break;
    686  1.1       cgd 
    687  1.1       cgd     default:
    688  1.1       cgd 	break;
    689  1.1       cgd     }
    690  1.1       cgd     va_end(va);
    691  1.1       cgd     return ev;
    692  1.1       cgd }
    693