Annotation of src/lib/libedit/history.c, Revision 1.17
1.17 ! christos 1: /* $NetBSD: history.c,v 1.16 2000/09/04 22:06:30 lukem Exp $ */
1.3 lukem 2:
1.1 cgd 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:
1.6 christos 39: #include <sys/cdefs.h>
1.1 cgd 40: #if !defined(lint) && !defined(SCCSID)
1.6 christos 41: #if 0
1.1 cgd 42: static char sccsid[] = "@(#)history.c 8.1 (Berkeley) 6/4/93";
1.6 christos 43: #else
1.17 ! christos 44: __RCSID("$NetBSD: history.c,v 1.16 2000/09/04 22:06:30 lukem Exp $");
1.6 christos 45: #endif
1.1 cgd 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: #include <stdarg.h>
1.12 christos 56: #include <vis.h>
1.17 ! christos 57: #include <sys/stat.h>
1.1 cgd 58:
1.12 christos 59: static const char hist_cookie[] = "_HiStOrY_V2_\n";
1.2 christos 60:
1.1 cgd 61: #include "histedit.h"
62:
1.16 lukem 63: typedef int (*history_gfun_t)(ptr_t, HistEvent *);
64: typedef int (*history_efun_t)(ptr_t, HistEvent *, const char *);
65: typedef void (*history_vfun_t)(ptr_t, HistEvent *);
66: typedef int (*history_sfun_t)(ptr_t, HistEvent *, const int);
1.1 cgd 67:
68: struct history {
1.16 lukem 69: ptr_t h_ref; /* Argument for history fcns */
70: int h_ent; /* Last entry point for history */
71: history_gfun_t h_first; /* Get the first element */
72: history_gfun_t h_next; /* Get the next element */
73: history_gfun_t h_last; /* Get the last element */
74: history_gfun_t h_prev; /* Get the previous element */
75: history_gfun_t h_curr; /* Get the current element */
76: history_sfun_t h_set; /* Set the current element */
77: history_vfun_t h_clear; /* Clear the history list */
78: history_efun_t h_enter; /* Add an element */
79: history_efun_t h_add; /* Append to an element */
1.1 cgd 80: };
1.16 lukem 81: #define HNEXT(h, ev) (*(h)->h_next)((h)->h_ref, ev)
82: #define HFIRST(h, ev) (*(h)->h_first)((h)->h_ref, ev)
83: #define HPREV(h, ev) (*(h)->h_prev)((h)->h_ref, ev)
84: #define HLAST(h, ev) (*(h)->h_last)((h)->h_ref, ev)
85: #define HCURR(h, ev) (*(h)->h_curr)((h)->h_ref, ev)
86: #define HSET(h, ev, n) (*(h)->h_set)((h)->h_ref, ev, n)
87: #define HCLEAR(h, ev) (*(h)->h_clear)((h)->h_ref, ev)
1.7 christos 88: #define HENTER(h, ev, str) (*(h)->h_enter)((h)->h_ref, ev, str)
89: #define HADD(h, ev, str) (*(h)->h_add)((h)->h_ref, ev, str)
1.1 cgd 90:
1.16 lukem 91: #define h_malloc(a) malloc(a)
92: #define h_realloc(a, b) realloc((a), (b))
93: #define h_free(a) free(a)
1.1 cgd 94:
95:
1.16 lukem 96: private int history_setsize(History *, HistEvent *, int);
97: private int history_getsize(History *, HistEvent *);
98: private int history_set_fun(History *, History *);
99: private int history_load(History *, const char *);
100: private int history_save(History *, const char *);
101: private int history_prev_event(History *, HistEvent *, int);
102: private int history_next_event(History *, HistEvent *, int);
103: private int history_next_string(History *, HistEvent *, const char *);
104: private int history_prev_string(History *, HistEvent *, const char *);
1.1 cgd 105:
106:
107: /***********************************************************************/
108:
109: /*
110: * Builtin- history implementation
111: */
112: typedef struct hentry_t {
1.16 lukem 113: HistEvent ev; /* What we return */
114: struct hentry_t *next; /* Next entry */
115: struct hentry_t *prev; /* Previous entry */
116: } hentry_t;
1.1 cgd 117:
118: typedef struct history_t {
1.16 lukem 119: hentry_t list; /* Fake list header element */
120: hentry_t *cursor; /* Current element in the list */
121: int max; /* Maximum number of events */
122: int cur; /* Current number of events */
123: int eventid; /* For generation of unique event id */
124: } history_t;
125:
126: private int history_def_first(ptr_t, HistEvent *);
127: private int history_def_last(ptr_t, HistEvent *);
128: private int history_def_next(ptr_t, HistEvent *);
129: private int history_def_prev(ptr_t, HistEvent *);
130: private int history_def_curr(ptr_t, HistEvent *);
131: private int history_def_set(ptr_t, HistEvent *, const int n);
132: private int history_def_enter(ptr_t, HistEvent *, const char *);
133: private int history_def_add(ptr_t, HistEvent *, const char *);
134: private void history_def_init(ptr_t *, HistEvent *, int);
135: private void history_def_clear(ptr_t, HistEvent *);
136: private int history_def_insert(history_t *, HistEvent *, const char *);
137: private void history_def_delete(history_t *, HistEvent *, hentry_t *);
1.1 cgd 138:
1.16 lukem 139: #define history_def_setsize(p, num)(void) (((history_t *) p)->max = (num))
140: #define history_def_getsize(p) (((history_t *) p)->cur)
1.1 cgd 141:
1.16 lukem 142: #define he_strerror(code) he_errlist[code]
143: #define he_seterrev(evp, code) {\
1.7 christos 144: evp->num = code;\
145: evp->str = he_strerror(code);\
146: }
1.14 simonb 147:
1.7 christos 148: /* error messages */
149: static const char *const he_errlist[] = {
1.16 lukem 150: "OK",
151: "unknown error",
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"
1.7 christos 166: };
167: /* error codes */
1.16 lukem 168: #define _HE_OK 0
169: #define _HE_UNKNOWN 1
170: #define _HE_MALLOC_FAILED 2
171: #define _HE_FIRST_NOTFOUND 3
172: #define _HE_LAST_NOTFOUND 4
173: #define _HE_EMPTY_LIST 5
174: #define _HE_END_REACHED 6
175: #define _HE_START_REACHED 7
176: #define _HE_CURR_INVALID 8
177: #define _HE_NOT_FOUND 9
178: #define _HE_HIST_READ 10
179: #define _HE_HIST_WRITE 11
180: #define _HE_PARAM_MISSING 12
181: #define _HE_SIZE_NEGATIVE 13
182: #define _HE_NOT_ALLOWED 14
183: #define _HE_BAD_PARAM 15
1.1 cgd 184:
185: /* history_def_first():
186: * Default function to return the first event in the history.
187: */
1.7 christos 188: private int
1.16 lukem 189: history_def_first(ptr_t p, HistEvent *ev)
1.1 cgd 190: {
1.16 lukem 191: history_t *h = (history_t *) p;
1.7 christos 192:
1.16 lukem 193: h->cursor = h->list.next;
194: if (h->cursor != &h->list)
195: *ev = h->cursor->ev;
196: else {
197: he_seterrev(ev, _HE_FIRST_NOTFOUND);
198: return (-1);
199: }
1.7 christos 200:
1.16 lukem 201: return (0);
1.1 cgd 202: }
203:
1.8 christos 204:
1.1 cgd 205: /* history_def_last():
206: * Default function to return the last event in the history.
207: */
1.7 christos 208: private int
1.16 lukem 209: history_def_last(ptr_t p, HistEvent *ev)
210: {
211: history_t *h = (history_t *) p;
212:
213: h->cursor = h->list.prev;
214: if (h->cursor != &h->list)
215: *ev = h->cursor->ev;
216: else {
217: he_seterrev(ev, _HE_LAST_NOTFOUND);
218: return (-1);
219: }
1.7 christos 220:
1.16 lukem 221: return (0);
1.1 cgd 222: }
223:
1.8 christos 224:
1.1 cgd 225: /* history_def_next():
226: * Default function to return the next event in the history.
227: */
1.7 christos 228: private int
1.16 lukem 229: history_def_next(ptr_t p, HistEvent *ev)
230: {
231: history_t *h = (history_t *) p;
232:
233: if (h->cursor != &h->list)
234: h->cursor = h->cursor->next;
235: else {
236: he_seterrev(ev, _HE_EMPTY_LIST);
237: return (-1);
238: }
1.1 cgd 239:
1.16 lukem 240: if (h->cursor != &h->list)
241: *ev = h->cursor->ev;
242: else {
243: he_seterrev(ev, _HE_END_REACHED);
244: return (-1);
245: }
1.7 christos 246:
1.16 lukem 247: return (0);
1.1 cgd 248: }
249:
250:
251: /* history_def_prev():
252: * Default function to return the previous event in the history.
253: */
1.7 christos 254: private int
1.16 lukem 255: history_def_prev(ptr_t p, HistEvent *ev)
256: {
257: history_t *h = (history_t *) p;
258:
259: if (h->cursor != &h->list)
260: h->cursor = h->cursor->prev;
261: else {
262: he_seterrev(ev,
263: (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST);
264: return (-1);
265: }
1.1 cgd 266:
1.16 lukem 267: if (h->cursor != &h->list)
268: *ev = h->cursor->ev;
269: else {
270: he_seterrev(ev, _HE_START_REACHED);
271: return (-1);
272: }
1.7 christos 273:
1.16 lukem 274: return (0);
1.1 cgd 275: }
276:
277:
278: /* history_def_curr():
279: * Default function to return the current event in the history.
280: */
1.7 christos 281: private int
1.16 lukem 282: history_def_curr(ptr_t p, HistEvent *ev)
1.1 cgd 283: {
1.16 lukem 284: history_t *h = (history_t *) p;
1.1 cgd 285:
1.16 lukem 286: if (h->cursor != &h->list)
287: *ev = h->cursor->ev;
288: else {
289: he_seterrev(ev,
290: (h->cur > 0) ? _HE_CURR_INVALID : _HE_EMPTY_LIST);
291: return (-1);
292: }
1.7 christos 293:
1.16 lukem 294: return (0);
1.1 cgd 295: }
296:
1.8 christos 297:
298: /* history_def_set():
299: * Default function to set the current event in the history to the
300: * given one.
301: */
302: private int
1.16 lukem 303: history_def_set(ptr_t p, HistEvent *ev, const int n)
304: {
305: history_t *h = (history_t *) p;
1.8 christos 306:
1.16 lukem 307: if (h->cur == 0) {
308: he_seterrev(ev, _HE_EMPTY_LIST);
309: return (-1);
310: }
311: if (h->cursor == &h->list || h->cursor->ev.num != n) {
312: for (h->cursor = h->list.next; h->cursor != &h->list;
313: h->cursor = h->cursor->next)
314: if (h->cursor->ev.num == n)
315: break;
316: }
317: if (h->cursor == &h->list) {
318: he_seterrev(ev, _HE_NOT_FOUND);
319: return (-1);
320: }
321: return (0);
1.8 christos 322: }
323:
324:
1.1 cgd 325: /* history_def_add():
326: * Append string to element
327: */
1.7 christos 328: private int
1.16 lukem 329: history_def_add(ptr_t p, HistEvent *ev, const char *str)
330: {
331: history_t *h = (history_t *) p;
332: size_t len;
333: char *s;
334:
335: if (h->cursor == &h->list)
336: return (history_def_enter(p, ev, str));
337: len = strlen(h->cursor->ev.str) + strlen(str) + 1;
338: s = (char *) h_malloc(len);
339: if (!s) {
340: he_seterrev(ev, _HE_MALLOC_FAILED);
341: return (-1);
342: }
343: (void) strlcpy(s, h->cursor->ev.str, len);
344: (void) strlcat(s, str, len);
345: /* LINTED const cast */
346: h_free((ptr_t) h->cursor->ev.str);
347: h->cursor->ev.str = s;
348: *ev = h->cursor->ev;
349: return (0);
1.1 cgd 350: }
351:
352:
353: /* history_def_delete():
354: * Delete element hp of the h list
355: */
1.11 christos 356: /* ARGSUSED */
1.1 cgd 357: private void
1.16 lukem 358: history_def_delete(history_t *h, HistEvent *ev, hentry_t *hp)
359: {
360:
361: if (hp == &h->list)
362: abort();
363: hp->prev->next = hp->next;
364: hp->next->prev = hp->prev;
365: /* LINTED const cast */
366: h_free((ptr_t) hp->ev.str);
367: h_free(hp);
368: h->cur--;
1.1 cgd 369: }
370:
371:
372: /* history_def_insert():
373: * Insert element with string str in the h list
374: */
1.7 christos 375: private int
1.16 lukem 376: history_def_insert(history_t *h, HistEvent *ev, const char *str)
377: {
378:
379: h->cursor = (hentry_t *) h_malloc(sizeof(hentry_t));
380: if (h->cursor)
381: h->cursor->ev.str = strdup(str);
382: if (!h->cursor || !h->cursor->ev.str) {
383: he_seterrev(ev, _HE_MALLOC_FAILED);
384: return (-1);
385: }
386: h->cursor->ev.num = ++h->eventid;
387: h->cursor->next = h->list.next;
388: h->cursor->prev = &h->list;
389: h->list.next->prev = h->cursor;
390: h->list.next = h->cursor;
391: h->cur++;
1.1 cgd 392:
1.16 lukem 393: *ev = h->cursor->ev;
394: return (0);
1.1 cgd 395: }
396:
397:
398: /* history_def_enter():
399: * Default function to enter an item in the history
400: */
1.7 christos 401: private int
1.16 lukem 402: history_def_enter(ptr_t p, HistEvent *ev, const char *str)
403: {
404: history_t *h = (history_t *) p;
405:
406: if (history_def_insert(h, ev, str) == -1)
407: return (-1); /* error, keep error message */
408:
409: /*
410: * Always keep at least one entry.
411: * This way we don't have to check for the empty list.
412: */
413: while (h->cur - 1 > h->max)
414: history_def_delete(h, ev, h->list.prev);
1.7 christos 415:
1.16 lukem 416: return (0);
1.1 cgd 417: }
418:
419:
420: /* history_def_init():
421: * Default history initialization function
422: */
1.11 christos 423: /* ARGSUSED */
1.1 cgd 424: private void
1.16 lukem 425: history_def_init(ptr_t *p, HistEvent *ev, int n)
426: {
427: history_t *h = (history_t *) h_malloc(sizeof(history_t));
428:
429: if (n <= 0)
430: n = 0;
431: h->eventid = 0;
432: h->cur = 0;
433: h->max = n;
434: h->list.next = h->list.prev = &h->list;
435: h->list.ev.str = NULL;
436: h->list.ev.num = 0;
437: h->cursor = &h->list;
438: *p = (ptr_t) h;
1.1 cgd 439: }
440:
441:
1.2 christos 442: /* history_def_clear():
1.1 cgd 443: * Default history cleanup function
444: */
445: private void
1.16 lukem 446: history_def_clear(ptr_t p, HistEvent *ev)
447: {
448: history_t *h = (history_t *) p;
449:
450: while (h->list.prev != &h->list)
451: history_def_delete(h, ev, h->list.prev);
452: h->eventid = 0;
453: h->cur = 0;
1.1 cgd 454: }
455:
1.2 christos 456:
457:
458:
1.1 cgd 459: /************************************************************************/
460:
461: /* history_init():
462: * Initialization function.
463: */
464: public History *
1.16 lukem 465: history_init(void)
1.1 cgd 466: {
1.16 lukem 467: History *h = (History *) h_malloc(sizeof(History));
468: HistEvent ev;
1.1 cgd 469:
1.16 lukem 470: history_def_init(&h->h_ref, &ev, 0);
471: h->h_ent = -1;
472: h->h_next = history_def_next;
473: h->h_first = history_def_first;
474: h->h_last = history_def_last;
475: h->h_prev = history_def_prev;
476: h->h_curr = history_def_curr;
477: h->h_set = history_def_set;
478: h->h_clear = history_def_clear;
479: h->h_enter = history_def_enter;
480: h->h_add = history_def_add;
1.1 cgd 481:
1.16 lukem 482: return (h);
1.1 cgd 483: }
484:
485:
486: /* history_end():
487: * clean up history;
488: */
489: public void
1.16 lukem 490: history_end(History *h)
1.1 cgd 491: {
1.16 lukem 492: HistEvent ev;
493:
494: if (h->h_next == history_def_next)
495: history_def_clear(h->h_ref, &ev);
1.1 cgd 496: }
497:
498:
499:
1.12 christos 500: /* history_setsize():
1.1 cgd 501: * Set history number of events
502: */
503: private int
1.16 lukem 504: history_setsize(History *h, HistEvent *ev, int num)
505: {
1.7 christos 506:
1.16 lukem 507: if (h->h_next != history_def_next) {
508: he_seterrev(ev, _HE_NOT_ALLOWED);
509: return (-1);
510: }
511: if (num < 0) {
512: he_seterrev(ev, _HE_BAD_PARAM);
513: return (-1);
514: }
515: history_def_setsize(h->h_ref, num);
516: return (0);
1.1 cgd 517: }
518:
1.16 lukem 519:
1.12 christos 520: /* history_getsize():
1.7 christos 521: * Get number of events currently in history
522: */
523: private int
1.16 lukem 524: history_getsize(History *h, HistEvent *ev)
525: {
526: int retval = 0;
1.7 christos 527:
1.16 lukem 528: if (h->h_next != history_def_next) {
529: he_seterrev(ev, _HE_NOT_ALLOWED);
530: return (-1);
531: }
532: retval = history_def_getsize(h->h_ref);
533: if (retval < -1) {
534: he_seterrev(ev, _HE_SIZE_NEGATIVE);
535: return (-1);
536: }
537: ev->num = retval;
538: return (0);
1.7 christos 539: }
1.1 cgd 540:
1.16 lukem 541:
1.1 cgd 542: /* history_set_fun():
543: * Set history functions
544: */
545: private int
1.16 lukem 546: history_set_fun(History *h, History *nh)
547: {
548: HistEvent ev;
549:
550: if (nh->h_first == NULL || nh->h_next == NULL || nh->h_last == NULL ||
551: nh->h_prev == NULL || nh->h_curr == NULL || nh->h_set == NULL ||
552: nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL ||
553: nh->h_ref == NULL) {
554: if (h->h_next != history_def_next) {
555: history_def_init(&h->h_ref, &ev, 0);
556: h->h_first = history_def_first;
557: h->h_next = history_def_next;
558: h->h_last = history_def_last;
559: h->h_prev = history_def_prev;
560: h->h_curr = history_def_curr;
561: h->h_set = history_def_set;
562: h->h_clear = history_def_clear;
563: h->h_enter = history_def_enter;
564: h->h_add = history_def_add;
565: }
566: return (-1);
567: }
568: if (h->h_next == history_def_next)
569: history_def_clear(h->h_ref, &ev);
570:
571: h->h_ent = -1;
572: h->h_first = nh->h_first;
573: h->h_next = nh->h_next;
574: h->h_last = nh->h_last;
575: h->h_prev = nh->h_prev;
576: h->h_curr = nh->h_curr;
577: h->h_set = nh->h_set;
578: h->h_clear = nh->h_clear;
579: h->h_enter = nh->h_enter;
580: h->h_add = nh->h_add;
1.1 cgd 581:
1.16 lukem 582: return (0);
1.1 cgd 583: }
584:
585:
1.2 christos 586: /* history_load():
587: * History load function
588: */
589: private int
1.16 lukem 590: history_load(History *h, const char *fname)
591: {
592: FILE *fp;
593: char *line;
594: size_t sz, max_size;
595: char *ptr;
596: int i = -1;
597: HistEvent ev;
598:
599: if ((fp = fopen(fname, "r")) == NULL)
600: return (i);
601:
602: if ((line = fgetln(fp, &sz)) == NULL)
603: goto done;
604:
605: if (strncmp(line, hist_cookie, sz) != 0)
606: goto done;
607:
608: ptr = h_malloc(max_size = 1024);
609: for (i = 0; (line = fgetln(fp, &sz)) != NULL; i++) {
610: char c = line[sz];
611:
612: if (sz != 0 && line[sz - 1] == '\n')
613: line[--sz] = '\0';
614: else
615: line[sz] = '\0';
616:
617: if (max_size < sz) {
618: max_size = (sz + 1023) & ~1023;
619: ptr = h_realloc(ptr, max_size);
620: }
621: (void) strunvis(ptr, line);
622: line[sz] = c;
623: HENTER(h, &ev, ptr);
624: }
625: h_free(ptr);
1.2 christos 626:
627: done:
1.16 lukem 628: (void) fclose(fp);
629: return (i);
1.2 christos 630: }
631:
632:
633: /* history_save():
634: * History save function
635: */
636: private int
1.16 lukem 637: history_save(History *h, const char *fname)
638: {
639: FILE *fp;
640: HistEvent ev;
641: int i = 0, retval;
642: size_t len, max_size;
643: char *ptr;
644:
645: if ((fp = fopen(fname, "w")) == NULL)
646: return (-1);
647:
1.17 ! christos 648: (void) fchmod(fileno(fp), S_IRUSR|S_IWUSR);
1.16 lukem 649: (void) fputs(hist_cookie, fp);
650: ptr = h_malloc(max_size = 1024);
651: for (retval = HLAST(h, &ev);
652: retval != -1;
653: retval = HPREV(h, &ev), i++) {
654: len = strlen(ev.str) * 4;
655: if (len >= max_size) {
656: max_size = (len + 1023) & 1023;
657: ptr = h_realloc(ptr, max_size);
658: }
659: (void) strvis(ptr, ev.str, VIS_WHITE);
660: (void) fprintf(fp, "%s\n", ev.str);
661: }
662: h_free(ptr);
663: (void) fclose(fp);
664: return (i);
1.2 christos 665: }
666:
667:
1.1 cgd 668: /* history_prev_event():
669: * Find the previous event, with number given
670: */
1.7 christos 671: private int
1.16 lukem 672: history_prev_event(History *h, HistEvent *ev, int num)
673: {
674: int retval;
1.7 christos 675:
1.16 lukem 676: for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
677: if (ev->num == num)
678: return (0);
679:
680: he_seterrev(ev, _HE_NOT_FOUND);
681: return (-1);
1.1 cgd 682: }
683:
684:
685: /* history_next_event():
686: * Find the next event, with number given
687: */
1.7 christos 688: private int
1.16 lukem 689: history_next_event(History *h, HistEvent *ev, int num)
690: {
691: int retval;
692:
693: for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
694: if (ev->num == num)
695: return (0);
1.7 christos 696:
1.16 lukem 697: he_seterrev(ev, _HE_NOT_FOUND);
698: return (-1);
1.1 cgd 699: }
700:
701:
702: /* history_prev_string():
703: * Find the previous event beginning with string
704: */
1.7 christos 705: private int
1.16 lukem 706: history_prev_string(History *h, HistEvent *ev, const char *str)
707: {
708: size_t len = strlen(str);
709: int retval;
1.7 christos 710:
1.16 lukem 711: for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
712: if (strncmp(str, ev->str, len) == 0)
713: return (0);
714:
715: he_seterrev(ev, _HE_NOT_FOUND);
716: return (-1);
1.1 cgd 717: }
718:
719:
720: /* history_next_string():
721: * Find the next event beginning with string
722: */
1.7 christos 723: private int
1.16 lukem 724: history_next_string(History *h, HistEvent *ev, const char *str)
725: {
726: size_t len = strlen(str);
727: int retval;
728:
729: for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
730: if (strncmp(str, ev->str, len) == 0)
731: return (0);
1.7 christos 732:
1.16 lukem 733: he_seterrev(ev, _HE_NOT_FOUND);
734: return (-1);
1.1 cgd 735: }
736:
737:
738: /* history():
739: * User interface to history functions.
740: */
1.7 christos 741: int
742: history(History *h, HistEvent *ev, int fun, ...)
1.1 cgd 743: {
1.16 lukem 744: va_list va;
745: const char *str;
746: int retval;
747:
748: va_start(va, fun);
749:
750: he_seterrev(ev, _HE_OK);
751:
752: switch (fun) {
753: case H_GETSIZE:
754: retval = history_getsize(h, ev);
755: break;
756:
757: case H_SETSIZE:
758: retval = history_setsize(h, ev, va_arg(va, int));
759: break;
760:
761: case H_ADD:
762: str = va_arg(va, const char *);
763: retval = HADD(h, ev, str);
764: break;
765:
766: case H_ENTER:
767: str = va_arg(va, const char *);
768: if ((retval = HENTER(h, ev, str)) != -1)
769: h->h_ent = ev->num;
770: break;
771:
772: case H_APPEND:
773: str = va_arg(va, const char *);
774: if ((retval = HSET(h, ev, h->h_ent)) != -1)
775: retval = HADD(h, ev, str);
776: break;
777:
778: case H_FIRST:
779: retval = HFIRST(h, ev);
780: break;
1.1 cgd 781:
1.16 lukem 782: case H_NEXT:
783: retval = HNEXT(h, ev);
784: break;
785:
786: case H_LAST:
787: retval = HLAST(h, ev);
788: break;
789:
790: case H_PREV:
791: retval = HPREV(h, ev);
792: break;
793:
794: case H_CURR:
795: retval = HCURR(h, ev);
796: break;
797:
798: case H_SET:
799: retval = HSET(h, ev, va_arg(va, const int));
800: break;
801:
802: case H_CLEAR:
803: HCLEAR(h, ev);
804: retval = 0;
805: break;
806:
807: case H_LOAD:
808: retval = history_load(h, va_arg(va, const char *));
809: if (retval == -1)
810: he_seterrev(ev, _HE_HIST_READ);
811: break;
812:
813: case H_SAVE:
814: retval = history_save(h, va_arg(va, const char *));
815: if (retval == -1)
816: he_seterrev(ev, _HE_HIST_WRITE);
817: break;
818:
819: case H_PREV_EVENT:
820: retval = history_prev_event(h, ev, va_arg(va, int));
821: break;
822:
823: case H_NEXT_EVENT:
824: retval = history_next_event(h, ev, va_arg(va, int));
825: break;
1.1 cgd 826:
1.16 lukem 827: case H_PREV_STR:
828: retval = history_prev_string(h, ev, va_arg(va, const char *));
829: break;
1.7 christos 830:
1.16 lukem 831: case H_NEXT_STR:
832: retval = history_next_string(h, ev, va_arg(va, const char *));
833: break;
1.1 cgd 834:
1.16 lukem 835: case H_FUNC:
1.1 cgd 836: {
1.16 lukem 837: History hf;
838:
839: hf.h_ref = va_arg(va, ptr_t);
840: h->h_ent = -1;
841: hf.h_first = va_arg(va, history_gfun_t);
842: hf.h_next = va_arg(va, history_gfun_t);
843: hf.h_last = va_arg(va, history_gfun_t);
844: hf.h_prev = va_arg(va, history_gfun_t);
845: hf.h_curr = va_arg(va, history_gfun_t);
846: hf.h_set = va_arg(va, history_sfun_t);
847: hf.h_clear = va_arg(va, history_vfun_t);
848: hf.h_enter = va_arg(va, history_efun_t);
849: hf.h_add = va_arg(va, history_efun_t);
1.8 christos 850:
1.16 lukem 851: if ((retval = history_set_fun(h, &hf)) == -1)
852: he_seterrev(ev, _HE_PARAM_MISSING);
853: break;
854: }
855:
856: case H_END:
857: history_end(h);
858: retval = 0;
859: break;
860:
861: default:
862: retval = -1;
863: he_seterrev(ev, _HE_UNKNOWN);
864: break;
865: }
866: va_end(va);
867: return (retval);
1.1 cgd 868: }
CVSweb <webmaster@jp.NetBSD.org>