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