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