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