Home | History | Annotate | Line # | Download | only in libedit
history.c revision 1.7
      1  1.7  christos /*	$NetBSD: history.c,v 1.7 1997/10/14 15:05:54 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.6  christos #include <sys/cdefs.h>
     40  1.1       cgd #if !defined(lint) && !defined(SCCSID)
     41  1.6  christos #if 0
     42  1.1       cgd static char sccsid[] = "@(#)history.c	8.1 (Berkeley) 6/4/93";
     43  1.6  christos #else
     44  1.7  christos __RCSID("$NetBSD: history.c,v 1.7 1997/10/14 15:05:54 christos Exp $");
     45  1.6  christos #endif
     46  1.1       cgd #endif /* not lint && not SCCSID */
     47  1.1       cgd 
     48  1.1       cgd /*
     49  1.1       cgd  * hist.c: History access functions
     50  1.1       cgd  */
     51  1.1       cgd #include "sys.h"
     52  1.1       cgd 
     53  1.1       cgd #include <string.h>
     54  1.1       cgd #include <stdlib.h>
     55  1.5  christos #ifdef __STDC__
     56  1.1       cgd #include <stdarg.h>
     57  1.1       cgd #else
     58  1.1       cgd #include <varargs.h>
     59  1.1       cgd #endif
     60  1.1       cgd 
     61  1.2  christos static const char hist_cookie[] = "_HiStOrY_V1_\n";
     62  1.2  christos 
     63  1.1       cgd #include "histedit.h"
     64  1.1       cgd 
     65  1.7  christos typedef int	(*history_gfun_t) __P((ptr_t, HistEvent *));
     66  1.7  christos typedef int	(*history_efun_t) __P((ptr_t, HistEvent *, const char *));
     67  1.7  christos typedef void 	(*history_vfun_t) __P((ptr_t, HistEvent *));
     68  1.1       cgd 
     69  1.1       cgd struct history {
     70  1.1       cgd     ptr_t	   h_ref;		/* Argument for history fcns	*/
     71  1.1       cgd     history_gfun_t h_first;		/* Get the first element	*/
     72  1.1       cgd     history_gfun_t h_next;		/* Get the next element		*/
     73  1.1       cgd     history_gfun_t h_last;		/* Get the last element		*/
     74  1.1       cgd     history_gfun_t h_prev;		/* Get the previous element	*/
     75  1.1       cgd     history_gfun_t h_curr;		/* Get the current element	*/
     76  1.2  christos     history_vfun_t h_clear;		/* Clear the history list	*/
     77  1.1       cgd     history_efun_t h_enter;		/* Add an element		*/
     78  1.1       cgd     history_efun_t h_add;		/* Append to an element		*/
     79  1.1       cgd };
     80  1.1       cgd 
     81  1.7  christos #define	HNEXT(h, ev)  	(*(h)->h_next)((h)->h_ref, ev)
     82  1.7  christos #define	HFIRST(h, ev) 	(*(h)->h_first)((h)->h_ref, ev)
     83  1.7  christos #define	HPREV(h, ev)  	(*(h)->h_prev)((h)->h_ref, ev)
     84  1.7  christos #define	HLAST(h, ev) 	(*(h)->h_last)((h)->h_ref, ev)
     85  1.7  christos #define	HCURR(h, ev) 	(*(h)->h_curr)((h)->h_ref, ev)
     86  1.7  christos #define	HCLEAR(h, ev) 	(*(h)->h_clear)((h)->h_ref, ev)
     87  1.7  christos #define	HENTER(h, ev, str)	(*(h)->h_enter)((h)->h_ref, ev, str)
     88  1.7  christos #define	HADD(h, ev, str)	(*(h)->h_add)((h)->h_ref, ev, str)
     89  1.1       cgd 
     90  1.1       cgd #define h_malloc(a)	malloc(a)
     91  1.1       cgd #define h_free(a)	free(a)
     92  1.1       cgd 
     93  1.1       cgd 
     94  1.7  christos private int	history_set_num		__P((History *, HistEvent *, int));
     95  1.7  christos private int	history_get_size	__P((History *, HistEvent *));
     96  1.7  christos private int	history_set_fun		__P((History *, History *));
     97  1.7  christos private int 	history_load		__P((History *, const char *));
     98  1.7  christos private int 	history_save		__P((History *, const char *));
     99  1.7  christos private int	history_prev_event	__P((History *, HistEvent *, int));
    100  1.7  christos private int	history_next_event	__P((History *, HistEvent *, int));
    101  1.7  christos private int	history_next_string	__P((History *, HistEvent *, const char *));
    102  1.7  christos private int	history_prev_string	__P((History *, HistEvent *, const char *));
    103  1.1       cgd 
    104  1.1       cgd 
    105  1.1       cgd /***********************************************************************/
    106  1.1       cgd 
    107  1.1       cgd /*
    108  1.1       cgd  * Builtin- history implementation
    109  1.1       cgd  */
    110  1.1       cgd typedef struct hentry_t {
    111  1.1       cgd     HistEvent ev;		/* What we return		*/
    112  1.1       cgd     struct hentry_t *next;	/* Next entry			*/
    113  1.1       cgd     struct hentry_t *prev;	/* Previous entry		*/
    114  1.1       cgd } hentry_t;
    115  1.1       cgd 
    116  1.1       cgd typedef struct history_t {
    117  1.1       cgd     hentry_t  list;		/* Fake list header element	*/
    118  1.1       cgd     hentry_t *cursor;		/* Current element in the list	*/
    119  1.1       cgd     int	max;			/* Maximum number of events	*/
    120  1.1       cgd     int cur;			/* Current number of events	*/
    121  1.7  christos     int	eventid;		/* For generation of unique event id	*/
    122  1.1       cgd } history_t;
    123  1.1       cgd 
    124  1.7  christos private int	history_def_first  __P((ptr_t, HistEvent *));
    125  1.7  christos private int	history_def_last   __P((ptr_t, HistEvent *));
    126  1.7  christos private int	history_def_next   __P((ptr_t, HistEvent *));
    127  1.7  christos private int	history_def_prev   __P((ptr_t, HistEvent *));
    128  1.7  christos private int	history_def_curr   __P((ptr_t, HistEvent *));
    129  1.7  christos private int	history_def_enter  __P((ptr_t, HistEvent *, const char *));
    130  1.7  christos private int	history_def_add    __P((ptr_t, HistEvent *, const char *));
    131  1.7  christos private void	history_def_init   __P((ptr_t *, HistEvent *, int));
    132  1.7  christos private void	history_def_clear  __P((ptr_t, HistEvent *));
    133  1.7  christos private int	history_def_insert __P((history_t *, HistEvent *,const char *));
    134  1.7  christos private void	history_def_delete __P((history_t *, HistEvent *, hentry_t *));
    135  1.1       cgd 
    136  1.1       cgd #define history_def_set(p, num)	(void) (((history_t *) p)->max = (num))
    137  1.7  christos #define history_def_getsize(p)  (((history_t *) p)->cur)
    138  1.1       cgd 
    139  1.7  christos #define he_strerror(code)	he_errlist[code]
    140  1.7  christos #define he_seterrev(evp, code)	{\
    141  1.7  christos 				    evp->num = code;\
    142  1.7  christos 				    evp->str = he_strerror(code);\
    143  1.7  christos 				}
    144  1.7  christos 
    145  1.7  christos /* error messages */
    146  1.7  christos static const char *const he_errlist[] = {
    147  1.7  christos 	"OK",
    148  1.7  christos 	"malloc() failed",
    149  1.7  christos 	"first event not found",
    150  1.7  christos 	"last event not found",
    151  1.7  christos 	"empty list",
    152  1.7  christos 	"no next event",
    153  1.7  christos 	"no previous event",
    154  1.7  christos 	"current event is invalid",
    155  1.7  christos 	"event not found",
    156  1.7  christos 	"can't read history from file",
    157  1.7  christos 	"can't write history",
    158  1.7  christos 	"required parameter(s) not supplied",
    159  1.7  christos 	"history size negative",
    160  1.7  christos 	"function not allowed with other history-functions-set the default",
    161  1.7  christos 	"bad parameters"
    162  1.7  christos };
    163  1.7  christos 
    164  1.7  christos /* error codes */
    165  1.7  christos #define _HE_OK                   0
    166  1.7  christos #define _HE_UNKNOWN		 1
    167  1.7  christos #define _HE_MALLOC_FAILED        2
    168  1.7  christos #define _HE_FIRST_NOTFOUND       3
    169  1.7  christos #define _HE_LAST_NOTFOUND        4
    170  1.7  christos #define _HE_EMPTY_LIST           5
    171  1.7  christos #define _HE_END_REACHED          6
    172  1.7  christos #define _HE_START_REACHED	 7
    173  1.7  christos #define _HE_CURR_INVALID	 8
    174  1.7  christos #define _HE_NOT_FOUND		 9
    175  1.7  christos #define _HE_HIST_READ		10
    176  1.7  christos #define _HE_HIST_WRITE		11
    177  1.7  christos #define _HE_PARAM_MISSING	12
    178  1.7  christos #define _HE_SIZE_NEGATIVE	13
    179  1.7  christos #define _HE_NOT_ALLOWED		14
    180  1.7  christos #define _HE_BAD_PARAM		15
    181  1.1       cgd 
    182  1.1       cgd /* history_def_first():
    183  1.1       cgd  *	Default function to return the first event in the history.
    184  1.1       cgd  */
    185  1.7  christos private int
    186  1.7  christos history_def_first(p, ev)
    187  1.1       cgd     ptr_t p;
    188  1.7  christos     HistEvent *ev;
    189  1.1       cgd {
    190  1.1       cgd     history_t *h = (history_t *) p;
    191  1.7  christos 
    192  1.1       cgd     h->cursor = h->list.next;
    193  1.1       cgd     if (h->cursor != &h->list)
    194  1.7  christos 	*ev = h->cursor->ev;
    195  1.7  christos     else {
    196  1.7  christos 	he_seterrev(ev, _HE_FIRST_NOTFOUND);
    197  1.7  christos 	return -1;
    198  1.7  christos     }
    199  1.7  christos 
    200  1.7  christos     return 0;
    201  1.1       cgd }
    202  1.1       cgd 
    203  1.1       cgd /* history_def_last():
    204  1.1       cgd  *	Default function to return the last event in the history.
    205  1.1       cgd  */
    206  1.7  christos private int
    207  1.7  christos history_def_last(p, ev)
    208  1.1       cgd     ptr_t p;
    209  1.7  christos     HistEvent *ev;
    210  1.1       cgd {
    211  1.1       cgd     history_t *h = (history_t *) p;
    212  1.7  christos 
    213  1.1       cgd     h->cursor = h->list.prev;
    214  1.1       cgd     if (h->cursor != &h->list)
    215  1.7  christos 	*ev =  h->cursor->ev;
    216  1.7  christos     else {
    217  1.7  christos 	he_seterrev(ev, _HE_LAST_NOTFOUND);
    218  1.7  christos 	return -1;
    219  1.7  christos     }
    220  1.7  christos 
    221  1.7  christos     return 0;
    222  1.1       cgd }
    223  1.1       cgd 
    224  1.1       cgd /* history_def_next():
    225  1.1       cgd  *	Default function to return the next event in the history.
    226  1.1       cgd  */
    227  1.7  christos private int
    228  1.7  christos history_def_next(p, ev)
    229  1.1       cgd     ptr_t p;
    230  1.7  christos     HistEvent *ev;
    231  1.1       cgd {
    232  1.1       cgd     history_t *h = (history_t *) p;
    233  1.1       cgd 
    234  1.1       cgd     if (h->cursor != &h->list)
    235  1.1       cgd 	h->cursor = h->cursor->next;
    236  1.7  christos     else {
    237  1.7  christos 	he_seterrev(ev, _HE_EMPTY_LIST);
    238  1.7  christos 	return -1;
    239  1.7  christos     }
    240  1.1       cgd 
    241  1.1       cgd     if (h->cursor != &h->list)
    242  1.7  christos 	*ev = h->cursor->ev;
    243  1.7  christos     else {
    244  1.7  christos 	he_seterrev(ev, _HE_END_REACHED);
    245  1.7  christos 	return -1;
    246  1.7  christos     }
    247  1.7  christos 
    248  1.7  christos     return 0;
    249  1.1       cgd }
    250  1.1       cgd 
    251  1.1       cgd 
    252  1.1       cgd /* history_def_prev():
    253  1.1       cgd  *	Default function to return the previous event in the history.
    254  1.1       cgd  */
    255  1.7  christos private int
    256  1.7  christos history_def_prev(p, ev)
    257  1.1       cgd     ptr_t p;
    258  1.7  christos    HistEvent *ev;
    259  1.1       cgd {
    260  1.1       cgd     history_t *h = (history_t *) p;
    261  1.1       cgd 
    262  1.1       cgd     if (h->cursor != &h->list)
    263  1.1       cgd 	h->cursor = h->cursor->prev;
    264  1.7  christos     else {
    265  1.7  christos 	he_seterrev(ev, (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST);
    266  1.7  christos 	return -1;
    267  1.7  christos    }
    268  1.1       cgd 
    269  1.1       cgd     if (h->cursor != &h->list)
    270  1.7  christos 	*ev = h->cursor->ev;
    271  1.7  christos     else {
    272  1.7  christos 	he_seterrev(ev, _HE_START_REACHED);
    273  1.7  christos 	return -1;
    274  1.7  christos     }
    275  1.7  christos 
    276  1.7  christos     return 0;
    277  1.1       cgd }
    278  1.1       cgd 
    279  1.1       cgd 
    280  1.1       cgd /* history_def_curr():
    281  1.1       cgd  *	Default function to return the current event in the history.
    282  1.1       cgd  */
    283  1.7  christos private int
    284  1.7  christos history_def_curr(p, ev)
    285  1.1       cgd     ptr_t p;
    286  1.7  christos    HistEvent *ev;
    287  1.1       cgd {
    288  1.1       cgd     history_t *h = (history_t *) p;
    289  1.1       cgd 
    290  1.1       cgd     if (h->cursor != &h->list)
    291  1.7  christos 	*ev = h->cursor->ev;
    292  1.7  christos     else {
    293  1.7  christos 	he_seterrev(ev, (h->cur > 0) ? _HE_CURR_INVALID : _HE_EMPTY_LIST);
    294  1.7  christos 	return -1;
    295  1.7  christos    }
    296  1.7  christos 
    297  1.7  christos     return 0;
    298  1.1       cgd }
    299  1.1       cgd 
    300  1.1       cgd /* history_def_add():
    301  1.1       cgd  *	Append string to element
    302  1.1       cgd  */
    303  1.7  christos private int
    304  1.7  christos history_def_add(p, ev, str)
    305  1.1       cgd     ptr_t p;
    306  1.7  christos     HistEvent *ev;
    307  1.1       cgd     const char *str;
    308  1.1       cgd {
    309  1.1       cgd     history_t *h = (history_t *) p;
    310  1.1       cgd     size_t len;
    311  1.1       cgd     char *s;
    312  1.1       cgd 
    313  1.1       cgd     if (h->cursor == &h->list)
    314  1.7  christos 	return (history_def_enter(p, ev, str));
    315  1.1       cgd     len = strlen(h->cursor->ev.str) + strlen(str) + 1;
    316  1.1       cgd     s = (char *) h_malloc(len);
    317  1.7  christos     if (!s) {
    318  1.7  christos 	he_seterrev(ev, _HE_MALLOC_FAILED);
    319  1.7  christos 	return -1;
    320  1.7  christos     }
    321  1.7  christos     (void)strcpy(s, h->cursor->ev.str);		/* XXX strcpy is safe */
    322  1.4       mrg     (void)strcat(s, str);			/* XXX strcat is safe */
    323  1.1       cgd     h_free((ptr_t) h->cursor->ev.str);
    324  1.1       cgd     h->cursor->ev.str = s;
    325  1.7  christos     *ev = h->cursor->ev;
    326  1.7  christos     return 0;
    327  1.1       cgd }
    328  1.1       cgd 
    329  1.1       cgd 
    330  1.1       cgd /* history_def_delete():
    331  1.1       cgd  *	Delete element hp of the h list
    332  1.1       cgd  */
    333  1.1       cgd private void
    334  1.7  christos history_def_delete(h, ev, hp)
    335  1.1       cgd     history_t *h;
    336  1.7  christos     HistEvent *ev;
    337  1.1       cgd     hentry_t *hp;
    338  1.1       cgd {
    339  1.1       cgd     if (hp == &h->list)
    340  1.1       cgd 	abort();
    341  1.1       cgd     hp->prev->next = hp->next;
    342  1.1       cgd     hp->next->prev = hp->prev;
    343  1.1       cgd     h_free((ptr_t) hp->ev.str);
    344  1.1       cgd     h_free(hp);
    345  1.1       cgd     h->cur--;
    346  1.1       cgd }
    347  1.1       cgd 
    348  1.1       cgd 
    349  1.1       cgd /* history_def_insert():
    350  1.1       cgd  *	Insert element with string str in the h list
    351  1.1       cgd  */
    352  1.7  christos private int
    353  1.7  christos history_def_insert(h, ev, str)
    354  1.1       cgd     history_t *h;
    355  1.7  christos     HistEvent *ev;
    356  1.1       cgd     const char *str;
    357  1.1       cgd {
    358  1.1       cgd     h->cursor = (hentry_t *) h_malloc(sizeof(hentry_t));
    359  1.7  christos     if (h->cursor)
    360  1.7  christos     	h->cursor->ev.str = strdup(str);
    361  1.7  christos     if (!h->cursor || !h->cursor->ev.str) {
    362  1.7  christos 	he_seterrev(ev, _HE_MALLOC_FAILED);
    363  1.7  christos 	return -1;
    364  1.7  christos     }
    365  1.7  christos     h->cursor->ev.num = ++h->eventid;
    366  1.1       cgd     h->cursor->next = h->list.next;
    367  1.1       cgd     h->cursor->prev = &h->list;
    368  1.1       cgd     h->list.next->prev = h->cursor;
    369  1.1       cgd     h->list.next = h->cursor;
    370  1.1       cgd     h->cur++;
    371  1.1       cgd 
    372  1.7  christos     *ev = h->cursor->ev;
    373  1.7  christos     return 0;
    374  1.1       cgd }
    375  1.1       cgd 
    376  1.1       cgd 
    377  1.1       cgd /* history_def_enter():
    378  1.1       cgd  *	Default function to enter an item in the history
    379  1.1       cgd  */
    380  1.7  christos private int
    381  1.7  christos history_def_enter(p, ev, str)
    382  1.1       cgd     ptr_t p;
    383  1.7  christos     HistEvent *ev;
    384  1.1       cgd     const char *str;
    385  1.1       cgd {
    386  1.1       cgd     history_t *h = (history_t *) p;
    387  1.1       cgd 
    388  1.7  christos     if (history_def_insert(h, ev, str) == -1)
    389  1.7  christos 	return -1; /* error, keep error message */
    390  1.1       cgd 
    391  1.1       cgd     /*
    392  1.1       cgd      * Always keep at least one entry.
    393  1.1       cgd      * This way we don't have to check for the empty list.
    394  1.1       cgd      */
    395  1.7  christos     while (h->cur - 1 > h->max)
    396  1.7  christos 	history_def_delete(h, ev, h->list.prev);
    397  1.7  christos 
    398  1.7  christos     return 0;
    399  1.1       cgd }
    400  1.1       cgd 
    401  1.1       cgd 
    402  1.1       cgd /* history_def_init():
    403  1.1       cgd  *	Default history initialization function
    404  1.1       cgd  */
    405  1.1       cgd private void
    406  1.7  christos history_def_init(p, ev, n)
    407  1.1       cgd     ptr_t *p;
    408  1.7  christos     HistEvent *ev;
    409  1.1       cgd     int n;
    410  1.1       cgd {
    411  1.1       cgd     history_t *h = (history_t *) h_malloc(sizeof(history_t));
    412  1.1       cgd     if (n <= 0)
    413  1.1       cgd 	n = 0;
    414  1.7  christos     h->eventid = 0;
    415  1.1       cgd     h->cur = 0;
    416  1.1       cgd     h->max = n;
    417  1.1       cgd     h->list.next = h->list.prev = &h->list;
    418  1.1       cgd     h->list.ev.str = NULL;
    419  1.1       cgd     h->list.ev.num = 0;
    420  1.1       cgd     h->cursor = &h->list;
    421  1.1       cgd     *p = (ptr_t) h;
    422  1.1       cgd }
    423  1.1       cgd 
    424  1.1       cgd 
    425  1.2  christos /* history_def_clear():
    426  1.1       cgd  *	Default history cleanup function
    427  1.1       cgd  */
    428  1.1       cgd private void
    429  1.7  christos history_def_clear(p, ev)
    430  1.1       cgd     ptr_t p;
    431  1.7  christos     HistEvent *ev;
    432  1.1       cgd {
    433  1.1       cgd     history_t *h = (history_t *) p;
    434  1.1       cgd 
    435  1.1       cgd     while (h->list.prev != &h->list)
    436  1.7  christos 	history_def_delete(h, ev, h->list.prev);
    437  1.7  christos     h->eventid = 0;
    438  1.2  christos     h->cur = 0;
    439  1.1       cgd }
    440  1.1       cgd 
    441  1.2  christos 
    442  1.2  christos 
    443  1.2  christos 
    444  1.1       cgd /************************************************************************/
    445  1.1       cgd 
    446  1.1       cgd /* history_init():
    447  1.1       cgd  *	Initialization function.
    448  1.1       cgd  */
    449  1.1       cgd public History *
    450  1.1       cgd history_init()
    451  1.1       cgd {
    452  1.1       cgd     History *h = (History *) h_malloc(sizeof(History));
    453  1.7  christos     HistEvent ev;
    454  1.1       cgd 
    455  1.7  christos     history_def_init(&h->h_ref, &ev, 0);
    456  1.1       cgd 
    457  1.1       cgd     h->h_next  = history_def_next;
    458  1.1       cgd     h->h_first = history_def_first;
    459  1.1       cgd     h->h_last  = history_def_last;
    460  1.1       cgd     h->h_prev  = history_def_prev;
    461  1.1       cgd     h->h_curr  = history_def_curr;
    462  1.2  christos     h->h_clear = history_def_clear;
    463  1.1       cgd     h->h_enter = history_def_enter;
    464  1.1       cgd     h->h_add   = history_def_add;
    465  1.1       cgd 
    466  1.1       cgd     return h;
    467  1.1       cgd }
    468  1.1       cgd 
    469  1.1       cgd 
    470  1.1       cgd /* history_end():
    471  1.1       cgd  *	clean up history;
    472  1.1       cgd  */
    473  1.1       cgd public void
    474  1.1       cgd history_end(h)
    475  1.1       cgd     History *h;
    476  1.1       cgd {
    477  1.7  christos     HistEvent ev;
    478  1.1       cgd     if (h->h_next == history_def_next)
    479  1.7  christos 	history_def_clear(h->h_ref, &ev);
    480  1.1       cgd }
    481  1.1       cgd 
    482  1.1       cgd 
    483  1.1       cgd 
    484  1.1       cgd /* history_set_num():
    485  1.1       cgd  *	Set history number of events
    486  1.1       cgd  */
    487  1.1       cgd private int
    488  1.7  christos history_set_num(h, ev, num)
    489  1.1       cgd     History *h;
    490  1.7  christos     HistEvent *ev;
    491  1.1       cgd     int num;
    492  1.1       cgd {
    493  1.7  christos     if (h->h_next != history_def_next) {
    494  1.7  christos 	he_seterrev(ev, _HE_NOT_ALLOWED);
    495  1.1       cgd 	return -1;
    496  1.7  christos     }
    497  1.7  christos 
    498  1.7  christos     if (num < 0) {
    499  1.7  christos 	he_seterrev(ev, _HE_BAD_PARAM);
    500  1.7  christos 	return -1;
    501  1.7  christos     }
    502  1.7  christos 
    503  1.1       cgd     history_def_set(h->h_ref, num);
    504  1.1       cgd     return 0;
    505  1.1       cgd }
    506  1.1       cgd 
    507  1.7  christos /* history_get_size():
    508  1.7  christos  *      Get number of events currently in history
    509  1.7  christos  */
    510  1.7  christos private int
    511  1.7  christos history_get_size(h, ev)
    512  1.7  christos     History *h;
    513  1.7  christos     HistEvent *ev;
    514  1.7  christos {
    515  1.7  christos     int retval=0;
    516  1.7  christos 
    517  1.7  christos     if (h->h_next != history_def_next) {
    518  1.7  christos 	he_seterrev(ev, _HE_NOT_ALLOWED);
    519  1.7  christos 	return -1;
    520  1.7  christos     }
    521  1.7  christos     retval = history_def_getsize(h->h_ref);
    522  1.7  christos     if (retval < -1) {
    523  1.7  christos 	he_seterrev(ev, _HE_SIZE_NEGATIVE);
    524  1.7  christos 	return -1;
    525  1.7  christos     }
    526  1.7  christos 
    527  1.7  christos     ev->num = retval;
    528  1.7  christos     return 0;
    529  1.7  christos }
    530  1.1       cgd 
    531  1.1       cgd /* history_set_fun():
    532  1.1       cgd  *	Set history functions
    533  1.1       cgd  */
    534  1.1       cgd private int
    535  1.2  christos history_set_fun(h, nh)
    536  1.7  christos     History *h;
    537  1.7  christos     History *nh;
    538  1.2  christos {
    539  1.7  christos     HistEvent ev;
    540  1.7  christos 
    541  1.2  christos     if (nh->h_first == NULL || nh->h_next == NULL ||
    542  1.2  christos         nh->h_last == NULL  || nh->h_prev == NULL || nh->h_curr == NULL ||
    543  1.2  christos 	nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL ||
    544  1.2  christos 	nh->h_ref == NULL) {
    545  1.1       cgd 	if (h->h_next != history_def_next) {
    546  1.7  christos 	    history_def_init(&h->h_ref, &ev, 0);
    547  1.1       cgd 	    h->h_first = history_def_first;
    548  1.1       cgd 	    h->h_next  = history_def_next;
    549  1.1       cgd 	    h->h_last  = history_def_last;
    550  1.1       cgd 	    h->h_prev  = history_def_prev;
    551  1.1       cgd 	    h->h_curr  = history_def_curr;
    552  1.2  christos 	    h->h_clear = history_def_clear;
    553  1.1       cgd 	    h->h_enter = history_def_enter;
    554  1.1       cgd 	    h->h_add   = history_def_add;
    555  1.1       cgd 	}
    556  1.1       cgd 	return -1;
    557  1.1       cgd     }
    558  1.1       cgd 
    559  1.1       cgd     if (h->h_next == history_def_next)
    560  1.7  christos 	history_def_clear(h->h_ref, &ev);
    561  1.2  christos 
    562  1.2  christos     h->h_first = nh->h_first;
    563  1.2  christos     h->h_next  = nh->h_next;
    564  1.2  christos     h->h_last  = nh->h_last;
    565  1.2  christos     h->h_prev  = nh->h_prev;
    566  1.2  christos     h->h_curr  = nh->h_curr;
    567  1.2  christos     h->h_clear = nh->h_clear;
    568  1.2  christos     h->h_enter = nh->h_enter;
    569  1.2  christos     h->h_add   = nh->h_add;
    570  1.1       cgd 
    571  1.1       cgd     return 0;
    572  1.1       cgd }
    573  1.1       cgd 
    574  1.1       cgd 
    575  1.2  christos /* history_load():
    576  1.2  christos  *	History load function
    577  1.2  christos  */
    578  1.2  christos private int
    579  1.2  christos history_load(h, fname)
    580  1.2  christos     History *h;
    581  1.2  christos     const char *fname;
    582  1.2  christos {
    583  1.2  christos     FILE *fp;
    584  1.2  christos     char *line;
    585  1.2  christos     size_t sz;
    586  1.2  christos     int i = -1;
    587  1.7  christos     HistEvent ev;
    588  1.2  christos 
    589  1.2  christos     if ((fp = fopen(fname, "r")) == NULL)
    590  1.2  christos 	return i;
    591  1.2  christos 
    592  1.2  christos     if ((line = fgetln(fp, &sz)) == NULL)
    593  1.2  christos 	goto done;
    594  1.2  christos 
    595  1.2  christos     if (strncmp(line, hist_cookie, sz) != 0)
    596  1.2  christos 	goto done;
    597  1.2  christos 
    598  1.2  christos     for (i = 0; (line = fgetln(fp, &sz)) != NULL; i++) {
    599  1.2  christos 	char c = line[sz];
    600  1.2  christos 	line[sz] = '\0';
    601  1.7  christos 	HENTER(h, &ev, line);
    602  1.2  christos 	line[sz] = c;
    603  1.2  christos     }
    604  1.2  christos 
    605  1.2  christos done:
    606  1.2  christos     (void) fclose(fp);
    607  1.2  christos     return i;
    608  1.2  christos }
    609  1.2  christos 
    610  1.2  christos 
    611  1.2  christos /* history_save():
    612  1.2  christos  *	History save function
    613  1.2  christos  */
    614  1.2  christos private int
    615  1.2  christos history_save(h, fname)
    616  1.2  christos     History *h;
    617  1.2  christos     const char *fname;
    618  1.2  christos {
    619  1.2  christos     FILE *fp;
    620  1.7  christos     HistEvent ev;
    621  1.7  christos     int i = 0, retval;
    622  1.2  christos 
    623  1.2  christos     if ((fp = fopen(fname, "w")) == NULL)
    624  1.2  christos 	return -1;
    625  1.2  christos 
    626  1.2  christos     (void) fputs(hist_cookie, fp);
    627  1.7  christos     for (retval = HLAST(h, &ev); retval != -1; retval = HPREV(h, &ev), i++)
    628  1.7  christos 	(void) fprintf(fp, "%s", ev.str);
    629  1.2  christos     (void) fclose(fp);
    630  1.2  christos     return i;
    631  1.2  christos }
    632  1.2  christos 
    633  1.2  christos 
    634  1.1       cgd /* history_prev_event():
    635  1.1       cgd  *	Find the previous event, with number given
    636  1.1       cgd  */
    637  1.7  christos private int
    638  1.7  christos history_prev_event(h, ev, num)
    639  1.1       cgd     History *h;
    640  1.7  christos     HistEvent *ev;
    641  1.1       cgd     int num;
    642  1.1       cgd {
    643  1.7  christos     int retval;
    644  1.7  christos     for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
    645  1.1       cgd 	if (ev->num == num)
    646  1.7  christos 	    return 0;
    647  1.7  christos 
    648  1.7  christos     he_seterrev(ev, _HE_NOT_FOUND);
    649  1.7  christos     return -1;
    650  1.1       cgd }
    651  1.1       cgd 
    652  1.1       cgd 
    653  1.1       cgd /* history_next_event():
    654  1.1       cgd  *	Find the next event, with number given
    655  1.1       cgd  */
    656  1.7  christos private int
    657  1.7  christos history_next_event(h, ev, num)
    658  1.1       cgd     History *h;
    659  1.7  christos     HistEvent *ev;
    660  1.1       cgd     int num;
    661  1.1       cgd {
    662  1.7  christos     int retval;
    663  1.7  christos     for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
    664  1.1       cgd 	if (ev->num == num)
    665  1.7  christos 	    return 0;
    666  1.7  christos 
    667  1.7  christos     he_seterrev(ev, _HE_NOT_FOUND);
    668  1.1       cgd     return NULL;
    669  1.1       cgd }
    670  1.1       cgd 
    671  1.1       cgd 
    672  1.1       cgd /* history_prev_string():
    673  1.1       cgd  *	Find the previous event beginning with string
    674  1.1       cgd  */
    675  1.7  christos private int
    676  1.7  christos history_prev_string(h, ev, str)
    677  1.1       cgd     History *h;
    678  1.7  christos     HistEvent *ev;
    679  1.1       cgd     const char* str;
    680  1.1       cgd {
    681  1.1       cgd     size_t len = strlen(str);
    682  1.7  christos     int retval;
    683  1.1       cgd 
    684  1.7  christos     for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
    685  1.1       cgd 	if (strncmp(str, ev->str, len) == 0)
    686  1.7  christos 	    return 0;
    687  1.7  christos 
    688  1.7  christos     he_seterrev(ev, _HE_NOT_FOUND);
    689  1.7  christos     return -1;
    690  1.1       cgd }
    691  1.1       cgd 
    692  1.1       cgd 
    693  1.2  christos 
    694  1.2  christos 
    695  1.1       cgd /* history_next_string():
    696  1.1       cgd  *	Find the next event beginning with string
    697  1.1       cgd  */
    698  1.7  christos private int
    699  1.7  christos history_next_string(h, ev, str)
    700  1.1       cgd     History *h;
    701  1.7  christos     HistEvent *ev;
    702  1.1       cgd     const char* str;
    703  1.1       cgd {
    704  1.1       cgd     size_t len = strlen(str);
    705  1.7  christos     int retval;
    706  1.1       cgd 
    707  1.7  christos     for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
    708  1.1       cgd 	if (strncmp(str, ev->str, len) == 0)
    709  1.7  christos 	    return 0;
    710  1.7  christos 
    711  1.7  christos     he_seterrev(ev, _HE_NOT_FOUND);
    712  1.7  christos     return -1;
    713  1.1       cgd }
    714  1.1       cgd 
    715  1.1       cgd 
    716  1.1       cgd /* history():
    717  1.1       cgd  *	User interface to history functions.
    718  1.1       cgd  */
    719  1.7  christos int
    720  1.5  christos #ifdef __STDC__
    721  1.7  christos history(History *h, HistEvent *ev, int fun, ...)
    722  1.1       cgd #else
    723  1.1       cgd history(va_alist)
    724  1.1       cgd     va_dcl
    725  1.1       cgd #endif
    726  1.1       cgd {
    727  1.1       cgd     va_list va;
    728  1.1       cgd     const char *str;
    729  1.7  christos     int retval;
    730  1.1       cgd 
    731  1.5  christos #ifdef __STDC__
    732  1.1       cgd     va_start(va, fun);
    733  1.1       cgd #else
    734  1.1       cgd     History *h;
    735  1.7  christos     HistEvent *ev;
    736  1.1       cgd     int fun;
    737  1.1       cgd     va_start(va);
    738  1.1       cgd     h = va_arg(va, History *);
    739  1.7  christos     ev = va_arg(va, HistEvent *);
    740  1.1       cgd     fun = va_arg(va, int);
    741  1.1       cgd #endif
    742  1.1       cgd 
    743  1.7  christos     he_seterrev(ev, _HE_OK);
    744  1.7  christos 
    745  1.1       cgd     switch (fun) {
    746  1.1       cgd     case H_ADD:
    747  1.1       cgd 	str = va_arg(va, const char *);
    748  1.7  christos 	retval = HADD(h, ev, str);
    749  1.1       cgd 	break;
    750  1.1       cgd 
    751  1.1       cgd     case H_ENTER:
    752  1.1       cgd 	str = va_arg(va, const char *);
    753  1.7  christos 	retval = HENTER(h, ev, str);
    754  1.1       cgd 	break;
    755  1.1       cgd 
    756  1.1       cgd     case H_FIRST:
    757  1.7  christos 	retval = HFIRST(h, ev);
    758  1.1       cgd 	break;
    759  1.1       cgd 
    760  1.1       cgd     case H_NEXT:
    761  1.7  christos 	retval = HNEXT(h, ev);
    762  1.1       cgd 	break;
    763  1.1       cgd 
    764  1.1       cgd     case H_LAST:
    765  1.7  christos 	retval = HLAST(h, ev);
    766  1.1       cgd 	break;
    767  1.1       cgd 
    768  1.1       cgd     case H_PREV:
    769  1.7  christos 	retval = HPREV(h, ev);
    770  1.1       cgd 	break;
    771  1.1       cgd 
    772  1.1       cgd     case H_CURR:
    773  1.7  christos 	retval = HCURR(h, ev);
    774  1.1       cgd 	break;
    775  1.1       cgd 
    776  1.2  christos     case H_CLEAR:
    777  1.7  christos 	HCLEAR(h, ev);
    778  1.7  christos 	retval = 0;
    779  1.2  christos 	break;
    780  1.2  christos 
    781  1.2  christos     case H_LOAD:
    782  1.7  christos 	retval = history_load(h, va_arg(va, const char *));
    783  1.7  christos 	if (retval == -1)
    784  1.7  christos 	    he_seterrev(ev, _HE_HIST_READ);
    785  1.2  christos 	break;
    786  1.2  christos 
    787  1.2  christos     case H_SAVE:
    788  1.7  christos 	retval = history_save(h, va_arg(va, const char *));
    789  1.7  christos 	if (retval == -1)
    790  1.7  christos 	    he_seterrev(ev, _HE_HIST_WRITE);
    791  1.2  christos 	break;
    792  1.2  christos 
    793  1.1       cgd     case H_PREV_EVENT:
    794  1.7  christos 	retval = history_prev_event(h, ev, va_arg(va, int));
    795  1.1       cgd 	break;
    796  1.1       cgd 
    797  1.1       cgd     case H_NEXT_EVENT:
    798  1.7  christos 	retval = history_next_event(h, ev, va_arg(va, int));
    799  1.1       cgd 	break;
    800  1.1       cgd 
    801  1.1       cgd     case H_PREV_STR:
    802  1.7  christos 	retval = history_prev_string(h, ev, va_arg(va, const char*));
    803  1.1       cgd 	break;
    804  1.1       cgd 
    805  1.1       cgd     case H_NEXT_STR:
    806  1.7  christos 	retval = history_next_string(h, ev, va_arg(va, const char*));
    807  1.1       cgd 	break;
    808  1.1       cgd 
    809  1.7  christos     case H_SETMAXSIZE:
    810  1.7  christos 	retval = history_set_num(h, ev, va_arg(va, int));
    811  1.1       cgd 	break;
    812  1.1       cgd 
    813  1.1       cgd     case H_FUNC:
    814  1.1       cgd 	{
    815  1.2  christos 	    History hf;
    816  1.2  christos 	    hf.h_ref   = va_arg(va, ptr_t);
    817  1.2  christos 	    hf.h_first = va_arg(va, history_gfun_t);
    818  1.2  christos 	    hf.h_next  = va_arg(va, history_gfun_t);
    819  1.2  christos 	    hf.h_last  = va_arg(va, history_gfun_t);
    820  1.2  christos 	    hf.h_prev  = va_arg(va, history_gfun_t);
    821  1.2  christos 	    hf.h_curr  = va_arg(va, history_gfun_t);
    822  1.2  christos 	    hf.h_clear = va_arg(va, history_vfun_t);
    823  1.2  christos 	    hf.h_enter = va_arg(va, history_efun_t);
    824  1.2  christos 	    hf.h_add   = va_arg(va, history_efun_t);
    825  1.1       cgd 
    826  1.7  christos 	    if ((retval = history_set_fun(h, &hf)) == -1)
    827  1.7  christos 		he_seterrev(ev, _HE_PARAM_MISSING);
    828  1.1       cgd 	}
    829  1.1       cgd 	break;
    830  1.1       cgd 
    831  1.1       cgd     case H_END:
    832  1.1       cgd 	history_end(h);
    833  1.7  christos 	retval = 0;
    834  1.7  christos 	break;
    835  1.7  christos 
    836  1.7  christos     case H_GETSIZE:
    837  1.7  christos 	retval = history_get_size(h, ev);
    838  1.1       cgd 	break;
    839  1.1       cgd 
    840  1.1       cgd     default:
    841  1.7  christos 	retval = -1;
    842  1.7  christos 	he_seterrev(ev, _HE_UNKNOWN);
    843  1.1       cgd 	break;
    844  1.1       cgd     }
    845  1.1       cgd     va_end(va);
    846  1.7  christos     return retval;
    847  1.1       cgd }
    848