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