Annotation of src/lib/libedit/history.c, Revision 1.44
1.44 ! christos 1: /* $NetBSD: history.c,v 1.43 2011/07/29 15:16:33 christos 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.
1.24 agc 18: * 3. Neither the name of the University nor the names of its contributors
1.1 cgd 19: * may be used to endorse or promote products derived from this software
20: * without specific prior written permission.
21: *
22: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32: * SUCH DAMAGE.
33: */
34:
1.19 christos 35: #include "config.h"
1.1 cgd 36: #if !defined(lint) && !defined(SCCSID)
1.6 christos 37: #if 0
1.1 cgd 38: static char sccsid[] = "@(#)history.c 8.1 (Berkeley) 6/4/93";
1.6 christos 39: #else
1.44 ! christos 40: __RCSID("$NetBSD: history.c,v 1.43 2011/07/29 15:16:33 christos Exp $");
1.6 christos 41: #endif
1.1 cgd 42: #endif /* not lint && not SCCSID */
43:
44: /*
1.35 christos 45: * hist.c: TYPE(History) access functions
1.1 cgd 46: */
47: #include <string.h>
48: #include <stdlib.h>
49: #include <stdarg.h>
1.12 christos 50: #include <vis.h>
1.17 christos 51: #include <sys/stat.h>
1.1 cgd 52:
1.12 christos 53: static const char hist_cookie[] = "_HiStOrY_V2_\n";
1.2 christos 54:
1.1 cgd 55: #include "histedit.h"
1.35 christos 56: #include "chartype.h"
1.1 cgd 57:
1.42 christos 58: typedef int (*history_gfun_t)(void *, TYPE(HistEvent) *);
59: typedef int (*history_efun_t)(void *, TYPE(HistEvent) *, const Char *);
60: typedef void (*history_vfun_t)(void *, TYPE(HistEvent) *);
61: typedef int (*history_sfun_t)(void *, TYPE(HistEvent) *, const int);
1.1 cgd 62:
1.37 christos 63: struct TYPE(history) {
1.42 christos 64: void *h_ref; /* Argument for history fcns */
1.16 lukem 65: int h_ent; /* Last entry point for history */
66: history_gfun_t h_first; /* Get the first element */
67: history_gfun_t h_next; /* Get the next element */
68: history_gfun_t h_last; /* Get the last element */
69: history_gfun_t h_prev; /* Get the previous element */
70: history_gfun_t h_curr; /* Get the current element */
71: history_sfun_t h_set; /* Set the current element */
1.30 christos 72: history_sfun_t h_del; /* Set the given element */
1.16 lukem 73: history_vfun_t h_clear; /* Clear the history list */
74: history_efun_t h_enter; /* Add an element */
75: history_efun_t h_add; /* Append to an element */
1.1 cgd 76: };
1.22 christos 77:
1.16 lukem 78: #define HNEXT(h, ev) (*(h)->h_next)((h)->h_ref, ev)
79: #define HFIRST(h, ev) (*(h)->h_first)((h)->h_ref, ev)
80: #define HPREV(h, ev) (*(h)->h_prev)((h)->h_ref, ev)
81: #define HLAST(h, ev) (*(h)->h_last)((h)->h_ref, ev)
82: #define HCURR(h, ev) (*(h)->h_curr)((h)->h_ref, ev)
83: #define HSET(h, ev, n) (*(h)->h_set)((h)->h_ref, ev, n)
84: #define HCLEAR(h, ev) (*(h)->h_clear)((h)->h_ref, ev)
1.7 christos 85: #define HENTER(h, ev, str) (*(h)->h_enter)((h)->h_ref, ev, str)
86: #define HADD(h, ev, str) (*(h)->h_add)((h)->h_ref, ev, str)
1.30 christos 87: #define HDEL(h, ev, n) (*(h)->h_del)((h)->h_ref, ev, n)
1.1 cgd 88:
1.35 christos 89: #define h_strdup(a) Strdup(a)
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:
1.19 christos 94: typedef struct {
95: int num;
1.35 christos 96: Char *str;
1.19 christos 97: } HistEventPrivate;
98:
99:
1.1 cgd 100:
1.35 christos 101: private int history_setsize(TYPE(History) *, TYPE(HistEvent) *, int);
102: private int history_getsize(TYPE(History) *, TYPE(HistEvent) *);
103: private int history_setunique(TYPE(History) *, TYPE(HistEvent) *, int);
104: private int history_getunique(TYPE(History) *, TYPE(HistEvent) *);
105: private int history_set_fun(TYPE(History) *, TYPE(History) *);
106: private int history_load(TYPE(History) *, const char *);
107: private int history_save(TYPE(History) *, const char *);
108: private int history_prev_event(TYPE(History) *, TYPE(HistEvent) *, int);
109: private int history_next_event(TYPE(History) *, TYPE(HistEvent) *, int);
110: private int history_next_string(TYPE(History) *, TYPE(HistEvent) *, const Char *);
111: private int history_prev_string(TYPE(History) *, TYPE(HistEvent) *, const Char *);
1.1 cgd 112:
113:
114: /***********************************************************************/
115:
116: /*
117: * Builtin- history implementation
118: */
119: typedef struct hentry_t {
1.35 christos 120: TYPE(HistEvent) ev; /* What we return */
1.34 christos 121: void *data; /* data */
1.16 lukem 122: struct hentry_t *next; /* Next entry */
123: struct hentry_t *prev; /* Previous entry */
1.22 christos 124: } hentry_t;
1.1 cgd 125:
126: typedef struct history_t {
1.22 christos 127: hentry_t list; /* Fake list header element */
128: hentry_t *cursor; /* Current element in the list */
129: int max; /* Maximum number of events */
130: int cur; /* Current number of events */
1.16 lukem 131: int eventid; /* For generation of unique event id */
1.35 christos 132: int flags; /* TYPE(History) flags */
1.22 christos 133: #define H_UNIQUE 1 /* Store only unique elements */
134: } history_t;
1.16 lukem 135:
1.42 christos 136: private int history_def_next(void *, TYPE(HistEvent) *);
137: private int history_def_first(void *, TYPE(HistEvent) *);
138: private int history_def_prev(void *, TYPE(HistEvent) *);
139: private int history_def_last(void *, TYPE(HistEvent) *);
140: private int history_def_curr(void *, TYPE(HistEvent) *);
141: private int history_def_set(void *, TYPE(HistEvent) *, const int);
142: private void history_def_clear(void *, TYPE(HistEvent) *);
143: private int history_def_enter(void *, TYPE(HistEvent) *, const Char *);
144: private int history_def_add(void *, TYPE(HistEvent) *, const Char *);
145: private int history_def_del(void *, TYPE(HistEvent) *, const int);
1.35 christos 146:
1.42 christos 147: private int history_def_init(void **, TYPE(HistEvent) *, int);
1.35 christos 148: private int history_def_insert(history_t *, TYPE(HistEvent) *, const Char *);
149: private void history_def_delete(history_t *, TYPE(HistEvent) *, hentry_t *);
1.1 cgd 150:
1.35 christos 151: private int history_deldata_nth(history_t *, TYPE(HistEvent) *, int, void **);
1.42 christos 152: private int history_set_nth(void *, TYPE(HistEvent) *, int);
1.34 christos 153:
1.22 christos 154: #define history_def_setsize(p, num)(void) (((history_t *)p)->max = (num))
155: #define history_def_getsize(p) (((history_t *)p)->cur)
156: #define history_def_getunique(p) (((((history_t *)p)->flags) & H_UNIQUE) != 0)
157: #define history_def_setunique(p, uni) \
158: if (uni) \
159: (((history_t *)p)->flags) |= H_UNIQUE; \
160: else \
161: (((history_t *)p)->flags) &= ~H_UNIQUE
1.1 cgd 162:
1.16 lukem 163: #define he_strerror(code) he_errlist[code]
164: #define he_seterrev(evp, code) {\
1.7 christos 165: evp->num = code;\
166: evp->str = he_strerror(code);\
167: }
1.14 simonb 168:
1.7 christos 169: /* error messages */
1.35 christos 170: static const Char *const he_errlist[] = {
171: STR("OK"),
172: STR("unknown error"),
173: STR("malloc() failed"),
174: STR("first event not found"),
175: STR("last event not found"),
176: STR("empty list"),
177: STR("no next event"),
178: STR("no previous event"),
179: STR("current event is invalid"),
180: STR("event not found"),
181: STR("can't read history from file"),
182: STR("can't write history"),
183: STR("required parameter(s) not supplied"),
184: STR("history size negative"),
185: STR("function not allowed with other history-functions-set the default"),
186: STR("bad parameters")
1.7 christos 187: };
188: /* error codes */
1.16 lukem 189: #define _HE_OK 0
190: #define _HE_UNKNOWN 1
191: #define _HE_MALLOC_FAILED 2
192: #define _HE_FIRST_NOTFOUND 3
193: #define _HE_LAST_NOTFOUND 4
194: #define _HE_EMPTY_LIST 5
195: #define _HE_END_REACHED 6
196: #define _HE_START_REACHED 7
197: #define _HE_CURR_INVALID 8
198: #define _HE_NOT_FOUND 9
199: #define _HE_HIST_READ 10
200: #define _HE_HIST_WRITE 11
201: #define _HE_PARAM_MISSING 12
202: #define _HE_SIZE_NEGATIVE 13
203: #define _HE_NOT_ALLOWED 14
204: #define _HE_BAD_PARAM 15
1.1 cgd 205:
206: /* history_def_first():
207: * Default function to return the first event in the history.
208: */
1.7 christos 209: private int
1.42 christos 210: history_def_first(void *p, TYPE(HistEvent) *ev)
1.1 cgd 211: {
1.16 lukem 212: history_t *h = (history_t *) p;
1.7 christos 213:
1.16 lukem 214: h->cursor = h->list.next;
215: if (h->cursor != &h->list)
216: *ev = h->cursor->ev;
217: else {
218: he_seterrev(ev, _HE_FIRST_NOTFOUND);
1.43 christos 219: return -1;
1.16 lukem 220: }
1.7 christos 221:
1.43 christos 222: return 0;
1.1 cgd 223: }
224:
1.8 christos 225:
1.1 cgd 226: /* history_def_last():
227: * Default function to return the last event in the history.
228: */
1.7 christos 229: private int
1.42 christos 230: history_def_last(void *p, TYPE(HistEvent) *ev)
1.16 lukem 231: {
232: history_t *h = (history_t *) p;
233:
234: h->cursor = h->list.prev;
235: if (h->cursor != &h->list)
236: *ev = h->cursor->ev;
237: else {
238: he_seterrev(ev, _HE_LAST_NOTFOUND);
1.43 christos 239: return -1;
1.16 lukem 240: }
1.7 christos 241:
1.43 christos 242: return 0;
1.1 cgd 243: }
244:
1.8 christos 245:
1.1 cgd 246: /* history_def_next():
247: * Default function to return the next event in the history.
248: */
1.7 christos 249: private int
1.42 christos 250: history_def_next(void *p, TYPE(HistEvent) *ev)
1.16 lukem 251: {
252: history_t *h = (history_t *) p;
253:
1.28 christos 254: if (h->cursor == &h->list) {
1.16 lukem 255: he_seterrev(ev, _HE_EMPTY_LIST);
1.43 christos 256: return -1;
1.16 lukem 257: }
1.1 cgd 258:
1.28 christos 259: if (h->cursor->next == &h->list) {
1.16 lukem 260: he_seterrev(ev, _HE_END_REACHED);
1.43 christos 261: return -1;
1.16 lukem 262: }
1.7 christos 263:
1.28 christos 264: h->cursor = h->cursor->next;
265: *ev = h->cursor->ev;
266:
1.43 christos 267: return 0;
1.1 cgd 268: }
269:
270:
271: /* history_def_prev():
272: * Default function to return the previous event in the history.
273: */
1.7 christos 274: private int
1.42 christos 275: history_def_prev(void *p, TYPE(HistEvent) *ev)
1.16 lukem 276: {
277: history_t *h = (history_t *) p;
278:
1.28 christos 279: if (h->cursor == &h->list) {
1.16 lukem 280: he_seterrev(ev,
281: (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST);
1.43 christos 282: return -1;
1.16 lukem 283: }
1.1 cgd 284:
1.28 christos 285: if (h->cursor->prev == &h->list) {
1.16 lukem 286: he_seterrev(ev, _HE_START_REACHED);
1.43 christos 287: return -1;
1.16 lukem 288: }
1.7 christos 289:
1.28 christos 290: h->cursor = h->cursor->prev;
291: *ev = h->cursor->ev;
292:
1.43 christos 293: return 0;
1.1 cgd 294: }
295:
296:
297: /* history_def_curr():
298: * Default function to return the current event in the history.
299: */
1.7 christos 300: private int
1.42 christos 301: history_def_curr(void *p, TYPE(HistEvent) *ev)
1.1 cgd 302: {
1.16 lukem 303: history_t *h = (history_t *) p;
1.1 cgd 304:
1.16 lukem 305: if (h->cursor != &h->list)
306: *ev = h->cursor->ev;
307: else {
308: he_seterrev(ev,
309: (h->cur > 0) ? _HE_CURR_INVALID : _HE_EMPTY_LIST);
1.43 christos 310: return -1;
1.16 lukem 311: }
1.7 christos 312:
1.43 christos 313: return 0;
1.1 cgd 314: }
315:
1.8 christos 316:
317: /* history_def_set():
318: * Default function to set the current event in the history to the
319: * given one.
320: */
321: private int
1.42 christos 322: history_def_set(void *p, TYPE(HistEvent) *ev, const int n)
1.16 lukem 323: {
324: history_t *h = (history_t *) p;
1.8 christos 325:
1.16 lukem 326: if (h->cur == 0) {
327: he_seterrev(ev, _HE_EMPTY_LIST);
1.43 christos 328: return -1;
1.16 lukem 329: }
330: if (h->cursor == &h->list || h->cursor->ev.num != n) {
331: for (h->cursor = h->list.next; h->cursor != &h->list;
332: h->cursor = h->cursor->next)
333: if (h->cursor->ev.num == n)
334: break;
335: }
336: if (h->cursor == &h->list) {
337: he_seterrev(ev, _HE_NOT_FOUND);
1.43 christos 338: return -1;
1.16 lukem 339: }
1.43 christos 340: return 0;
1.8 christos 341: }
342:
343:
1.34 christos 344: /* history_set_nth():
345: * Default function to set the current event in the history to the
346: * n-th one.
347: */
348: private int
1.42 christos 349: history_set_nth(void *p, TYPE(HistEvent) *ev, int n)
1.34 christos 350: {
351: history_t *h = (history_t *) p;
352:
353: if (h->cur == 0) {
354: he_seterrev(ev, _HE_EMPTY_LIST);
1.43 christos 355: return -1;
1.34 christos 356: }
357: for (h->cursor = h->list.prev; h->cursor != &h->list;
358: h->cursor = h->cursor->prev)
359: if (n-- <= 0)
360: break;
361: if (h->cursor == &h->list) {
362: he_seterrev(ev, _HE_NOT_FOUND);
1.43 christos 363: return -1;
1.34 christos 364: }
1.43 christos 365: return 0;
1.34 christos 366: }
367:
368:
1.1 cgd 369: /* history_def_add():
370: * Append string to element
371: */
1.7 christos 372: private int
1.42 christos 373: history_def_add(void *p, TYPE(HistEvent) *ev, const Char *str)
1.16 lukem 374: {
375: history_t *h = (history_t *) p;
376: size_t len;
1.35 christos 377: Char *s;
1.19 christos 378: HistEventPrivate *evp = (void *)&h->cursor->ev;
1.16 lukem 379:
380: if (h->cursor == &h->list)
1.43 christos 381: return history_def_enter(p, ev, str);
1.35 christos 382: len = Strlen(evp->str) + Strlen(str) + 1;
383: s = h_malloc(len * sizeof(*s));
1.21 christos 384: if (s == NULL) {
1.16 lukem 385: he_seterrev(ev, _HE_MALLOC_FAILED);
1.43 christos 386: return -1;
1.16 lukem 387: }
1.35 christos 388: (void) Strncpy(s, h->cursor->ev.str, len);
389: s[len - 1] = '\0';
390: (void) Strncat(s, str, len - Strlen(s) - 1);
1.42 christos 391: h_free(evp->str);
1.19 christos 392: evp->str = s;
1.16 lukem 393: *ev = h->cursor->ev;
1.43 christos 394: return 0;
1.1 cgd 395: }
396:
397:
1.34 christos 398: private int
1.35 christos 399: history_deldata_nth(history_t *h, TYPE(HistEvent) *ev,
1.34 christos 400: int num, void **data)
401: {
402: if (history_set_nth(h, ev, num) != 0)
1.43 christos 403: return -1;
1.34 christos 404: /* magic value to skip delete (just set to n-th history) */
405: if (data == (void **)-1)
1.43 christos 406: return 0;
1.35 christos 407: ev->str = Strdup(h->cursor->ev.str);
1.34 christos 408: ev->num = h->cursor->ev.num;
409: if (data)
410: *data = h->cursor->data;
411: history_def_delete(h, ev, h->cursor);
1.43 christos 412: return 0;
1.34 christos 413: }
414:
415:
1.30 christos 416: /* history_def_del():
417: * Delete element hp of the h list
418: */
419: /* ARGSUSED */
420: private int
1.42 christos 421: history_def_del(void *p, TYPE(HistEvent) *ev __attribute__((__unused__)),
1.30 christos 422: const int num)
423: {
424: history_t *h = (history_t *) p;
425: if (history_def_set(h, ev, num) != 0)
1.43 christos 426: return -1;
1.35 christos 427: ev->str = Strdup(h->cursor->ev.str);
1.30 christos 428: ev->num = h->cursor->ev.num;
429: history_def_delete(h, ev, h->cursor);
1.43 christos 430: return 0;
1.30 christos 431: }
432:
433:
1.1 cgd 434: /* history_def_delete():
435: * Delete element hp of the h list
436: */
1.11 christos 437: /* ARGSUSED */
1.1 cgd 438: private void
1.23 christos 439: history_def_delete(history_t *h,
1.35 christos 440: TYPE(HistEvent) *ev __attribute__((__unused__)), hentry_t *hp)
1.16 lukem 441: {
1.19 christos 442: HistEventPrivate *evp = (void *)&hp->ev;
1.16 lukem 443: if (hp == &h->list)
444: abort();
1.34 christos 445: if (h->cursor == hp) {
1.30 christos 446: h->cursor = hp->prev;
1.34 christos 447: if (h->cursor == &h->list)
448: h->cursor = hp->next;
449: }
1.16 lukem 450: hp->prev->next = hp->next;
451: hp->next->prev = hp->prev;
1.42 christos 452: h_free(evp->str);
1.16 lukem 453: h_free(hp);
454: h->cur--;
1.1 cgd 455: }
456:
457:
458: /* history_def_insert():
459: * Insert element with string str in the h list
460: */
1.7 christos 461: private int
1.35 christos 462: history_def_insert(history_t *h, TYPE(HistEvent) *ev, const Char *str)
1.16 lukem 463: {
1.39 christos 464: hentry_t *c;
1.16 lukem 465:
1.39 christos 466: c = h_malloc(sizeof(*c));
467: if (c == NULL)
1.21 christos 468: goto oomem;
1.39 christos 469: if ((c->ev.str = h_strdup(str)) == NULL) {
1.42 christos 470: h_free(c);
1.21 christos 471: goto oomem;
1.16 lukem 472: }
1.39 christos 473: c->data = NULL;
474: c->ev.num = ++h->eventid;
475: c->next = h->list.next;
476: c->prev = &h->list;
477: h->list.next->prev = c;
478: h->list.next = c;
1.16 lukem 479: h->cur++;
1.39 christos 480: h->cursor = c;
1.1 cgd 481:
1.39 christos 482: *ev = c->ev;
1.43 christos 483: return 0;
1.21 christos 484: oomem:
485: he_seterrev(ev, _HE_MALLOC_FAILED);
1.43 christos 486: return -1;
1.1 cgd 487: }
488:
489:
490: /* history_def_enter():
491: * Default function to enter an item in the history
492: */
1.7 christos 493: private int
1.42 christos 494: history_def_enter(void *p, TYPE(HistEvent) *ev, const Char *str)
1.16 lukem 495: {
496: history_t *h = (history_t *) p;
497:
1.22 christos 498: if ((h->flags & H_UNIQUE) != 0 && h->list.next != &h->list &&
1.35 christos 499: Strcmp(h->list.next->ev.str, str) == 0)
1.43 christos 500: return 0;
1.22 christos 501:
1.16 lukem 502: if (history_def_insert(h, ev, str) == -1)
1.43 christos 503: return -1; /* error, keep error message */
1.16 lukem 504:
505: /*
506: * Always keep at least one entry.
507: * This way we don't have to check for the empty list.
508: */
1.18 jdolecek 509: while (h->cur > h->max && h->cur > 0)
1.16 lukem 510: history_def_delete(h, ev, h->list.prev);
1.7 christos 511:
1.43 christos 512: return 1;
1.1 cgd 513: }
514:
515:
516: /* history_def_init():
517: * Default history initialization function
518: */
1.11 christos 519: /* ARGSUSED */
1.21 christos 520: private int
1.42 christos 521: history_def_init(void **p, TYPE(HistEvent) *ev __attribute__((__unused__)), int n)
1.16 lukem 522: {
1.42 christos 523: history_t *h = (history_t *) h_malloc(sizeof(*h));
1.21 christos 524: if (h == NULL)
525: return -1;
1.16 lukem 526:
527: if (n <= 0)
528: n = 0;
529: h->eventid = 0;
530: h->cur = 0;
531: h->max = n;
532: h->list.next = h->list.prev = &h->list;
533: h->list.ev.str = NULL;
534: h->list.ev.num = 0;
535: h->cursor = &h->list;
1.22 christos 536: h->flags = 0;
1.42 christos 537: *p = h;
1.21 christos 538: return 0;
1.1 cgd 539: }
540:
541:
1.2 christos 542: /* history_def_clear():
1.1 cgd 543: * Default history cleanup function
544: */
545: private void
1.42 christos 546: history_def_clear(void *p, TYPE(HistEvent) *ev)
1.16 lukem 547: {
548: history_t *h = (history_t *) p;
549:
550: while (h->list.prev != &h->list)
551: history_def_delete(h, ev, h->list.prev);
1.39 christos 552: h->cursor = &h->list;
1.16 lukem 553: h->eventid = 0;
554: h->cur = 0;
1.1 cgd 555: }
556:
1.2 christos 557:
558:
559:
1.1 cgd 560: /************************************************************************/
561:
562: /* history_init():
563: * Initialization function.
564: */
1.36 christos 565: public TYPE(History) *
1.35 christos 566: FUN(history,init)(void)
1.1 cgd 567: {
1.35 christos 568: TYPE(HistEvent) ev;
1.42 christos 569: TYPE(History) *h = (TYPE(History) *) h_malloc(sizeof(*h));
1.21 christos 570: if (h == NULL)
571: return NULL;
1.1 cgd 572:
1.21 christos 573: if (history_def_init(&h->h_ref, &ev, 0) == -1) {
1.42 christos 574: h_free(h);
1.21 christos 575: return NULL;
576: }
1.16 lukem 577: h->h_ent = -1;
578: h->h_next = history_def_next;
579: h->h_first = history_def_first;
580: h->h_last = history_def_last;
581: h->h_prev = history_def_prev;
582: h->h_curr = history_def_curr;
583: h->h_set = history_def_set;
584: h->h_clear = history_def_clear;
585: h->h_enter = history_def_enter;
586: h->h_add = history_def_add;
1.31 christos 587: h->h_del = history_def_del;
1.1 cgd 588:
1.43 christos 589: return h;
1.1 cgd 590: }
591:
592:
593: /* history_end():
594: * clean up history;
595: */
596: public void
1.35 christos 597: FUN(history,end)(TYPE(History) *h)
1.1 cgd 598: {
1.35 christos 599: TYPE(HistEvent) ev;
1.16 lukem 600:
601: if (h->h_next == history_def_next)
602: history_def_clear(h->h_ref, &ev);
1.32 christos 603: h_free(h->h_ref);
1.29 christos 604: h_free(h);
1.1 cgd 605: }
606:
607:
608:
1.12 christos 609: /* history_setsize():
1.1 cgd 610: * Set history number of events
611: */
612: private int
1.35 christos 613: history_setsize(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
1.16 lukem 614: {
1.7 christos 615:
1.16 lukem 616: if (h->h_next != history_def_next) {
617: he_seterrev(ev, _HE_NOT_ALLOWED);
1.43 christos 618: return -1;
1.16 lukem 619: }
620: if (num < 0) {
621: he_seterrev(ev, _HE_BAD_PARAM);
1.43 christos 622: return -1;
1.16 lukem 623: }
624: history_def_setsize(h->h_ref, num);
1.43 christos 625: return 0;
1.1 cgd 626: }
627:
1.16 lukem 628:
1.12 christos 629: /* history_getsize():
1.7 christos 630: * Get number of events currently in history
631: */
632: private int
1.35 christos 633: history_getsize(TYPE(History) *h, TYPE(HistEvent) *ev)
1.16 lukem 634: {
1.22 christos 635: if (h->h_next != history_def_next) {
636: he_seterrev(ev, _HE_NOT_ALLOWED);
1.43 christos 637: return -1;
1.22 christos 638: }
639: ev->num = history_def_getsize(h->h_ref);
640: if (ev->num < -1) {
641: he_seterrev(ev, _HE_SIZE_NEGATIVE);
1.43 christos 642: return -1;
1.22 christos 643: }
1.43 christos 644: return 0;
1.22 christos 645: }
646:
647:
648: /* history_setunique():
649: * Set if adjacent equal events should not be entered in history.
650: */
651: private int
1.35 christos 652: history_setunique(TYPE(History) *h, TYPE(HistEvent) *ev, int uni)
1.22 christos 653: {
1.7 christos 654:
1.16 lukem 655: if (h->h_next != history_def_next) {
656: he_seterrev(ev, _HE_NOT_ALLOWED);
1.43 christos 657: return -1;
1.16 lukem 658: }
1.22 christos 659: history_def_setunique(h->h_ref, uni);
1.43 christos 660: return 0;
1.22 christos 661: }
662:
663:
664: /* history_getunique():
665: * Get if adjacent equal events should not be entered in history.
666: */
667: private int
1.35 christos 668: history_getunique(TYPE(History) *h, TYPE(HistEvent) *ev)
1.22 christos 669: {
670: if (h->h_next != history_def_next) {
671: he_seterrev(ev, _HE_NOT_ALLOWED);
1.43 christos 672: return -1;
1.16 lukem 673: }
1.22 christos 674: ev->num = history_def_getunique(h->h_ref);
1.43 christos 675: return 0;
1.7 christos 676: }
1.1 cgd 677:
1.16 lukem 678:
1.1 cgd 679: /* history_set_fun():
680: * Set history functions
681: */
682: private int
1.35 christos 683: history_set_fun(TYPE(History) *h, TYPE(History) *nh)
1.16 lukem 684: {
1.35 christos 685: TYPE(HistEvent) ev;
1.16 lukem 686:
687: if (nh->h_first == NULL || nh->h_next == NULL || nh->h_last == NULL ||
688: nh->h_prev == NULL || nh->h_curr == NULL || nh->h_set == NULL ||
689: nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL ||
1.30 christos 690: nh->h_del == NULL || nh->h_ref == NULL) {
1.16 lukem 691: if (h->h_next != history_def_next) {
692: history_def_init(&h->h_ref, &ev, 0);
693: h->h_first = history_def_first;
694: h->h_next = history_def_next;
695: h->h_last = history_def_last;
696: h->h_prev = history_def_prev;
697: h->h_curr = history_def_curr;
698: h->h_set = history_def_set;
699: h->h_clear = history_def_clear;
700: h->h_enter = history_def_enter;
701: h->h_add = history_def_add;
1.30 christos 702: h->h_del = history_def_del;
1.16 lukem 703: }
1.43 christos 704: return -1;
1.16 lukem 705: }
706: if (h->h_next == history_def_next)
707: history_def_clear(h->h_ref, &ev);
708:
709: h->h_ent = -1;
710: h->h_first = nh->h_first;
711: h->h_next = nh->h_next;
712: h->h_last = nh->h_last;
713: h->h_prev = nh->h_prev;
714: h->h_curr = nh->h_curr;
715: h->h_set = nh->h_set;
716: h->h_clear = nh->h_clear;
717: h->h_enter = nh->h_enter;
718: h->h_add = nh->h_add;
1.30 christos 719: h->h_del = nh->h_del;
1.1 cgd 720:
1.43 christos 721: return 0;
1.1 cgd 722: }
723:
724:
1.2 christos 725: /* history_load():
1.35 christos 726: * TYPE(History) load function
1.2 christos 727: */
728: private int
1.35 christos 729: history_load(TYPE(History) *h, const char *fname)
1.16 lukem 730: {
731: FILE *fp;
732: char *line;
733: size_t sz, max_size;
734: char *ptr;
735: int i = -1;
1.35 christos 736: TYPE(HistEvent) ev;
737: #ifdef WIDECHAR
1.36 christos 738: static ct_buffer_t conv;
1.35 christos 739: #endif
1.16 lukem 740:
741: if ((fp = fopen(fname, "r")) == NULL)
1.43 christos 742: return i;
1.16 lukem 743:
744: if ((line = fgetln(fp, &sz)) == NULL)
745: goto done;
746:
747: if (strncmp(line, hist_cookie, sz) != 0)
748: goto done;
749:
1.42 christos 750: ptr = h_malloc((max_size = 1024) * sizeof(*ptr));
1.21 christos 751: if (ptr == NULL)
752: goto done;
1.16 lukem 753: for (i = 0; (line = fgetln(fp, &sz)) != NULL; i++) {
754: char c = line[sz];
755:
756: if (sz != 0 && line[sz - 1] == '\n')
757: line[--sz] = '\0';
758: else
759: line[sz] = '\0';
760:
761: if (max_size < sz) {
1.21 christos 762: char *nptr;
1.27 christos 763: max_size = (sz + 1024) & ~1023;
1.42 christos 764: nptr = h_realloc(ptr, max_size * sizeof(*ptr));
1.21 christos 765: if (nptr == NULL) {
766: i = -1;
767: goto oomem;
768: }
769: ptr = nptr;
1.16 lukem 770: }
771: (void) strunvis(ptr, line);
772: line[sz] = c;
1.35 christos 773: if (HENTER(h, &ev, ct_decode_string(ptr, &conv)) == -1) {
1.33 sketch 774: i = -1;
775: goto oomem;
1.21 christos 776: }
1.16 lukem 777: }
1.21 christos 778: oomem:
1.42 christos 779: h_free(ptr);
1.2 christos 780: done:
1.16 lukem 781: (void) fclose(fp);
1.43 christos 782: return i;
1.2 christos 783: }
784:
785:
786: /* history_save():
1.35 christos 787: * TYPE(History) save function
1.2 christos 788: */
789: private int
1.35 christos 790: history_save(TYPE(History) *h, const char *fname)
1.16 lukem 791: {
792: FILE *fp;
1.35 christos 793: TYPE(HistEvent) ev;
1.21 christos 794: int i = -1, retval;
1.16 lukem 795: size_t len, max_size;
1.40 christos 796: char *ptr;
797: const char *str;
1.35 christos 798: #ifdef WIDECHAR
1.36 christos 799: static ct_buffer_t conv;
1.35 christos 800: #endif
1.16 lukem 801:
802: if ((fp = fopen(fname, "w")) == NULL)
1.43 christos 803: return -1;
1.16 lukem 804:
1.21 christos 805: if (fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1)
806: goto done;
807: if (fputs(hist_cookie, fp) == EOF)
808: goto done;
1.42 christos 809: ptr = h_malloc((max_size = 1024) * sizeof(*ptr));
1.21 christos 810: if (ptr == NULL)
811: goto done;
812: for (i = 0, retval = HLAST(h, &ev);
1.16 lukem 813: retval != -1;
814: retval = HPREV(h, &ev), i++) {
1.39 christos 815: str = ct_encode_string(ev.str, &conv);
816: len = strlen(str) * 4;
1.16 lukem 817: if (len >= max_size) {
1.21 christos 818: char *nptr;
1.27 christos 819: max_size = (len + 1024) & ~1023;
1.42 christos 820: nptr = h_realloc(ptr, max_size * sizeof(*ptr));
1.21 christos 821: if (nptr == NULL) {
822: i = -1;
823: goto oomem;
824: }
825: ptr = nptr;
1.16 lukem 826: }
1.39 christos 827: (void) strvis(ptr, str, VIS_WHITE);
1.20 christos 828: (void) fprintf(fp, "%s\n", ptr);
1.16 lukem 829: }
1.21 christos 830: oomem:
1.42 christos 831: h_free(ptr);
1.21 christos 832: done:
1.16 lukem 833: (void) fclose(fp);
1.43 christos 834: return i;
1.2 christos 835: }
836:
837:
1.1 cgd 838: /* history_prev_event():
839: * Find the previous event, with number given
840: */
1.7 christos 841: private int
1.35 christos 842: history_prev_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
1.16 lukem 843: {
844: int retval;
1.7 christos 845:
1.16 lukem 846: for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
847: if (ev->num == num)
1.43 christos 848: return 0;
1.16 lukem 849:
850: he_seterrev(ev, _HE_NOT_FOUND);
1.43 christos 851: return -1;
1.1 cgd 852: }
853:
854:
1.34 christos 855: private int
1.35 christos 856: history_next_evdata(TYPE(History) *h, TYPE(HistEvent) *ev, int num, void **d)
1.34 christos 857: {
858: int retval;
859:
860: for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
1.38 christos 861: if (ev->num == num) {
1.34 christos 862: if (d)
863: *d = ((history_t *)h->h_ref)->cursor->data;
1.43 christos 864: return 0;
1.34 christos 865: }
866:
867: he_seterrev(ev, _HE_NOT_FOUND);
1.43 christos 868: return -1;
1.34 christos 869: }
870:
871:
1.1 cgd 872: /* history_next_event():
873: * Find the next event, with number given
874: */
1.7 christos 875: private int
1.35 christos 876: history_next_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
1.16 lukem 877: {
878: int retval;
879:
880: for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
881: if (ev->num == num)
1.43 christos 882: return 0;
1.7 christos 883:
1.16 lukem 884: he_seterrev(ev, _HE_NOT_FOUND);
1.43 christos 885: return -1;
1.1 cgd 886: }
887:
888:
889: /* history_prev_string():
890: * Find the previous event beginning with string
891: */
1.7 christos 892: private int
1.35 christos 893: history_prev_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str)
1.16 lukem 894: {
1.35 christos 895: size_t len = Strlen(str);
1.16 lukem 896: int retval;
1.7 christos 897:
1.16 lukem 898: for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
1.35 christos 899: if (Strncmp(str, ev->str, len) == 0)
1.43 christos 900: return 0;
1.16 lukem 901:
902: he_seterrev(ev, _HE_NOT_FOUND);
1.43 christos 903: return -1;
1.1 cgd 904: }
905:
906:
907: /* history_next_string():
908: * Find the next event beginning with string
909: */
1.7 christos 910: private int
1.35 christos 911: history_next_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str)
1.16 lukem 912: {
1.35 christos 913: size_t len = Strlen(str);
1.16 lukem 914: int retval;
915:
916: for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
1.35 christos 917: if (Strncmp(str, ev->str, len) == 0)
1.43 christos 918: return 0;
1.7 christos 919:
1.16 lukem 920: he_seterrev(ev, _HE_NOT_FOUND);
1.43 christos 921: return -1;
1.1 cgd 922: }
923:
924:
925: /* history():
926: * User interface to history functions.
927: */
1.7 christos 928: int
1.35 christos 929: FUNW(history)(TYPE(History) *h, TYPE(HistEvent) *ev, int fun, ...)
1.1 cgd 930: {
1.16 lukem 931: va_list va;
1.35 christos 932: const Char *str;
1.16 lukem 933: int retval;
934:
935: va_start(va, fun);
936:
937: he_seterrev(ev, _HE_OK);
938:
939: switch (fun) {
940: case H_GETSIZE:
941: retval = history_getsize(h, ev);
942: break;
943:
944: case H_SETSIZE:
945: retval = history_setsize(h, ev, va_arg(va, int));
1.22 christos 946: break;
947:
948: case H_GETUNIQUE:
949: retval = history_getunique(h, ev);
950: break;
951:
952: case H_SETUNIQUE:
953: retval = history_setunique(h, ev, va_arg(va, int));
1.16 lukem 954: break;
955:
956: case H_ADD:
1.35 christos 957: str = va_arg(va, const Char *);
1.16 lukem 958: retval = HADD(h, ev, str);
959: break;
960:
1.30 christos 961: case H_DEL:
962: retval = HDEL(h, ev, va_arg(va, const int));
963: break;
964:
1.16 lukem 965: case H_ENTER:
1.35 christos 966: str = va_arg(va, const Char *);
1.16 lukem 967: if ((retval = HENTER(h, ev, str)) != -1)
968: h->h_ent = ev->num;
969: break;
970:
971: case H_APPEND:
1.35 christos 972: str = va_arg(va, const Char *);
1.16 lukem 973: if ((retval = HSET(h, ev, h->h_ent)) != -1)
974: retval = HADD(h, ev, str);
975: break;
976:
977: case H_FIRST:
978: retval = HFIRST(h, ev);
979: break;
1.1 cgd 980:
1.16 lukem 981: case H_NEXT:
982: retval = HNEXT(h, ev);
983: break;
984:
985: case H_LAST:
986: retval = HLAST(h, ev);
987: break;
988:
989: case H_PREV:
990: retval = HPREV(h, ev);
991: break;
992:
993: case H_CURR:
994: retval = HCURR(h, ev);
995: break;
996:
997: case H_SET:
998: retval = HSET(h, ev, va_arg(va, const int));
999: break;
1000:
1001: case H_CLEAR:
1002: HCLEAR(h, ev);
1003: retval = 0;
1004: break;
1005:
1006: case H_LOAD:
1007: retval = history_load(h, va_arg(va, const char *));
1008: if (retval == -1)
1009: he_seterrev(ev, _HE_HIST_READ);
1010: break;
1011:
1012: case H_SAVE:
1013: retval = history_save(h, va_arg(va, const char *));
1014: if (retval == -1)
1015: he_seterrev(ev, _HE_HIST_WRITE);
1016: break;
1017:
1018: case H_PREV_EVENT:
1019: retval = history_prev_event(h, ev, va_arg(va, int));
1020: break;
1021:
1022: case H_NEXT_EVENT:
1023: retval = history_next_event(h, ev, va_arg(va, int));
1024: break;
1.1 cgd 1025:
1.16 lukem 1026: case H_PREV_STR:
1.35 christos 1027: retval = history_prev_string(h, ev, va_arg(va, const Char *));
1.16 lukem 1028: break;
1.7 christos 1029:
1.16 lukem 1030: case H_NEXT_STR:
1.35 christos 1031: retval = history_next_string(h, ev, va_arg(va, const Char *));
1.16 lukem 1032: break;
1.1 cgd 1033:
1.16 lukem 1034: case H_FUNC:
1.1 cgd 1035: {
1.35 christos 1036: TYPE(History) hf;
1.16 lukem 1037:
1.42 christos 1038: hf.h_ref = va_arg(va, void *);
1.16 lukem 1039: h->h_ent = -1;
1040: hf.h_first = va_arg(va, history_gfun_t);
1041: hf.h_next = va_arg(va, history_gfun_t);
1042: hf.h_last = va_arg(va, history_gfun_t);
1043: hf.h_prev = va_arg(va, history_gfun_t);
1044: hf.h_curr = va_arg(va, history_gfun_t);
1045: hf.h_set = va_arg(va, history_sfun_t);
1046: hf.h_clear = va_arg(va, history_vfun_t);
1047: hf.h_enter = va_arg(va, history_efun_t);
1048: hf.h_add = va_arg(va, history_efun_t);
1.30 christos 1049: hf.h_del = va_arg(va, history_sfun_t);
1.8 christos 1050:
1.16 lukem 1051: if ((retval = history_set_fun(h, &hf)) == -1)
1052: he_seterrev(ev, _HE_PARAM_MISSING);
1053: break;
1054: }
1055:
1056: case H_END:
1.36 christos 1057: FUN(history,end)(h);
1.16 lukem 1058: retval = 0;
1059: break;
1060:
1.34 christos 1061: case H_NEXT_EVDATA:
1062: {
1063: int num = va_arg(va, int);
1064: void **d = va_arg(va, void **);
1065: retval = history_next_evdata(h, ev, num, d);
1066: break;
1067: }
1068:
1069: case H_DELDATA:
1070: {
1071: int num = va_arg(va, int);
1072: void **d = va_arg(va, void **);
1073: retval = history_deldata_nth((history_t *)h->h_ref, ev, num, d);
1074: break;
1075: }
1076:
1077: case H_REPLACE: /* only use after H_NEXT_EVDATA */
1078: {
1.35 christos 1079: const Char *line = va_arg(va, const Char *);
1.34 christos 1080: void *d = va_arg(va, void *);
1.35 christos 1081: const Char *s;
1082: if(!line || !(s = Strdup(line))) {
1.34 christos 1083: retval = -1;
1084: break;
1085: }
1086: ((history_t *)h->h_ref)->cursor->ev.str = s;
1087: ((history_t *)h->h_ref)->cursor->data = d;
1088: retval = 0;
1089: break;
1090: }
1091:
1.16 lukem 1092: default:
1093: retval = -1;
1094: he_seterrev(ev, _HE_UNKNOWN);
1095: break;
1096: }
1097: va_end(va);
1.34 christos 1098: return retval;
1.1 cgd 1099: }
CVSweb <webmaster@jp.NetBSD.org>