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