Home | History | Annotate | Line # | Download | only in libedit
history.c revision 1.1
      1  1.1  cgd /*-
      2  1.1  cgd  * Copyright (c) 1992, 1993
      3  1.1  cgd  *	The Regents of the University of California.  All rights reserved.
      4  1.1  cgd  *
      5  1.1  cgd  * This code is derived from software contributed to Berkeley by
      6  1.1  cgd  * Christos Zoulas of Cornell University.
      7  1.1  cgd  *
      8  1.1  cgd  * Redistribution and use in source and binary forms, with or without
      9  1.1  cgd  * modification, are permitted provided that the following conditions
     10  1.1  cgd  * are met:
     11  1.1  cgd  * 1. Redistributions of source code must retain the above copyright
     12  1.1  cgd  *    notice, this list of conditions and the following disclaimer.
     13  1.1  cgd  * 2. Redistributions in binary form must reproduce the above copyright
     14  1.1  cgd  *    notice, this list of conditions and the following disclaimer in the
     15  1.1  cgd  *    documentation and/or other materials provided with the distribution.
     16  1.1  cgd  * 3. All advertising materials mentioning features or use of this software
     17  1.1  cgd  *    must display the following acknowledgement:
     18  1.1  cgd  *	This product includes software developed by the University of
     19  1.1  cgd  *	California, Berkeley and its contributors.
     20  1.1  cgd  * 4. Neither the name of the University nor the names of its contributors
     21  1.1  cgd  *    may be used to endorse or promote products derived from this software
     22  1.1  cgd  *    without specific prior written permission.
     23  1.1  cgd  *
     24  1.1  cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     25  1.1  cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     26  1.1  cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27  1.1  cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     28  1.1  cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     29  1.1  cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     30  1.1  cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     31  1.1  cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32  1.1  cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     33  1.1  cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     34  1.1  cgd  * SUCH DAMAGE.
     35  1.1  cgd  */
     36  1.1  cgd 
     37  1.1  cgd #if !defined(lint) && !defined(SCCSID)
     38  1.1  cgd static char sccsid[] = "@(#)history.c	8.1 (Berkeley) 6/4/93";
     39  1.1  cgd #endif /* not lint && not SCCSID */
     40  1.1  cgd 
     41  1.1  cgd /*
     42  1.1  cgd  * hist.c: History access functions
     43  1.1  cgd  */
     44  1.1  cgd #include "sys.h"
     45  1.1  cgd 
     46  1.1  cgd #include <string.h>
     47  1.1  cgd #include <stdlib.h>
     48  1.1  cgd #if __STDC__
     49  1.1  cgd #include <stdarg.h>
     50  1.1  cgd #else
     51  1.1  cgd #include <varargs.h>
     52  1.1  cgd #endif
     53  1.1  cgd 
     54  1.1  cgd #include "histedit.h"
     55  1.1  cgd 
     56  1.1  cgd typedef const HistEvent *	(*history_gfun_t) __P((ptr_t));
     57  1.1  cgd typedef const HistEvent *	(*history_efun_t) __P((ptr_t, const char *));
     58  1.1  cgd 
     59  1.1  cgd struct history {
     60  1.1  cgd     ptr_t	   h_ref;		/* Argument for history fcns	*/
     61  1.1  cgd     history_gfun_t h_first;		/* Get the first element	*/
     62  1.1  cgd     history_gfun_t h_next;		/* Get the next element		*/
     63  1.1  cgd     history_gfun_t h_last;		/* Get the last element		*/
     64  1.1  cgd     history_gfun_t h_prev;		/* Get the previous element	*/
     65  1.1  cgd     history_gfun_t h_curr;		/* Get the current element	*/
     66  1.1  cgd     history_efun_t h_enter;		/* Add an element		*/
     67  1.1  cgd     history_efun_t h_add;		/* Append to an element		*/
     68  1.1  cgd };
     69  1.1  cgd 
     70  1.1  cgd #define	HNEXT(h)  	(*(h)->h_next)((h)->h_ref)
     71  1.1  cgd #define	HFIRST(h) 	(*(h)->h_first)((h)->h_ref)
     72  1.1  cgd #define	HPREV(h)  	(*(h)->h_prev)((h)->h_ref)
     73  1.1  cgd #define	HLAST(h) 	(*(h)->h_last)((h)->h_ref)
     74  1.1  cgd #define	HCURR(h) 	(*(h)->h_curr)((h)->h_ref)
     75  1.1  cgd #define	HENTER(h, str)	(*(h)->h_enter)((h)->h_ref, str)
     76  1.1  cgd #define	HADD(h, str)	(*(h)->h_add)((h)->h_ref, str)
     77  1.1  cgd 
     78  1.1  cgd #define h_malloc(a)	malloc(a)
     79  1.1  cgd #define h_free(a)	free(a)
     80  1.1  cgd 
     81  1.1  cgd 
     82  1.1  cgd private int		 history_set_num	__P((History *, int));
     83  1.1  cgd private int		 history_set_fun	__P((History *, history_gfun_t,
     84  1.1  cgd 						     history_gfun_t,
     85  1.1  cgd 						     history_gfun_t,
     86  1.1  cgd 						     history_gfun_t,
     87  1.1  cgd 						     history_gfun_t,
     88  1.1  cgd 						     history_efun_t,
     89  1.1  cgd 						     history_efun_t, ptr_t));
     90  1.1  cgd private const HistEvent *history_prev_event	__P((History *, int));
     91  1.1  cgd private const HistEvent *history_next_event	__P((History *, int));
     92  1.1  cgd private const HistEvent *history_next_string	__P((History *, const char *));
     93  1.1  cgd private const HistEvent *history_prev_string	__P((History *, const char *));
     94  1.1  cgd 
     95  1.1  cgd 
     96  1.1  cgd /***********************************************************************/
     97  1.1  cgd 
     98  1.1  cgd /*
     99  1.1  cgd  * Builtin- history implementation
    100  1.1  cgd  */
    101  1.1  cgd typedef struct hentry_t {
    102  1.1  cgd     HistEvent ev;		/* What we return		*/
    103  1.1  cgd     struct hentry_t *next;	/* Next entry			*/
    104  1.1  cgd     struct hentry_t *prev;	/* Previous entry		*/
    105  1.1  cgd } hentry_t;
    106  1.1  cgd 
    107  1.1  cgd typedef struct history_t {
    108  1.1  cgd     hentry_t  list;		/* Fake list header element	*/
    109  1.1  cgd     hentry_t *cursor;		/* Current element in the list	*/
    110  1.1  cgd     int	max;			/* Maximum number of events	*/
    111  1.1  cgd     int cur;			/* Current number of events	*/
    112  1.1  cgd     int	eventno;		/* Current event number		*/
    113  1.1  cgd } history_t;
    114  1.1  cgd 
    115  1.1  cgd private const HistEvent *history_def_first  __P((ptr_t));
    116  1.1  cgd private const HistEvent *history_def_last   __P((ptr_t));
    117  1.1  cgd private const HistEvent *history_def_next   __P((ptr_t));
    118  1.1  cgd private const HistEvent *history_def_prev   __P((ptr_t));
    119  1.1  cgd private const HistEvent *history_def_curr   __P((ptr_t));
    120  1.1  cgd private const HistEvent *history_def_enter  __P((ptr_t, const char *));
    121  1.1  cgd private const HistEvent *history_def_add    __P((ptr_t, const char *));
    122  1.1  cgd private void             history_def_init   __P((ptr_t *, int));
    123  1.1  cgd private void             history_def_end    __P((ptr_t));
    124  1.1  cgd private const HistEvent *history_def_insert __P((history_t *, const char *));
    125  1.1  cgd private void             history_def_delete __P((history_t *, hentry_t *));
    126  1.1  cgd 
    127  1.1  cgd #define history_def_set(p, num)	(void) (((history_t *) p)->max = (num))
    128  1.1  cgd 
    129  1.1  cgd 
    130  1.1  cgd /* history_def_first():
    131  1.1  cgd  *	Default function to return the first event in the history.
    132  1.1  cgd  */
    133  1.1  cgd private const HistEvent *
    134  1.1  cgd history_def_first(p)
    135  1.1  cgd     ptr_t p;
    136  1.1  cgd {
    137  1.1  cgd     history_t *h = (history_t *) p;
    138  1.1  cgd     h->cursor = h->list.next;
    139  1.1  cgd     if (h->cursor != &h->list)
    140  1.1  cgd 	return &h->cursor->ev;
    141  1.1  cgd     else
    142  1.1  cgd 	return NULL;
    143  1.1  cgd }
    144  1.1  cgd 
    145  1.1  cgd /* history_def_last():
    146  1.1  cgd  *	Default function to return the last event in the history.
    147  1.1  cgd  */
    148  1.1  cgd private const HistEvent *
    149  1.1  cgd history_def_last(p)
    150  1.1  cgd     ptr_t p;
    151  1.1  cgd {
    152  1.1  cgd     history_t *h = (history_t *) p;
    153  1.1  cgd     h->cursor = h->list.prev;
    154  1.1  cgd     if (h->cursor != &h->list)
    155  1.1  cgd 	return &h->cursor->ev;
    156  1.1  cgd     else
    157  1.1  cgd 	return NULL;
    158  1.1  cgd }
    159  1.1  cgd 
    160  1.1  cgd /* history_def_next():
    161  1.1  cgd  *	Default function to return the next event in the history.
    162  1.1  cgd  */
    163  1.1  cgd private const HistEvent *
    164  1.1  cgd history_def_next(p)
    165  1.1  cgd     ptr_t p;
    166  1.1  cgd {
    167  1.1  cgd     history_t *h = (history_t *) p;
    168  1.1  cgd 
    169  1.1  cgd     if (h->cursor != &h->list)
    170  1.1  cgd 	h->cursor = h->cursor->next;
    171  1.1  cgd     else
    172  1.1  cgd 	return NULL;
    173  1.1  cgd 
    174  1.1  cgd     if (h->cursor != &h->list)
    175  1.1  cgd 	return &h->cursor->ev;
    176  1.1  cgd     else
    177  1.1  cgd 	return NULL;
    178  1.1  cgd }
    179  1.1  cgd 
    180  1.1  cgd 
    181  1.1  cgd /* history_def_prev():
    182  1.1  cgd  *	Default function to return the previous event in the history.
    183  1.1  cgd  */
    184  1.1  cgd private const HistEvent *
    185  1.1  cgd history_def_prev(p)
    186  1.1  cgd     ptr_t p;
    187  1.1  cgd {
    188  1.1  cgd     history_t *h = (history_t *) p;
    189  1.1  cgd 
    190  1.1  cgd     if (h->cursor != &h->list)
    191  1.1  cgd 	h->cursor = h->cursor->prev;
    192  1.1  cgd     else
    193  1.1  cgd 	return NULL;
    194  1.1  cgd 
    195  1.1  cgd     if (h->cursor != &h->list)
    196  1.1  cgd 	return &h->cursor->ev;
    197  1.1  cgd     else
    198  1.1  cgd 	return NULL;
    199  1.1  cgd }
    200  1.1  cgd 
    201  1.1  cgd 
    202  1.1  cgd /* history_def_curr():
    203  1.1  cgd  *	Default function to return the current event in the history.
    204  1.1  cgd  */
    205  1.1  cgd private const HistEvent *
    206  1.1  cgd history_def_curr(p)
    207  1.1  cgd     ptr_t p;
    208  1.1  cgd {
    209  1.1  cgd     history_t *h = (history_t *) p;
    210  1.1  cgd 
    211  1.1  cgd     if (h->cursor != &h->list)
    212  1.1  cgd 	return &h->cursor->ev;
    213  1.1  cgd     else
    214  1.1  cgd 	return NULL;
    215  1.1  cgd }
    216  1.1  cgd 
    217  1.1  cgd 
    218  1.1  cgd /* history_def_add():
    219  1.1  cgd  *	Append string to element
    220  1.1  cgd  */
    221  1.1  cgd private const HistEvent *
    222  1.1  cgd history_def_add(p, str)
    223  1.1  cgd     ptr_t p;
    224  1.1  cgd     const char *str;
    225  1.1  cgd {
    226  1.1  cgd     history_t *h = (history_t *) p;
    227  1.1  cgd     size_t len;
    228  1.1  cgd     char *s;
    229  1.1  cgd 
    230  1.1  cgd     if (h->cursor == &h->list)
    231  1.1  cgd 	return (history_def_enter(p, str));
    232  1.1  cgd     len = strlen(h->cursor->ev.str) + strlen(str) + 1;
    233  1.1  cgd     s = (char *) h_malloc(len);
    234  1.1  cgd     (void) strcpy(s, h->cursor->ev.str);
    235  1.1  cgd     (void) strcat(s, str);
    236  1.1  cgd     h_free((ptr_t) h->cursor->ev.str);
    237  1.1  cgd     h->cursor->ev.str = s;
    238  1.1  cgd     return &h->cursor->ev;
    239  1.1  cgd }
    240  1.1  cgd 
    241  1.1  cgd 
    242  1.1  cgd /* history_def_delete():
    243  1.1  cgd  *	Delete element hp of the h list
    244  1.1  cgd  */
    245  1.1  cgd private void
    246  1.1  cgd history_def_delete(h, hp)
    247  1.1  cgd     history_t *h;
    248  1.1  cgd     hentry_t *hp;
    249  1.1  cgd {
    250  1.1  cgd     if (hp == &h->list)
    251  1.1  cgd 	abort();
    252  1.1  cgd     hp->prev->next = hp->next;
    253  1.1  cgd     hp->next->prev = hp->prev;
    254  1.1  cgd     h_free((ptr_t) hp->ev.str);
    255  1.1  cgd     h_free(hp);
    256  1.1  cgd     h->cur--;
    257  1.1  cgd }
    258  1.1  cgd 
    259  1.1  cgd 
    260  1.1  cgd /* history_def_insert():
    261  1.1  cgd  *	Insert element with string str in the h list
    262  1.1  cgd  */
    263  1.1  cgd private const HistEvent *
    264  1.1  cgd history_def_insert(h, str)
    265  1.1  cgd     history_t *h;
    266  1.1  cgd     const char *str;
    267  1.1  cgd {
    268  1.1  cgd     h->cursor = (hentry_t *) h_malloc(sizeof(hentry_t));
    269  1.1  cgd     h->cursor->ev.str = strdup(str);
    270  1.1  cgd     h->cursor->next = h->list.next;
    271  1.1  cgd     h->cursor->prev = &h->list;
    272  1.1  cgd     h->list.next->prev = h->cursor;
    273  1.1  cgd     h->list.next = h->cursor;
    274  1.1  cgd     h->cur++;
    275  1.1  cgd 
    276  1.1  cgd     return &h->cursor->ev;
    277  1.1  cgd }
    278  1.1  cgd 
    279  1.1  cgd 
    280  1.1  cgd /* history_def_enter():
    281  1.1  cgd  *	Default function to enter an item in the history
    282  1.1  cgd  */
    283  1.1  cgd private const HistEvent *
    284  1.1  cgd history_def_enter(p, str)
    285  1.1  cgd     ptr_t p;
    286  1.1  cgd     const char *str;
    287  1.1  cgd {
    288  1.1  cgd     history_t *h = (history_t *) p;
    289  1.1  cgd     const HistEvent *ev;
    290  1.1  cgd 
    291  1.1  cgd 
    292  1.1  cgd     ev = history_def_insert(h, str);
    293  1.1  cgd     ((HistEvent*) ev)->num = ++h->eventno;
    294  1.1  cgd 
    295  1.1  cgd     /*
    296  1.1  cgd      * Always keep at least one entry.
    297  1.1  cgd      * This way we don't have to check for the empty list.
    298  1.1  cgd      */
    299  1.1  cgd     while (h->cur > h->max + 1)
    300  1.1  cgd 	history_def_delete(h, h->list.prev);
    301  1.1  cgd     return ev;
    302  1.1  cgd }
    303  1.1  cgd 
    304  1.1  cgd 
    305  1.1  cgd /* history_def_init():
    306  1.1  cgd  *	Default history initialization function
    307  1.1  cgd  */
    308  1.1  cgd private void
    309  1.1  cgd history_def_init(p, n)
    310  1.1  cgd     ptr_t *p;
    311  1.1  cgd     int n;
    312  1.1  cgd {
    313  1.1  cgd     history_t *h = (history_t *) h_malloc(sizeof(history_t));
    314  1.1  cgd     if (n <= 0)
    315  1.1  cgd 	n = 0;
    316  1.1  cgd     h->eventno = 0;
    317  1.1  cgd     h->cur = 0;
    318  1.1  cgd     h->max = n;
    319  1.1  cgd     h->list.next = h->list.prev = &h->list;
    320  1.1  cgd     h->list.ev.str = NULL;
    321  1.1  cgd     h->list.ev.num = 0;
    322  1.1  cgd     h->cursor = &h->list;
    323  1.1  cgd     *p = (ptr_t) h;
    324  1.1  cgd }
    325  1.1  cgd 
    326  1.1  cgd 
    327  1.1  cgd /* history_def_end():
    328  1.1  cgd  *	Default history cleanup function
    329  1.1  cgd  */
    330  1.1  cgd private void
    331  1.1  cgd history_def_end(p)
    332  1.1  cgd     ptr_t p;
    333  1.1  cgd {
    334  1.1  cgd     history_t *h = (history_t *) p;
    335  1.1  cgd 
    336  1.1  cgd     while (h->list.prev != &h->list)
    337  1.1  cgd 	history_def_delete(h, h->list.prev);
    338  1.1  cgd }
    339  1.1  cgd 
    340  1.1  cgd /************************************************************************/
    341  1.1  cgd 
    342  1.1  cgd /* history_init():
    343  1.1  cgd  *	Initialization function.
    344  1.1  cgd  */
    345  1.1  cgd public History *
    346  1.1  cgd history_init()
    347  1.1  cgd {
    348  1.1  cgd     History *h = (History *) h_malloc(sizeof(History));
    349  1.1  cgd 
    350  1.1  cgd     history_def_init(&h->h_ref, 0);
    351  1.1  cgd 
    352  1.1  cgd     h->h_next  = history_def_next;
    353  1.1  cgd     h->h_first = history_def_first;
    354  1.1  cgd     h->h_last  = history_def_last;
    355  1.1  cgd     h->h_prev  = history_def_prev;
    356  1.1  cgd     h->h_curr  = history_def_curr;
    357  1.1  cgd     h->h_enter = history_def_enter;
    358  1.1  cgd     h->h_add   = history_def_add;
    359  1.1  cgd 
    360  1.1  cgd     return h;
    361  1.1  cgd }
    362  1.1  cgd 
    363  1.1  cgd 
    364  1.1  cgd /* history_end():
    365  1.1  cgd  *	clean up history;
    366  1.1  cgd  */
    367  1.1  cgd public void
    368  1.1  cgd history_end(h)
    369  1.1  cgd     History *h;
    370  1.1  cgd {
    371  1.1  cgd     if (h->h_next == history_def_next)
    372  1.1  cgd 	history_def_end(h->h_ref);
    373  1.1  cgd }
    374  1.1  cgd 
    375  1.1  cgd 
    376  1.1  cgd 
    377  1.1  cgd /* history_set_num():
    378  1.1  cgd  *	Set history number of events
    379  1.1  cgd  */
    380  1.1  cgd private int
    381  1.1  cgd history_set_num(h, num)
    382  1.1  cgd     History *h;
    383  1.1  cgd     int num;
    384  1.1  cgd {
    385  1.1  cgd     if (h->h_next != history_def_next || num < 0)
    386  1.1  cgd 	return -1;
    387  1.1  cgd     history_def_set(h->h_ref, num);
    388  1.1  cgd     return 0;
    389  1.1  cgd }
    390  1.1  cgd 
    391  1.1  cgd 
    392  1.1  cgd /* history_set_fun():
    393  1.1  cgd  *	Set history functions
    394  1.1  cgd  */
    395  1.1  cgd private int
    396  1.1  cgd history_set_fun(h, first, next, last, prev, curr, enter, add, ptr)
    397  1.1  cgd     History *h;
    398  1.1  cgd     history_gfun_t first, next, last, prev, curr;
    399  1.1  cgd     history_efun_t enter, add;
    400  1.1  cgd     ptr_t ptr;
    401  1.1  cgd {
    402  1.1  cgd     if (first == NULL || next == NULL ||
    403  1.1  cgd         last == NULL  || prev == NULL || curr == NULL ||
    404  1.1  cgd 	enter == NULL || add == NULL ||
    405  1.1  cgd 	ptr == NULL ) {
    406  1.1  cgd 	if (h->h_next != history_def_next) {
    407  1.1  cgd 	    history_def_init(&h->h_ref, 0);
    408  1.1  cgd 	    h->h_first = history_def_first;
    409  1.1  cgd 	    h->h_next  = history_def_next;
    410  1.1  cgd 	    h->h_last  = history_def_last;
    411  1.1  cgd 	    h->h_prev  = history_def_prev;
    412  1.1  cgd 	    h->h_curr  = history_def_curr;
    413  1.1  cgd 	    h->h_enter = history_def_enter;
    414  1.1  cgd 	    h->h_add   = history_def_add;
    415  1.1  cgd 	}
    416  1.1  cgd 	return -1;
    417  1.1  cgd     }
    418  1.1  cgd 
    419  1.1  cgd     if (h->h_next == history_def_next)
    420  1.1  cgd 	history_def_end(h->h_ref);
    421  1.1  cgd 
    422  1.1  cgd     h->h_next  = next;
    423  1.1  cgd     h->h_first = first;
    424  1.1  cgd     h->h_enter = enter;
    425  1.1  cgd     h->h_add   = add;
    426  1.1  cgd     return 0;
    427  1.1  cgd }
    428  1.1  cgd 
    429  1.1  cgd 
    430  1.1  cgd /* history_prev_event():
    431  1.1  cgd  *	Find the previous event, with number given
    432  1.1  cgd  */
    433  1.1  cgd private const HistEvent *
    434  1.1  cgd history_prev_event(h, num)
    435  1.1  cgd     History *h;
    436  1.1  cgd     int num;
    437  1.1  cgd {
    438  1.1  cgd     const HistEvent *ev;
    439  1.1  cgd     for (ev = HCURR(h); ev != NULL; ev = HPREV(h))
    440  1.1  cgd 	if (ev->num == num)
    441  1.1  cgd 	    return ev;
    442  1.1  cgd     return NULL;
    443  1.1  cgd }
    444  1.1  cgd 
    445  1.1  cgd 
    446  1.1  cgd /* history_next_event():
    447  1.1  cgd  *	Find the next event, with number given
    448  1.1  cgd  */
    449  1.1  cgd private const HistEvent *
    450  1.1  cgd history_next_event(h, num)
    451  1.1  cgd     History *h;
    452  1.1  cgd     int num;
    453  1.1  cgd {
    454  1.1  cgd     const HistEvent *ev;
    455  1.1  cgd     for (ev = HCURR(h); ev != NULL; ev = HNEXT(h))
    456  1.1  cgd 	if (ev->num == num)
    457  1.1  cgd 	    return ev;
    458  1.1  cgd     return NULL;
    459  1.1  cgd }
    460  1.1  cgd 
    461  1.1  cgd 
    462  1.1  cgd /* history_prev_string():
    463  1.1  cgd  *	Find the previous event beginning with string
    464  1.1  cgd  */
    465  1.1  cgd private const HistEvent *
    466  1.1  cgd history_prev_string(h, str)
    467  1.1  cgd     History *h;
    468  1.1  cgd     const char* str;
    469  1.1  cgd {
    470  1.1  cgd     const HistEvent *ev;
    471  1.1  cgd     size_t len = strlen(str);
    472  1.1  cgd 
    473  1.1  cgd     for (ev = HCURR(h); ev != NULL; ev = HNEXT(h))
    474  1.1  cgd 	if (strncmp(str, ev->str, len) == 0)
    475  1.1  cgd 	    return ev;
    476  1.1  cgd     return NULL;
    477  1.1  cgd }
    478  1.1  cgd 
    479  1.1  cgd 
    480  1.1  cgd /* history_next_string():
    481  1.1  cgd  *	Find the next event beginning with string
    482  1.1  cgd  */
    483  1.1  cgd private const HistEvent *
    484  1.1  cgd history_next_string(h, str)
    485  1.1  cgd     History *h;
    486  1.1  cgd     const char* str;
    487  1.1  cgd {
    488  1.1  cgd     const HistEvent *ev;
    489  1.1  cgd     size_t len = strlen(str);
    490  1.1  cgd 
    491  1.1  cgd     for (ev = HCURR(h); ev != NULL; ev = HPREV(h))
    492  1.1  cgd 	if (strncmp(str, ev->str, len) == 0)
    493  1.1  cgd 	    return ev;
    494  1.1  cgd     return NULL;
    495  1.1  cgd }
    496  1.1  cgd 
    497  1.1  cgd 
    498  1.1  cgd /* history():
    499  1.1  cgd  *	User interface to history functions.
    500  1.1  cgd  */
    501  1.1  cgd const HistEvent *
    502  1.1  cgd #if __STDC__
    503  1.1  cgd history(History *h, int fun, ...)
    504  1.1  cgd #else
    505  1.1  cgd history(va_alist)
    506  1.1  cgd     va_dcl
    507  1.1  cgd #endif
    508  1.1  cgd {
    509  1.1  cgd     va_list va;
    510  1.1  cgd     const HistEvent *ev = NULL;
    511  1.1  cgd     const char *str;
    512  1.1  cgd     static const HistEvent sev = { 0, "" };
    513  1.1  cgd 
    514  1.1  cgd #if __STDC__
    515  1.1  cgd     va_start(va, fun);
    516  1.1  cgd #else
    517  1.1  cgd     History *h;
    518  1.1  cgd     int fun;
    519  1.1  cgd     va_start(va);
    520  1.1  cgd     h = va_arg(va, History *);
    521  1.1  cgd     fun = va_arg(va, int);
    522  1.1  cgd #endif
    523  1.1  cgd 
    524  1.1  cgd     switch (fun) {
    525  1.1  cgd     case H_ADD:
    526  1.1  cgd 	str = va_arg(va, const char *);
    527  1.1  cgd 	ev = HADD(h, str);
    528  1.1  cgd 	break;
    529  1.1  cgd 
    530  1.1  cgd     case H_ENTER:
    531  1.1  cgd 	str = va_arg(va, const char *);
    532  1.1  cgd 	ev = HENTER(h, str);
    533  1.1  cgd 	break;
    534  1.1  cgd 
    535  1.1  cgd     case H_FIRST:
    536  1.1  cgd 	ev = HFIRST(h);
    537  1.1  cgd 	break;
    538  1.1  cgd 
    539  1.1  cgd     case H_NEXT:
    540  1.1  cgd 	ev = HNEXT(h);
    541  1.1  cgd 	break;
    542  1.1  cgd 
    543  1.1  cgd     case H_LAST:
    544  1.1  cgd 	ev = HLAST(h);
    545  1.1  cgd 	break;
    546  1.1  cgd 
    547  1.1  cgd     case H_PREV:
    548  1.1  cgd 	ev = HPREV(h);
    549  1.1  cgd 	break;
    550  1.1  cgd 
    551  1.1  cgd     case H_CURR:
    552  1.1  cgd 	ev = HCURR(h);
    553  1.1  cgd 	break;
    554  1.1  cgd 
    555  1.1  cgd     case H_PREV_EVENT:
    556  1.1  cgd 	ev = history_prev_event(h, va_arg(va, int));
    557  1.1  cgd 	break;
    558  1.1  cgd 
    559  1.1  cgd     case H_NEXT_EVENT:
    560  1.1  cgd 	ev = history_next_event(h, va_arg(va, int));
    561  1.1  cgd 	break;
    562  1.1  cgd 
    563  1.1  cgd     case H_PREV_STR:
    564  1.1  cgd 	ev = history_prev_string(h, va_arg(va, const char*));
    565  1.1  cgd 	break;
    566  1.1  cgd 
    567  1.1  cgd     case H_NEXT_STR:
    568  1.1  cgd 	ev = history_next_string(h, va_arg(va, const char*));
    569  1.1  cgd 	break;
    570  1.1  cgd 
    571  1.1  cgd     case H_EVENT:
    572  1.1  cgd 	if (history_set_num(h, va_arg(va, int)) == 0)
    573  1.1  cgd 	    ev = &sev;
    574  1.1  cgd 	break;
    575  1.1  cgd 
    576  1.1  cgd     case H_FUNC:
    577  1.1  cgd 	{
    578  1.1  cgd 	    history_gfun_t	first = va_arg(va, history_gfun_t);
    579  1.1  cgd 	    history_gfun_t	next  = va_arg(va, history_gfun_t);
    580  1.1  cgd 	    history_gfun_t	last  = va_arg(va, history_gfun_t);
    581  1.1  cgd 	    history_gfun_t	prev  = va_arg(va, history_gfun_t);
    582  1.1  cgd 	    history_gfun_t	curr  = va_arg(va, history_gfun_t);
    583  1.1  cgd 	    history_efun_t	enter = va_arg(va, history_efun_t);
    584  1.1  cgd 	    history_efun_t	add   = va_arg(va, history_efun_t);
    585  1.1  cgd 	    ptr_t		ptr   = va_arg(va, ptr_t);
    586  1.1  cgd 
    587  1.1  cgd 	    if (history_set_fun(h, first, next, last, prev,
    588  1.1  cgd 				   curr, enter, add, ptr) == 0)
    589  1.1  cgd 		ev = &sev;
    590  1.1  cgd 	}
    591  1.1  cgd 	break;
    592  1.1  cgd 
    593  1.1  cgd     case H_END:
    594  1.1  cgd 	history_end(h);
    595  1.1  cgd 	break;
    596  1.1  cgd 
    597  1.1  cgd     default:
    598  1.1  cgd 	break;
    599  1.1  cgd     }
    600  1.1  cgd     va_end(va);
    601  1.1  cgd     return ev;
    602  1.1  cgd }
    603