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