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