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