Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/libedit/history.c
39475 views
1
/* $NetBSD: history.c,v 1.64 2024/07/11 05:41:24 kre Exp $ */
2
3
/*-
4
* Copyright (c) 1992, 1993
5
* The Regents of the University of California. All rights reserved.
6
*
7
* This code is derived from software contributed to Berkeley by
8
* Christos Zoulas of Cornell University.
9
*
10
* Redistribution and use in source and binary forms, with or without
11
* modification, are permitted provided that the following conditions
12
* are met:
13
* 1. Redistributions of source code must retain the above copyright
14
* notice, this list of conditions and the following disclaimer.
15
* 2. Redistributions in binary form must reproduce the above copyright
16
* notice, this list of conditions and the following disclaimer in the
17
* documentation and/or other materials provided with the distribution.
18
* 3. Neither the name of the University nor the names of its contributors
19
* may be used to endorse or promote products derived from this software
20
* without specific prior written permission.
21
*
22
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32
* SUCH DAMAGE.
33
*/
34
35
#include "config.h"
36
#if !defined(lint) && !defined(SCCSID)
37
#if 0
38
static char sccsid[] = "@(#)history.c 8.1 (Berkeley) 6/4/93";
39
#else
40
__RCSID("$NetBSD: history.c,v 1.64 2024/07/11 05:41:24 kre Exp $");
41
#endif
42
#endif /* not lint && not SCCSID */
43
44
/*
45
* hist.c: TYPE(History) access functions
46
*/
47
#include <sys/stat.h>
48
#include <fcntl.h>
49
#include <stdarg.h>
50
#include <stdlib.h>
51
#include <string.h>
52
#include <vis.h>
53
54
static const char hist_cookie[] = "_HiStOrY_V2_\n";
55
56
#include "histedit.h"
57
58
59
#ifdef NARROWCHAR
60
61
#define Char char
62
#define FUN(prefix, rest) prefix ## _ ## rest
63
#define FUNW(type) type
64
#define TYPE(type) type
65
#define STR(x) x
66
67
#define Strlen(s) strlen(s)
68
#define Strdup(s) strdup(s)
69
#define Strcmp(d, s) strcmp(d, s)
70
#define Strncmp(d, s, n) strncmp(d, s, n)
71
#define Strncpy(d, s, n) strncpy(d, s, n)
72
#define Strncat(d, s, n) strncat(d, s, n)
73
#define ct_decode_string(s, b) (s)
74
#define ct_encode_string(s, b) (s)
75
76
#else
77
#include "chartype.h"
78
79
#define Char wchar_t
80
#define FUN(prefix, rest) prefix ## _w ## rest
81
#define FUNW(type) type ## _w
82
#define TYPE(type) type ## W
83
#define STR(x) L ## x
84
85
#define Strlen(s) wcslen(s)
86
#define Strdup(s) wcsdup(s)
87
#define Strcmp(d, s) wcscmp(d, s)
88
#define Strncmp(d, s, n) wcsncmp(d, s, n)
89
#define Strncpy(d, s, n) wcsncpy(d, s, n)
90
#define Strncat(d, s, n) wcsncat(d, s, n)
91
92
#endif
93
94
95
typedef int (*history_gfun_t)(void *, TYPE(HistEvent) *);
96
typedef int (*history_efun_t)(void *, TYPE(HistEvent) *, const Char *);
97
typedef void (*history_vfun_t)(void *, TYPE(HistEvent) *);
98
typedef int (*history_sfun_t)(void *, TYPE(HistEvent) *, const int);
99
100
struct TYPE(history) {
101
void *h_ref; /* Argument for history fcns */
102
int h_ent; /* Last entry point for history */
103
history_gfun_t h_first; /* Get the first element */
104
history_gfun_t h_next; /* Get the next element */
105
history_gfun_t h_last; /* Get the last element */
106
history_gfun_t h_prev; /* Get the previous element */
107
history_gfun_t h_curr; /* Get the current element */
108
history_sfun_t h_set; /* Set the current element */
109
history_sfun_t h_del; /* Set the given element */
110
history_vfun_t h_clear; /* Clear the history list */
111
history_efun_t h_enter; /* Add an element */
112
history_efun_t h_add; /* Append to an element */
113
};
114
115
#define HNEXT(h, ev) (*(h)->h_next)((h)->h_ref, ev)
116
#define HFIRST(h, ev) (*(h)->h_first)((h)->h_ref, ev)
117
#define HPREV(h, ev) (*(h)->h_prev)((h)->h_ref, ev)
118
#define HLAST(h, ev) (*(h)->h_last)((h)->h_ref, ev)
119
#define HCURR(h, ev) (*(h)->h_curr)((h)->h_ref, ev)
120
#define HSET(h, ev, n) (*(h)->h_set)((h)->h_ref, ev, n)
121
#define HCLEAR(h, ev) (*(h)->h_clear)((h)->h_ref, ev)
122
#define HENTER(h, ev, str) (*(h)->h_enter)((h)->h_ref, ev, str)
123
#define HADD(h, ev, str) (*(h)->h_add)((h)->h_ref, ev, str)
124
#define HDEL(h, ev, n) (*(h)->h_del)((h)->h_ref, ev, n)
125
126
#define h_strdup(a) Strdup(a)
127
#define h_malloc(a) malloc(a)
128
#define h_realloc(a, b) realloc((a), (b))
129
#define h_free(a) free(a)
130
131
typedef struct {
132
int num;
133
Char *str;
134
} HistEventPrivate;
135
136
137
static int history_setsize(TYPE(History) *, TYPE(HistEvent) *, int);
138
static int history_getsize(TYPE(History) *, TYPE(HistEvent) *);
139
static int history_setunique(TYPE(History) *, TYPE(HistEvent) *, int);
140
static int history_getunique(TYPE(History) *, TYPE(HistEvent) *);
141
static int history_set_fun(TYPE(History) *, TYPE(History) *);
142
static int history_load(TYPE(History) *, const char *);
143
static int history_save(TYPE(History) *, const char *);
144
static int history_save_fp(TYPE(History) *, size_t, FILE *);
145
static int history_prev_event(TYPE(History) *, TYPE(HistEvent) *, int);
146
static int history_next_event(TYPE(History) *, TYPE(HistEvent) *, int);
147
static int history_next_string(TYPE(History) *, TYPE(HistEvent) *,
148
const Char *);
149
static int history_prev_string(TYPE(History) *, TYPE(HistEvent) *,
150
const Char *);
151
152
153
/***********************************************************************/
154
155
/*
156
* Builtin- history implementation
157
*/
158
typedef struct hentry_t {
159
TYPE(HistEvent) ev; /* What we return */
160
void *data; /* data */
161
struct hentry_t *next; /* Next entry */
162
struct hentry_t *prev; /* Previous entry */
163
} hentry_t;
164
165
typedef struct history_t {
166
hentry_t list; /* Fake list header element */
167
hentry_t *cursor; /* Current element in the list */
168
int max; /* Maximum number of events */
169
int cur; /* Current number of events */
170
int eventid; /* For generation of unique event id */
171
int flags; /* TYPE(History) flags */
172
#define H_UNIQUE 1 /* Store only unique elements */
173
} history_t;
174
175
static int history_def_next(void *, TYPE(HistEvent) *);
176
static int history_def_first(void *, TYPE(HistEvent) *);
177
static int history_def_prev(void *, TYPE(HistEvent) *);
178
static int history_def_last(void *, TYPE(HistEvent) *);
179
static int history_def_curr(void *, TYPE(HistEvent) *);
180
static int history_def_set(void *, TYPE(HistEvent) *, const int);
181
static void history_def_clear(void *, TYPE(HistEvent) *);
182
static int history_def_enter(void *, TYPE(HistEvent) *, const Char *);
183
static int history_def_add(void *, TYPE(HistEvent) *, const Char *);
184
static int history_def_del(void *, TYPE(HistEvent) *, const int);
185
186
static int history_def_init(void **, TYPE(HistEvent) *, int);
187
static int history_def_insert(history_t *, TYPE(HistEvent) *, const Char *);
188
static void history_def_delete(history_t *, TYPE(HistEvent) *, hentry_t *);
189
190
static int history_deldata_nth(history_t *, TYPE(HistEvent) *, int, void **);
191
static int history_set_nth(void *, TYPE(HistEvent) *, int);
192
193
#define history_def_setsize(p, num)(void) (((history_t *)p)->max = (num))
194
#define history_def_getsize(p) (((history_t *)p)->cur)
195
#define history_def_getunique(p) (((((history_t *)p)->flags) & H_UNIQUE) != 0)
196
#define history_def_setunique(p, uni) \
197
if (uni) \
198
(((history_t *)p)->flags) |= H_UNIQUE; \
199
else \
200
(((history_t *)p)->flags) &= ~H_UNIQUE
201
202
#define he_strerror(code) he_errlist[code]
203
#define he_seterrev(evp, code) {\
204
evp->num = code;\
205
evp->str = he_strerror(code);\
206
}
207
208
/* error messages */
209
static const Char *const he_errlist[] = {
210
STR("OK"),
211
STR("unknown error"),
212
STR("malloc() failed"),
213
STR("first event not found"),
214
STR("last event not found"),
215
STR("empty list"),
216
STR("no next event"),
217
STR("no previous event"),
218
STR("current event is invalid"),
219
STR("event not found"),
220
STR("can't read history from file"),
221
STR("can't write history"),
222
STR("required parameter(s) not supplied"),
223
STR("history size negative"),
224
STR("function not allowed with other history-functions-set the default"),
225
STR("bad parameters")
226
};
227
/* error codes */
228
#define _HE_OK 0
229
#define _HE_UNKNOWN 1
230
#define _HE_MALLOC_FAILED 2
231
#define _HE_FIRST_NOTFOUND 3
232
#define _HE_LAST_NOTFOUND 4
233
#define _HE_EMPTY_LIST 5
234
#define _HE_END_REACHED 6
235
#define _HE_START_REACHED 7
236
#define _HE_CURR_INVALID 8
237
#define _HE_NOT_FOUND 9
238
#define _HE_HIST_READ 10
239
#define _HE_HIST_WRITE 11
240
#define _HE_PARAM_MISSING 12
241
#define _HE_SIZE_NEGATIVE 13
242
#define _HE_NOT_ALLOWED 14
243
#define _HE_BAD_PARAM 15
244
245
/* history_def_first():
246
* Default function to return the first event in the history.
247
*/
248
static int
249
history_def_first(void *p, TYPE(HistEvent) *ev)
250
{
251
history_t *h = (history_t *) p;
252
253
h->cursor = h->list.next;
254
if (h->cursor != &h->list)
255
*ev = h->cursor->ev;
256
else {
257
he_seterrev(ev, _HE_FIRST_NOTFOUND);
258
return -1;
259
}
260
261
return 0;
262
}
263
264
265
/* history_def_last():
266
* Default function to return the last event in the history.
267
*/
268
static int
269
history_def_last(void *p, TYPE(HistEvent) *ev)
270
{
271
history_t *h = (history_t *) p;
272
273
h->cursor = h->list.prev;
274
if (h->cursor != &h->list)
275
*ev = h->cursor->ev;
276
else {
277
he_seterrev(ev, _HE_LAST_NOTFOUND);
278
return -1;
279
}
280
281
return 0;
282
}
283
284
285
/* history_def_next():
286
* Default function to return the next event in the history.
287
*/
288
static int
289
history_def_next(void *p, TYPE(HistEvent) *ev)
290
{
291
history_t *h = (history_t *) p;
292
293
if (h->cursor == &h->list) {
294
he_seterrev(ev, _HE_EMPTY_LIST);
295
return -1;
296
}
297
298
if (h->cursor->next == &h->list) {
299
he_seterrev(ev, _HE_END_REACHED);
300
return -1;
301
}
302
303
h->cursor = h->cursor->next;
304
*ev = h->cursor->ev;
305
306
return 0;
307
}
308
309
310
/* history_def_prev():
311
* Default function to return the previous event in the history.
312
*/
313
static int
314
history_def_prev(void *p, TYPE(HistEvent) *ev)
315
{
316
history_t *h = (history_t *) p;
317
318
if (h->cursor == &h->list) {
319
he_seterrev(ev,
320
(h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST);
321
return -1;
322
}
323
324
if (h->cursor->prev == &h->list) {
325
he_seterrev(ev, _HE_START_REACHED);
326
return -1;
327
}
328
329
h->cursor = h->cursor->prev;
330
*ev = h->cursor->ev;
331
332
return 0;
333
}
334
335
336
/* history_def_curr():
337
* Default function to return the current event in the history.
338
*/
339
static int
340
history_def_curr(void *p, TYPE(HistEvent) *ev)
341
{
342
history_t *h = (history_t *) p;
343
344
if (h->cursor != &h->list)
345
*ev = h->cursor->ev;
346
else {
347
he_seterrev(ev,
348
(h->cur > 0) ? _HE_CURR_INVALID : _HE_EMPTY_LIST);
349
return -1;
350
}
351
352
return 0;
353
}
354
355
356
/* history_def_set():
357
* Default function to set the current event in the history to the
358
* given one.
359
*/
360
static int
361
history_def_set(void *p, TYPE(HistEvent) *ev, const int n)
362
{
363
history_t *h = (history_t *) p;
364
365
if (h->cur == 0) {
366
he_seterrev(ev, _HE_EMPTY_LIST);
367
return -1;
368
}
369
if (h->cursor == &h->list || h->cursor->ev.num != n) {
370
for (h->cursor = h->list.next; h->cursor != &h->list;
371
h->cursor = h->cursor->next)
372
if (h->cursor->ev.num == n)
373
break;
374
}
375
if (h->cursor == &h->list) {
376
he_seterrev(ev, _HE_NOT_FOUND);
377
return -1;
378
}
379
return 0;
380
}
381
382
383
/* history_set_nth():
384
* Default function to set the current event in the history to the
385
* n-th one.
386
*/
387
static int
388
history_set_nth(void *p, TYPE(HistEvent) *ev, int n)
389
{
390
history_t *h = (history_t *) p;
391
392
if (h->cur == 0) {
393
he_seterrev(ev, _HE_EMPTY_LIST);
394
return -1;
395
}
396
for (h->cursor = h->list.prev; h->cursor != &h->list;
397
h->cursor = h->cursor->prev)
398
if (n-- <= 0)
399
break;
400
if (h->cursor == &h->list) {
401
he_seterrev(ev, _HE_NOT_FOUND);
402
return -1;
403
}
404
return 0;
405
}
406
407
408
/* history_def_add():
409
* Append string to element
410
*/
411
static int
412
history_def_add(void *p, TYPE(HistEvent) *ev, const Char *str)
413
{
414
history_t *h = (history_t *) p;
415
size_t len, elen, slen;
416
Char *s;
417
HistEventPrivate *evp = (void *)&h->cursor->ev;
418
419
if (h->cursor == &h->list)
420
return history_def_enter(p, ev, str);
421
elen = Strlen(evp->str);
422
slen = Strlen(str);
423
len = elen + slen + 1;
424
s = h_malloc(len * sizeof(*s));
425
if (s == NULL) {
426
he_seterrev(ev, _HE_MALLOC_FAILED);
427
return -1;
428
}
429
memcpy(s, evp->str, elen * sizeof(*s));
430
memcpy(s + elen, str, slen * sizeof(*s));
431
s[len - 1] = '\0';
432
h_free(evp->str);
433
evp->str = s;
434
*ev = h->cursor->ev;
435
return 0;
436
}
437
438
439
static int
440
history_deldata_nth(history_t *h, TYPE(HistEvent) *ev,
441
int num, void **data)
442
{
443
if (history_set_nth(h, ev, num) != 0)
444
return -1;
445
/* magic value to skip delete (just set to n-th history) */
446
if (data == (void **)-1)
447
return 0;
448
ev->str = Strdup(h->cursor->ev.str);
449
ev->num = h->cursor->ev.num;
450
if (data)
451
*data = h->cursor->data;
452
history_def_delete(h, ev, h->cursor);
453
return 0;
454
}
455
456
457
/* history_def_del():
458
* Delete element hp of the h list
459
*/
460
/* ARGSUSED */
461
static int
462
history_def_del(void *p, TYPE(HistEvent) *ev __attribute__((__unused__)),
463
const int num)
464
{
465
history_t *h = (history_t *) p;
466
if (history_def_set(h, ev, num) != 0)
467
return -1;
468
ev->str = Strdup(h->cursor->ev.str);
469
ev->num = h->cursor->ev.num;
470
history_def_delete(h, ev, h->cursor);
471
return 0;
472
}
473
474
475
/* history_def_delete():
476
* Delete element hp of the h list
477
*/
478
/* ARGSUSED */
479
static void
480
history_def_delete(history_t *h,
481
TYPE(HistEvent) *ev __attribute__((__unused__)), hentry_t *hp)
482
{
483
HistEventPrivate *evp = (void *)&hp->ev;
484
if (hp == &h->list)
485
abort();
486
if (h->cursor == hp) {
487
h->cursor = hp->prev;
488
if (h->cursor == &h->list)
489
h->cursor = hp->next;
490
}
491
hp->prev->next = hp->next;
492
hp->next->prev = hp->prev;
493
h_free(evp->str);
494
h_free(hp);
495
h->cur--;
496
}
497
498
499
/* history_def_insert():
500
* Insert element with string str in the h list
501
*/
502
static int
503
history_def_insert(history_t *h, TYPE(HistEvent) *ev, const Char *str)
504
{
505
hentry_t *c;
506
507
c = h_malloc(sizeof(*c));
508
if (c == NULL)
509
goto oomem;
510
if ((c->ev.str = h_strdup(str)) == NULL) {
511
h_free(c);
512
goto oomem;
513
}
514
c->data = NULL;
515
c->ev.num = ++h->eventid;
516
c->next = h->list.next;
517
c->prev = &h->list;
518
h->list.next->prev = c;
519
h->list.next = c;
520
h->cur++;
521
h->cursor = c;
522
523
*ev = c->ev;
524
return 0;
525
oomem:
526
he_seterrev(ev, _HE_MALLOC_FAILED);
527
return -1;
528
}
529
530
531
/* history_def_enter():
532
* Default function to enter an item in the history
533
*/
534
static int
535
history_def_enter(void *p, TYPE(HistEvent) *ev, const Char *str)
536
{
537
history_t *h = (history_t *) p;
538
539
if ((h->flags & H_UNIQUE) != 0 && h->list.next != &h->list &&
540
Strcmp(h->list.next->ev.str, str) == 0)
541
return 0;
542
543
if (history_def_insert(h, ev, str) == -1)
544
return -1; /* error, keep error message */
545
546
/*
547
* Always keep at least one entry.
548
* This way we don't have to check for the empty list.
549
*/
550
while (h->cur > h->max && h->cur > 0)
551
history_def_delete(h, ev, h->list.prev);
552
553
return 1;
554
}
555
556
557
/* history_def_init():
558
* Default history initialization function
559
*/
560
/* ARGSUSED */
561
static int
562
history_def_init(void **p, TYPE(HistEvent) *ev __attribute__((__unused__)), int n)
563
{
564
history_t *h = (history_t *) h_malloc(sizeof(*h));
565
if (h == NULL)
566
return -1;
567
568
if (n <= 0)
569
n = 0;
570
h->eventid = 0;
571
h->cur = 0;
572
h->max = n;
573
h->list.next = h->list.prev = &h->list;
574
h->list.ev.str = NULL;
575
h->list.ev.num = 0;
576
h->cursor = &h->list;
577
h->flags = 0;
578
*p = h;
579
return 0;
580
}
581
582
583
/* history_def_clear():
584
* Default history cleanup function
585
*/
586
static void
587
history_def_clear(void *p, TYPE(HistEvent) *ev)
588
{
589
history_t *h = (history_t *) p;
590
591
while (h->list.prev != &h->list)
592
history_def_delete(h, ev, h->list.prev);
593
h->cursor = &h->list;
594
h->eventid = 0;
595
h->cur = 0;
596
}
597
598
599
600
601
/************************************************************************/
602
603
/* history_init():
604
* Initialization function.
605
*/
606
TYPE(History) *
607
FUN(history,init)(void)
608
{
609
TYPE(HistEvent) ev;
610
TYPE(History) *h = (TYPE(History) *) h_malloc(sizeof(*h));
611
if (h == NULL)
612
return NULL;
613
614
if (history_def_init(&h->h_ref, &ev, 0) == -1) {
615
h_free(h);
616
return NULL;
617
}
618
h->h_ent = -1;
619
h->h_next = history_def_next;
620
h->h_first = history_def_first;
621
h->h_last = history_def_last;
622
h->h_prev = history_def_prev;
623
h->h_curr = history_def_curr;
624
h->h_set = history_def_set;
625
h->h_clear = history_def_clear;
626
h->h_enter = history_def_enter;
627
h->h_add = history_def_add;
628
h->h_del = history_def_del;
629
630
return h;
631
}
632
633
634
/* history_end():
635
* clean up history;
636
*/
637
void
638
FUN(history,end)(TYPE(History) *h)
639
{
640
TYPE(HistEvent) ev;
641
642
if (h->h_next == history_def_next)
643
history_def_clear(h->h_ref, &ev);
644
h_free(h->h_ref);
645
h_free(h);
646
}
647
648
649
650
/* history_setsize():
651
* Set history number of events
652
*/
653
static int
654
history_setsize(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
655
{
656
657
if (h->h_next != history_def_next) {
658
he_seterrev(ev, _HE_NOT_ALLOWED);
659
return -1;
660
}
661
if (num < 0) {
662
he_seterrev(ev, _HE_BAD_PARAM);
663
return -1;
664
}
665
history_def_setsize(h->h_ref, num);
666
return 0;
667
}
668
669
670
/* history_getsize():
671
* Get number of events currently in history
672
*/
673
static int
674
history_getsize(TYPE(History) *h, TYPE(HistEvent) *ev)
675
{
676
if (h->h_next != history_def_next) {
677
he_seterrev(ev, _HE_NOT_ALLOWED);
678
return -1;
679
}
680
ev->num = history_def_getsize(h->h_ref);
681
if (ev->num < -1) {
682
he_seterrev(ev, _HE_SIZE_NEGATIVE);
683
return -1;
684
}
685
return 0;
686
}
687
688
689
/* history_setunique():
690
* Set if adjacent equal events should not be entered in history.
691
*/
692
static int
693
history_setunique(TYPE(History) *h, TYPE(HistEvent) *ev, int uni)
694
{
695
696
if (h->h_next != history_def_next) {
697
he_seterrev(ev, _HE_NOT_ALLOWED);
698
return -1;
699
}
700
history_def_setunique(h->h_ref, uni);
701
return 0;
702
}
703
704
705
/* history_getunique():
706
* Get if adjacent equal events should not be entered in history.
707
*/
708
static int
709
history_getunique(TYPE(History) *h, TYPE(HistEvent) *ev)
710
{
711
if (h->h_next != history_def_next) {
712
he_seterrev(ev, _HE_NOT_ALLOWED);
713
return -1;
714
}
715
ev->num = history_def_getunique(h->h_ref);
716
return 0;
717
}
718
719
720
/* history_set_fun():
721
* Set history functions
722
*/
723
static int
724
history_set_fun(TYPE(History) *h, TYPE(History) *nh)
725
{
726
TYPE(HistEvent) ev;
727
728
if (nh->h_first == NULL || nh->h_next == NULL || nh->h_last == NULL ||
729
nh->h_prev == NULL || nh->h_curr == NULL || nh->h_set == NULL ||
730
nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL ||
731
nh->h_del == NULL || nh->h_ref == NULL) {
732
if (h->h_next != history_def_next) {
733
if (history_def_init(&h->h_ref, &ev, 0) == -1)
734
return -1;
735
h->h_first = history_def_first;
736
h->h_next = history_def_next;
737
h->h_last = history_def_last;
738
h->h_prev = history_def_prev;
739
h->h_curr = history_def_curr;
740
h->h_set = history_def_set;
741
h->h_clear = history_def_clear;
742
h->h_enter = history_def_enter;
743
h->h_add = history_def_add;
744
h->h_del = history_def_del;
745
}
746
return -1;
747
}
748
if (h->h_next == history_def_next)
749
history_def_clear(h->h_ref, &ev);
750
751
h->h_ent = -1;
752
h->h_first = nh->h_first;
753
h->h_next = nh->h_next;
754
h->h_last = nh->h_last;
755
h->h_prev = nh->h_prev;
756
h->h_curr = nh->h_curr;
757
h->h_set = nh->h_set;
758
h->h_clear = nh->h_clear;
759
h->h_enter = nh->h_enter;
760
h->h_add = nh->h_add;
761
h->h_del = nh->h_del;
762
763
return 0;
764
}
765
766
767
/* history_load():
768
* TYPE(History) load function
769
*/
770
static int
771
history_load(TYPE(History) *h, const char *fname)
772
{
773
FILE *fp;
774
char *line;
775
size_t llen;
776
ssize_t sz;
777
size_t max_size;
778
char *ptr;
779
int i = -1;
780
TYPE(HistEvent) ev;
781
Char *decode_result;
782
#ifndef NARROWCHAR
783
static ct_buffer_t conv;
784
#endif
785
786
if ((fp = fopen(fname, "r")) == NULL)
787
return i;
788
789
line = NULL;
790
llen = 0;
791
if ((sz = getline(&line, &llen, fp)) == -1)
792
goto done;
793
794
if (strncmp(line, hist_cookie, (size_t)sz) != 0)
795
goto done;
796
797
ptr = h_malloc((max_size = 1024) * sizeof(*ptr));
798
if (ptr == NULL)
799
goto done;
800
for (i = 0; (sz = getline(&line, &llen, fp)) != -1; i++) {
801
if (sz > 0 && line[sz - 1] == '\n')
802
line[--sz] = '\0';
803
if (max_size < (size_t)sz) {
804
char *nptr;
805
max_size = ((size_t)sz + 1024) & (size_t)~1023;
806
nptr = h_realloc(ptr, max_size * sizeof(*ptr));
807
if (nptr == NULL) {
808
i = -1;
809
goto oomem;
810
}
811
ptr = nptr;
812
}
813
(void) strunvis(ptr, line);
814
decode_result = ct_decode_string(ptr, &conv);
815
if (decode_result == NULL)
816
continue;
817
if (HENTER(h, &ev, decode_result) == -1) {
818
i = -1;
819
goto oomem;
820
}
821
}
822
oomem:
823
h_free(ptr);
824
done:
825
free(line);
826
(void) fclose(fp);
827
return i;
828
}
829
830
831
/* history_save_fp():
832
* TYPE(History) save function
833
*/
834
static int
835
history_save_fp(TYPE(History) *h, size_t nelem, FILE *fp)
836
{
837
TYPE(HistEvent) ev;
838
int i = -1, retval;
839
size_t len, max_size;
840
char *ptr;
841
const char *str;
842
#ifndef NARROWCHAR
843
static ct_buffer_t conv;
844
#endif
845
846
if (ftell(fp) == 0 && fputs(hist_cookie, fp) == EOF)
847
goto done;
848
ptr = h_malloc((max_size = 1024) * sizeof(*ptr));
849
if (ptr == NULL)
850
goto done;
851
if (nelem != (size_t)-1) {
852
for (retval = HFIRST(h, &ev); retval != -1 && nelem-- > 0;
853
retval = HNEXT(h, &ev))
854
continue;
855
} else
856
retval = -1;
857
858
if (retval == -1)
859
retval = HLAST(h, &ev);
860
861
for (i = 0; retval != -1; retval = HPREV(h, &ev), i++) {
862
str = ct_encode_string(ev.str, &conv);
863
len = strlen(str) * 4 + 1;
864
if (len > max_size) {
865
char *nptr;
866
max_size = (len + 1024) & (size_t)~1023;
867
nptr = h_realloc(ptr, max_size * sizeof(*ptr));
868
if (nptr == NULL) {
869
i = -1;
870
goto oomem;
871
}
872
ptr = nptr;
873
}
874
(void) strvis(ptr, str, VIS_WHITE);
875
(void) fprintf(fp, "%s\n", ptr);
876
}
877
oomem:
878
h_free(ptr);
879
done:
880
return i;
881
}
882
883
884
/* history_save():
885
* History save function
886
*/
887
static int
888
history_save(TYPE(History) *h, const char *fname)
889
{
890
FILE *fp;
891
int i;
892
893
if ((i = open(fname, O_WRONLY|O_CREAT|O_TRUNC,
894
S_IRUSR|S_IWUSR)) == -1)
895
return -1;
896
897
if ((fp = fdopen(i, "w")) == NULL)
898
return -1;
899
900
i = history_save_fp(h, (size_t)-1, fp);
901
902
(void) fclose(fp);
903
return i;
904
}
905
906
907
/* history_prev_event():
908
* Find the previous event, with number given
909
*/
910
static int
911
history_prev_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
912
{
913
int retval;
914
915
for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
916
if (ev->num == num)
917
return 0;
918
919
he_seterrev(ev, _HE_NOT_FOUND);
920
return -1;
921
}
922
923
924
static int
925
history_next_evdata(TYPE(History) *h, TYPE(HistEvent) *ev, int num, void **d)
926
{
927
int retval;
928
929
for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
930
if (ev->num == num) {
931
if (d)
932
*d = ((history_t *)h->h_ref)->cursor->data;
933
return 0;
934
}
935
936
he_seterrev(ev, _HE_NOT_FOUND);
937
return -1;
938
}
939
940
941
/* history_next_event():
942
* Find the next event, with number given
943
*/
944
static int
945
history_next_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
946
{
947
int retval;
948
949
for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
950
if (ev->num == num)
951
return 0;
952
953
he_seterrev(ev, _HE_NOT_FOUND);
954
return -1;
955
}
956
957
958
/* history_prev_string():
959
* Find the previous event beginning with string
960
*/
961
static int
962
history_prev_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str)
963
{
964
size_t len = Strlen(str);
965
int retval;
966
967
for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
968
if (Strncmp(str, ev->str, len) == 0)
969
return 0;
970
971
he_seterrev(ev, _HE_NOT_FOUND);
972
return -1;
973
}
974
975
976
/* history_next_string():
977
* Find the next event beginning with string
978
*/
979
static int
980
history_next_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str)
981
{
982
size_t len = Strlen(str);
983
int retval;
984
985
for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
986
if (Strncmp(str, ev->str, len) == 0)
987
return 0;
988
989
he_seterrev(ev, _HE_NOT_FOUND);
990
return -1;
991
}
992
993
994
/* history():
995
* User interface to history functions.
996
*/
997
int
998
FUNW(history)(TYPE(History) *h, TYPE(HistEvent) *ev, int fun, ...)
999
{
1000
va_list va;
1001
const Char *str;
1002
int retval;
1003
1004
va_start(va, fun);
1005
1006
he_seterrev(ev, _HE_OK);
1007
1008
switch (fun) {
1009
case H_GETSIZE:
1010
retval = history_getsize(h, ev);
1011
break;
1012
1013
case H_SETSIZE:
1014
retval = history_setsize(h, ev, va_arg(va, int));
1015
break;
1016
1017
case H_GETUNIQUE:
1018
retval = history_getunique(h, ev);
1019
break;
1020
1021
case H_SETUNIQUE:
1022
retval = history_setunique(h, ev, va_arg(va, int));
1023
break;
1024
1025
case H_ADD:
1026
str = va_arg(va, const Char *);
1027
retval = HADD(h, ev, str);
1028
break;
1029
1030
case H_DEL:
1031
retval = HDEL(h, ev, va_arg(va, const int));
1032
break;
1033
1034
case H_ENTER:
1035
str = va_arg(va, const Char *);
1036
if ((retval = HENTER(h, ev, str)) != -1)
1037
h->h_ent = ev->num;
1038
break;
1039
1040
case H_APPEND:
1041
str = va_arg(va, const Char *);
1042
if ((retval = HSET(h, ev, h->h_ent)) != -1)
1043
retval = HADD(h, ev, str);
1044
break;
1045
1046
case H_FIRST:
1047
retval = HFIRST(h, ev);
1048
break;
1049
1050
case H_NEXT:
1051
retval = HNEXT(h, ev);
1052
break;
1053
1054
case H_LAST:
1055
retval = HLAST(h, ev);
1056
break;
1057
1058
case H_PREV:
1059
retval = HPREV(h, ev);
1060
break;
1061
1062
case H_CURR:
1063
retval = HCURR(h, ev);
1064
break;
1065
1066
case H_SET:
1067
retval = HSET(h, ev, va_arg(va, const int));
1068
break;
1069
1070
case H_CLEAR:
1071
HCLEAR(h, ev);
1072
retval = 0;
1073
break;
1074
1075
case H_LOAD:
1076
retval = history_load(h, va_arg(va, const char *));
1077
if (retval == -1)
1078
he_seterrev(ev, _HE_HIST_READ);
1079
break;
1080
1081
case H_SAVE:
1082
retval = history_save(h, va_arg(va, const char *));
1083
if (retval == -1)
1084
he_seterrev(ev, _HE_HIST_WRITE);
1085
break;
1086
1087
case H_SAVE_FP:
1088
retval = history_save_fp(h, (size_t)-1, va_arg(va, FILE *));
1089
if (retval == -1)
1090
he_seterrev(ev, _HE_HIST_WRITE);
1091
break;
1092
1093
case H_NSAVE_FP:
1094
{
1095
size_t sz = va_arg(va, size_t);
1096
retval = history_save_fp(h, sz, va_arg(va, FILE *));
1097
if (retval == -1)
1098
he_seterrev(ev, _HE_HIST_WRITE);
1099
break;
1100
}
1101
1102
case H_PREV_EVENT:
1103
retval = history_prev_event(h, ev, va_arg(va, int));
1104
break;
1105
1106
case H_NEXT_EVENT:
1107
retval = history_next_event(h, ev, va_arg(va, int));
1108
break;
1109
1110
case H_PREV_STR:
1111
retval = history_prev_string(h, ev, va_arg(va, const Char *));
1112
break;
1113
1114
case H_NEXT_STR:
1115
retval = history_next_string(h, ev, va_arg(va, const Char *));
1116
break;
1117
1118
case H_FUNC:
1119
{
1120
TYPE(History) hf;
1121
1122
hf.h_ref = va_arg(va, void *);
1123
h->h_ent = -1;
1124
hf.h_first = va_arg(va, history_gfun_t);
1125
hf.h_next = va_arg(va, history_gfun_t);
1126
hf.h_last = va_arg(va, history_gfun_t);
1127
hf.h_prev = va_arg(va, history_gfun_t);
1128
hf.h_curr = va_arg(va, history_gfun_t);
1129
hf.h_set = va_arg(va, history_sfun_t);
1130
hf.h_clear = va_arg(va, history_vfun_t);
1131
hf.h_enter = va_arg(va, history_efun_t);
1132
hf.h_add = va_arg(va, history_efun_t);
1133
hf.h_del = va_arg(va, history_sfun_t);
1134
1135
if ((retval = history_set_fun(h, &hf)) == -1)
1136
he_seterrev(ev, _HE_PARAM_MISSING);
1137
break;
1138
}
1139
1140
case H_END:
1141
FUN(history,end)(h);
1142
retval = 0;
1143
break;
1144
1145
case H_NEXT_EVDATA:
1146
{
1147
int num = va_arg(va, int);
1148
void **d = va_arg(va, void **);
1149
retval = history_next_evdata(h, ev, num, d);
1150
break;
1151
}
1152
1153
case H_DELDATA:
1154
{
1155
int num = va_arg(va, int);
1156
void **d = va_arg(va, void **);
1157
retval = history_deldata_nth((history_t *)h->h_ref, ev, num, d);
1158
break;
1159
}
1160
1161
case H_REPLACE: /* only use after H_NEXT_EVDATA */
1162
{
1163
const Char *line = va_arg(va, const Char *);
1164
void *d = va_arg(va, void *);
1165
const Char *s;
1166
if(!line || !(s = Strdup(line))) {
1167
retval = -1;
1168
break;
1169
}
1170
((history_t *)h->h_ref)->cursor->ev.str = s;
1171
((history_t *)h->h_ref)->cursor->data = d;
1172
retval = 0;
1173
break;
1174
}
1175
1176
default:
1177
retval = -1;
1178
he_seterrev(ev, _HE_UNKNOWN);
1179
break;
1180
}
1181
va_end(va);
1182
return retval;
1183
}
1184
1185