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