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