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