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