1*60ecde0cSDaniel Fojt /* $NetBSD: history.c,v 1.63 2019/10/08 19:17:57 christos Exp $ */
232fe07f8SJohn Marino
332fe07f8SJohn Marino /*-
432fe07f8SJohn Marino * Copyright (c) 1992, 1993
532fe07f8SJohn Marino * The Regents of the University of California. All rights reserved.
632fe07f8SJohn Marino *
732fe07f8SJohn Marino * This code is derived from software contributed to Berkeley by
832fe07f8SJohn Marino * Christos Zoulas of Cornell University.
932fe07f8SJohn Marino *
1032fe07f8SJohn Marino * Redistribution and use in source and binary forms, with or without
1132fe07f8SJohn Marino * modification, are permitted provided that the following conditions
1232fe07f8SJohn Marino * are met:
1332fe07f8SJohn Marino * 1. Redistributions of source code must retain the above copyright
1432fe07f8SJohn Marino * notice, this list of conditions and the following disclaimer.
1532fe07f8SJohn Marino * 2. Redistributions in binary form must reproduce the above copyright
1632fe07f8SJohn Marino * notice, this list of conditions and the following disclaimer in the
1732fe07f8SJohn Marino * documentation and/or other materials provided with the distribution.
1832fe07f8SJohn Marino * 3. Neither the name of the University nor the names of its contributors
1932fe07f8SJohn Marino * may be used to endorse or promote products derived from this software
2032fe07f8SJohn Marino * without specific prior written permission.
2132fe07f8SJohn Marino *
2232fe07f8SJohn Marino * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2332fe07f8SJohn Marino * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2432fe07f8SJohn Marino * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2532fe07f8SJohn Marino * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2632fe07f8SJohn Marino * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2732fe07f8SJohn Marino * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2832fe07f8SJohn Marino * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2932fe07f8SJohn Marino * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3032fe07f8SJohn Marino * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3132fe07f8SJohn Marino * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3232fe07f8SJohn Marino * SUCH DAMAGE.
3332fe07f8SJohn Marino */
3432fe07f8SJohn Marino
3532fe07f8SJohn Marino #ifndef NARROWCHAR
3632fe07f8SJohn Marino #include "config.h"
3732fe07f8SJohn Marino #endif
3832fe07f8SJohn Marino
3932fe07f8SJohn Marino #if !defined(lint) && !defined(SCCSID)
4032fe07f8SJohn Marino #if 0
4132fe07f8SJohn Marino static char sccsid[] = "@(#)history.c 8.1 (Berkeley) 6/4/93";
4232fe07f8SJohn Marino #else
43*60ecde0cSDaniel Fojt __RCSID("$NetBSD: history.c,v 1.63 2019/10/08 19:17:57 christos Exp $");
4432fe07f8SJohn Marino #endif
4532fe07f8SJohn Marino #endif /* not lint && not SCCSID */
4632fe07f8SJohn Marino
4732fe07f8SJohn Marino /*
4832fe07f8SJohn Marino * hist.c: TYPE(History) access functions
4932fe07f8SJohn Marino */
5032fe07f8SJohn Marino #include <sys/stat.h>
5112db70c8Szrj #include <stdarg.h>
5212db70c8Szrj #include <stdlib.h>
5312db70c8Szrj #include <string.h>
5412db70c8Szrj #include <vis.h>
5532fe07f8SJohn Marino
5632fe07f8SJohn Marino static const char hist_cookie[] = "_HiStOrY_V2_\n";
5732fe07f8SJohn Marino
5832fe07f8SJohn Marino #include "histedit.h"
5912db70c8Szrj
6012db70c8Szrj
6112db70c8Szrj #ifdef NARROWCHAR
6212db70c8Szrj
6312db70c8Szrj #define Char char
6412db70c8Szrj #define FUN(prefix, rest) prefix ## _ ## rest
6512db70c8Szrj #define FUNW(type) type
6612db70c8Szrj #define TYPE(type) type
6712db70c8Szrj #define STR(x) x
6812db70c8Szrj
6912db70c8Szrj #define Strlen(s) strlen(s)
7012db70c8Szrj #define Strdup(s) strdup(s)
7112db70c8Szrj #define Strcmp(d, s) strcmp(d, s)
7212db70c8Szrj #define Strncmp(d, s, n) strncmp(d, s, n)
7312db70c8Szrj #define Strncpy(d, s, n) strncpy(d, s, n)
7412db70c8Szrj #define Strncat(d, s, n) strncat(d, s, n)
7512db70c8Szrj #define ct_decode_string(s, b) (s)
7612db70c8Szrj #define ct_encode_string(s, b) (s)
7712db70c8Szrj
7812db70c8Szrj #else
7932fe07f8SJohn Marino #include "chartype.h"
8032fe07f8SJohn Marino
8112db70c8Szrj #define Char wchar_t
8212db70c8Szrj #define FUN(prefix, rest) prefix ## _w ## rest
8312db70c8Szrj #define FUNW(type) type ## _w
8412db70c8Szrj #define TYPE(type) type ## W
8512db70c8Szrj #define STR(x) L ## x
8612db70c8Szrj
8712db70c8Szrj #define Strlen(s) wcslen(s)
8812db70c8Szrj #define Strdup(s) wcsdup(s)
8912db70c8Szrj #define Strcmp(d, s) wcscmp(d, s)
9012db70c8Szrj #define Strncmp(d, s, n) wcsncmp(d, s, n)
9112db70c8Szrj #define Strncpy(d, s, n) wcsncpy(d, s, n)
9212db70c8Szrj #define Strncat(d, s, n) wcsncat(d, s, n)
9312db70c8Szrj
9412db70c8Szrj #endif
9512db70c8Szrj
9612db70c8Szrj
9732fe07f8SJohn Marino typedef int (*history_gfun_t)(void *, TYPE(HistEvent) *);
9832fe07f8SJohn Marino typedef int (*history_efun_t)(void *, TYPE(HistEvent) *, const Char *);
9932fe07f8SJohn Marino typedef void (*history_vfun_t)(void *, TYPE(HistEvent) *);
10032fe07f8SJohn Marino typedef int (*history_sfun_t)(void *, TYPE(HistEvent) *, const int);
10132fe07f8SJohn Marino
TYPE(history)10232fe07f8SJohn Marino struct TYPE(history) {
10332fe07f8SJohn Marino void *h_ref; /* Argument for history fcns */
10432fe07f8SJohn Marino int h_ent; /* Last entry point for history */
10532fe07f8SJohn Marino history_gfun_t h_first; /* Get the first element */
10632fe07f8SJohn Marino history_gfun_t h_next; /* Get the next element */
10732fe07f8SJohn Marino history_gfun_t h_last; /* Get the last element */
10832fe07f8SJohn Marino history_gfun_t h_prev; /* Get the previous element */
10932fe07f8SJohn Marino history_gfun_t h_curr; /* Get the current element */
11032fe07f8SJohn Marino history_sfun_t h_set; /* Set the current element */
11132fe07f8SJohn Marino history_sfun_t h_del; /* Set the given element */
11232fe07f8SJohn Marino history_vfun_t h_clear; /* Clear the history list */
11332fe07f8SJohn Marino history_efun_t h_enter; /* Add an element */
11432fe07f8SJohn Marino history_efun_t h_add; /* Append to an element */
11532fe07f8SJohn Marino };
11632fe07f8SJohn Marino
11732fe07f8SJohn Marino #define HNEXT(h, ev) (*(h)->h_next)((h)->h_ref, ev)
11832fe07f8SJohn Marino #define HFIRST(h, ev) (*(h)->h_first)((h)->h_ref, ev)
11932fe07f8SJohn Marino #define HPREV(h, ev) (*(h)->h_prev)((h)->h_ref, ev)
12032fe07f8SJohn Marino #define HLAST(h, ev) (*(h)->h_last)((h)->h_ref, ev)
12132fe07f8SJohn Marino #define HCURR(h, ev) (*(h)->h_curr)((h)->h_ref, ev)
12232fe07f8SJohn Marino #define HSET(h, ev, n) (*(h)->h_set)((h)->h_ref, ev, n)
12332fe07f8SJohn Marino #define HCLEAR(h, ev) (*(h)->h_clear)((h)->h_ref, ev)
12432fe07f8SJohn Marino #define HENTER(h, ev, str) (*(h)->h_enter)((h)->h_ref, ev, str)
12532fe07f8SJohn Marino #define HADD(h, ev, str) (*(h)->h_add)((h)->h_ref, ev, str)
12632fe07f8SJohn Marino #define HDEL(h, ev, n) (*(h)->h_del)((h)->h_ref, ev, n)
12732fe07f8SJohn Marino
12832fe07f8SJohn Marino #define h_strdup(a) Strdup(a)
12932fe07f8SJohn Marino #define h_malloc(a) malloc(a)
13032fe07f8SJohn Marino #define h_realloc(a, b) realloc((a), (b))
13132fe07f8SJohn Marino #define h_free(a) free(a)
13232fe07f8SJohn Marino
13332fe07f8SJohn Marino typedef struct {
13432fe07f8SJohn Marino int num;
13532fe07f8SJohn Marino Char *str;
13632fe07f8SJohn Marino } HistEventPrivate;
13732fe07f8SJohn Marino
13832fe07f8SJohn Marino
13912db70c8Szrj static int history_setsize(TYPE(History) *, TYPE(HistEvent) *, int);
14012db70c8Szrj static int history_getsize(TYPE(History) *, TYPE(HistEvent) *);
14112db70c8Szrj static int history_setunique(TYPE(History) *, TYPE(HistEvent) *, int);
14212db70c8Szrj static int history_getunique(TYPE(History) *, TYPE(HistEvent) *);
14312db70c8Szrj static int history_set_fun(TYPE(History) *, TYPE(History) *);
14412db70c8Szrj static int history_load(TYPE(History) *, const char *);
14512db70c8Szrj static int history_save(TYPE(History) *, const char *);
146ae19eda8Szrj static int history_save_fp(TYPE(History) *, size_t, FILE *);
14712db70c8Szrj static int history_prev_event(TYPE(History) *, TYPE(HistEvent) *, int);
14812db70c8Szrj static int history_next_event(TYPE(History) *, TYPE(HistEvent) *, int);
14912db70c8Szrj static int history_next_string(TYPE(History) *, TYPE(HistEvent) *,
15012db70c8Szrj const Char *);
15112db70c8Szrj static int history_prev_string(TYPE(History) *, TYPE(HistEvent) *,
15212db70c8Szrj const Char *);
15332fe07f8SJohn Marino
15432fe07f8SJohn Marino
15532fe07f8SJohn Marino /***********************************************************************/
15632fe07f8SJohn Marino
15732fe07f8SJohn Marino /*
15832fe07f8SJohn Marino * Builtin- history implementation
15932fe07f8SJohn Marino */
16032fe07f8SJohn Marino typedef struct hentry_t {
16132fe07f8SJohn Marino TYPE(HistEvent) ev; /* What we return */
16232fe07f8SJohn Marino void *data; /* data */
16332fe07f8SJohn Marino struct hentry_t *next; /* Next entry */
16432fe07f8SJohn Marino struct hentry_t *prev; /* Previous entry */
16532fe07f8SJohn Marino } hentry_t;
16632fe07f8SJohn Marino
16732fe07f8SJohn Marino typedef struct history_t {
16832fe07f8SJohn Marino hentry_t list; /* Fake list header element */
16932fe07f8SJohn Marino hentry_t *cursor; /* Current element in the list */
17032fe07f8SJohn Marino int max; /* Maximum number of events */
17132fe07f8SJohn Marino int cur; /* Current number of events */
17232fe07f8SJohn Marino int eventid; /* For generation of unique event id */
17332fe07f8SJohn Marino int flags; /* TYPE(History) flags */
17432fe07f8SJohn Marino #define H_UNIQUE 1 /* Store only unique elements */
17532fe07f8SJohn Marino } history_t;
17632fe07f8SJohn Marino
17712db70c8Szrj static int history_def_next(void *, TYPE(HistEvent) *);
17812db70c8Szrj static int history_def_first(void *, TYPE(HistEvent) *);
17912db70c8Szrj static int history_def_prev(void *, TYPE(HistEvent) *);
18012db70c8Szrj static int history_def_last(void *, TYPE(HistEvent) *);
18112db70c8Szrj static int history_def_curr(void *, TYPE(HistEvent) *);
18212db70c8Szrj static int history_def_set(void *, TYPE(HistEvent) *, const int);
18312db70c8Szrj static void history_def_clear(void *, TYPE(HistEvent) *);
18412db70c8Szrj static int history_def_enter(void *, TYPE(HistEvent) *, const Char *);
18512db70c8Szrj static int history_def_add(void *, TYPE(HistEvent) *, const Char *);
18612db70c8Szrj static int history_def_del(void *, TYPE(HistEvent) *, const int);
18732fe07f8SJohn Marino
18812db70c8Szrj static int history_def_init(void **, TYPE(HistEvent) *, int);
18912db70c8Szrj static int history_def_insert(history_t *, TYPE(HistEvent) *, const Char *);
19012db70c8Szrj static void history_def_delete(history_t *, TYPE(HistEvent) *, hentry_t *);
19132fe07f8SJohn Marino
19212db70c8Szrj static int history_deldata_nth(history_t *, TYPE(HistEvent) *, int, void **);
19312db70c8Szrj static int history_set_nth(void *, TYPE(HistEvent) *, int);
19432fe07f8SJohn Marino
19532fe07f8SJohn Marino #define history_def_setsize(p, num)(void) (((history_t *)p)->max = (num))
19632fe07f8SJohn Marino #define history_def_getsize(p) (((history_t *)p)->cur)
19732fe07f8SJohn Marino #define history_def_getunique(p) (((((history_t *)p)->flags) & H_UNIQUE) != 0)
19832fe07f8SJohn Marino #define history_def_setunique(p, uni) \
19932fe07f8SJohn Marino if (uni) \
20032fe07f8SJohn Marino (((history_t *)p)->flags) |= H_UNIQUE; \
20132fe07f8SJohn Marino else \
20232fe07f8SJohn Marino (((history_t *)p)->flags) &= ~H_UNIQUE
20332fe07f8SJohn Marino
20432fe07f8SJohn Marino #define he_strerror(code) he_errlist[code]
20532fe07f8SJohn Marino #define he_seterrev(evp, code) {\
20632fe07f8SJohn Marino evp->num = code;\
20732fe07f8SJohn Marino evp->str = he_strerror(code);\
20832fe07f8SJohn Marino }
20932fe07f8SJohn Marino
21032fe07f8SJohn Marino /* error messages */
21132fe07f8SJohn Marino static const Char *const he_errlist[] = {
21232fe07f8SJohn Marino STR("OK"),
21332fe07f8SJohn Marino STR("unknown error"),
21432fe07f8SJohn Marino STR("malloc() failed"),
21532fe07f8SJohn Marino STR("first event not found"),
21632fe07f8SJohn Marino STR("last event not found"),
21732fe07f8SJohn Marino STR("empty list"),
21832fe07f8SJohn Marino STR("no next event"),
21932fe07f8SJohn Marino STR("no previous event"),
22032fe07f8SJohn Marino STR("current event is invalid"),
22132fe07f8SJohn Marino STR("event not found"),
22232fe07f8SJohn Marino STR("can't read history from file"),
22332fe07f8SJohn Marino STR("can't write history"),
22432fe07f8SJohn Marino STR("required parameter(s) not supplied"),
22532fe07f8SJohn Marino STR("history size negative"),
22632fe07f8SJohn Marino STR("function not allowed with other history-functions-set the default"),
22732fe07f8SJohn Marino STR("bad parameters")
22832fe07f8SJohn Marino };
22932fe07f8SJohn Marino /* error codes */
23032fe07f8SJohn Marino #define _HE_OK 0
23132fe07f8SJohn Marino #define _HE_UNKNOWN 1
23232fe07f8SJohn Marino #define _HE_MALLOC_FAILED 2
23332fe07f8SJohn Marino #define _HE_FIRST_NOTFOUND 3
23432fe07f8SJohn Marino #define _HE_LAST_NOTFOUND 4
23532fe07f8SJohn Marino #define _HE_EMPTY_LIST 5
23632fe07f8SJohn Marino #define _HE_END_REACHED 6
23732fe07f8SJohn Marino #define _HE_START_REACHED 7
23832fe07f8SJohn Marino #define _HE_CURR_INVALID 8
23932fe07f8SJohn Marino #define _HE_NOT_FOUND 9
24032fe07f8SJohn Marino #define _HE_HIST_READ 10
24132fe07f8SJohn Marino #define _HE_HIST_WRITE 11
24232fe07f8SJohn Marino #define _HE_PARAM_MISSING 12
24332fe07f8SJohn Marino #define _HE_SIZE_NEGATIVE 13
24432fe07f8SJohn Marino #define _HE_NOT_ALLOWED 14
24532fe07f8SJohn Marino #define _HE_BAD_PARAM 15
24632fe07f8SJohn Marino
24732fe07f8SJohn Marino /* history_def_first():
24832fe07f8SJohn Marino * Default function to return the first event in the history.
24932fe07f8SJohn Marino */
25012db70c8Szrj static int
history_def_first(void * p,TYPE (HistEvent)* ev)25132fe07f8SJohn Marino history_def_first(void *p, TYPE(HistEvent) *ev)
25232fe07f8SJohn Marino {
25332fe07f8SJohn Marino history_t *h = (history_t *) p;
25432fe07f8SJohn Marino
25532fe07f8SJohn Marino h->cursor = h->list.next;
25632fe07f8SJohn Marino if (h->cursor != &h->list)
25732fe07f8SJohn Marino *ev = h->cursor->ev;
25832fe07f8SJohn Marino else {
25932fe07f8SJohn Marino he_seterrev(ev, _HE_FIRST_NOTFOUND);
26032fe07f8SJohn Marino return -1;
26132fe07f8SJohn Marino }
26232fe07f8SJohn Marino
26332fe07f8SJohn Marino return 0;
26432fe07f8SJohn Marino }
26532fe07f8SJohn Marino
26632fe07f8SJohn Marino
26732fe07f8SJohn Marino /* history_def_last():
26832fe07f8SJohn Marino * Default function to return the last event in the history.
26932fe07f8SJohn Marino */
27012db70c8Szrj static int
history_def_last(void * p,TYPE (HistEvent)* ev)27132fe07f8SJohn Marino history_def_last(void *p, TYPE(HistEvent) *ev)
27232fe07f8SJohn Marino {
27332fe07f8SJohn Marino history_t *h = (history_t *) p;
27432fe07f8SJohn Marino
27532fe07f8SJohn Marino h->cursor = h->list.prev;
27632fe07f8SJohn Marino if (h->cursor != &h->list)
27732fe07f8SJohn Marino *ev = h->cursor->ev;
27832fe07f8SJohn Marino else {
27932fe07f8SJohn Marino he_seterrev(ev, _HE_LAST_NOTFOUND);
28032fe07f8SJohn Marino return -1;
28132fe07f8SJohn Marino }
28232fe07f8SJohn Marino
28332fe07f8SJohn Marino return 0;
28432fe07f8SJohn Marino }
28532fe07f8SJohn Marino
28632fe07f8SJohn Marino
28732fe07f8SJohn Marino /* history_def_next():
28832fe07f8SJohn Marino * Default function to return the next event in the history.
28932fe07f8SJohn Marino */
29012db70c8Szrj static int
history_def_next(void * p,TYPE (HistEvent)* ev)29132fe07f8SJohn Marino history_def_next(void *p, TYPE(HistEvent) *ev)
29232fe07f8SJohn Marino {
29332fe07f8SJohn Marino history_t *h = (history_t *) p;
29432fe07f8SJohn Marino
29532fe07f8SJohn Marino if (h->cursor == &h->list) {
29632fe07f8SJohn Marino he_seterrev(ev, _HE_EMPTY_LIST);
29732fe07f8SJohn Marino return -1;
29832fe07f8SJohn Marino }
29932fe07f8SJohn Marino
30032fe07f8SJohn Marino if (h->cursor->next == &h->list) {
30132fe07f8SJohn Marino he_seterrev(ev, _HE_END_REACHED);
30232fe07f8SJohn Marino return -1;
30332fe07f8SJohn Marino }
30432fe07f8SJohn Marino
30532fe07f8SJohn Marino h->cursor = h->cursor->next;
30632fe07f8SJohn Marino *ev = h->cursor->ev;
30732fe07f8SJohn Marino
30832fe07f8SJohn Marino return 0;
30932fe07f8SJohn Marino }
31032fe07f8SJohn Marino
31132fe07f8SJohn Marino
31232fe07f8SJohn Marino /* history_def_prev():
31332fe07f8SJohn Marino * Default function to return the previous event in the history.
31432fe07f8SJohn Marino */
31512db70c8Szrj static int
history_def_prev(void * p,TYPE (HistEvent)* ev)31632fe07f8SJohn Marino history_def_prev(void *p, TYPE(HistEvent) *ev)
31732fe07f8SJohn Marino {
31832fe07f8SJohn Marino history_t *h = (history_t *) p;
31932fe07f8SJohn Marino
32032fe07f8SJohn Marino if (h->cursor == &h->list) {
32132fe07f8SJohn Marino he_seterrev(ev,
32232fe07f8SJohn Marino (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST);
32332fe07f8SJohn Marino return -1;
32432fe07f8SJohn Marino }
32532fe07f8SJohn Marino
32632fe07f8SJohn Marino if (h->cursor->prev == &h->list) {
32732fe07f8SJohn Marino he_seterrev(ev, _HE_START_REACHED);
32832fe07f8SJohn Marino return -1;
32932fe07f8SJohn Marino }
33032fe07f8SJohn Marino
33132fe07f8SJohn Marino h->cursor = h->cursor->prev;
33232fe07f8SJohn Marino *ev = h->cursor->ev;
33332fe07f8SJohn Marino
33432fe07f8SJohn Marino return 0;
33532fe07f8SJohn Marino }
33632fe07f8SJohn Marino
33732fe07f8SJohn Marino
33832fe07f8SJohn Marino /* history_def_curr():
33932fe07f8SJohn Marino * Default function to return the current event in the history.
34032fe07f8SJohn Marino */
34112db70c8Szrj static int
history_def_curr(void * p,TYPE (HistEvent)* ev)34232fe07f8SJohn Marino history_def_curr(void *p, TYPE(HistEvent) *ev)
34332fe07f8SJohn Marino {
34432fe07f8SJohn Marino history_t *h = (history_t *) p;
34532fe07f8SJohn Marino
34632fe07f8SJohn Marino if (h->cursor != &h->list)
34732fe07f8SJohn Marino *ev = h->cursor->ev;
34832fe07f8SJohn Marino else {
34932fe07f8SJohn Marino he_seterrev(ev,
35032fe07f8SJohn Marino (h->cur > 0) ? _HE_CURR_INVALID : _HE_EMPTY_LIST);
35132fe07f8SJohn Marino return -1;
35232fe07f8SJohn Marino }
35332fe07f8SJohn Marino
35432fe07f8SJohn Marino return 0;
35532fe07f8SJohn Marino }
35632fe07f8SJohn Marino
35732fe07f8SJohn Marino
35832fe07f8SJohn Marino /* history_def_set():
35932fe07f8SJohn Marino * Default function to set the current event in the history to the
36032fe07f8SJohn Marino * given one.
36132fe07f8SJohn Marino */
36212db70c8Szrj static int
history_def_set(void * p,TYPE (HistEvent)* ev,const int n)36332fe07f8SJohn Marino history_def_set(void *p, TYPE(HistEvent) *ev, const int n)
36432fe07f8SJohn Marino {
36532fe07f8SJohn Marino history_t *h = (history_t *) p;
36632fe07f8SJohn Marino
36732fe07f8SJohn Marino if (h->cur == 0) {
36832fe07f8SJohn Marino he_seterrev(ev, _HE_EMPTY_LIST);
36932fe07f8SJohn Marino return -1;
37032fe07f8SJohn Marino }
37132fe07f8SJohn Marino if (h->cursor == &h->list || h->cursor->ev.num != n) {
37232fe07f8SJohn Marino for (h->cursor = h->list.next; h->cursor != &h->list;
37332fe07f8SJohn Marino h->cursor = h->cursor->next)
37432fe07f8SJohn Marino if (h->cursor->ev.num == n)
37532fe07f8SJohn Marino break;
37632fe07f8SJohn Marino }
37732fe07f8SJohn Marino if (h->cursor == &h->list) {
37832fe07f8SJohn Marino he_seterrev(ev, _HE_NOT_FOUND);
37932fe07f8SJohn Marino return -1;
38032fe07f8SJohn Marino }
38132fe07f8SJohn Marino return 0;
38232fe07f8SJohn Marino }
38332fe07f8SJohn Marino
38432fe07f8SJohn Marino
38532fe07f8SJohn Marino /* history_set_nth():
38632fe07f8SJohn Marino * Default function to set the current event in the history to the
38732fe07f8SJohn Marino * n-th one.
38832fe07f8SJohn Marino */
38912db70c8Szrj static int
history_set_nth(void * p,TYPE (HistEvent)* ev,int n)39032fe07f8SJohn Marino history_set_nth(void *p, TYPE(HistEvent) *ev, int n)
39132fe07f8SJohn Marino {
39232fe07f8SJohn Marino history_t *h = (history_t *) p;
39332fe07f8SJohn Marino
39432fe07f8SJohn Marino if (h->cur == 0) {
39532fe07f8SJohn Marino he_seterrev(ev, _HE_EMPTY_LIST);
39632fe07f8SJohn Marino return -1;
39732fe07f8SJohn Marino }
39832fe07f8SJohn Marino for (h->cursor = h->list.prev; h->cursor != &h->list;
39932fe07f8SJohn Marino h->cursor = h->cursor->prev)
40032fe07f8SJohn Marino if (n-- <= 0)
40132fe07f8SJohn Marino break;
40232fe07f8SJohn Marino if (h->cursor == &h->list) {
40332fe07f8SJohn Marino he_seterrev(ev, _HE_NOT_FOUND);
40432fe07f8SJohn Marino return -1;
40532fe07f8SJohn Marino }
40632fe07f8SJohn Marino return 0;
40732fe07f8SJohn Marino }
40832fe07f8SJohn Marino
40932fe07f8SJohn Marino
41032fe07f8SJohn Marino /* history_def_add():
41132fe07f8SJohn Marino * Append string to element
41232fe07f8SJohn Marino */
41312db70c8Szrj static int
history_def_add(void * p,TYPE (HistEvent)* ev,const Char * str)41432fe07f8SJohn Marino history_def_add(void *p, TYPE(HistEvent) *ev, const Char *str)
41532fe07f8SJohn Marino {
41632fe07f8SJohn Marino history_t *h = (history_t *) p;
417*60ecde0cSDaniel Fojt size_t len, elen, slen;
41832fe07f8SJohn Marino Char *s;
41932fe07f8SJohn Marino HistEventPrivate *evp = (void *)&h->cursor->ev;
42032fe07f8SJohn Marino
42132fe07f8SJohn Marino if (h->cursor == &h->list)
42232fe07f8SJohn Marino return history_def_enter(p, ev, str);
423*60ecde0cSDaniel Fojt elen = Strlen(evp->str);
424*60ecde0cSDaniel Fojt slen = Strlen(str);
425*60ecde0cSDaniel Fojt len = elen + slen + 1;
42632fe07f8SJohn Marino s = h_malloc(len * sizeof(*s));
42732fe07f8SJohn Marino if (s == NULL) {
42832fe07f8SJohn Marino he_seterrev(ev, _HE_MALLOC_FAILED);
42932fe07f8SJohn Marino return -1;
43032fe07f8SJohn Marino }
431*60ecde0cSDaniel Fojt memcpy(s, evp->str, elen * sizeof(*s));
432*60ecde0cSDaniel Fojt memcpy(s + elen, str, slen * sizeof(*s));
43332fe07f8SJohn Marino s[len - 1] = '\0';
43432fe07f8SJohn Marino h_free(evp->str);
43532fe07f8SJohn Marino evp->str = s;
43632fe07f8SJohn Marino *ev = h->cursor->ev;
43732fe07f8SJohn Marino return 0;
43832fe07f8SJohn Marino }
43932fe07f8SJohn Marino
44032fe07f8SJohn Marino
44112db70c8Szrj static int
history_deldata_nth(history_t * h,TYPE (HistEvent)* ev,int num,void ** data)44232fe07f8SJohn Marino history_deldata_nth(history_t *h, TYPE(HistEvent) *ev,
44332fe07f8SJohn Marino int num, void **data)
44432fe07f8SJohn Marino {
44532fe07f8SJohn Marino if (history_set_nth(h, ev, num) != 0)
44632fe07f8SJohn Marino return -1;
44732fe07f8SJohn Marino /* magic value to skip delete (just set to n-th history) */
44832fe07f8SJohn Marino if (data == (void **)-1)
44932fe07f8SJohn Marino return 0;
45032fe07f8SJohn Marino ev->str = Strdup(h->cursor->ev.str);
45132fe07f8SJohn Marino ev->num = h->cursor->ev.num;
45232fe07f8SJohn Marino if (data)
45332fe07f8SJohn Marino *data = h->cursor->data;
45432fe07f8SJohn Marino history_def_delete(h, ev, h->cursor);
45532fe07f8SJohn Marino return 0;
45632fe07f8SJohn Marino }
45732fe07f8SJohn Marino
45832fe07f8SJohn Marino
45932fe07f8SJohn Marino /* history_def_del():
46032fe07f8SJohn Marino * Delete element hp of the h list
46132fe07f8SJohn Marino */
46232fe07f8SJohn Marino /* ARGSUSED */
46312db70c8Szrj static int
history_def_del(void * p,TYPE (HistEvent)* ev,const int num)46432fe07f8SJohn Marino history_def_del(void *p, TYPE(HistEvent) *ev __attribute__((__unused__)),
46532fe07f8SJohn Marino const int num)
46632fe07f8SJohn Marino {
46732fe07f8SJohn Marino history_t *h = (history_t *) p;
46832fe07f8SJohn Marino if (history_def_set(h, ev, num) != 0)
46932fe07f8SJohn Marino return -1;
47032fe07f8SJohn Marino ev->str = Strdup(h->cursor->ev.str);
47132fe07f8SJohn Marino ev->num = h->cursor->ev.num;
47232fe07f8SJohn Marino history_def_delete(h, ev, h->cursor);
47332fe07f8SJohn Marino return 0;
47432fe07f8SJohn Marino }
47532fe07f8SJohn Marino
47632fe07f8SJohn Marino
47732fe07f8SJohn Marino /* history_def_delete():
47832fe07f8SJohn Marino * Delete element hp of the h list
47932fe07f8SJohn Marino */
48032fe07f8SJohn Marino /* ARGSUSED */
48112db70c8Szrj static void
history_def_delete(history_t * h,TYPE (HistEvent)* ev,hentry_t * hp)48232fe07f8SJohn Marino history_def_delete(history_t *h,
48332fe07f8SJohn Marino TYPE(HistEvent) *ev __attribute__((__unused__)), hentry_t *hp)
48432fe07f8SJohn Marino {
48532fe07f8SJohn Marino HistEventPrivate *evp = (void *)&hp->ev;
48632fe07f8SJohn Marino if (hp == &h->list)
48732fe07f8SJohn Marino abort();
48832fe07f8SJohn Marino if (h->cursor == hp) {
48932fe07f8SJohn Marino h->cursor = hp->prev;
49032fe07f8SJohn Marino if (h->cursor == &h->list)
49132fe07f8SJohn Marino h->cursor = hp->next;
49232fe07f8SJohn Marino }
49332fe07f8SJohn Marino hp->prev->next = hp->next;
49432fe07f8SJohn Marino hp->next->prev = hp->prev;
49532fe07f8SJohn Marino h_free(evp->str);
49632fe07f8SJohn Marino h_free(hp);
49732fe07f8SJohn Marino h->cur--;
49832fe07f8SJohn Marino }
49932fe07f8SJohn Marino
50032fe07f8SJohn Marino
50132fe07f8SJohn Marino /* history_def_insert():
50232fe07f8SJohn Marino * Insert element with string str in the h list
50332fe07f8SJohn Marino */
50412db70c8Szrj static int
history_def_insert(history_t * h,TYPE (HistEvent)* ev,const Char * str)50532fe07f8SJohn Marino history_def_insert(history_t *h, TYPE(HistEvent) *ev, const Char *str)
50632fe07f8SJohn Marino {
50732fe07f8SJohn Marino hentry_t *c;
50832fe07f8SJohn Marino
50932fe07f8SJohn Marino c = h_malloc(sizeof(*c));
51032fe07f8SJohn Marino if (c == NULL)
51132fe07f8SJohn Marino goto oomem;
51232fe07f8SJohn Marino if ((c->ev.str = h_strdup(str)) == NULL) {
51332fe07f8SJohn Marino h_free(c);
51432fe07f8SJohn Marino goto oomem;
51532fe07f8SJohn Marino }
51632fe07f8SJohn Marino c->data = NULL;
51732fe07f8SJohn Marino c->ev.num = ++h->eventid;
51832fe07f8SJohn Marino c->next = h->list.next;
51932fe07f8SJohn Marino c->prev = &h->list;
52032fe07f8SJohn Marino h->list.next->prev = c;
52132fe07f8SJohn Marino h->list.next = c;
52232fe07f8SJohn Marino h->cur++;
52332fe07f8SJohn Marino h->cursor = c;
52432fe07f8SJohn Marino
52532fe07f8SJohn Marino *ev = c->ev;
52632fe07f8SJohn Marino return 0;
52732fe07f8SJohn Marino oomem:
52832fe07f8SJohn Marino he_seterrev(ev, _HE_MALLOC_FAILED);
52932fe07f8SJohn Marino return -1;
53032fe07f8SJohn Marino }
53132fe07f8SJohn Marino
53232fe07f8SJohn Marino
53332fe07f8SJohn Marino /* history_def_enter():
53432fe07f8SJohn Marino * Default function to enter an item in the history
53532fe07f8SJohn Marino */
53612db70c8Szrj static int
history_def_enter(void * p,TYPE (HistEvent)* ev,const Char * str)53732fe07f8SJohn Marino history_def_enter(void *p, TYPE(HistEvent) *ev, const Char *str)
53832fe07f8SJohn Marino {
53932fe07f8SJohn Marino history_t *h = (history_t *) p;
54032fe07f8SJohn Marino
54132fe07f8SJohn Marino if ((h->flags & H_UNIQUE) != 0 && h->list.next != &h->list &&
54232fe07f8SJohn Marino Strcmp(h->list.next->ev.str, str) == 0)
54332fe07f8SJohn Marino return 0;
54432fe07f8SJohn Marino
54532fe07f8SJohn Marino if (history_def_insert(h, ev, str) == -1)
54632fe07f8SJohn Marino return -1; /* error, keep error message */
54732fe07f8SJohn Marino
54832fe07f8SJohn Marino /*
54932fe07f8SJohn Marino * Always keep at least one entry.
55032fe07f8SJohn Marino * This way we don't have to check for the empty list.
55132fe07f8SJohn Marino */
55232fe07f8SJohn Marino while (h->cur > h->max && h->cur > 0)
55332fe07f8SJohn Marino history_def_delete(h, ev, h->list.prev);
55432fe07f8SJohn Marino
55532fe07f8SJohn Marino return 1;
55632fe07f8SJohn Marino }
55732fe07f8SJohn Marino
55832fe07f8SJohn Marino
55932fe07f8SJohn Marino /* history_def_init():
56032fe07f8SJohn Marino * Default history initialization function
56132fe07f8SJohn Marino */
56232fe07f8SJohn Marino /* ARGSUSED */
56312db70c8Szrj static int
history_def_init(void ** p,TYPE (HistEvent)* ev,int n)56432fe07f8SJohn Marino history_def_init(void **p, TYPE(HistEvent) *ev __attribute__((__unused__)), int n)
56532fe07f8SJohn Marino {
56632fe07f8SJohn Marino history_t *h = (history_t *) h_malloc(sizeof(*h));
56732fe07f8SJohn Marino if (h == NULL)
56832fe07f8SJohn Marino return -1;
56932fe07f8SJohn Marino
57032fe07f8SJohn Marino if (n <= 0)
57132fe07f8SJohn Marino n = 0;
57232fe07f8SJohn Marino h->eventid = 0;
57332fe07f8SJohn Marino h->cur = 0;
57432fe07f8SJohn Marino h->max = n;
57532fe07f8SJohn Marino h->list.next = h->list.prev = &h->list;
57632fe07f8SJohn Marino h->list.ev.str = NULL;
57732fe07f8SJohn Marino h->list.ev.num = 0;
57832fe07f8SJohn Marino h->cursor = &h->list;
57932fe07f8SJohn Marino h->flags = 0;
58032fe07f8SJohn Marino *p = h;
58132fe07f8SJohn Marino return 0;
58232fe07f8SJohn Marino }
58332fe07f8SJohn Marino
58432fe07f8SJohn Marino
58532fe07f8SJohn Marino /* history_def_clear():
58632fe07f8SJohn Marino * Default history cleanup function
58732fe07f8SJohn Marino */
58812db70c8Szrj static void
history_def_clear(void * p,TYPE (HistEvent)* ev)58932fe07f8SJohn Marino history_def_clear(void *p, TYPE(HistEvent) *ev)
59032fe07f8SJohn Marino {
59132fe07f8SJohn Marino history_t *h = (history_t *) p;
59232fe07f8SJohn Marino
59332fe07f8SJohn Marino while (h->list.prev != &h->list)
59432fe07f8SJohn Marino history_def_delete(h, ev, h->list.prev);
59532fe07f8SJohn Marino h->cursor = &h->list;
59632fe07f8SJohn Marino h->eventid = 0;
59732fe07f8SJohn Marino h->cur = 0;
59832fe07f8SJohn Marino }
59932fe07f8SJohn Marino
60032fe07f8SJohn Marino
60132fe07f8SJohn Marino
60232fe07f8SJohn Marino
60332fe07f8SJohn Marino /************************************************************************/
60432fe07f8SJohn Marino
60532fe07f8SJohn Marino /* history_init():
60632fe07f8SJohn Marino * Initialization function.
60732fe07f8SJohn Marino */
TYPE(History)60812db70c8Szrj TYPE(History) *
60932fe07f8SJohn Marino FUN(history,init)(void)
61032fe07f8SJohn Marino {
61132fe07f8SJohn Marino TYPE(HistEvent) ev;
61232fe07f8SJohn Marino TYPE(History) *h = (TYPE(History) *) h_malloc(sizeof(*h));
61332fe07f8SJohn Marino if (h == NULL)
61432fe07f8SJohn Marino return NULL;
61532fe07f8SJohn Marino
61632fe07f8SJohn Marino if (history_def_init(&h->h_ref, &ev, 0) == -1) {
61732fe07f8SJohn Marino h_free(h);
61832fe07f8SJohn Marino return NULL;
61932fe07f8SJohn Marino }
62032fe07f8SJohn Marino h->h_ent = -1;
62132fe07f8SJohn Marino h->h_next = history_def_next;
62232fe07f8SJohn Marino h->h_first = history_def_first;
62332fe07f8SJohn Marino h->h_last = history_def_last;
62432fe07f8SJohn Marino h->h_prev = history_def_prev;
62532fe07f8SJohn Marino h->h_curr = history_def_curr;
62632fe07f8SJohn Marino h->h_set = history_def_set;
62732fe07f8SJohn Marino h->h_clear = history_def_clear;
62832fe07f8SJohn Marino h->h_enter = history_def_enter;
62932fe07f8SJohn Marino h->h_add = history_def_add;
63032fe07f8SJohn Marino h->h_del = history_def_del;
63132fe07f8SJohn Marino
63232fe07f8SJohn Marino return h;
63332fe07f8SJohn Marino }
63432fe07f8SJohn Marino
63532fe07f8SJohn Marino
63632fe07f8SJohn Marino /* history_end():
63732fe07f8SJohn Marino * clean up history;
63832fe07f8SJohn Marino */
63912db70c8Szrj void
FUN(history,end)64032fe07f8SJohn Marino FUN(history,end)(TYPE(History) *h)
64132fe07f8SJohn Marino {
64232fe07f8SJohn Marino TYPE(HistEvent) ev;
64332fe07f8SJohn Marino
64432fe07f8SJohn Marino if (h->h_next == history_def_next)
64532fe07f8SJohn Marino history_def_clear(h->h_ref, &ev);
64632fe07f8SJohn Marino h_free(h->h_ref);
64732fe07f8SJohn Marino h_free(h);
64832fe07f8SJohn Marino }
64932fe07f8SJohn Marino
65032fe07f8SJohn Marino
65132fe07f8SJohn Marino
65232fe07f8SJohn Marino /* history_setsize():
65332fe07f8SJohn Marino * Set history number of events
65432fe07f8SJohn Marino */
65512db70c8Szrj static int
history_setsize(TYPE (History)* h,TYPE (HistEvent)* ev,int num)65632fe07f8SJohn Marino history_setsize(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
65732fe07f8SJohn Marino {
65832fe07f8SJohn Marino
65932fe07f8SJohn Marino if (h->h_next != history_def_next) {
66032fe07f8SJohn Marino he_seterrev(ev, _HE_NOT_ALLOWED);
66132fe07f8SJohn Marino return -1;
66232fe07f8SJohn Marino }
66332fe07f8SJohn Marino if (num < 0) {
66432fe07f8SJohn Marino he_seterrev(ev, _HE_BAD_PARAM);
66532fe07f8SJohn Marino return -1;
66632fe07f8SJohn Marino }
66732fe07f8SJohn Marino history_def_setsize(h->h_ref, num);
66832fe07f8SJohn Marino return 0;
66932fe07f8SJohn Marino }
67032fe07f8SJohn Marino
67132fe07f8SJohn Marino
67232fe07f8SJohn Marino /* history_getsize():
67332fe07f8SJohn Marino * Get number of events currently in history
67432fe07f8SJohn Marino */
67512db70c8Szrj static int
history_getsize(TYPE (History)* h,TYPE (HistEvent)* ev)67632fe07f8SJohn Marino history_getsize(TYPE(History) *h, TYPE(HistEvent) *ev)
67732fe07f8SJohn Marino {
67832fe07f8SJohn Marino if (h->h_next != history_def_next) {
67932fe07f8SJohn Marino he_seterrev(ev, _HE_NOT_ALLOWED);
68032fe07f8SJohn Marino return -1;
68132fe07f8SJohn Marino }
68232fe07f8SJohn Marino ev->num = history_def_getsize(h->h_ref);
68332fe07f8SJohn Marino if (ev->num < -1) {
68432fe07f8SJohn Marino he_seterrev(ev, _HE_SIZE_NEGATIVE);
68532fe07f8SJohn Marino return -1;
68632fe07f8SJohn Marino }
68732fe07f8SJohn Marino return 0;
68832fe07f8SJohn Marino }
68932fe07f8SJohn Marino
69032fe07f8SJohn Marino
69132fe07f8SJohn Marino /* history_setunique():
69232fe07f8SJohn Marino * Set if adjacent equal events should not be entered in history.
69332fe07f8SJohn Marino */
69412db70c8Szrj static int
history_setunique(TYPE (History)* h,TYPE (HistEvent)* ev,int uni)69532fe07f8SJohn Marino history_setunique(TYPE(History) *h, TYPE(HistEvent) *ev, int uni)
69632fe07f8SJohn Marino {
69732fe07f8SJohn Marino
69832fe07f8SJohn Marino if (h->h_next != history_def_next) {
69932fe07f8SJohn Marino he_seterrev(ev, _HE_NOT_ALLOWED);
70032fe07f8SJohn Marino return -1;
70132fe07f8SJohn Marino }
70232fe07f8SJohn Marino history_def_setunique(h->h_ref, uni);
70332fe07f8SJohn Marino return 0;
70432fe07f8SJohn Marino }
70532fe07f8SJohn Marino
70632fe07f8SJohn Marino
70732fe07f8SJohn Marino /* history_getunique():
70832fe07f8SJohn Marino * Get if adjacent equal events should not be entered in history.
70932fe07f8SJohn Marino */
71012db70c8Szrj static int
history_getunique(TYPE (History)* h,TYPE (HistEvent)* ev)71132fe07f8SJohn Marino history_getunique(TYPE(History) *h, TYPE(HistEvent) *ev)
71232fe07f8SJohn Marino {
71332fe07f8SJohn Marino if (h->h_next != history_def_next) {
71432fe07f8SJohn Marino he_seterrev(ev, _HE_NOT_ALLOWED);
71532fe07f8SJohn Marino return -1;
71632fe07f8SJohn Marino }
71732fe07f8SJohn Marino ev->num = history_def_getunique(h->h_ref);
71832fe07f8SJohn Marino return 0;
71932fe07f8SJohn Marino }
72032fe07f8SJohn Marino
72132fe07f8SJohn Marino
72232fe07f8SJohn Marino /* history_set_fun():
72332fe07f8SJohn Marino * Set history functions
72432fe07f8SJohn Marino */
72512db70c8Szrj static int
history_set_fun(TYPE (History)* h,TYPE (History)* nh)72632fe07f8SJohn Marino history_set_fun(TYPE(History) *h, TYPE(History) *nh)
72732fe07f8SJohn Marino {
72832fe07f8SJohn Marino TYPE(HistEvent) ev;
72932fe07f8SJohn Marino
73032fe07f8SJohn Marino if (nh->h_first == NULL || nh->h_next == NULL || nh->h_last == NULL ||
73132fe07f8SJohn Marino nh->h_prev == NULL || nh->h_curr == NULL || nh->h_set == NULL ||
73232fe07f8SJohn Marino nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL ||
73332fe07f8SJohn Marino nh->h_del == NULL || nh->h_ref == NULL) {
73432fe07f8SJohn Marino if (h->h_next != history_def_next) {
73532fe07f8SJohn Marino if (history_def_init(&h->h_ref, &ev, 0) == -1)
73632fe07f8SJohn Marino return -1;
73732fe07f8SJohn Marino h->h_first = history_def_first;
73832fe07f8SJohn Marino h->h_next = history_def_next;
73932fe07f8SJohn Marino h->h_last = history_def_last;
74032fe07f8SJohn Marino h->h_prev = history_def_prev;
74132fe07f8SJohn Marino h->h_curr = history_def_curr;
74232fe07f8SJohn Marino h->h_set = history_def_set;
74332fe07f8SJohn Marino h->h_clear = history_def_clear;
74432fe07f8SJohn Marino h->h_enter = history_def_enter;
74532fe07f8SJohn Marino h->h_add = history_def_add;
74632fe07f8SJohn Marino h->h_del = history_def_del;
74732fe07f8SJohn Marino }
74832fe07f8SJohn Marino return -1;
74932fe07f8SJohn Marino }
75032fe07f8SJohn Marino if (h->h_next == history_def_next)
75132fe07f8SJohn Marino history_def_clear(h->h_ref, &ev);
75232fe07f8SJohn Marino
75332fe07f8SJohn Marino h->h_ent = -1;
75432fe07f8SJohn Marino h->h_first = nh->h_first;
75532fe07f8SJohn Marino h->h_next = nh->h_next;
75632fe07f8SJohn Marino h->h_last = nh->h_last;
75732fe07f8SJohn Marino h->h_prev = nh->h_prev;
75832fe07f8SJohn Marino h->h_curr = nh->h_curr;
75932fe07f8SJohn Marino h->h_set = nh->h_set;
76032fe07f8SJohn Marino h->h_clear = nh->h_clear;
76132fe07f8SJohn Marino h->h_enter = nh->h_enter;
76232fe07f8SJohn Marino h->h_add = nh->h_add;
76332fe07f8SJohn Marino h->h_del = nh->h_del;
76432fe07f8SJohn Marino
76532fe07f8SJohn Marino return 0;
76632fe07f8SJohn Marino }
76732fe07f8SJohn Marino
76832fe07f8SJohn Marino
76932fe07f8SJohn Marino /* history_load():
77032fe07f8SJohn Marino * TYPE(History) load function
77132fe07f8SJohn Marino */
77212db70c8Szrj static int
history_load(TYPE (History)* h,const char * fname)77332fe07f8SJohn Marino history_load(TYPE(History) *h, const char *fname)
77432fe07f8SJohn Marino {
77532fe07f8SJohn Marino FILE *fp;
77632fe07f8SJohn Marino char *line;
77712db70c8Szrj size_t llen;
77812db70c8Szrj ssize_t sz;
77912db70c8Szrj size_t max_size;
78032fe07f8SJohn Marino char *ptr;
78132fe07f8SJohn Marino int i = -1;
78232fe07f8SJohn Marino TYPE(HistEvent) ev;
783ae19eda8Szrj Char *decode_result;
78412db70c8Szrj #ifndef NARROWCHAR
78532fe07f8SJohn Marino static ct_buffer_t conv;
78632fe07f8SJohn Marino #endif
78732fe07f8SJohn Marino
78832fe07f8SJohn Marino if ((fp = fopen(fname, "r")) == NULL)
78932fe07f8SJohn Marino return i;
79032fe07f8SJohn Marino
79112db70c8Szrj line = NULL;
79212db70c8Szrj llen = 0;
79312db70c8Szrj if ((sz = getline(&line, &llen, fp)) == -1)
79432fe07f8SJohn Marino goto done;
79532fe07f8SJohn Marino
79612db70c8Szrj if (strncmp(line, hist_cookie, (size_t)sz) != 0)
79732fe07f8SJohn Marino goto done;
79832fe07f8SJohn Marino
79932fe07f8SJohn Marino ptr = h_malloc((max_size = 1024) * sizeof(*ptr));
80032fe07f8SJohn Marino if (ptr == NULL)
80132fe07f8SJohn Marino goto done;
80212db70c8Szrj for (i = 0; (sz = getline(&line, &llen, fp)) != -1; i++) {
80312db70c8Szrj if (sz > 0 && line[sz - 1] == '\n')
80432fe07f8SJohn Marino line[--sz] = '\0';
80512db70c8Szrj if (max_size < (size_t)sz) {
80632fe07f8SJohn Marino char *nptr;
80712db70c8Szrj max_size = ((size_t)sz + 1024) & (size_t)~1023;
80832fe07f8SJohn Marino nptr = h_realloc(ptr, max_size * sizeof(*ptr));
80932fe07f8SJohn Marino if (nptr == NULL) {
81032fe07f8SJohn Marino i = -1;
81132fe07f8SJohn Marino goto oomem;
81232fe07f8SJohn Marino }
81332fe07f8SJohn Marino ptr = nptr;
81432fe07f8SJohn Marino }
81532fe07f8SJohn Marino (void) strunvis(ptr, line);
816ae19eda8Szrj decode_result = ct_decode_string(ptr, &conv);
817ae19eda8Szrj if (decode_result == NULL)
818ae19eda8Szrj continue;
819ae19eda8Szrj if (HENTER(h, &ev, decode_result) == -1) {
82032fe07f8SJohn Marino i = -1;
82132fe07f8SJohn Marino goto oomem;
82232fe07f8SJohn Marino }
82332fe07f8SJohn Marino }
82432fe07f8SJohn Marino oomem:
82532fe07f8SJohn Marino h_free(ptr);
82632fe07f8SJohn Marino done:
82712db70c8Szrj free(line);
82832fe07f8SJohn Marino (void) fclose(fp);
82932fe07f8SJohn Marino return i;
83032fe07f8SJohn Marino }
83132fe07f8SJohn Marino
83232fe07f8SJohn Marino
83384b940c1SJohn Marino /* history_save_fp():
83432fe07f8SJohn Marino * TYPE(History) save function
83532fe07f8SJohn Marino */
83612db70c8Szrj static int
history_save_fp(TYPE (History)* h,size_t nelem,FILE * fp)837ae19eda8Szrj history_save_fp(TYPE(History) *h, size_t nelem, FILE *fp)
83832fe07f8SJohn Marino {
83932fe07f8SJohn Marino TYPE(HistEvent) ev;
84032fe07f8SJohn Marino int i = -1, retval;
84132fe07f8SJohn Marino size_t len, max_size;
84232fe07f8SJohn Marino char *ptr;
84332fe07f8SJohn Marino const char *str;
84412db70c8Szrj #ifndef NARROWCHAR
84532fe07f8SJohn Marino static ct_buffer_t conv;
84632fe07f8SJohn Marino #endif
84732fe07f8SJohn Marino
84832fe07f8SJohn Marino if (fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1)
84932fe07f8SJohn Marino goto done;
850ae19eda8Szrj if (ftell(fp) == 0 && fputs(hist_cookie, fp) == EOF)
85132fe07f8SJohn Marino goto done;
85232fe07f8SJohn Marino ptr = h_malloc((max_size = 1024) * sizeof(*ptr));
85332fe07f8SJohn Marino if (ptr == NULL)
85432fe07f8SJohn Marino goto done;
855ae19eda8Szrj if (nelem != (size_t)-1) {
856ae19eda8Szrj for (retval = HFIRST(h, &ev); retval != -1 && nelem-- > 0;
857ae19eda8Szrj retval = HNEXT(h, &ev))
858ae19eda8Szrj continue;
859ae19eda8Szrj } else
860ae19eda8Szrj retval = -1;
861ae19eda8Szrj
862ae19eda8Szrj if (retval == -1)
863ae19eda8Szrj retval = HLAST(h, &ev);
864ae19eda8Szrj
865ae19eda8Szrj for (i = 0; retval != -1; retval = HPREV(h, &ev), i++) {
86632fe07f8SJohn Marino str = ct_encode_string(ev.str, &conv);
86712db70c8Szrj len = strlen(str) * 4 + 1;
86812db70c8Szrj if (len > max_size) {
86932fe07f8SJohn Marino char *nptr;
87032fe07f8SJohn Marino max_size = (len + 1024) & (size_t)~1023;
87132fe07f8SJohn Marino nptr = h_realloc(ptr, max_size * sizeof(*ptr));
87232fe07f8SJohn Marino if (nptr == NULL) {
87332fe07f8SJohn Marino i = -1;
87432fe07f8SJohn Marino goto oomem;
87532fe07f8SJohn Marino }
87632fe07f8SJohn Marino ptr = nptr;
87732fe07f8SJohn Marino }
87832fe07f8SJohn Marino (void) strvis(ptr, str, VIS_WHITE);
87932fe07f8SJohn Marino (void) fprintf(fp, "%s\n", ptr);
88032fe07f8SJohn Marino }
88132fe07f8SJohn Marino oomem:
88232fe07f8SJohn Marino h_free(ptr);
88332fe07f8SJohn Marino done:
88484b940c1SJohn Marino return i;
88584b940c1SJohn Marino }
88684b940c1SJohn Marino
88784b940c1SJohn Marino
88884b940c1SJohn Marino /* history_save():
88984b940c1SJohn Marino * History save function
89084b940c1SJohn Marino */
89112db70c8Szrj static int
history_save(TYPE (History)* h,const char * fname)89284b940c1SJohn Marino history_save(TYPE(History) *h, const char *fname)
89384b940c1SJohn Marino {
89484b940c1SJohn Marino FILE *fp;
89584b940c1SJohn Marino int i;
89684b940c1SJohn Marino
89784b940c1SJohn Marino if ((fp = fopen(fname, "w")) == NULL)
89884b940c1SJohn Marino return -1;
89984b940c1SJohn Marino
900ae19eda8Szrj i = history_save_fp(h, (size_t)-1, fp);
90184b940c1SJohn Marino
90232fe07f8SJohn Marino (void) fclose(fp);
90332fe07f8SJohn Marino return i;
90432fe07f8SJohn Marino }
90532fe07f8SJohn Marino
90632fe07f8SJohn Marino
90732fe07f8SJohn Marino /* history_prev_event():
90832fe07f8SJohn Marino * Find the previous event, with number given
90932fe07f8SJohn Marino */
91012db70c8Szrj static int
history_prev_event(TYPE (History)* h,TYPE (HistEvent)* ev,int num)91132fe07f8SJohn Marino history_prev_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
91232fe07f8SJohn Marino {
91332fe07f8SJohn Marino int retval;
91432fe07f8SJohn Marino
91532fe07f8SJohn Marino for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
91632fe07f8SJohn Marino if (ev->num == num)
91732fe07f8SJohn Marino return 0;
91832fe07f8SJohn Marino
91932fe07f8SJohn Marino he_seterrev(ev, _HE_NOT_FOUND);
92032fe07f8SJohn Marino return -1;
92132fe07f8SJohn Marino }
92232fe07f8SJohn Marino
92332fe07f8SJohn Marino
92412db70c8Szrj static int
history_next_evdata(TYPE (History)* h,TYPE (HistEvent)* ev,int num,void ** d)92532fe07f8SJohn Marino history_next_evdata(TYPE(History) *h, TYPE(HistEvent) *ev, int num, void **d)
92632fe07f8SJohn Marino {
92732fe07f8SJohn Marino int retval;
92832fe07f8SJohn Marino
92932fe07f8SJohn Marino for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
93032fe07f8SJohn Marino if (ev->num == num) {
93132fe07f8SJohn Marino if (d)
93232fe07f8SJohn Marino *d = ((history_t *)h->h_ref)->cursor->data;
93332fe07f8SJohn Marino return 0;
93432fe07f8SJohn Marino }
93532fe07f8SJohn Marino
93632fe07f8SJohn Marino he_seterrev(ev, _HE_NOT_FOUND);
93732fe07f8SJohn Marino return -1;
93832fe07f8SJohn Marino }
93932fe07f8SJohn Marino
94032fe07f8SJohn Marino
94132fe07f8SJohn Marino /* history_next_event():
94232fe07f8SJohn Marino * Find the next event, with number given
94332fe07f8SJohn Marino */
94412db70c8Szrj static int
history_next_event(TYPE (History)* h,TYPE (HistEvent)* ev,int num)94532fe07f8SJohn Marino history_next_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
94632fe07f8SJohn Marino {
94732fe07f8SJohn Marino int retval;
94832fe07f8SJohn Marino
94932fe07f8SJohn Marino for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
95032fe07f8SJohn Marino if (ev->num == num)
95132fe07f8SJohn Marino return 0;
95232fe07f8SJohn Marino
95332fe07f8SJohn Marino he_seterrev(ev, _HE_NOT_FOUND);
95432fe07f8SJohn Marino return -1;
95532fe07f8SJohn Marino }
95632fe07f8SJohn Marino
95732fe07f8SJohn Marino
95832fe07f8SJohn Marino /* history_prev_string():
95932fe07f8SJohn Marino * Find the previous event beginning with string
96032fe07f8SJohn Marino */
96112db70c8Szrj static int
history_prev_string(TYPE (History)* h,TYPE (HistEvent)* ev,const Char * str)96232fe07f8SJohn Marino history_prev_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str)
96332fe07f8SJohn Marino {
96432fe07f8SJohn Marino size_t len = Strlen(str);
96532fe07f8SJohn Marino int retval;
96632fe07f8SJohn Marino
96732fe07f8SJohn Marino for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
96832fe07f8SJohn Marino if (Strncmp(str, ev->str, len) == 0)
96932fe07f8SJohn Marino return 0;
97032fe07f8SJohn Marino
97132fe07f8SJohn Marino he_seterrev(ev, _HE_NOT_FOUND);
97232fe07f8SJohn Marino return -1;
97332fe07f8SJohn Marino }
97432fe07f8SJohn Marino
97532fe07f8SJohn Marino
97632fe07f8SJohn Marino /* history_next_string():
97732fe07f8SJohn Marino * Find the next event beginning with string
97832fe07f8SJohn Marino */
97912db70c8Szrj static int
history_next_string(TYPE (History)* h,TYPE (HistEvent)* ev,const Char * str)98032fe07f8SJohn Marino history_next_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str)
98132fe07f8SJohn Marino {
98232fe07f8SJohn Marino size_t len = Strlen(str);
98332fe07f8SJohn Marino int retval;
98432fe07f8SJohn Marino
98532fe07f8SJohn Marino for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
98632fe07f8SJohn Marino if (Strncmp(str, ev->str, len) == 0)
98732fe07f8SJohn Marino return 0;
98832fe07f8SJohn Marino
98932fe07f8SJohn Marino he_seterrev(ev, _HE_NOT_FOUND);
99032fe07f8SJohn Marino return -1;
99132fe07f8SJohn Marino }
99232fe07f8SJohn Marino
99332fe07f8SJohn Marino
99432fe07f8SJohn Marino /* history():
99532fe07f8SJohn Marino * User interface to history functions.
99632fe07f8SJohn Marino */
99732fe07f8SJohn Marino int
FUNW(history)99832fe07f8SJohn Marino FUNW(history)(TYPE(History) *h, TYPE(HistEvent) *ev, int fun, ...)
99932fe07f8SJohn Marino {
100032fe07f8SJohn Marino va_list va;
100132fe07f8SJohn Marino const Char *str;
100232fe07f8SJohn Marino int retval;
100332fe07f8SJohn Marino
100432fe07f8SJohn Marino va_start(va, fun);
100532fe07f8SJohn Marino
100632fe07f8SJohn Marino he_seterrev(ev, _HE_OK);
100732fe07f8SJohn Marino
100832fe07f8SJohn Marino switch (fun) {
100932fe07f8SJohn Marino case H_GETSIZE:
101032fe07f8SJohn Marino retval = history_getsize(h, ev);
101132fe07f8SJohn Marino break;
101232fe07f8SJohn Marino
101332fe07f8SJohn Marino case H_SETSIZE:
101432fe07f8SJohn Marino retval = history_setsize(h, ev, va_arg(va, int));
101532fe07f8SJohn Marino break;
101632fe07f8SJohn Marino
101732fe07f8SJohn Marino case H_GETUNIQUE:
101832fe07f8SJohn Marino retval = history_getunique(h, ev);
101932fe07f8SJohn Marino break;
102032fe07f8SJohn Marino
102132fe07f8SJohn Marino case H_SETUNIQUE:
102232fe07f8SJohn Marino retval = history_setunique(h, ev, va_arg(va, int));
102332fe07f8SJohn Marino break;
102432fe07f8SJohn Marino
102532fe07f8SJohn Marino case H_ADD:
102632fe07f8SJohn Marino str = va_arg(va, const Char *);
102732fe07f8SJohn Marino retval = HADD(h, ev, str);
102832fe07f8SJohn Marino break;
102932fe07f8SJohn Marino
103032fe07f8SJohn Marino case H_DEL:
103132fe07f8SJohn Marino retval = HDEL(h, ev, va_arg(va, const int));
103232fe07f8SJohn Marino break;
103332fe07f8SJohn Marino
103432fe07f8SJohn Marino case H_ENTER:
103532fe07f8SJohn Marino str = va_arg(va, const Char *);
103632fe07f8SJohn Marino if ((retval = HENTER(h, ev, str)) != -1)
103732fe07f8SJohn Marino h->h_ent = ev->num;
103832fe07f8SJohn Marino break;
103932fe07f8SJohn Marino
104032fe07f8SJohn Marino case H_APPEND:
104132fe07f8SJohn Marino str = va_arg(va, const Char *);
104232fe07f8SJohn Marino if ((retval = HSET(h, ev, h->h_ent)) != -1)
104332fe07f8SJohn Marino retval = HADD(h, ev, str);
104432fe07f8SJohn Marino break;
104532fe07f8SJohn Marino
104632fe07f8SJohn Marino case H_FIRST:
104732fe07f8SJohn Marino retval = HFIRST(h, ev);
104832fe07f8SJohn Marino break;
104932fe07f8SJohn Marino
105032fe07f8SJohn Marino case H_NEXT:
105132fe07f8SJohn Marino retval = HNEXT(h, ev);
105232fe07f8SJohn Marino break;
105332fe07f8SJohn Marino
105432fe07f8SJohn Marino case H_LAST:
105532fe07f8SJohn Marino retval = HLAST(h, ev);
105632fe07f8SJohn Marino break;
105732fe07f8SJohn Marino
105832fe07f8SJohn Marino case H_PREV:
105932fe07f8SJohn Marino retval = HPREV(h, ev);
106032fe07f8SJohn Marino break;
106132fe07f8SJohn Marino
106232fe07f8SJohn Marino case H_CURR:
106332fe07f8SJohn Marino retval = HCURR(h, ev);
106432fe07f8SJohn Marino break;
106532fe07f8SJohn Marino
106632fe07f8SJohn Marino case H_SET:
106732fe07f8SJohn Marino retval = HSET(h, ev, va_arg(va, const int));
106832fe07f8SJohn Marino break;
106932fe07f8SJohn Marino
107032fe07f8SJohn Marino case H_CLEAR:
107132fe07f8SJohn Marino HCLEAR(h, ev);
107232fe07f8SJohn Marino retval = 0;
107332fe07f8SJohn Marino break;
107432fe07f8SJohn Marino
107532fe07f8SJohn Marino case H_LOAD:
107632fe07f8SJohn Marino retval = history_load(h, va_arg(va, const char *));
107732fe07f8SJohn Marino if (retval == -1)
107832fe07f8SJohn Marino he_seterrev(ev, _HE_HIST_READ);
107932fe07f8SJohn Marino break;
108032fe07f8SJohn Marino
108132fe07f8SJohn Marino case H_SAVE:
108232fe07f8SJohn Marino retval = history_save(h, va_arg(va, const char *));
108332fe07f8SJohn Marino if (retval == -1)
108432fe07f8SJohn Marino he_seterrev(ev, _HE_HIST_WRITE);
108532fe07f8SJohn Marino break;
108632fe07f8SJohn Marino
108784b940c1SJohn Marino case H_SAVE_FP:
1088ae19eda8Szrj retval = history_save_fp(h, (size_t)-1, va_arg(va, FILE *));
108984b940c1SJohn Marino if (retval == -1)
109084b940c1SJohn Marino he_seterrev(ev, _HE_HIST_WRITE);
109184b940c1SJohn Marino break;
109284b940c1SJohn Marino
1093ae19eda8Szrj case H_NSAVE_FP:
1094ae19eda8Szrj {
1095ae19eda8Szrj size_t sz = va_arg(va, size_t);
1096ae19eda8Szrj retval = history_save_fp(h, sz, va_arg(va, FILE *));
1097ae19eda8Szrj if (retval == -1)
1098ae19eda8Szrj he_seterrev(ev, _HE_HIST_WRITE);
1099ae19eda8Szrj break;
1100ae19eda8Szrj }
1101ae19eda8Szrj
110232fe07f8SJohn Marino case H_PREV_EVENT:
110332fe07f8SJohn Marino retval = history_prev_event(h, ev, va_arg(va, int));
110432fe07f8SJohn Marino break;
110532fe07f8SJohn Marino
110632fe07f8SJohn Marino case H_NEXT_EVENT:
110732fe07f8SJohn Marino retval = history_next_event(h, ev, va_arg(va, int));
110832fe07f8SJohn Marino break;
110932fe07f8SJohn Marino
111032fe07f8SJohn Marino case H_PREV_STR:
111132fe07f8SJohn Marino retval = history_prev_string(h, ev, va_arg(va, const Char *));
111232fe07f8SJohn Marino break;
111332fe07f8SJohn Marino
111432fe07f8SJohn Marino case H_NEXT_STR:
111532fe07f8SJohn Marino retval = history_next_string(h, ev, va_arg(va, const Char *));
111632fe07f8SJohn Marino break;
111732fe07f8SJohn Marino
111832fe07f8SJohn Marino case H_FUNC:
111932fe07f8SJohn Marino {
112032fe07f8SJohn Marino TYPE(History) hf;
112132fe07f8SJohn Marino
112232fe07f8SJohn Marino hf.h_ref = va_arg(va, void *);
112332fe07f8SJohn Marino h->h_ent = -1;
112432fe07f8SJohn Marino hf.h_first = va_arg(va, history_gfun_t);
112532fe07f8SJohn Marino hf.h_next = va_arg(va, history_gfun_t);
112632fe07f8SJohn Marino hf.h_last = va_arg(va, history_gfun_t);
112732fe07f8SJohn Marino hf.h_prev = va_arg(va, history_gfun_t);
112832fe07f8SJohn Marino hf.h_curr = va_arg(va, history_gfun_t);
112932fe07f8SJohn Marino hf.h_set = va_arg(va, history_sfun_t);
113032fe07f8SJohn Marino hf.h_clear = va_arg(va, history_vfun_t);
113132fe07f8SJohn Marino hf.h_enter = va_arg(va, history_efun_t);
113232fe07f8SJohn Marino hf.h_add = va_arg(va, history_efun_t);
113332fe07f8SJohn Marino hf.h_del = va_arg(va, history_sfun_t);
113432fe07f8SJohn Marino
113532fe07f8SJohn Marino if ((retval = history_set_fun(h, &hf)) == -1)
113632fe07f8SJohn Marino he_seterrev(ev, _HE_PARAM_MISSING);
113732fe07f8SJohn Marino break;
113832fe07f8SJohn Marino }
113932fe07f8SJohn Marino
114032fe07f8SJohn Marino case H_END:
114132fe07f8SJohn Marino FUN(history,end)(h);
114232fe07f8SJohn Marino retval = 0;
114332fe07f8SJohn Marino break;
114432fe07f8SJohn Marino
114532fe07f8SJohn Marino case H_NEXT_EVDATA:
114632fe07f8SJohn Marino {
114732fe07f8SJohn Marino int num = va_arg(va, int);
114832fe07f8SJohn Marino void **d = va_arg(va, void **);
114932fe07f8SJohn Marino retval = history_next_evdata(h, ev, num, d);
115032fe07f8SJohn Marino break;
115132fe07f8SJohn Marino }
115232fe07f8SJohn Marino
115332fe07f8SJohn Marino case H_DELDATA:
115432fe07f8SJohn Marino {
115532fe07f8SJohn Marino int num = va_arg(va, int);
115632fe07f8SJohn Marino void **d = va_arg(va, void **);
115732fe07f8SJohn Marino retval = history_deldata_nth((history_t *)h->h_ref, ev, num, d);
115832fe07f8SJohn Marino break;
115932fe07f8SJohn Marino }
116032fe07f8SJohn Marino
116132fe07f8SJohn Marino case H_REPLACE: /* only use after H_NEXT_EVDATA */
116232fe07f8SJohn Marino {
116332fe07f8SJohn Marino const Char *line = va_arg(va, const Char *);
116432fe07f8SJohn Marino void *d = va_arg(va, void *);
116532fe07f8SJohn Marino const Char *s;
116632fe07f8SJohn Marino if(!line || !(s = Strdup(line))) {
116732fe07f8SJohn Marino retval = -1;
116832fe07f8SJohn Marino break;
116932fe07f8SJohn Marino }
117032fe07f8SJohn Marino ((history_t *)h->h_ref)->cursor->ev.str = s;
117132fe07f8SJohn Marino ((history_t *)h->h_ref)->cursor->data = d;
117232fe07f8SJohn Marino retval = 0;
117332fe07f8SJohn Marino break;
117432fe07f8SJohn Marino }
117532fe07f8SJohn Marino
117632fe07f8SJohn Marino default:
117732fe07f8SJohn Marino retval = -1;
117832fe07f8SJohn Marino he_seterrev(ev, _HE_UNKNOWN);
117932fe07f8SJohn Marino break;
118032fe07f8SJohn Marino }
118132fe07f8SJohn Marino va_end(va);
118232fe07f8SJohn Marino return retval;
118332fe07f8SJohn Marino }
1184