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