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