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