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