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