history.c revision 1.11 1 1.11 christos /* $NetBSD: history.c,v 1.11 1998/12/12 19:52:51 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.6 christos #include <sys/cdefs.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.11 christos __RCSID("$NetBSD: history.c,v 1.11 1998/12/12 19:52:51 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 "sys.h"
52 1.1 cgd
53 1.1 cgd #include <string.h>
54 1.1 cgd #include <stdlib.h>
55 1.5 christos #ifdef __STDC__
56 1.1 cgd #include <stdarg.h>
57 1.1 cgd #else
58 1.1 cgd #include <varargs.h>
59 1.1 cgd #endif
60 1.1 cgd
61 1.2 christos static const char hist_cookie[] = "_HiStOrY_V1_\n";
62 1.2 christos
63 1.1 cgd #include "histedit.h"
64 1.1 cgd
65 1.7 christos typedef int (*history_gfun_t) __P((ptr_t, HistEvent *));
66 1.7 christos typedef int (*history_efun_t) __P((ptr_t, HistEvent *, const char *));
67 1.7 christos typedef void (*history_vfun_t) __P((ptr_t, HistEvent *));
68 1.8 christos typedef int (*history_sfun_t) __P((ptr_t, HistEvent *, const int));
69 1.1 cgd
70 1.1 cgd struct history {
71 1.1 cgd ptr_t h_ref; /* Argument for history fcns */
72 1.9 christos int h_ent; /* Last entry point for history */
73 1.1 cgd history_gfun_t h_first; /* Get the first element */
74 1.1 cgd history_gfun_t h_next; /* Get the next element */
75 1.1 cgd history_gfun_t h_last; /* Get the last element */
76 1.1 cgd history_gfun_t h_prev; /* Get the previous element */
77 1.1 cgd history_gfun_t h_curr; /* Get the current element */
78 1.8 christos history_sfun_t h_set; /* Set the current element */
79 1.2 christos history_vfun_t h_clear; /* Clear the history list */
80 1.1 cgd history_efun_t h_enter; /* Add an element */
81 1.1 cgd history_efun_t h_add; /* Append to an element */
82 1.1 cgd };
83 1.1 cgd
84 1.8 christos #define HNEXT(h, ev) (*(h)->h_next)((h)->h_ref, ev)
85 1.8 christos #define HFIRST(h, ev) (*(h)->h_first)((h)->h_ref, ev)
86 1.8 christos #define HPREV(h, ev) (*(h)->h_prev)((h)->h_ref, ev)
87 1.8 christos #define HLAST(h, ev) (*(h)->h_last)((h)->h_ref, ev)
88 1.8 christos #define HCURR(h, ev) (*(h)->h_curr)((h)->h_ref, ev)
89 1.8 christos #define HSET(h, ev, n) (*(h)->h_set)((h)->h_ref, ev, n)
90 1.8 christos #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.1 cgd #define h_malloc(a) malloc(a)
95 1.1 cgd #define h_free(a) free(a)
96 1.1 cgd
97 1.1 cgd
98 1.7 christos private int history_set_num __P((History *, HistEvent *, int));
99 1.7 christos private int history_get_size __P((History *, HistEvent *));
100 1.7 christos private int history_set_fun __P((History *, History *));
101 1.7 christos private int history_load __P((History *, const char *));
102 1.7 christos private int history_save __P((History *, const char *));
103 1.7 christos private int history_prev_event __P((History *, HistEvent *, int));
104 1.7 christos private int history_next_event __P((History *, HistEvent *, int));
105 1.7 christos private int history_next_string __P((History *, HistEvent *, const char *));
106 1.7 christos private int history_prev_string __P((History *, HistEvent *, const char *));
107 1.1 cgd
108 1.1 cgd
109 1.1 cgd /***********************************************************************/
110 1.1 cgd
111 1.1 cgd /*
112 1.1 cgd * Builtin- history implementation
113 1.1 cgd */
114 1.1 cgd typedef struct hentry_t {
115 1.1 cgd HistEvent ev; /* What we return */
116 1.1 cgd struct hentry_t *next; /* Next entry */
117 1.1 cgd struct hentry_t *prev; /* Previous entry */
118 1.1 cgd } hentry_t;
119 1.1 cgd
120 1.1 cgd typedef struct history_t {
121 1.1 cgd hentry_t list; /* Fake list header element */
122 1.1 cgd hentry_t *cursor; /* Current element in the list */
123 1.1 cgd int max; /* Maximum number of events */
124 1.1 cgd int cur; /* Current number of events */
125 1.7 christos int eventid; /* For generation of unique event id */
126 1.1 cgd } history_t;
127 1.1 cgd
128 1.7 christos private int history_def_first __P((ptr_t, HistEvent *));
129 1.7 christos private int history_def_last __P((ptr_t, HistEvent *));
130 1.7 christos private int history_def_next __P((ptr_t, HistEvent *));
131 1.7 christos private int history_def_prev __P((ptr_t, HistEvent *));
132 1.7 christos private int history_def_curr __P((ptr_t, HistEvent *));
133 1.8 christos private int history_def_set __P((ptr_t, HistEvent *, const int n));
134 1.7 christos private int history_def_enter __P((ptr_t, HistEvent *, const char *));
135 1.7 christos private int history_def_add __P((ptr_t, HistEvent *, const char *));
136 1.7 christos private void history_def_init __P((ptr_t *, HistEvent *, int));
137 1.7 christos private void history_def_clear __P((ptr_t, HistEvent *));
138 1.7 christos private int history_def_insert __P((history_t *, HistEvent *,const char *));
139 1.7 christos private void history_def_delete __P((history_t *, HistEvent *, hentry_t *));
140 1.1 cgd
141 1.8 christos #define history_def_setsize(p, num)(void) (((history_t *) p)->max = (num))
142 1.7 christos #define history_def_getsize(p) (((history_t *) p)->cur)
143 1.1 cgd
144 1.7 christos #define he_strerror(code) he_errlist[code]
145 1.7 christos #define he_seterrev(evp, code) {\
146 1.7 christos evp->num = code;\
147 1.7 christos evp->str = he_strerror(code);\
148 1.7 christos }
149 1.7 christos
150 1.7 christos /* error messages */
151 1.7 christos static const char *const he_errlist[] = {
152 1.8 christos "OK",
153 1.11 christos "unknown error"
154 1.8 christos "malloc() failed",
155 1.8 christos "first event not found",
156 1.8 christos "last event not found",
157 1.8 christos "empty list",
158 1.8 christos "no next event",
159 1.8 christos "no previous event",
160 1.8 christos "current event is invalid",
161 1.8 christos "event not found",
162 1.8 christos "can't read history from file",
163 1.8 christos "can't write history",
164 1.8 christos "required parameter(s) not supplied",
165 1.8 christos "history size negative",
166 1.8 christos "function not allowed with other history-functions-set the default",
167 1.8 christos "bad parameters"
168 1.7 christos };
169 1.7 christos
170 1.7 christos /* error codes */
171 1.7 christos #define _HE_OK 0
172 1.7 christos #define _HE_UNKNOWN 1
173 1.7 christos #define _HE_MALLOC_FAILED 2
174 1.7 christos #define _HE_FIRST_NOTFOUND 3
175 1.7 christos #define _HE_LAST_NOTFOUND 4
176 1.7 christos #define _HE_EMPTY_LIST 5
177 1.7 christos #define _HE_END_REACHED 6
178 1.7 christos #define _HE_START_REACHED 7
179 1.7 christos #define _HE_CURR_INVALID 8
180 1.7 christos #define _HE_NOT_FOUND 9
181 1.7 christos #define _HE_HIST_READ 10
182 1.7 christos #define _HE_HIST_WRITE 11
183 1.7 christos #define _HE_PARAM_MISSING 12
184 1.7 christos #define _HE_SIZE_NEGATIVE 13
185 1.7 christos #define _HE_NOT_ALLOWED 14
186 1.7 christos #define _HE_BAD_PARAM 15
187 1.1 cgd
188 1.1 cgd /* history_def_first():
189 1.1 cgd * Default function to return the first event in the history.
190 1.1 cgd */
191 1.7 christos private int
192 1.7 christos history_def_first(p, ev)
193 1.1 cgd ptr_t p;
194 1.7 christos HistEvent *ev;
195 1.1 cgd {
196 1.1 cgd history_t *h = (history_t *) p;
197 1.7 christos
198 1.1 cgd h->cursor = h->list.next;
199 1.1 cgd if (h->cursor != &h->list)
200 1.7 christos *ev = h->cursor->ev;
201 1.7 christos else {
202 1.7 christos he_seterrev(ev, _HE_FIRST_NOTFOUND);
203 1.7 christos return -1;
204 1.7 christos }
205 1.7 christos
206 1.7 christos return 0;
207 1.1 cgd }
208 1.1 cgd
209 1.8 christos
210 1.1 cgd /* history_def_last():
211 1.1 cgd * Default function to return the last event in the history.
212 1.1 cgd */
213 1.7 christos private int
214 1.7 christos history_def_last(p, ev)
215 1.1 cgd ptr_t p;
216 1.7 christos HistEvent *ev;
217 1.1 cgd {
218 1.1 cgd history_t *h = (history_t *) p;
219 1.7 christos
220 1.1 cgd h->cursor = h->list.prev;
221 1.1 cgd if (h->cursor != &h->list)
222 1.7 christos *ev = h->cursor->ev;
223 1.7 christos else {
224 1.7 christos he_seterrev(ev, _HE_LAST_NOTFOUND);
225 1.7 christos return -1;
226 1.7 christos }
227 1.7 christos
228 1.7 christos return 0;
229 1.1 cgd }
230 1.1 cgd
231 1.8 christos
232 1.1 cgd /* history_def_next():
233 1.1 cgd * Default function to return the next event in the history.
234 1.1 cgd */
235 1.7 christos private int
236 1.7 christos history_def_next(p, ev)
237 1.1 cgd ptr_t p;
238 1.7 christos HistEvent *ev;
239 1.1 cgd {
240 1.1 cgd history_t *h = (history_t *) p;
241 1.1 cgd
242 1.1 cgd if (h->cursor != &h->list)
243 1.1 cgd h->cursor = h->cursor->next;
244 1.7 christos else {
245 1.7 christos he_seterrev(ev, _HE_EMPTY_LIST);
246 1.7 christos return -1;
247 1.7 christos }
248 1.1 cgd
249 1.1 cgd if (h->cursor != &h->list)
250 1.7 christos *ev = h->cursor->ev;
251 1.7 christos else {
252 1.7 christos he_seterrev(ev, _HE_END_REACHED);
253 1.7 christos return -1;
254 1.7 christos }
255 1.7 christos
256 1.7 christos return 0;
257 1.1 cgd }
258 1.1 cgd
259 1.1 cgd
260 1.1 cgd /* history_def_prev():
261 1.1 cgd * Default function to return the previous event in the history.
262 1.1 cgd */
263 1.7 christos private int
264 1.7 christos history_def_prev(p, ev)
265 1.1 cgd ptr_t p;
266 1.8 christos HistEvent *ev;
267 1.1 cgd {
268 1.1 cgd history_t *h = (history_t *) p;
269 1.1 cgd
270 1.1 cgd if (h->cursor != &h->list)
271 1.1 cgd h->cursor = h->cursor->prev;
272 1.7 christos else {
273 1.7 christos he_seterrev(ev, (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST);
274 1.7 christos return -1;
275 1.7 christos }
276 1.1 cgd
277 1.1 cgd if (h->cursor != &h->list)
278 1.7 christos *ev = h->cursor->ev;
279 1.7 christos else {
280 1.7 christos he_seterrev(ev, _HE_START_REACHED);
281 1.7 christos return -1;
282 1.7 christos }
283 1.7 christos
284 1.7 christos return 0;
285 1.1 cgd }
286 1.1 cgd
287 1.1 cgd
288 1.1 cgd /* history_def_curr():
289 1.1 cgd * Default function to return the current event in the history.
290 1.1 cgd */
291 1.7 christos private int
292 1.7 christos history_def_curr(p, ev)
293 1.1 cgd ptr_t p;
294 1.8 christos HistEvent *ev;
295 1.1 cgd {
296 1.1 cgd history_t *h = (history_t *) p;
297 1.1 cgd
298 1.1 cgd if (h->cursor != &h->list)
299 1.7 christos *ev = h->cursor->ev;
300 1.7 christos else {
301 1.7 christos he_seterrev(ev, (h->cur > 0) ? _HE_CURR_INVALID : _HE_EMPTY_LIST);
302 1.7 christos return -1;
303 1.7 christos }
304 1.7 christos
305 1.7 christos return 0;
306 1.1 cgd }
307 1.1 cgd
308 1.8 christos
309 1.8 christos /* history_def_set():
310 1.8 christos * Default function to set the current event in the history to the
311 1.8 christos * given one.
312 1.8 christos */
313 1.8 christos private int
314 1.8 christos history_def_set(p, ev, n)
315 1.8 christos ptr_t p;
316 1.8 christos HistEvent *ev;
317 1.8 christos int n;
318 1.8 christos {
319 1.8 christos history_t *h = (history_t *) p;
320 1.8 christos
321 1.8 christos if (h->cur == 0) {
322 1.8 christos he_seterrev(ev, _HE_EMPTY_LIST);
323 1.8 christos return -1;
324 1.8 christos }
325 1.8 christos
326 1.8 christos if (h->cursor == &h->list || h->cursor->ev.num != n) {
327 1.8 christos for (h->cursor = h->list.next; h->cursor != &h->list;
328 1.8 christos h->cursor = h->cursor->next)
329 1.8 christos if (h->cursor->ev.num == n)
330 1.8 christos break;
331 1.8 christos }
332 1.8 christos
333 1.8 christos if (h->cursor == &h->list) {
334 1.8 christos he_seterrev(ev, _HE_NOT_FOUND);
335 1.8 christos return -1;
336 1.8 christos }
337 1.8 christos
338 1.8 christos return 0;
339 1.8 christos }
340 1.8 christos
341 1.8 christos
342 1.1 cgd /* history_def_add():
343 1.1 cgd * Append string to element
344 1.1 cgd */
345 1.7 christos private int
346 1.7 christos history_def_add(p, ev, str)
347 1.1 cgd ptr_t p;
348 1.7 christos HistEvent *ev;
349 1.1 cgd const char *str;
350 1.1 cgd {
351 1.1 cgd history_t *h = (history_t *) p;
352 1.1 cgd size_t len;
353 1.1 cgd char *s;
354 1.1 cgd
355 1.1 cgd if (h->cursor == &h->list)
356 1.7 christos return (history_def_enter(p, ev, str));
357 1.1 cgd len = strlen(h->cursor->ev.str) + strlen(str) + 1;
358 1.1 cgd s = (char *) h_malloc(len);
359 1.7 christos if (!s) {
360 1.7 christos he_seterrev(ev, _HE_MALLOC_FAILED);
361 1.7 christos return -1;
362 1.7 christos }
363 1.7 christos (void)strcpy(s, h->cursor->ev.str); /* XXX strcpy is safe */
364 1.4 mrg (void)strcat(s, str); /* XXX strcat is safe */
365 1.11 christos /* LINTED const cast */
366 1.1 cgd h_free((ptr_t) h->cursor->ev.str);
367 1.1 cgd h->cursor->ev.str = s;
368 1.7 christos *ev = h->cursor->ev;
369 1.7 christos return 0;
370 1.1 cgd }
371 1.1 cgd
372 1.1 cgd
373 1.1 cgd /* history_def_delete():
374 1.1 cgd * Delete element hp of the h list
375 1.1 cgd */
376 1.11 christos /* ARGSUSED */
377 1.1 cgd private void
378 1.7 christos history_def_delete(h, ev, hp)
379 1.1 cgd history_t *h;
380 1.7 christos HistEvent *ev;
381 1.1 cgd hentry_t *hp;
382 1.1 cgd {
383 1.1 cgd if (hp == &h->list)
384 1.1 cgd abort();
385 1.1 cgd hp->prev->next = hp->next;
386 1.1 cgd hp->next->prev = hp->prev;
387 1.11 christos /* LINTED const cast */
388 1.1 cgd h_free((ptr_t) hp->ev.str);
389 1.1 cgd h_free(hp);
390 1.1 cgd h->cur--;
391 1.1 cgd }
392 1.1 cgd
393 1.1 cgd
394 1.1 cgd /* history_def_insert():
395 1.1 cgd * Insert element with string str in the h list
396 1.1 cgd */
397 1.7 christos private int
398 1.7 christos history_def_insert(h, ev, str)
399 1.1 cgd history_t *h;
400 1.7 christos HistEvent *ev;
401 1.1 cgd const char *str;
402 1.1 cgd {
403 1.1 cgd h->cursor = (hentry_t *) h_malloc(sizeof(hentry_t));
404 1.7 christos if (h->cursor)
405 1.7 christos h->cursor->ev.str = strdup(str);
406 1.7 christos if (!h->cursor || !h->cursor->ev.str) {
407 1.7 christos he_seterrev(ev, _HE_MALLOC_FAILED);
408 1.7 christos return -1;
409 1.7 christos }
410 1.7 christos h->cursor->ev.num = ++h->eventid;
411 1.1 cgd h->cursor->next = h->list.next;
412 1.1 cgd h->cursor->prev = &h->list;
413 1.1 cgd h->list.next->prev = h->cursor;
414 1.1 cgd h->list.next = h->cursor;
415 1.1 cgd h->cur++;
416 1.1 cgd
417 1.7 christos *ev = h->cursor->ev;
418 1.7 christos return 0;
419 1.1 cgd }
420 1.1 cgd
421 1.1 cgd
422 1.1 cgd /* history_def_enter():
423 1.1 cgd * Default function to enter an item in the history
424 1.1 cgd */
425 1.7 christos private int
426 1.7 christos history_def_enter(p, ev, str)
427 1.1 cgd ptr_t p;
428 1.7 christos HistEvent *ev;
429 1.1 cgd const char *str;
430 1.1 cgd {
431 1.1 cgd history_t *h = (history_t *) p;
432 1.1 cgd
433 1.7 christos if (history_def_insert(h, ev, str) == -1)
434 1.7 christos return -1; /* error, keep error message */
435 1.1 cgd
436 1.1 cgd /*
437 1.1 cgd * Always keep at least one entry.
438 1.1 cgd * This way we don't have to check for the empty list.
439 1.1 cgd */
440 1.7 christos while (h->cur - 1 > h->max)
441 1.7 christos history_def_delete(h, ev, h->list.prev);
442 1.7 christos
443 1.7 christos return 0;
444 1.1 cgd }
445 1.1 cgd
446 1.1 cgd
447 1.1 cgd /* history_def_init():
448 1.1 cgd * Default history initialization function
449 1.1 cgd */
450 1.11 christos /* ARGSUSED */
451 1.1 cgd private void
452 1.7 christos history_def_init(p, ev, n)
453 1.1 cgd ptr_t *p;
454 1.7 christos HistEvent *ev;
455 1.1 cgd int n;
456 1.1 cgd {
457 1.1 cgd history_t *h = (history_t *) h_malloc(sizeof(history_t));
458 1.1 cgd if (n <= 0)
459 1.1 cgd n = 0;
460 1.7 christos h->eventid = 0;
461 1.1 cgd h->cur = 0;
462 1.1 cgd h->max = n;
463 1.1 cgd h->list.next = h->list.prev = &h->list;
464 1.1 cgd h->list.ev.str = NULL;
465 1.1 cgd h->list.ev.num = 0;
466 1.1 cgd h->cursor = &h->list;
467 1.1 cgd *p = (ptr_t) h;
468 1.1 cgd }
469 1.1 cgd
470 1.1 cgd
471 1.2 christos /* history_def_clear():
472 1.1 cgd * Default history cleanup function
473 1.1 cgd */
474 1.1 cgd private void
475 1.7 christos history_def_clear(p, ev)
476 1.1 cgd ptr_t p;
477 1.7 christos HistEvent *ev;
478 1.1 cgd {
479 1.1 cgd history_t *h = (history_t *) p;
480 1.1 cgd
481 1.1 cgd while (h->list.prev != &h->list)
482 1.7 christos history_def_delete(h, ev, h->list.prev);
483 1.7 christos h->eventid = 0;
484 1.2 christos h->cur = 0;
485 1.1 cgd }
486 1.1 cgd
487 1.2 christos
488 1.2 christos
489 1.2 christos
490 1.1 cgd /************************************************************************/
491 1.1 cgd
492 1.1 cgd /* history_init():
493 1.1 cgd * Initialization function.
494 1.1 cgd */
495 1.1 cgd public History *
496 1.1 cgd history_init()
497 1.1 cgd {
498 1.1 cgd History *h = (History *) h_malloc(sizeof(History));
499 1.7 christos HistEvent ev;
500 1.1 cgd
501 1.7 christos history_def_init(&h->h_ref, &ev, 0);
502 1.9 christos h->h_ent = -1;
503 1.1 cgd h->h_next = history_def_next;
504 1.1 cgd h->h_first = history_def_first;
505 1.1 cgd h->h_last = history_def_last;
506 1.1 cgd h->h_prev = history_def_prev;
507 1.1 cgd h->h_curr = history_def_curr;
508 1.8 christos h->h_set = history_def_set;
509 1.2 christos h->h_clear = history_def_clear;
510 1.1 cgd h->h_enter = history_def_enter;
511 1.1 cgd h->h_add = history_def_add;
512 1.1 cgd
513 1.1 cgd return h;
514 1.1 cgd }
515 1.1 cgd
516 1.1 cgd
517 1.1 cgd /* history_end():
518 1.1 cgd * clean up history;
519 1.1 cgd */
520 1.1 cgd public void
521 1.1 cgd history_end(h)
522 1.1 cgd History *h;
523 1.1 cgd {
524 1.7 christos HistEvent ev;
525 1.1 cgd if (h->h_next == history_def_next)
526 1.7 christos history_def_clear(h->h_ref, &ev);
527 1.1 cgd }
528 1.1 cgd
529 1.1 cgd
530 1.1 cgd
531 1.1 cgd /* history_set_num():
532 1.1 cgd * Set history number of events
533 1.1 cgd */
534 1.1 cgd private int
535 1.7 christos history_set_num(h, ev, num)
536 1.1 cgd History *h;
537 1.7 christos HistEvent *ev;
538 1.1 cgd int num;
539 1.1 cgd {
540 1.7 christos if (h->h_next != history_def_next) {
541 1.7 christos he_seterrev(ev, _HE_NOT_ALLOWED);
542 1.1 cgd return -1;
543 1.7 christos }
544 1.7 christos
545 1.7 christos if (num < 0) {
546 1.7 christos he_seterrev(ev, _HE_BAD_PARAM);
547 1.7 christos return -1;
548 1.7 christos }
549 1.7 christos
550 1.8 christos history_def_setsize(h->h_ref, num);
551 1.1 cgd return 0;
552 1.1 cgd }
553 1.1 cgd
554 1.7 christos /* history_get_size():
555 1.7 christos * Get number of events currently in history
556 1.7 christos */
557 1.7 christos private int
558 1.7 christos history_get_size(h, ev)
559 1.7 christos History *h;
560 1.7 christos HistEvent *ev;
561 1.7 christos {
562 1.7 christos int retval=0;
563 1.7 christos
564 1.7 christos if (h->h_next != history_def_next) {
565 1.7 christos he_seterrev(ev, _HE_NOT_ALLOWED);
566 1.7 christos return -1;
567 1.7 christos }
568 1.7 christos retval = history_def_getsize(h->h_ref);
569 1.7 christos if (retval < -1) {
570 1.7 christos he_seterrev(ev, _HE_SIZE_NEGATIVE);
571 1.7 christos return -1;
572 1.7 christos }
573 1.7 christos
574 1.7 christos ev->num = retval;
575 1.7 christos return 0;
576 1.7 christos }
577 1.1 cgd
578 1.1 cgd /* history_set_fun():
579 1.1 cgd * Set history functions
580 1.1 cgd */
581 1.1 cgd private int
582 1.2 christos history_set_fun(h, nh)
583 1.7 christos History *h;
584 1.7 christos History *nh;
585 1.2 christos {
586 1.7 christos HistEvent ev;
587 1.7 christos
588 1.8 christos if (nh->h_first == NULL || nh->h_next == NULL || nh->h_last == NULL ||
589 1.8 christos nh->h_prev == NULL || nh->h_curr == NULL || nh->h_set == NULL ||
590 1.2 christos nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL ||
591 1.2 christos nh->h_ref == NULL) {
592 1.1 cgd if (h->h_next != history_def_next) {
593 1.7 christos history_def_init(&h->h_ref, &ev, 0);
594 1.1 cgd h->h_first = history_def_first;
595 1.1 cgd h->h_next = history_def_next;
596 1.1 cgd h->h_last = history_def_last;
597 1.1 cgd h->h_prev = history_def_prev;
598 1.1 cgd h->h_curr = history_def_curr;
599 1.8 christos h->h_set = history_def_set;
600 1.2 christos h->h_clear = history_def_clear;
601 1.1 cgd h->h_enter = history_def_enter;
602 1.1 cgd h->h_add = history_def_add;
603 1.1 cgd }
604 1.1 cgd return -1;
605 1.1 cgd }
606 1.1 cgd
607 1.1 cgd if (h->h_next == history_def_next)
608 1.7 christos history_def_clear(h->h_ref, &ev);
609 1.2 christos
610 1.9 christos h->h_ent = -1;
611 1.2 christos h->h_first = nh->h_first;
612 1.2 christos h->h_next = nh->h_next;
613 1.2 christos h->h_last = nh->h_last;
614 1.2 christos h->h_prev = nh->h_prev;
615 1.2 christos h->h_curr = nh->h_curr;
616 1.8 christos h->h_set = nh->h_set;
617 1.2 christos h->h_clear = nh->h_clear;
618 1.2 christos h->h_enter = nh->h_enter;
619 1.2 christos h->h_add = nh->h_add;
620 1.1 cgd
621 1.1 cgd return 0;
622 1.1 cgd }
623 1.1 cgd
624 1.1 cgd
625 1.2 christos /* history_load():
626 1.2 christos * History load function
627 1.2 christos */
628 1.2 christos private int
629 1.2 christos history_load(h, fname)
630 1.2 christos History *h;
631 1.2 christos const char *fname;
632 1.2 christos {
633 1.2 christos FILE *fp;
634 1.2 christos char *line;
635 1.2 christos size_t sz;
636 1.2 christos int i = -1;
637 1.7 christos HistEvent ev;
638 1.2 christos
639 1.2 christos if ((fp = fopen(fname, "r")) == NULL)
640 1.2 christos return i;
641 1.2 christos
642 1.2 christos if ((line = fgetln(fp, &sz)) == NULL)
643 1.2 christos goto done;
644 1.2 christos
645 1.2 christos if (strncmp(line, hist_cookie, sz) != 0)
646 1.2 christos goto done;
647 1.2 christos
648 1.2 christos for (i = 0; (line = fgetln(fp, &sz)) != NULL; i++) {
649 1.2 christos char c = line[sz];
650 1.2 christos line[sz] = '\0';
651 1.7 christos HENTER(h, &ev, line);
652 1.2 christos line[sz] = c;
653 1.2 christos }
654 1.2 christos
655 1.2 christos done:
656 1.2 christos (void) fclose(fp);
657 1.2 christos return i;
658 1.2 christos }
659 1.2 christos
660 1.2 christos
661 1.2 christos /* history_save():
662 1.2 christos * History save function
663 1.2 christos */
664 1.2 christos private int
665 1.2 christos history_save(h, fname)
666 1.2 christos History *h;
667 1.2 christos const char *fname;
668 1.2 christos {
669 1.2 christos FILE *fp;
670 1.7 christos HistEvent ev;
671 1.7 christos int i = 0, retval;
672 1.2 christos
673 1.2 christos if ((fp = fopen(fname, "w")) == NULL)
674 1.2 christos return -1;
675 1.2 christos
676 1.2 christos (void) fputs(hist_cookie, fp);
677 1.7 christos for (retval = HLAST(h, &ev); retval != -1; retval = HPREV(h, &ev), i++)
678 1.7 christos (void) fprintf(fp, "%s", ev.str);
679 1.2 christos (void) fclose(fp);
680 1.2 christos return i;
681 1.2 christos }
682 1.2 christos
683 1.2 christos
684 1.1 cgd /* history_prev_event():
685 1.1 cgd * Find the previous event, with number given
686 1.1 cgd */
687 1.7 christos private int
688 1.7 christos history_prev_event(h, ev, num)
689 1.1 cgd History *h;
690 1.7 christos HistEvent *ev;
691 1.1 cgd int num;
692 1.1 cgd {
693 1.7 christos int retval;
694 1.7 christos for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
695 1.1 cgd if (ev->num == num)
696 1.7 christos return 0;
697 1.7 christos
698 1.7 christos he_seterrev(ev, _HE_NOT_FOUND);
699 1.7 christos return -1;
700 1.1 cgd }
701 1.1 cgd
702 1.1 cgd
703 1.1 cgd /* history_next_event():
704 1.1 cgd * Find the next event, with number given
705 1.1 cgd */
706 1.7 christos private int
707 1.7 christos history_next_event(h, ev, num)
708 1.1 cgd History *h;
709 1.7 christos HistEvent *ev;
710 1.1 cgd int num;
711 1.1 cgd {
712 1.7 christos int retval;
713 1.7 christos for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
714 1.1 cgd if (ev->num == num)
715 1.7 christos return 0;
716 1.7 christos
717 1.7 christos he_seterrev(ev, _HE_NOT_FOUND);
718 1.10 cgd return -1;
719 1.1 cgd }
720 1.1 cgd
721 1.1 cgd
722 1.1 cgd /* history_prev_string():
723 1.1 cgd * Find the previous event beginning with string
724 1.1 cgd */
725 1.7 christos private int
726 1.7 christos history_prev_string(h, ev, str)
727 1.1 cgd History *h;
728 1.7 christos HistEvent *ev;
729 1.1 cgd const char* str;
730 1.1 cgd {
731 1.1 cgd size_t len = strlen(str);
732 1.7 christos int retval;
733 1.1 cgd
734 1.7 christos for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
735 1.1 cgd if (strncmp(str, ev->str, len) == 0)
736 1.7 christos return 0;
737 1.7 christos
738 1.7 christos he_seterrev(ev, _HE_NOT_FOUND);
739 1.7 christos return -1;
740 1.1 cgd }
741 1.1 cgd
742 1.1 cgd
743 1.2 christos
744 1.2 christos
745 1.1 cgd /* history_next_string():
746 1.1 cgd * Find the next event beginning with string
747 1.1 cgd */
748 1.7 christos private int
749 1.7 christos history_next_string(h, ev, str)
750 1.1 cgd History *h;
751 1.7 christos HistEvent *ev;
752 1.1 cgd const char* str;
753 1.1 cgd {
754 1.1 cgd size_t len = strlen(str);
755 1.7 christos int retval;
756 1.1 cgd
757 1.7 christos for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
758 1.1 cgd if (strncmp(str, ev->str, len) == 0)
759 1.7 christos return 0;
760 1.7 christos
761 1.7 christos he_seterrev(ev, _HE_NOT_FOUND);
762 1.7 christos return -1;
763 1.1 cgd }
764 1.1 cgd
765 1.1 cgd
766 1.1 cgd /* history():
767 1.1 cgd * User interface to history functions.
768 1.1 cgd */
769 1.7 christos int
770 1.5 christos #ifdef __STDC__
771 1.7 christos history(History *h, HistEvent *ev, int fun, ...)
772 1.1 cgd #else
773 1.1 cgd history(va_alist)
774 1.1 cgd va_dcl
775 1.1 cgd #endif
776 1.1 cgd {
777 1.1 cgd va_list va;
778 1.1 cgd const char *str;
779 1.7 christos int retval;
780 1.1 cgd
781 1.5 christos #ifdef __STDC__
782 1.1 cgd va_start(va, fun);
783 1.1 cgd #else
784 1.1 cgd History *h;
785 1.7 christos HistEvent *ev;
786 1.1 cgd int fun;
787 1.1 cgd va_start(va);
788 1.1 cgd h = va_arg(va, History *);
789 1.7 christos ev = va_arg(va, HistEvent *);
790 1.1 cgd fun = va_arg(va, int);
791 1.1 cgd #endif
792 1.1 cgd
793 1.7 christos he_seterrev(ev, _HE_OK);
794 1.7 christos
795 1.1 cgd switch (fun) {
796 1.8 christos case H_GETSIZE:
797 1.8 christos retval = history_get_size(h, ev);
798 1.8 christos break;
799 1.8 christos
800 1.8 christos case H_SETSIZE:
801 1.8 christos retval = history_set_num(h, ev, va_arg(va, int));
802 1.8 christos break;
803 1.8 christos
804 1.1 cgd case H_ADD:
805 1.1 cgd str = va_arg(va, const char *);
806 1.7 christos retval = HADD(h, ev, str);
807 1.1 cgd break;
808 1.1 cgd
809 1.1 cgd case H_ENTER:
810 1.1 cgd str = va_arg(va, const char *);
811 1.9 christos if ((retval = HENTER(h, ev, str)) != -1)
812 1.9 christos h->h_ent = ev->num;
813 1.9 christos break;
814 1.9 christos
815 1.9 christos case H_APPEND:
816 1.9 christos str = va_arg(va, const char *);
817 1.9 christos if ((retval = HSET(h, ev, h->h_ent)) != -1)
818 1.9 christos retval = HADD(h, ev, str);
819 1.1 cgd break;
820 1.1 cgd
821 1.1 cgd case H_FIRST:
822 1.7 christos retval = HFIRST(h, ev);
823 1.1 cgd break;
824 1.1 cgd
825 1.1 cgd case H_NEXT:
826 1.7 christos retval = HNEXT(h, ev);
827 1.1 cgd break;
828 1.1 cgd
829 1.1 cgd case H_LAST:
830 1.7 christos retval = HLAST(h, ev);
831 1.1 cgd break;
832 1.1 cgd
833 1.1 cgd case H_PREV:
834 1.7 christos retval = HPREV(h, ev);
835 1.1 cgd break;
836 1.1 cgd
837 1.1 cgd case H_CURR:
838 1.7 christos retval = HCURR(h, ev);
839 1.1 cgd break;
840 1.1 cgd
841 1.8 christos case H_SET:
842 1.8 christos retval = HSET(h, ev, va_arg(va, const int));
843 1.8 christos break;
844 1.8 christos
845 1.2 christos case H_CLEAR:
846 1.7 christos HCLEAR(h, ev);
847 1.7 christos retval = 0;
848 1.2 christos break;
849 1.2 christos
850 1.2 christos case H_LOAD:
851 1.7 christos retval = history_load(h, va_arg(va, const char *));
852 1.7 christos if (retval == -1)
853 1.7 christos he_seterrev(ev, _HE_HIST_READ);
854 1.2 christos break;
855 1.2 christos
856 1.2 christos case H_SAVE:
857 1.7 christos retval = history_save(h, va_arg(va, const char *));
858 1.7 christos if (retval == -1)
859 1.7 christos he_seterrev(ev, _HE_HIST_WRITE);
860 1.2 christos break;
861 1.2 christos
862 1.1 cgd case H_PREV_EVENT:
863 1.7 christos retval = history_prev_event(h, ev, va_arg(va, int));
864 1.1 cgd break;
865 1.1 cgd
866 1.1 cgd case H_NEXT_EVENT:
867 1.7 christos retval = history_next_event(h, ev, va_arg(va, int));
868 1.1 cgd break;
869 1.1 cgd
870 1.1 cgd case H_PREV_STR:
871 1.7 christos retval = history_prev_string(h, ev, va_arg(va, const char*));
872 1.1 cgd break;
873 1.1 cgd
874 1.1 cgd case H_NEXT_STR:
875 1.7 christos retval = history_next_string(h, ev, va_arg(va, const char*));
876 1.1 cgd break;
877 1.1 cgd
878 1.1 cgd case H_FUNC:
879 1.1 cgd {
880 1.2 christos History hf;
881 1.8 christos
882 1.2 christos hf.h_ref = va_arg(va, ptr_t);
883 1.9 christos h->h_ent = -1;
884 1.2 christos hf.h_first = va_arg(va, history_gfun_t);
885 1.2 christos hf.h_next = va_arg(va, history_gfun_t);
886 1.2 christos hf.h_last = va_arg(va, history_gfun_t);
887 1.2 christos hf.h_prev = va_arg(va, history_gfun_t);
888 1.2 christos hf.h_curr = va_arg(va, history_gfun_t);
889 1.8 christos hf.h_set = va_arg(va, history_sfun_t);
890 1.2 christos hf.h_clear = va_arg(va, history_vfun_t);
891 1.2 christos hf.h_enter = va_arg(va, history_efun_t);
892 1.2 christos hf.h_add = va_arg(va, history_efun_t);
893 1.1 cgd
894 1.7 christos if ((retval = history_set_fun(h, &hf)) == -1)
895 1.7 christos he_seterrev(ev, _HE_PARAM_MISSING);
896 1.1 cgd }
897 1.1 cgd break;
898 1.1 cgd
899 1.1 cgd case H_END:
900 1.1 cgd history_end(h);
901 1.7 christos retval = 0;
902 1.1 cgd break;
903 1.1 cgd
904 1.1 cgd default:
905 1.7 christos retval = -1;
906 1.7 christos he_seterrev(ev, _HE_UNKNOWN);
907 1.1 cgd break;
908 1.1 cgd }
909 1.1 cgd va_end(va);
910 1.7 christos return retval;
911 1.1 cgd }
912