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