1*4d36c519Skre /* $NetBSD: history.c,v 1.64 2024/07/11 05:41:24 kre Exp $ */
22543e3e6Slukem
36dc2f1dbScgd /*-
46dc2f1dbScgd * Copyright (c) 1992, 1993
56dc2f1dbScgd * The Regents of the University of California. All rights reserved.
66dc2f1dbScgd *
76dc2f1dbScgd * This code is derived from software contributed to Berkeley by
86dc2f1dbScgd * Christos Zoulas of Cornell University.
96dc2f1dbScgd *
106dc2f1dbScgd * Redistribution and use in source and binary forms, with or without
116dc2f1dbScgd * modification, are permitted provided that the following conditions
126dc2f1dbScgd * are met:
136dc2f1dbScgd * 1. Redistributions of source code must retain the above copyright
146dc2f1dbScgd * notice, this list of conditions and the following disclaimer.
156dc2f1dbScgd * 2. Redistributions in binary form must reproduce the above copyright
166dc2f1dbScgd * notice, this list of conditions and the following disclaimer in the
176dc2f1dbScgd * documentation and/or other materials provided with the distribution.
18eb7c1594Sagc * 3. Neither the name of the University nor the names of its contributors
196dc2f1dbScgd * may be used to endorse or promote products derived from this software
206dc2f1dbScgd * without specific prior written permission.
216dc2f1dbScgd *
226dc2f1dbScgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
236dc2f1dbScgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
246dc2f1dbScgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
256dc2f1dbScgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
266dc2f1dbScgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
276dc2f1dbScgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
286dc2f1dbScgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
296dc2f1dbScgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
306dc2f1dbScgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
316dc2f1dbScgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
326dc2f1dbScgd * SUCH DAMAGE.
336dc2f1dbScgd */
346dc2f1dbScgd
350e0ac6b7Schristos #include "config.h"
366dc2f1dbScgd #if !defined(lint) && !defined(SCCSID)
3754fac685Schristos #if 0
386dc2f1dbScgd static char sccsid[] = "@(#)history.c 8.1 (Berkeley) 6/4/93";
3954fac685Schristos #else
40*4d36c519Skre __RCSID("$NetBSD: history.c,v 1.64 2024/07/11 05:41:24 kre Exp $");
4154fac685Schristos #endif
426dc2f1dbScgd #endif /* not lint && not SCCSID */
436dc2f1dbScgd
446dc2f1dbScgd /*
4534e53048Schristos * hist.c: TYPE(History) access functions
466dc2f1dbScgd */
47e125f8f1Schristos #include <sys/stat.h>
48*4d36c519Skre #include <fcntl.h>
4922383670Schristos #include <stdarg.h>
5022383670Schristos #include <stdlib.h>
5122383670Schristos #include <string.h>
5222383670Schristos #include <vis.h>
536dc2f1dbScgd
5484ee55f1Schristos static const char hist_cookie[] = "_HiStOrY_V2_\n";
5595b0e87bSchristos
566dc2f1dbScgd #include "histedit.h"
576dc2f1dbScgd
580aefc7f9Schristos
590aefc7f9Schristos #ifdef NARROWCHAR
600aefc7f9Schristos
610594af80Schristos #define Char char
620aefc7f9Schristos #define FUN(prefix, rest) prefix ## _ ## rest
630aefc7f9Schristos #define FUNW(type) type
640aefc7f9Schristos #define TYPE(type) type
650aefc7f9Schristos #define STR(x) x
660aefc7f9Schristos
670aefc7f9Schristos #define Strlen(s) strlen(s)
680aefc7f9Schristos #define Strdup(s) strdup(s)
690aefc7f9Schristos #define Strcmp(d, s) strcmp(d, s)
700aefc7f9Schristos #define Strncmp(d, s, n) strncmp(d, s, n)
710aefc7f9Schristos #define Strncpy(d, s, n) strncpy(d, s, n)
720aefc7f9Schristos #define Strncat(d, s, n) strncat(d, s, n)
73a75ea7b9Schristos #define ct_decode_string(s, b) (s)
74a75ea7b9Schristos #define ct_encode_string(s, b) (s)
750aefc7f9Schristos
760aefc7f9Schristos #else
77a75ea7b9Schristos #include "chartype.h"
780aefc7f9Schristos
790594af80Schristos #define Char wchar_t
800aefc7f9Schristos #define FUN(prefix, rest) prefix ## _w ## rest
810aefc7f9Schristos #define FUNW(type) type ## _w
820aefc7f9Schristos #define TYPE(type) type ## W
830aefc7f9Schristos #define STR(x) L ## x
840aefc7f9Schristos
850aefc7f9Schristos #define Strlen(s) wcslen(s)
860aefc7f9Schristos #define Strdup(s) wcsdup(s)
870aefc7f9Schristos #define Strcmp(d, s) wcscmp(d, s)
880aefc7f9Schristos #define Strncmp(d, s, n) wcsncmp(d, s, n)
890aefc7f9Schristos #define Strncpy(d, s, n) wcsncpy(d, s, n)
900aefc7f9Schristos #define Strncat(d, s, n) wcsncat(d, s, n)
910aefc7f9Schristos
920aefc7f9Schristos #endif
930aefc7f9Schristos
940aefc7f9Schristos
95a13cd756Schristos typedef int (*history_gfun_t)(void *, TYPE(HistEvent) *);
96a13cd756Schristos typedef int (*history_efun_t)(void *, TYPE(HistEvent) *, const Char *);
97a13cd756Schristos typedef void (*history_vfun_t)(void *, TYPE(HistEvent) *);
98a13cd756Schristos typedef int (*history_sfun_t)(void *, TYPE(HistEvent) *, const int);
996dc2f1dbScgd
TYPE(history)10073eda9feSchristos struct TYPE(history) {
101a13cd756Schristos void *h_ref; /* Argument for history fcns */
102eac8b136Schristos int h_ent; /* Last entry point for history */
1036dc2f1dbScgd history_gfun_t h_first; /* Get the first element */
1046dc2f1dbScgd history_gfun_t h_next; /* Get the next element */
1056dc2f1dbScgd history_gfun_t h_last; /* Get the last element */
1066dc2f1dbScgd history_gfun_t h_prev; /* Get the previous element */
1076dc2f1dbScgd history_gfun_t h_curr; /* Get the current element */
108ccac6ba8Schristos history_sfun_t h_set; /* Set the current element */
10945542456Schristos history_sfun_t h_del; /* Set the given element */
11095b0e87bSchristos history_vfun_t h_clear; /* Clear the history list */
1116dc2f1dbScgd history_efun_t h_enter; /* Add an element */
1126dc2f1dbScgd history_efun_t h_add; /* Append to an element */
1136dc2f1dbScgd };
114f24857bfSchristos
115a7db9a79Schristos #define HNEXT(h, ev) (*(h)->h_next)((h)->h_ref, ev)
116a7db9a79Schristos #define HFIRST(h, ev) (*(h)->h_first)((h)->h_ref, ev)
117a7db9a79Schristos #define HPREV(h, ev) (*(h)->h_prev)((h)->h_ref, ev)
118a7db9a79Schristos #define HLAST(h, ev) (*(h)->h_last)((h)->h_ref, ev)
119a7db9a79Schristos #define HCURR(h, ev) (*(h)->h_curr)((h)->h_ref, ev)
120ccac6ba8Schristos #define HSET(h, ev, n) (*(h)->h_set)((h)->h_ref, ev, n)
121a7db9a79Schristos #define HCLEAR(h, ev) (*(h)->h_clear)((h)->h_ref, ev)
122a7db9a79Schristos #define HENTER(h, ev, str) (*(h)->h_enter)((h)->h_ref, ev, str)
123a7db9a79Schristos #define HADD(h, ev, str) (*(h)->h_add)((h)->h_ref, ev, str)
12445542456Schristos #define HDEL(h, ev, n) (*(h)->h_del)((h)->h_ref, ev, n)
1256dc2f1dbScgd
12634e53048Schristos #define h_strdup(a) Strdup(a)
1276dc2f1dbScgd #define h_malloc(a) malloc(a)
12884ee55f1Schristos #define h_realloc(a, b) realloc((a), (b))
1296dc2f1dbScgd #define h_free(a) free(a)
1306dc2f1dbScgd
1310e0ac6b7Schristos typedef struct {
1320e0ac6b7Schristos int num;
13334e53048Schristos Char *str;
1340e0ac6b7Schristos } HistEventPrivate;
1350e0ac6b7Schristos
1360e0ac6b7Schristos
137469d44f8Schristos static int history_setsize(TYPE(History) *, TYPE(HistEvent) *, int);
138469d44f8Schristos static int history_getsize(TYPE(History) *, TYPE(HistEvent) *);
139469d44f8Schristos static int history_setunique(TYPE(History) *, TYPE(HistEvent) *, int);
140469d44f8Schristos static int history_getunique(TYPE(History) *, TYPE(HistEvent) *);
141469d44f8Schristos static int history_set_fun(TYPE(History) *, TYPE(History) *);
142469d44f8Schristos static int history_load(TYPE(History) *, const char *);
143469d44f8Schristos static int history_save(TYPE(History) *, const char *);
14427916d7cSchristos static int history_save_fp(TYPE(History) *, size_t, FILE *);
145469d44f8Schristos static int history_prev_event(TYPE(History) *, TYPE(HistEvent) *, int);
146469d44f8Schristos static int history_next_event(TYPE(History) *, TYPE(HistEvent) *, int);
147469d44f8Schristos static int history_next_string(TYPE(History) *, TYPE(HistEvent) *,
148469d44f8Schristos const Char *);
149469d44f8Schristos static int history_prev_string(TYPE(History) *, TYPE(HistEvent) *,
150469d44f8Schristos const Char *);
1516dc2f1dbScgd
1526dc2f1dbScgd
1536dc2f1dbScgd /***********************************************************************/
1546dc2f1dbScgd
1556dc2f1dbScgd /*
1566dc2f1dbScgd * Builtin- history implementation
1576dc2f1dbScgd */
1586dc2f1dbScgd typedef struct hentry_t {
15934e53048Schristos TYPE(HistEvent) ev; /* What we return */
160ea3813edSchristos void *data; /* data */
1616dc2f1dbScgd struct hentry_t *next; /* Next entry */
1626dc2f1dbScgd struct hentry_t *prev; /* Previous entry */
1636dc2f1dbScgd } hentry_t;
1646dc2f1dbScgd
1656dc2f1dbScgd typedef struct history_t {
1666dc2f1dbScgd hentry_t list; /* Fake list header element */
1676dc2f1dbScgd hentry_t *cursor; /* Current element in the list */
1686dc2f1dbScgd int max; /* Maximum number of events */
1696dc2f1dbScgd int cur; /* Current number of events */
170a7db9a79Schristos int eventid; /* For generation of unique event id */
17134e53048Schristos int flags; /* TYPE(History) flags */
172f24857bfSchristos #define H_UNIQUE 1 /* Store only unique elements */
1736dc2f1dbScgd } history_t;
1746dc2f1dbScgd
175469d44f8Schristos static int history_def_next(void *, TYPE(HistEvent) *);
176469d44f8Schristos static int history_def_first(void *, TYPE(HistEvent) *);
177469d44f8Schristos static int history_def_prev(void *, TYPE(HistEvent) *);
178469d44f8Schristos static int history_def_last(void *, TYPE(HistEvent) *);
179469d44f8Schristos static int history_def_curr(void *, TYPE(HistEvent) *);
180469d44f8Schristos static int history_def_set(void *, TYPE(HistEvent) *, const int);
181469d44f8Schristos static void history_def_clear(void *, TYPE(HistEvent) *);
182469d44f8Schristos static int history_def_enter(void *, TYPE(HistEvent) *, const Char *);
183469d44f8Schristos static int history_def_add(void *, TYPE(HistEvent) *, const Char *);
184469d44f8Schristos static int history_def_del(void *, TYPE(HistEvent) *, const int);
18545542456Schristos
186469d44f8Schristos static int history_def_init(void **, TYPE(HistEvent) *, int);
187469d44f8Schristos static int history_def_insert(history_t *, TYPE(HistEvent) *, const Char *);
188469d44f8Schristos static void history_def_delete(history_t *, TYPE(HistEvent) *, hentry_t *);
1896dc2f1dbScgd
190469d44f8Schristos static int history_deldata_nth(history_t *, TYPE(HistEvent) *, int, void **);
191469d44f8Schristos static int history_set_nth(void *, TYPE(HistEvent) *, int);
192ea3813edSchristos
193ccac6ba8Schristos #define history_def_setsize(p, num)(void) (((history_t *)p)->max = (num))
194a7db9a79Schristos #define history_def_getsize(p) (((history_t *)p)->cur)
195f24857bfSchristos #define history_def_getunique(p) (((((history_t *)p)->flags) & H_UNIQUE) != 0)
196f24857bfSchristos #define history_def_setunique(p, uni) \
197f24857bfSchristos if (uni) \
198f24857bfSchristos (((history_t *)p)->flags) |= H_UNIQUE; \
199f24857bfSchristos else \
200f24857bfSchristos (((history_t *)p)->flags) &= ~H_UNIQUE
2016dc2f1dbScgd
202a7db9a79Schristos #define he_strerror(code) he_errlist[code]
203a7db9a79Schristos #define he_seterrev(evp, code) {\
204a7db9a79Schristos evp->num = code;\
205a7db9a79Schristos evp->str = he_strerror(code);\
206a7db9a79Schristos }
207a7db9a79Schristos
208a7db9a79Schristos /* error messages */
20934e53048Schristos static const Char *const he_errlist[] = {
21034e53048Schristos STR("OK"),
21134e53048Schristos STR("unknown error"),
21234e53048Schristos STR("malloc() failed"),
21334e53048Schristos STR("first event not found"),
21434e53048Schristos STR("last event not found"),
21534e53048Schristos STR("empty list"),
21634e53048Schristos STR("no next event"),
21734e53048Schristos STR("no previous event"),
21834e53048Schristos STR("current event is invalid"),
21934e53048Schristos STR("event not found"),
22034e53048Schristos STR("can't read history from file"),
22134e53048Schristos STR("can't write history"),
22234e53048Schristos STR("required parameter(s) not supplied"),
22334e53048Schristos STR("history size negative"),
22434e53048Schristos STR("function not allowed with other history-functions-set the default"),
22534e53048Schristos STR("bad parameters")
226a7db9a79Schristos };
227a7db9a79Schristos /* error codes */
228a7db9a79Schristos #define _HE_OK 0
229a7db9a79Schristos #define _HE_UNKNOWN 1
230a7db9a79Schristos #define _HE_MALLOC_FAILED 2
231a7db9a79Schristos #define _HE_FIRST_NOTFOUND 3
232a7db9a79Schristos #define _HE_LAST_NOTFOUND 4
233a7db9a79Schristos #define _HE_EMPTY_LIST 5
234a7db9a79Schristos #define _HE_END_REACHED 6
235a7db9a79Schristos #define _HE_START_REACHED 7
236a7db9a79Schristos #define _HE_CURR_INVALID 8
237a7db9a79Schristos #define _HE_NOT_FOUND 9
238a7db9a79Schristos #define _HE_HIST_READ 10
239a7db9a79Schristos #define _HE_HIST_WRITE 11
240a7db9a79Schristos #define _HE_PARAM_MISSING 12
241a7db9a79Schristos #define _HE_SIZE_NEGATIVE 13
242a7db9a79Schristos #define _HE_NOT_ALLOWED 14
243a7db9a79Schristos #define _HE_BAD_PARAM 15
2446dc2f1dbScgd
2456dc2f1dbScgd /* history_def_first():
2466dc2f1dbScgd * Default function to return the first event in the history.
2476dc2f1dbScgd */
248469d44f8Schristos static int
history_def_first(void * p,TYPE (HistEvent)* ev)249a13cd756Schristos history_def_first(void *p, TYPE(HistEvent) *ev)
2506dc2f1dbScgd {
2516dc2f1dbScgd history_t *h = (history_t *) p;
252a7db9a79Schristos
2536dc2f1dbScgd h->cursor = h->list.next;
2546dc2f1dbScgd if (h->cursor != &h->list)
255a7db9a79Schristos *ev = h->cursor->ev;
256a7db9a79Schristos else {
257a7db9a79Schristos he_seterrev(ev, _HE_FIRST_NOTFOUND);
258b71bed95Schristos return -1;
259a7db9a79Schristos }
260a7db9a79Schristos
261b71bed95Schristos return 0;
2626dc2f1dbScgd }
2636dc2f1dbScgd
264ccac6ba8Schristos
2656dc2f1dbScgd /* history_def_last():
2666dc2f1dbScgd * Default function to return the last event in the history.
2676dc2f1dbScgd */
268469d44f8Schristos static int
history_def_last(void * p,TYPE (HistEvent)* ev)269a13cd756Schristos history_def_last(void *p, TYPE(HistEvent) *ev)
2706dc2f1dbScgd {
2716dc2f1dbScgd history_t *h = (history_t *) p;
272a7db9a79Schristos
2736dc2f1dbScgd h->cursor = h->list.prev;
2746dc2f1dbScgd if (h->cursor != &h->list)
275a7db9a79Schristos *ev = h->cursor->ev;
276a7db9a79Schristos else {
277a7db9a79Schristos he_seterrev(ev, _HE_LAST_NOTFOUND);
278b71bed95Schristos return -1;
279a7db9a79Schristos }
280a7db9a79Schristos
281b71bed95Schristos return 0;
2826dc2f1dbScgd }
2836dc2f1dbScgd
284ccac6ba8Schristos
2856dc2f1dbScgd /* history_def_next():
2866dc2f1dbScgd * Default function to return the next event in the history.
2876dc2f1dbScgd */
288469d44f8Schristos static int
history_def_next(void * p,TYPE (HistEvent)* ev)289a13cd756Schristos history_def_next(void *p, TYPE(HistEvent) *ev)
2906dc2f1dbScgd {
2916dc2f1dbScgd history_t *h = (history_t *) p;
2926dc2f1dbScgd
2933bca82ecSchristos if (h->cursor == &h->list) {
294a7db9a79Schristos he_seterrev(ev, _HE_EMPTY_LIST);
295b71bed95Schristos return -1;
296a7db9a79Schristos }
2976dc2f1dbScgd
2983bca82ecSchristos if (h->cursor->next == &h->list) {
299a7db9a79Schristos he_seterrev(ev, _HE_END_REACHED);
300b71bed95Schristos return -1;
301a7db9a79Schristos }
302a7db9a79Schristos
3033bca82ecSchristos h->cursor = h->cursor->next;
3043bca82ecSchristos *ev = h->cursor->ev;
3053bca82ecSchristos
306b71bed95Schristos return 0;
3076dc2f1dbScgd }
3086dc2f1dbScgd
3096dc2f1dbScgd
3106dc2f1dbScgd /* history_def_prev():
3116dc2f1dbScgd * Default function to return the previous event in the history.
3126dc2f1dbScgd */
313469d44f8Schristos static int
history_def_prev(void * p,TYPE (HistEvent)* ev)314a13cd756Schristos history_def_prev(void *p, TYPE(HistEvent) *ev)
3156dc2f1dbScgd {
3166dc2f1dbScgd history_t *h = (history_t *) p;
3176dc2f1dbScgd
3183bca82ecSchristos if (h->cursor == &h->list) {
319d30d584aSlukem he_seterrev(ev,
320d30d584aSlukem (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST);
321b71bed95Schristos return -1;
322a7db9a79Schristos }
3236dc2f1dbScgd
3243bca82ecSchristos if (h->cursor->prev == &h->list) {
325a7db9a79Schristos he_seterrev(ev, _HE_START_REACHED);
326b71bed95Schristos return -1;
327a7db9a79Schristos }
328a7db9a79Schristos
3293bca82ecSchristos h->cursor = h->cursor->prev;
3303bca82ecSchristos *ev = h->cursor->ev;
3313bca82ecSchristos
332b71bed95Schristos return 0;
3336dc2f1dbScgd }
3346dc2f1dbScgd
3356dc2f1dbScgd
3366dc2f1dbScgd /* history_def_curr():
3376dc2f1dbScgd * Default function to return the current event in the history.
3386dc2f1dbScgd */
339469d44f8Schristos static int
history_def_curr(void * p,TYPE (HistEvent)* ev)340a13cd756Schristos history_def_curr(void *p, TYPE(HistEvent) *ev)
3416dc2f1dbScgd {
3426dc2f1dbScgd history_t *h = (history_t *) p;
3436dc2f1dbScgd
3446dc2f1dbScgd if (h->cursor != &h->list)
345a7db9a79Schristos *ev = h->cursor->ev;
346a7db9a79Schristos else {
347d30d584aSlukem he_seterrev(ev,
348d30d584aSlukem (h->cur > 0) ? _HE_CURR_INVALID : _HE_EMPTY_LIST);
349b71bed95Schristos return -1;
350a7db9a79Schristos }
351a7db9a79Schristos
352b71bed95Schristos return 0;
3536dc2f1dbScgd }
3546dc2f1dbScgd
355ccac6ba8Schristos
356ccac6ba8Schristos /* history_def_set():
357ccac6ba8Schristos * Default function to set the current event in the history to the
358ccac6ba8Schristos * given one.
359ccac6ba8Schristos */
360469d44f8Schristos static int
history_def_set(void * p,TYPE (HistEvent)* ev,const int n)361a13cd756Schristos history_def_set(void *p, TYPE(HistEvent) *ev, const int n)
362ccac6ba8Schristos {
363ccac6ba8Schristos history_t *h = (history_t *) p;
364ccac6ba8Schristos
365ccac6ba8Schristos if (h->cur == 0) {
366ccac6ba8Schristos he_seterrev(ev, _HE_EMPTY_LIST);
367b71bed95Schristos return -1;
368ccac6ba8Schristos }
369ccac6ba8Schristos if (h->cursor == &h->list || h->cursor->ev.num != n) {
370ccac6ba8Schristos for (h->cursor = h->list.next; h->cursor != &h->list;
371ccac6ba8Schristos h->cursor = h->cursor->next)
372ccac6ba8Schristos if (h->cursor->ev.num == n)
373ccac6ba8Schristos break;
374ccac6ba8Schristos }
375ccac6ba8Schristos if (h->cursor == &h->list) {
376ccac6ba8Schristos he_seterrev(ev, _HE_NOT_FOUND);
377b71bed95Schristos return -1;
378ccac6ba8Schristos }
379b71bed95Schristos return 0;
380ccac6ba8Schristos }
381ccac6ba8Schristos
382ccac6ba8Schristos
383ea3813edSchristos /* history_set_nth():
384ea3813edSchristos * Default function to set the current event in the history to the
385ea3813edSchristos * n-th one.
386ea3813edSchristos */
387469d44f8Schristos static int
history_set_nth(void * p,TYPE (HistEvent)* ev,int n)388a13cd756Schristos history_set_nth(void *p, TYPE(HistEvent) *ev, int n)
389ea3813edSchristos {
390ea3813edSchristos history_t *h = (history_t *) p;
391ea3813edSchristos
392ea3813edSchristos if (h->cur == 0) {
393ea3813edSchristos he_seterrev(ev, _HE_EMPTY_LIST);
394b71bed95Schristos return -1;
395ea3813edSchristos }
396ea3813edSchristos for (h->cursor = h->list.prev; h->cursor != &h->list;
397ea3813edSchristos h->cursor = h->cursor->prev)
398ea3813edSchristos if (n-- <= 0)
399ea3813edSchristos break;
400ea3813edSchristos if (h->cursor == &h->list) {
401ea3813edSchristos he_seterrev(ev, _HE_NOT_FOUND);
402b71bed95Schristos return -1;
403ea3813edSchristos }
404b71bed95Schristos return 0;
405ea3813edSchristos }
406ea3813edSchristos
407ea3813edSchristos
4086dc2f1dbScgd /* history_def_add():
4096dc2f1dbScgd * Append string to element
4106dc2f1dbScgd */
411469d44f8Schristos static int
history_def_add(void * p,TYPE (HistEvent)* ev,const Char * str)412a13cd756Schristos history_def_add(void *p, TYPE(HistEvent) *ev, const Char *str)
4136dc2f1dbScgd {
4146dc2f1dbScgd history_t *h = (history_t *) p;
415991f6216Schristos size_t len, elen, slen;
41634e53048Schristos Char *s;
4170e0ac6b7Schristos HistEventPrivate *evp = (void *)&h->cursor->ev;
4186dc2f1dbScgd
4196dc2f1dbScgd if (h->cursor == &h->list)
420b71bed95Schristos return history_def_enter(p, ev, str);
421991f6216Schristos elen = Strlen(evp->str);
422991f6216Schristos slen = Strlen(str);
423991f6216Schristos len = elen + slen + 1;
42434e53048Schristos s = h_malloc(len * sizeof(*s));
425e6ee0301Schristos if (s == NULL) {
426a7db9a79Schristos he_seterrev(ev, _HE_MALLOC_FAILED);
427b71bed95Schristos return -1;
428a7db9a79Schristos }
429991f6216Schristos memcpy(s, evp->str, elen * sizeof(*s));
430991f6216Schristos memcpy(s + elen, str, slen * sizeof(*s));
43134e53048Schristos s[len - 1] = '\0';
432a13cd756Schristos h_free(evp->str);
4330e0ac6b7Schristos evp->str = s;
434a7db9a79Schristos *ev = h->cursor->ev;
435b71bed95Schristos return 0;
4366dc2f1dbScgd }
4376dc2f1dbScgd
4386dc2f1dbScgd
439469d44f8Schristos static int
history_deldata_nth(history_t * h,TYPE (HistEvent)* ev,int num,void ** data)44034e53048Schristos history_deldata_nth(history_t *h, TYPE(HistEvent) *ev,
441ea3813edSchristos int num, void **data)
442ea3813edSchristos {
443ea3813edSchristos if (history_set_nth(h, ev, num) != 0)
444b71bed95Schristos return -1;
445ea3813edSchristos /* magic value to skip delete (just set to n-th history) */
446ea3813edSchristos if (data == (void **)-1)
447b71bed95Schristos return 0;
44834e53048Schristos ev->str = Strdup(h->cursor->ev.str);
449ea3813edSchristos ev->num = h->cursor->ev.num;
450ea3813edSchristos if (data)
451ea3813edSchristos *data = h->cursor->data;
452ea3813edSchristos history_def_delete(h, ev, h->cursor);
453b71bed95Schristos return 0;
454ea3813edSchristos }
455ea3813edSchristos
456ea3813edSchristos
45745542456Schristos /* history_def_del():
45845542456Schristos * Delete element hp of the h list
45945542456Schristos */
46045542456Schristos /* ARGSUSED */
461469d44f8Schristos static int
history_def_del(void * p,TYPE (HistEvent)* ev,const int num)462a13cd756Schristos history_def_del(void *p, TYPE(HistEvent) *ev __attribute__((__unused__)),
46345542456Schristos const int num)
46445542456Schristos {
46545542456Schristos history_t *h = (history_t *) p;
46645542456Schristos if (history_def_set(h, ev, num) != 0)
467b71bed95Schristos return -1;
46834e53048Schristos ev->str = Strdup(h->cursor->ev.str);
46945542456Schristos ev->num = h->cursor->ev.num;
47045542456Schristos history_def_delete(h, ev, h->cursor);
471b71bed95Schristos return 0;
47245542456Schristos }
47345542456Schristos
47445542456Schristos
4756dc2f1dbScgd /* history_def_delete():
4766dc2f1dbScgd * Delete element hp of the h list
4776dc2f1dbScgd */
47861df62e6Schristos /* ARGSUSED */
479469d44f8Schristos static void
history_def_delete(history_t * h,TYPE (HistEvent)* ev,hentry_t * hp)480839ca00bSchristos history_def_delete(history_t *h,
48134e53048Schristos TYPE(HistEvent) *ev __attribute__((__unused__)), hentry_t *hp)
4826dc2f1dbScgd {
4830e0ac6b7Schristos HistEventPrivate *evp = (void *)&hp->ev;
4846dc2f1dbScgd if (hp == &h->list)
4856dc2f1dbScgd abort();
486ea3813edSchristos if (h->cursor == hp) {
48745542456Schristos h->cursor = hp->prev;
488ea3813edSchristos if (h->cursor == &h->list)
489ea3813edSchristos h->cursor = hp->next;
490ea3813edSchristos }
4916dc2f1dbScgd hp->prev->next = hp->next;
4926dc2f1dbScgd hp->next->prev = hp->prev;
493a13cd756Schristos h_free(evp->str);
4946dc2f1dbScgd h_free(hp);
4956dc2f1dbScgd h->cur--;
4966dc2f1dbScgd }
4976dc2f1dbScgd
4986dc2f1dbScgd
4996dc2f1dbScgd /* history_def_insert():
5006dc2f1dbScgd * Insert element with string str in the h list
5016dc2f1dbScgd */
502469d44f8Schristos static int
history_def_insert(history_t * h,TYPE (HistEvent)* ev,const Char * str)50334e53048Schristos history_def_insert(history_t *h, TYPE(HistEvent) *ev, const Char *str)
5046dc2f1dbScgd {
50532d7653dSchristos hentry_t *c;
506d30d584aSlukem
50732d7653dSchristos c = h_malloc(sizeof(*c));
50832d7653dSchristos if (c == NULL)
509e6ee0301Schristos goto oomem;
51032d7653dSchristos if ((c->ev.str = h_strdup(str)) == NULL) {
511a13cd756Schristos h_free(c);
512e6ee0301Schristos goto oomem;
513a7db9a79Schristos }
51432d7653dSchristos c->data = NULL;
51532d7653dSchristos c->ev.num = ++h->eventid;
51632d7653dSchristos c->next = h->list.next;
51732d7653dSchristos c->prev = &h->list;
51832d7653dSchristos h->list.next->prev = c;
51932d7653dSchristos h->list.next = c;
5206dc2f1dbScgd h->cur++;
52132d7653dSchristos h->cursor = c;
5226dc2f1dbScgd
52332d7653dSchristos *ev = c->ev;
524b71bed95Schristos return 0;
525e6ee0301Schristos oomem:
526e6ee0301Schristos he_seterrev(ev, _HE_MALLOC_FAILED);
527b71bed95Schristos return -1;
5286dc2f1dbScgd }
5296dc2f1dbScgd
5306dc2f1dbScgd
5316dc2f1dbScgd /* history_def_enter():
5326dc2f1dbScgd * Default function to enter an item in the history
5336dc2f1dbScgd */
534469d44f8Schristos static int
history_def_enter(void * p,TYPE (HistEvent)* ev,const Char * str)535a13cd756Schristos history_def_enter(void *p, TYPE(HistEvent) *ev, const Char *str)
5366dc2f1dbScgd {
5376dc2f1dbScgd history_t *h = (history_t *) p;
5386dc2f1dbScgd
539f24857bfSchristos if ((h->flags & H_UNIQUE) != 0 && h->list.next != &h->list &&
54034e53048Schristos Strcmp(h->list.next->ev.str, str) == 0)
541b71bed95Schristos return 0;
542f24857bfSchristos
543a7db9a79Schristos if (history_def_insert(h, ev, str) == -1)
544b71bed95Schristos return -1; /* error, keep error message */
5456dc2f1dbScgd
5466dc2f1dbScgd /*
5476dc2f1dbScgd * Always keep at least one entry.
5486dc2f1dbScgd * This way we don't have to check for the empty list.
5496dc2f1dbScgd */
550e7e71e37Sjdolecek while (h->cur > h->max && h->cur > 0)
551a7db9a79Schristos history_def_delete(h, ev, h->list.prev);
552a7db9a79Schristos
553b71bed95Schristos return 1;
5546dc2f1dbScgd }
5556dc2f1dbScgd
5566dc2f1dbScgd
5576dc2f1dbScgd /* history_def_init():
5586dc2f1dbScgd * Default history initialization function
5596dc2f1dbScgd */
56061df62e6Schristos /* ARGSUSED */
561469d44f8Schristos static int
history_def_init(void ** p,TYPE (HistEvent)* ev,int n)562a13cd756Schristos history_def_init(void **p, TYPE(HistEvent) *ev __attribute__((__unused__)), int n)
5636dc2f1dbScgd {
564a13cd756Schristos history_t *h = (history_t *) h_malloc(sizeof(*h));
565e6ee0301Schristos if (h == NULL)
566e6ee0301Schristos return -1;
567d30d584aSlukem
5686dc2f1dbScgd if (n <= 0)
5696dc2f1dbScgd n = 0;
570a7db9a79Schristos h->eventid = 0;
5716dc2f1dbScgd h->cur = 0;
5726dc2f1dbScgd h->max = n;
5736dc2f1dbScgd h->list.next = h->list.prev = &h->list;
5746dc2f1dbScgd h->list.ev.str = NULL;
5756dc2f1dbScgd h->list.ev.num = 0;
5766dc2f1dbScgd h->cursor = &h->list;
577f24857bfSchristos h->flags = 0;
578a13cd756Schristos *p = h;
579e6ee0301Schristos return 0;
5806dc2f1dbScgd }
5816dc2f1dbScgd
5826dc2f1dbScgd
58395b0e87bSchristos /* history_def_clear():
5846dc2f1dbScgd * Default history cleanup function
5856dc2f1dbScgd */
586469d44f8Schristos static void
history_def_clear(void * p,TYPE (HistEvent)* ev)587a13cd756Schristos history_def_clear(void *p, TYPE(HistEvent) *ev)
5886dc2f1dbScgd {
5896dc2f1dbScgd history_t *h = (history_t *) p;
5906dc2f1dbScgd
5916dc2f1dbScgd while (h->list.prev != &h->list)
592a7db9a79Schristos history_def_delete(h, ev, h->list.prev);
59332d7653dSchristos h->cursor = &h->list;
594a7db9a79Schristos h->eventid = 0;
59595b0e87bSchristos h->cur = 0;
5966dc2f1dbScgd }
5976dc2f1dbScgd
59895b0e87bSchristos
59995b0e87bSchristos
60095b0e87bSchristos
6016dc2f1dbScgd /************************************************************************/
6026dc2f1dbScgd
6036dc2f1dbScgd /* history_init():
6046dc2f1dbScgd * Initialization function.
6056dc2f1dbScgd */
TYPE(History)606469d44f8Schristos TYPE(History) *
60734e53048Schristos FUN(history,init)(void)
6086dc2f1dbScgd {
60934e53048Schristos TYPE(HistEvent) ev;
610a13cd756Schristos TYPE(History) *h = (TYPE(History) *) h_malloc(sizeof(*h));
611e6ee0301Schristos if (h == NULL)
612e6ee0301Schristos return NULL;
6136dc2f1dbScgd
614e6ee0301Schristos if (history_def_init(&h->h_ref, &ev, 0) == -1) {
615a13cd756Schristos h_free(h);
616e6ee0301Schristos return NULL;
617e6ee0301Schristos }
618eac8b136Schristos h->h_ent = -1;
6196dc2f1dbScgd h->h_next = history_def_next;
6206dc2f1dbScgd h->h_first = history_def_first;
6216dc2f1dbScgd h->h_last = history_def_last;
6226dc2f1dbScgd h->h_prev = history_def_prev;
6236dc2f1dbScgd h->h_curr = history_def_curr;
624ccac6ba8Schristos h->h_set = history_def_set;
62595b0e87bSchristos h->h_clear = history_def_clear;
6266dc2f1dbScgd h->h_enter = history_def_enter;
6276dc2f1dbScgd h->h_add = history_def_add;
628ee399edcSchristos h->h_del = history_def_del;
6296dc2f1dbScgd
630b71bed95Schristos return h;
6316dc2f1dbScgd }
6326dc2f1dbScgd
6336dc2f1dbScgd
6346dc2f1dbScgd /* history_end():
6356dc2f1dbScgd * clean up history;
6366dc2f1dbScgd */
637469d44f8Schristos void
FUN(history,end)63834e53048Schristos FUN(history,end)(TYPE(History) *h)
6396dc2f1dbScgd {
64034e53048Schristos TYPE(HistEvent) ev;
641d30d584aSlukem
6426dc2f1dbScgd if (h->h_next == history_def_next)
643a7db9a79Schristos history_def_clear(h->h_ref, &ev);
644d9590bcaSchristos h_free(h->h_ref);
64532bff6afSchristos h_free(h);
6466dc2f1dbScgd }
6476dc2f1dbScgd
6486dc2f1dbScgd
6496dc2f1dbScgd
65084ee55f1Schristos /* history_setsize():
6516dc2f1dbScgd * Set history number of events
6526dc2f1dbScgd */
653469d44f8Schristos static int
history_setsize(TYPE (History)* h,TYPE (HistEvent)* ev,int num)65434e53048Schristos history_setsize(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
6556dc2f1dbScgd {
656d30d584aSlukem
657a7db9a79Schristos if (h->h_next != history_def_next) {
658a7db9a79Schristos he_seterrev(ev, _HE_NOT_ALLOWED);
659b71bed95Schristos return -1;
660a7db9a79Schristos }
661a7db9a79Schristos if (num < 0) {
662a7db9a79Schristos he_seterrev(ev, _HE_BAD_PARAM);
663b71bed95Schristos return -1;
664d30d584aSlukem }
665d30d584aSlukem history_def_setsize(h->h_ref, num);
666b71bed95Schristos return 0;
667a7db9a79Schristos }
668a7db9a79Schristos
6696dc2f1dbScgd
67084ee55f1Schristos /* history_getsize():
671a7db9a79Schristos * Get number of events currently in history
672a7db9a79Schristos */
673469d44f8Schristos static int
history_getsize(TYPE (History)* h,TYPE (HistEvent)* ev)67434e53048Schristos history_getsize(TYPE(History) *h, TYPE(HistEvent) *ev)
675a7db9a79Schristos {
676f24857bfSchristos if (h->h_next != history_def_next) {
677f24857bfSchristos he_seterrev(ev, _HE_NOT_ALLOWED);
678b71bed95Schristos return -1;
679f24857bfSchristos }
680f24857bfSchristos ev->num = history_def_getsize(h->h_ref);
681f24857bfSchristos if (ev->num < -1) {
682f24857bfSchristos he_seterrev(ev, _HE_SIZE_NEGATIVE);
683b71bed95Schristos return -1;
684f24857bfSchristos }
685b71bed95Schristos return 0;
686f24857bfSchristos }
687f24857bfSchristos
688f24857bfSchristos
689f24857bfSchristos /* history_setunique():
690f24857bfSchristos * Set if adjacent equal events should not be entered in history.
691f24857bfSchristos */
692469d44f8Schristos static int
history_setunique(TYPE (History)* h,TYPE (HistEvent)* ev,int uni)69334e53048Schristos history_setunique(TYPE(History) *h, TYPE(HistEvent) *ev, int uni)
694f24857bfSchristos {
695a7db9a79Schristos
696a7db9a79Schristos if (h->h_next != history_def_next) {
697a7db9a79Schristos he_seterrev(ev, _HE_NOT_ALLOWED);
698b71bed95Schristos return -1;
699a7db9a79Schristos }
700f24857bfSchristos history_def_setunique(h->h_ref, uni);
701b71bed95Schristos return 0;
702f24857bfSchristos }
703f24857bfSchristos
704f24857bfSchristos
705f24857bfSchristos /* history_getunique():
706f24857bfSchristos * Get if adjacent equal events should not be entered in history.
707f24857bfSchristos */
708469d44f8Schristos static int
history_getunique(TYPE (History)* h,TYPE (HistEvent)* ev)70934e53048Schristos history_getunique(TYPE(History) *h, TYPE(HistEvent) *ev)
710f24857bfSchristos {
711f24857bfSchristos if (h->h_next != history_def_next) {
712f24857bfSchristos he_seterrev(ev, _HE_NOT_ALLOWED);
713b71bed95Schristos return -1;
714d30d584aSlukem }
715f24857bfSchristos ev->num = history_def_getunique(h->h_ref);
716b71bed95Schristos return 0;
717a7db9a79Schristos }
718a7db9a79Schristos
7196dc2f1dbScgd
7206dc2f1dbScgd /* history_set_fun():
7216dc2f1dbScgd * Set history functions
7226dc2f1dbScgd */
723469d44f8Schristos static int
history_set_fun(TYPE (History)* h,TYPE (History)* nh)72434e53048Schristos history_set_fun(TYPE(History) *h, TYPE(History) *nh)
7256dc2f1dbScgd {
72634e53048Schristos TYPE(HistEvent) ev;
727a7db9a79Schristos
728ccac6ba8Schristos if (nh->h_first == NULL || nh->h_next == NULL || nh->h_last == NULL ||
729ccac6ba8Schristos nh->h_prev == NULL || nh->h_curr == NULL || nh->h_set == NULL ||
73095b0e87bSchristos nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL ||
73145542456Schristos nh->h_del == NULL || nh->h_ref == NULL) {
7326dc2f1dbScgd if (h->h_next != history_def_next) {
733ae5295eeSchristos if (history_def_init(&h->h_ref, &ev, 0) == -1)
734ae5295eeSchristos return -1;
7356dc2f1dbScgd h->h_first = history_def_first;
7366dc2f1dbScgd h->h_next = history_def_next;
7376dc2f1dbScgd h->h_last = history_def_last;
7386dc2f1dbScgd h->h_prev = history_def_prev;
7396dc2f1dbScgd h->h_curr = history_def_curr;
740ccac6ba8Schristos h->h_set = history_def_set;
74195b0e87bSchristos h->h_clear = history_def_clear;
7426dc2f1dbScgd h->h_enter = history_def_enter;
7436dc2f1dbScgd h->h_add = history_def_add;
74445542456Schristos h->h_del = history_def_del;
7456dc2f1dbScgd }
746b71bed95Schristos return -1;
7476dc2f1dbScgd }
7486dc2f1dbScgd if (h->h_next == history_def_next)
749a7db9a79Schristos history_def_clear(h->h_ref, &ev);
7506dc2f1dbScgd
751eac8b136Schristos h->h_ent = -1;
75295b0e87bSchristos h->h_first = nh->h_first;
75395b0e87bSchristos h->h_next = nh->h_next;
75495b0e87bSchristos h->h_last = nh->h_last;
75595b0e87bSchristos h->h_prev = nh->h_prev;
75695b0e87bSchristos h->h_curr = nh->h_curr;
757ccac6ba8Schristos h->h_set = nh->h_set;
75895b0e87bSchristos h->h_clear = nh->h_clear;
75995b0e87bSchristos h->h_enter = nh->h_enter;
76095b0e87bSchristos h->h_add = nh->h_add;
76145542456Schristos h->h_del = nh->h_del;
76295b0e87bSchristos
763b71bed95Schristos return 0;
7646dc2f1dbScgd }
7656dc2f1dbScgd
7666dc2f1dbScgd
76795b0e87bSchristos /* history_load():
76834e53048Schristos * TYPE(History) load function
76995b0e87bSchristos */
770469d44f8Schristos static int
history_load(TYPE (History)* h,const char * fname)77134e53048Schristos history_load(TYPE(History) *h, const char *fname)
77295b0e87bSchristos {
77395b0e87bSchristos FILE *fp;
77495b0e87bSchristos char *line;
775a7ab79fbSchristos size_t llen;
776a7ab79fbSchristos ssize_t sz;
777a7ab79fbSchristos size_t max_size;
77884ee55f1Schristos char *ptr;
77995b0e87bSchristos int i = -1;
78034e53048Schristos TYPE(HistEvent) ev;
7816da79ee0Schristos Char *decode_result;
7824e541d85Schristos #ifndef NARROWCHAR
7830b9ae3fdSchristos static ct_buffer_t conv;
78434e53048Schristos #endif
78595b0e87bSchristos
78695b0e87bSchristos if ((fp = fopen(fname, "r")) == NULL)
787b71bed95Schristos return i;
78895b0e87bSchristos
789a7ab79fbSchristos line = NULL;
790a7ab79fbSchristos llen = 0;
791a7ab79fbSchristos if ((sz = getline(&line, &llen, fp)) == -1)
79295b0e87bSchristos goto done;
79395b0e87bSchristos
794a7ab79fbSchristos if (strncmp(line, hist_cookie, (size_t)sz) != 0)
79595b0e87bSchristos goto done;
79695b0e87bSchristos
797a13cd756Schristos ptr = h_malloc((max_size = 1024) * sizeof(*ptr));
798e6ee0301Schristos if (ptr == NULL)
799e6ee0301Schristos goto done;
800a7ab79fbSchristos for (i = 0; (sz = getline(&line, &llen, fp)) != -1; i++) {
801a7ab79fbSchristos if (sz > 0 && line[sz - 1] == '\n')
802a7ab79fbSchristos line[--sz] = '\0';
803a7ab79fbSchristos if (max_size < (size_t)sz) {
804e6ee0301Schristos char *nptr;
805a7ab79fbSchristos max_size = ((size_t)sz + 1024) & (size_t)~1023;
806a13cd756Schristos nptr = h_realloc(ptr, max_size * sizeof(*ptr));
807e6ee0301Schristos if (nptr == NULL) {
808e6ee0301Schristos i = -1;
809e6ee0301Schristos goto oomem;
810e6ee0301Schristos }
811e6ee0301Schristos ptr = nptr;
81295b0e87bSchristos }
81384ee55f1Schristos (void) strunvis(ptr, line);
8146da79ee0Schristos decode_result = ct_decode_string(ptr, &conv);
8156da79ee0Schristos if (decode_result == NULL)
8166da79ee0Schristos continue;
817b8b0289dSkre if (HENTER(h, &ev, decode_result) == -1) {
818fe96b18cSsketch i = -1;
819fe96b18cSsketch goto oomem;
82084ee55f1Schristos }
821e6ee0301Schristos }
822e6ee0301Schristos oomem:
823a13cd756Schristos h_free(ptr);
82495b0e87bSchristos done:
82587240809Schristos free(line);
82695b0e87bSchristos (void) fclose(fp);
827b71bed95Schristos return i;
82895b0e87bSchristos }
82995b0e87bSchristos
83095b0e87bSchristos
83158ced3d7Schristos /* history_save_fp():
83234e53048Schristos * TYPE(History) save function
83395b0e87bSchristos */
834469d44f8Schristos static int
history_save_fp(TYPE (History)* h,size_t nelem,FILE * fp)83527916d7cSchristos history_save_fp(TYPE(History) *h, size_t nelem, FILE *fp)
83695b0e87bSchristos {
83734e53048Schristos TYPE(HistEvent) ev;
838e6ee0301Schristos int i = -1, retval;
83984ee55f1Schristos size_t len, max_size;
8405bf2e3dbSchristos char *ptr;
8415bf2e3dbSchristos const char *str;
8424e541d85Schristos #ifndef NARROWCHAR
8430b9ae3fdSchristos static ct_buffer_t conv;
84434e53048Schristos #endif
84584ee55f1Schristos
84627916d7cSchristos if (ftell(fp) == 0 && fputs(hist_cookie, fp) == EOF)
847e6ee0301Schristos goto done;
848a13cd756Schristos ptr = h_malloc((max_size = 1024) * sizeof(*ptr));
849e6ee0301Schristos if (ptr == NULL)
850e6ee0301Schristos goto done;
85127916d7cSchristos if (nelem != (size_t)-1) {
85227916d7cSchristos for (retval = HFIRST(h, &ev); retval != -1 && nelem-- > 0;
85327916d7cSchristos retval = HNEXT(h, &ev))
85427916d7cSchristos continue;
85527916d7cSchristos } else
85627916d7cSchristos retval = -1;
85727916d7cSchristos
85827916d7cSchristos if (retval == -1)
85927916d7cSchristos retval = HLAST(h, &ev);
86027916d7cSchristos
86127916d7cSchristos for (i = 0; retval != -1; retval = HPREV(h, &ev), i++) {
86232d7653dSchristos str = ct_encode_string(ev.str, &conv);
863c8255363Schristos len = strlen(str) * 4 + 1;
864c8255363Schristos if (len > max_size) {
865e6ee0301Schristos char *nptr;
866c11bd863Schristos max_size = (len + 1024) & (size_t)~1023;
867a13cd756Schristos nptr = h_realloc(ptr, max_size * sizeof(*ptr));
868e6ee0301Schristos if (nptr == NULL) {
869e6ee0301Schristos i = -1;
870e6ee0301Schristos goto oomem;
871e6ee0301Schristos }
872e6ee0301Schristos ptr = nptr;
87384ee55f1Schristos }
87432d7653dSchristos (void) strvis(ptr, str, VIS_WHITE);
8754a964eafSchristos (void) fprintf(fp, "%s\n", ptr);
87684ee55f1Schristos }
877e6ee0301Schristos oomem:
878a13cd756Schristos h_free(ptr);
879e6ee0301Schristos done:
88058ced3d7Schristos return i;
88158ced3d7Schristos }
88258ced3d7Schristos
88358ced3d7Schristos
88458ced3d7Schristos /* history_save():
88558ced3d7Schristos * History save function
88658ced3d7Schristos */
887469d44f8Schristos static int
history_save(TYPE (History)* h,const char * fname)88858ced3d7Schristos history_save(TYPE(History) *h, const char *fname)
88958ced3d7Schristos {
89058ced3d7Schristos FILE *fp;
89158ced3d7Schristos int i;
89258ced3d7Schristos
893*4d36c519Skre if ((i = open(fname, O_WRONLY|O_CREAT|O_TRUNC,
894*4d36c519Skre S_IRUSR|S_IWUSR)) == -1)
895*4d36c519Skre return -1;
896*4d36c519Skre
897*4d36c519Skre if ((fp = fdopen(i, "w")) == NULL)
89858ced3d7Schristos return -1;
89958ced3d7Schristos
90027916d7cSchristos i = history_save_fp(h, (size_t)-1, fp);
90158ced3d7Schristos
90295b0e87bSchristos (void) fclose(fp);
903b71bed95Schristos return i;
90495b0e87bSchristos }
90595b0e87bSchristos
90695b0e87bSchristos
9076dc2f1dbScgd /* history_prev_event():
9086dc2f1dbScgd * Find the previous event, with number given
9096dc2f1dbScgd */
910469d44f8Schristos static int
history_prev_event(TYPE (History)* h,TYPE (HistEvent)* ev,int num)91134e53048Schristos history_prev_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
9126dc2f1dbScgd {
913a7db9a79Schristos int retval;
914d30d584aSlukem
915a7db9a79Schristos for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
9166dc2f1dbScgd if (ev->num == num)
917b71bed95Schristos return 0;
918a7db9a79Schristos
919a7db9a79Schristos he_seterrev(ev, _HE_NOT_FOUND);
920b71bed95Schristos return -1;
9216dc2f1dbScgd }
9226dc2f1dbScgd
9236dc2f1dbScgd
924469d44f8Schristos static int
history_next_evdata(TYPE (History)* h,TYPE (HistEvent)* ev,int num,void ** d)92534e53048Schristos history_next_evdata(TYPE(History) *h, TYPE(HistEvent) *ev, int num, void **d)
926ea3813edSchristos {
927ea3813edSchristos int retval;
928ea3813edSchristos
929ea3813edSchristos for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
9307350622eSchristos if (ev->num == num) {
931ea3813edSchristos if (d)
932ea3813edSchristos *d = ((history_t *)h->h_ref)->cursor->data;
933b71bed95Schristos return 0;
934ea3813edSchristos }
935ea3813edSchristos
936ea3813edSchristos he_seterrev(ev, _HE_NOT_FOUND);
937b71bed95Schristos return -1;
938ea3813edSchristos }
939ea3813edSchristos
940ea3813edSchristos
9416dc2f1dbScgd /* history_next_event():
9426dc2f1dbScgd * Find the next event, with number given
9436dc2f1dbScgd */
944469d44f8Schristos static int
history_next_event(TYPE (History)* h,TYPE (HistEvent)* ev,int num)94534e53048Schristos history_next_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
9466dc2f1dbScgd {
947a7db9a79Schristos int retval;
948d30d584aSlukem
949a7db9a79Schristos for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
9506dc2f1dbScgd if (ev->num == num)
951b71bed95Schristos return 0;
952a7db9a79Schristos
953a7db9a79Schristos he_seterrev(ev, _HE_NOT_FOUND);
954b71bed95Schristos return -1;
9556dc2f1dbScgd }
9566dc2f1dbScgd
9576dc2f1dbScgd
9586dc2f1dbScgd /* history_prev_string():
9596dc2f1dbScgd * Find the previous event beginning with string
9606dc2f1dbScgd */
961469d44f8Schristos static int
history_prev_string(TYPE (History)* h,TYPE (HistEvent)* ev,const Char * str)96234e53048Schristos history_prev_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str)
9636dc2f1dbScgd {
96434e53048Schristos size_t len = Strlen(str);
965a7db9a79Schristos int retval;
9666dc2f1dbScgd
967a7db9a79Schristos for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
96834e53048Schristos if (Strncmp(str, ev->str, len) == 0)
969b71bed95Schristos return 0;
970a7db9a79Schristos
971a7db9a79Schristos he_seterrev(ev, _HE_NOT_FOUND);
972b71bed95Schristos return -1;
9736dc2f1dbScgd }
9746dc2f1dbScgd
9756dc2f1dbScgd
9766dc2f1dbScgd /* history_next_string():
9776dc2f1dbScgd * Find the next event beginning with string
9786dc2f1dbScgd */
979469d44f8Schristos static int
history_next_string(TYPE (History)* h,TYPE (HistEvent)* ev,const Char * str)98034e53048Schristos history_next_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str)
9816dc2f1dbScgd {
98234e53048Schristos size_t len = Strlen(str);
983a7db9a79Schristos int retval;
9846dc2f1dbScgd
985a7db9a79Schristos for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
98634e53048Schristos if (Strncmp(str, ev->str, len) == 0)
987b71bed95Schristos return 0;
988a7db9a79Schristos
989a7db9a79Schristos he_seterrev(ev, _HE_NOT_FOUND);
990b71bed95Schristos return -1;
9916dc2f1dbScgd }
9926dc2f1dbScgd
9936dc2f1dbScgd
9946dc2f1dbScgd /* history():
9956dc2f1dbScgd * User interface to history functions.
9966dc2f1dbScgd */
997a7db9a79Schristos int
FUNW(history)99834e53048Schristos FUNW(history)(TYPE(History) *h, TYPE(HistEvent) *ev, int fun, ...)
9996dc2f1dbScgd {
10006dc2f1dbScgd va_list va;
100134e53048Schristos const Char *str;
1002a7db9a79Schristos int retval;
10036dc2f1dbScgd
10046dc2f1dbScgd va_start(va, fun);
10056dc2f1dbScgd
1006a7db9a79Schristos he_seterrev(ev, _HE_OK);
1007a7db9a79Schristos
10086dc2f1dbScgd switch (fun) {
1009ccac6ba8Schristos case H_GETSIZE:
101084ee55f1Schristos retval = history_getsize(h, ev);
1011ccac6ba8Schristos break;
1012ccac6ba8Schristos
1013ccac6ba8Schristos case H_SETSIZE:
101484ee55f1Schristos retval = history_setsize(h, ev, va_arg(va, int));
1015ccac6ba8Schristos break;
1016ccac6ba8Schristos
1017f24857bfSchristos case H_GETUNIQUE:
1018f24857bfSchristos retval = history_getunique(h, ev);
1019f24857bfSchristos break;
1020f24857bfSchristos
1021f24857bfSchristos case H_SETUNIQUE:
1022f24857bfSchristos retval = history_setunique(h, ev, va_arg(va, int));
1023f24857bfSchristos break;
1024f24857bfSchristos
10256dc2f1dbScgd case H_ADD:
102634e53048Schristos str = va_arg(va, const Char *);
1027a7db9a79Schristos retval = HADD(h, ev, str);
10286dc2f1dbScgd break;
10296dc2f1dbScgd
103045542456Schristos case H_DEL:
103145542456Schristos retval = HDEL(h, ev, va_arg(va, const int));
103245542456Schristos break;
103345542456Schristos
10346dc2f1dbScgd case H_ENTER:
103534e53048Schristos str = va_arg(va, const Char *);
1036eac8b136Schristos if ((retval = HENTER(h, ev, str)) != -1)
1037eac8b136Schristos h->h_ent = ev->num;
1038eac8b136Schristos break;
1039eac8b136Schristos
1040eac8b136Schristos case H_APPEND:
104134e53048Schristos str = va_arg(va, const Char *);
1042eac8b136Schristos if ((retval = HSET(h, ev, h->h_ent)) != -1)
1043eac8b136Schristos retval = HADD(h, ev, str);
10446dc2f1dbScgd break;
10456dc2f1dbScgd
10466dc2f1dbScgd case H_FIRST:
1047a7db9a79Schristos retval = HFIRST(h, ev);
10486dc2f1dbScgd break;
10496dc2f1dbScgd
10506dc2f1dbScgd case H_NEXT:
1051a7db9a79Schristos retval = HNEXT(h, ev);
10526dc2f1dbScgd break;
10536dc2f1dbScgd
10546dc2f1dbScgd case H_LAST:
1055a7db9a79Schristos retval = HLAST(h, ev);
10566dc2f1dbScgd break;
10576dc2f1dbScgd
10586dc2f1dbScgd case H_PREV:
1059a7db9a79Schristos retval = HPREV(h, ev);
10606dc2f1dbScgd break;
10616dc2f1dbScgd
10626dc2f1dbScgd case H_CURR:
1063a7db9a79Schristos retval = HCURR(h, ev);
10646dc2f1dbScgd break;
10656dc2f1dbScgd
1066ccac6ba8Schristos case H_SET:
1067ccac6ba8Schristos retval = HSET(h, ev, va_arg(va, const int));
1068ccac6ba8Schristos break;
1069ccac6ba8Schristos
107095b0e87bSchristos case H_CLEAR:
1071a7db9a79Schristos HCLEAR(h, ev);
1072a7db9a79Schristos retval = 0;
107395b0e87bSchristos break;
107495b0e87bSchristos
107595b0e87bSchristos case H_LOAD:
1076a7db9a79Schristos retval = history_load(h, va_arg(va, const char *));
1077a7db9a79Schristos if (retval == -1)
1078a7db9a79Schristos he_seterrev(ev, _HE_HIST_READ);
107995b0e87bSchristos break;
108095b0e87bSchristos
108195b0e87bSchristos case H_SAVE:
1082a7db9a79Schristos retval = history_save(h, va_arg(va, const char *));
1083a7db9a79Schristos if (retval == -1)
1084a7db9a79Schristos he_seterrev(ev, _HE_HIST_WRITE);
108595b0e87bSchristos break;
108695b0e87bSchristos
108758ced3d7Schristos case H_SAVE_FP:
108827916d7cSchristos retval = history_save_fp(h, (size_t)-1, va_arg(va, FILE *));
108927916d7cSchristos if (retval == -1)
109027916d7cSchristos he_seterrev(ev, _HE_HIST_WRITE);
109127916d7cSchristos break;
109227916d7cSchristos
109327916d7cSchristos case H_NSAVE_FP:
1094ec59efb2Suwe {
1095ec59efb2Suwe size_t sz = va_arg(va, size_t);
1096ec59efb2Suwe retval = history_save_fp(h, sz, va_arg(va, FILE *));
109758ced3d7Schristos if (retval == -1)
109858ced3d7Schristos he_seterrev(ev, _HE_HIST_WRITE);
109958ced3d7Schristos break;
1100ec59efb2Suwe }
110158ced3d7Schristos
11026dc2f1dbScgd case H_PREV_EVENT:
1103a7db9a79Schristos retval = history_prev_event(h, ev, va_arg(va, int));
11046dc2f1dbScgd break;
11056dc2f1dbScgd
11066dc2f1dbScgd case H_NEXT_EVENT:
1107a7db9a79Schristos retval = history_next_event(h, ev, va_arg(va, int));
11086dc2f1dbScgd break;
11096dc2f1dbScgd
11106dc2f1dbScgd case H_PREV_STR:
111134e53048Schristos retval = history_prev_string(h, ev, va_arg(va, const Char *));
11126dc2f1dbScgd break;
11136dc2f1dbScgd
11146dc2f1dbScgd case H_NEXT_STR:
111534e53048Schristos retval = history_next_string(h, ev, va_arg(va, const Char *));
11166dc2f1dbScgd break;
11176dc2f1dbScgd
11186dc2f1dbScgd case H_FUNC:
11196dc2f1dbScgd {
112034e53048Schristos TYPE(History) hf;
1121ccac6ba8Schristos
1122a13cd756Schristos hf.h_ref = va_arg(va, void *);
1123eac8b136Schristos h->h_ent = -1;
112495b0e87bSchristos hf.h_first = va_arg(va, history_gfun_t);
112595b0e87bSchristos hf.h_next = va_arg(va, history_gfun_t);
112695b0e87bSchristos hf.h_last = va_arg(va, history_gfun_t);
112795b0e87bSchristos hf.h_prev = va_arg(va, history_gfun_t);
112895b0e87bSchristos hf.h_curr = va_arg(va, history_gfun_t);
1129ccac6ba8Schristos hf.h_set = va_arg(va, history_sfun_t);
113095b0e87bSchristos hf.h_clear = va_arg(va, history_vfun_t);
113195b0e87bSchristos hf.h_enter = va_arg(va, history_efun_t);
113295b0e87bSchristos hf.h_add = va_arg(va, history_efun_t);
113345542456Schristos hf.h_del = va_arg(va, history_sfun_t);
11346dc2f1dbScgd
1135a7db9a79Schristos if ((retval = history_set_fun(h, &hf)) == -1)
1136a7db9a79Schristos he_seterrev(ev, _HE_PARAM_MISSING);
11376dc2f1dbScgd break;
1138d30d584aSlukem }
11396dc2f1dbScgd
11406dc2f1dbScgd case H_END:
11410b9ae3fdSchristos FUN(history,end)(h);
1142a7db9a79Schristos retval = 0;
1143a7db9a79Schristos break;
1144a7db9a79Schristos
1145ea3813edSchristos case H_NEXT_EVDATA:
1146ea3813edSchristos {
1147ea3813edSchristos int num = va_arg(va, int);
1148ea3813edSchristos void **d = va_arg(va, void **);
1149ea3813edSchristos retval = history_next_evdata(h, ev, num, d);
1150ea3813edSchristos break;
1151ea3813edSchristos }
1152ea3813edSchristos
1153ea3813edSchristos case H_DELDATA:
1154ea3813edSchristos {
1155ea3813edSchristos int num = va_arg(va, int);
1156ea3813edSchristos void **d = va_arg(va, void **);
1157ea3813edSchristos retval = history_deldata_nth((history_t *)h->h_ref, ev, num, d);
1158ea3813edSchristos break;
1159ea3813edSchristos }
1160ea3813edSchristos
1161ea3813edSchristos case H_REPLACE: /* only use after H_NEXT_EVDATA */
1162ea3813edSchristos {
116334e53048Schristos const Char *line = va_arg(va, const Char *);
1164ea3813edSchristos void *d = va_arg(va, void *);
116534e53048Schristos const Char *s;
116634e53048Schristos if(!line || !(s = Strdup(line))) {
1167ea3813edSchristos retval = -1;
1168ea3813edSchristos break;
1169ea3813edSchristos }
1170ea3813edSchristos ((history_t *)h->h_ref)->cursor->ev.str = s;
1171ea3813edSchristos ((history_t *)h->h_ref)->cursor->data = d;
1172ea3813edSchristos retval = 0;
1173ea3813edSchristos break;
1174ea3813edSchristos }
1175ea3813edSchristos
11766dc2f1dbScgd default:
1177a7db9a79Schristos retval = -1;
1178a7db9a79Schristos he_seterrev(ev, _HE_UNKNOWN);
11796dc2f1dbScgd break;
11806dc2f1dbScgd }
11816dc2f1dbScgd va_end(va);
1182ea3813edSchristos return retval;
11836dc2f1dbScgd }
1184