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