GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libedit/history.c Lines: 173 418 41.4 %
Date: 2017-11-07 Branches: 68 288 23.6 %

Line Branch Exec Source
1
/*	$OpenBSD: history.c,v 1.28 2016/04/11 21:17:29 schwarze Exp $	*/
2
/*	$NetBSD: history.c,v 1.37 2010/01/03 18:27:10 christos Exp $	*/
3
4
/*-
5
 * Copyright (c) 1992, 1993
6
 *	The Regents of the University of California.  All rights reserved.
7
 *
8
 * This code is derived from software contributed to Berkeley by
9
 * Christos Zoulas of Cornell University.
10
 *
11
 * Redistribution and use in source and binary forms, with or without
12
 * modification, are permitted provided that the following conditions
13
 * are met:
14
 * 1. Redistributions of source code must retain the above copyright
15
 *    notice, this list of conditions and the following disclaimer.
16
 * 2. Redistributions in binary form must reproduce the above copyright
17
 *    notice, this list of conditions and the following disclaimer in the
18
 *    documentation and/or other materials provided with the distribution.
19
 * 3. Neither the name of the University nor the names of its contributors
20
 *    may be used to endorse or promote products derived from this software
21
 *    without specific prior written permission.
22
 *
23
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33
 * SUCH DAMAGE.
34
 */
35
36
#include "config.h"
37
38
/*
39
 * hist.c: TYPE(History) access functions
40
 */
41
#include <sys/stat.h>
42
#include <stdarg.h>
43
#include <stdlib.h>
44
#include <string.h>
45
#ifdef HAVE_VIS_H
46
#include <vis.h>
47
#else
48
#include "np/vis.h"
49
#endif
50
51
static const char hist_cookie[] = "_HiStOrY_V2_\n";
52
53
#include "histedit.h"
54
55
56
#ifdef NARROWCHAR
57
58
#define	Char			char
59
#define	FUN(prefix, rest)	prefix ## _ ## rest
60
#define	FUNW(type)		type
61
#define	TYPE(type)		type
62
#define	STR(x)			x
63
64
#define	Strlen(s)		strlen(s)
65
#define	Strdup(s)		strdup(s)
66
#define	Strcmp(d, s)		strcmp(d, s)
67
#define	Strncmp(d, s, n)	strncmp(d, s, n)
68
#define	Strncpy(d, s, n)	strncpy(d, s, n)
69
#define	Strncat(d, s, n)	strncat(d, s, n)
70
#define	ct_decode_string(s, b)	(s)
71
#define	ct_encode_string(s, b)	(s)
72
73
#else
74
#include "chartype.h"
75
76
#define	Char			wchar_t
77
#define	FUN(prefix, rest)	prefix ## _w ## rest
78
#define	FUNW(type)		type ## _w
79
#define	TYPE(type)		type ## W
80
#define	STR(x)			L ## x
81
82
#define	Strlen(s)		wcslen(s)
83
#define	Strdup(s)		wcsdup(s)
84
#define	Strcmp(d, s)		wcscmp(d, s)
85
#define	Strncmp(d, s, n)	wcsncmp(d, s, n)
86
#define	Strncpy(d, s, n)	wcsncpy(d, s, n)
87
#define	Strncat(d, s, n)	wcsncat(d, s, n)
88
89
#endif
90
91
92
typedef int (*history_gfun_t)(void *, TYPE(HistEvent) *);
93
typedef int (*history_efun_t)(void *, TYPE(HistEvent) *, const Char *);
94
typedef void (*history_vfun_t)(void *, TYPE(HistEvent) *);
95
typedef int (*history_sfun_t)(void *, TYPE(HistEvent) *, const int);
96
97
struct TYPE(history) {
98
	void *h_ref;		/* Argument for history fcns	 */
99
	int h_ent;		/* Last entry point for history	 */
100
	history_gfun_t h_first;	/* Get the first element	 */
101
	history_gfun_t h_next;	/* Get the next element		 */
102
	history_gfun_t h_last;	/* Get the last element		 */
103
	history_gfun_t h_prev;	/* Get the previous element	 */
104
	history_gfun_t h_curr;	/* Get the current element	 */
105
	history_sfun_t h_set;	/* Set the current element	 */
106
	history_sfun_t h_del;	/* Set the given element	 */
107
	history_vfun_t h_clear;	/* Clear the history list	 */
108
	history_efun_t h_enter;	/* Add an element		 */
109
	history_efun_t h_add;	/* Append to an element		 */
110
};
111
112
#define	HNEXT(h, ev)		(*(h)->h_next)((h)->h_ref, ev)
113
#define	HFIRST(h, ev)		(*(h)->h_first)((h)->h_ref, ev)
114
#define	HPREV(h, ev)		(*(h)->h_prev)((h)->h_ref, ev)
115
#define	HLAST(h, ev)		(*(h)->h_last)((h)->h_ref, ev)
116
#define	HCURR(h, ev)		(*(h)->h_curr)((h)->h_ref, ev)
117
#define	HSET(h, ev, n)		(*(h)->h_set)((h)->h_ref, ev, n)
118
#define	HCLEAR(h, ev)		(*(h)->h_clear)((h)->h_ref, ev)
119
#define	HENTER(h, ev, str)	(*(h)->h_enter)((h)->h_ref, ev, str)
120
#define	HADD(h, ev, str)	(*(h)->h_add)((h)->h_ref, ev, str)
121
#define	HDEL(h, ev, n)		(*(h)->h_del)((h)->h_ref, ev, n)
122
123
#define	h_strdup(a)	Strdup(a)
124
125
typedef struct {
126
    int		num;
127
    Char	*str;
128
} HistEventPrivate;
129
130
131
static int history_setsize(TYPE(History) *, TYPE(HistEvent) *, int);
132
static int history_getsize(TYPE(History) *, TYPE(HistEvent) *);
133
static int history_setunique(TYPE(History) *, TYPE(HistEvent) *, int);
134
static int history_getunique(TYPE(History) *, TYPE(HistEvent) *);
135
static int history_set_fun(TYPE(History) *, TYPE(History) *);
136
static int history_load(TYPE(History) *, const char *);
137
static int history_save(TYPE(History) *, const char *);
138
static int history_save_fp(TYPE(History) *, FILE *);
139
static int history_prev_event(TYPE(History) *, TYPE(HistEvent) *, int);
140
static int history_next_event(TYPE(History) *, TYPE(HistEvent) *, int);
141
static int history_next_string(TYPE(History) *, TYPE(HistEvent) *,
142
    const Char *);
143
static int history_prev_string(TYPE(History) *, TYPE(HistEvent) *,
144
    const Char *);
145
146
147
/***********************************************************************/
148
149
/*
150
 * Builtin- history implementation
151
 */
152
typedef struct hentry_t {
153
	TYPE(HistEvent) ev;		/* What we return		 */
154
	void *data;		/* data				 */
155
	struct hentry_t *next;	/* Next entry			 */
156
	struct hentry_t *prev;	/* Previous entry		 */
157
} hentry_t;
158
159
typedef struct history_t {
160
	hentry_t list;		/* Fake list header element	*/
161
	hentry_t *cursor;	/* Current element in the list	*/
162
	int max;		/* Maximum number of events	*/
163
	int cur;		/* Current number of events	*/
164
	int eventid;		/* For generation of unique event id	 */
165
	int flags;		/* TYPE(History) flags		*/
166
#define H_UNIQUE	1	/* Store only unique elements	*/
167
} history_t;
168
169
static int history_def_next(void *, TYPE(HistEvent) *);
170
static int history_def_first(void *, TYPE(HistEvent) *);
171
static int history_def_prev(void *, TYPE(HistEvent) *);
172
static int history_def_last(void *, TYPE(HistEvent) *);
173
static int history_def_curr(void *, TYPE(HistEvent) *);
174
static int history_def_set(void *, TYPE(HistEvent) *, const int);
175
static void history_def_clear(void *, TYPE(HistEvent) *);
176
static int history_def_enter(void *, TYPE(HistEvent) *, const Char *);
177
static int history_def_add(void *, TYPE(HistEvent) *, const Char *);
178
static int history_def_del(void *, TYPE(HistEvent) *, const int);
179
180
static int history_def_init(void **, TYPE(HistEvent) *, int);
181
static int history_def_insert(history_t *, TYPE(HistEvent) *, const Char *);
182
static void history_def_delete(history_t *, TYPE(HistEvent) *, hentry_t *);
183
184
static int history_deldata_nth(history_t *, TYPE(HistEvent) *, int, void **);
185
static int history_set_nth(void *, TYPE(HistEvent) *, int);
186
187
#define	history_def_setsize(p, num)(void) (((history_t *)p)->max = (num))
188
#define	history_def_getsize(p)  (((history_t *)p)->cur)
189
#define	history_def_getunique(p) (((((history_t *)p)->flags) & H_UNIQUE) != 0)
190
#define	history_def_setunique(p, uni) \
191
    if (uni) \
192
	(((history_t *)p)->flags) |= H_UNIQUE; \
193
    else \
194
	(((history_t *)p)->flags) &= ~H_UNIQUE
195
196
#define	he_strerror(code)	he_errlist[code]
197
#define	he_seterrev(evp, code)	{\
198
				    evp->num = code;\
199
				    evp->str = he_strerror(code);\
200
				}
201
202
/* error messages */
203
static const Char *const he_errlist[] = {
204
	STR("OK"),
205
	STR("unknown error"),
206
	STR("malloc() failed"),
207
	STR("first event not found"),
208
	STR("last event not found"),
209
	STR("empty list"),
210
	STR("no next event"),
211
	STR("no previous event"),
212
	STR("current event is invalid"),
213
	STR("event not found"),
214
	STR("can't read history from file"),
215
	STR("can't write history"),
216
	STR("required parameter(s) not supplied"),
217
	STR("history size negative"),
218
	STR("function not allowed with other history-functions-set the default"),
219
	STR("bad parameters")
220
};
221
/* error codes */
222
#define	_HE_OK                   0
223
#define	_HE_UNKNOWN		 1
224
#define	_HE_MALLOC_FAILED        2
225
#define	_HE_FIRST_NOTFOUND       3
226
#define	_HE_LAST_NOTFOUND        4
227
#define	_HE_EMPTY_LIST           5
228
#define	_HE_END_REACHED          6
229
#define	_HE_START_REACHED	 7
230
#define	_HE_CURR_INVALID	 8
231
#define	_HE_NOT_FOUND		 9
232
#define	_HE_HIST_READ		10
233
#define	_HE_HIST_WRITE		11
234
#define	_HE_PARAM_MISSING	12
235
#define	_HE_SIZE_NEGATIVE	13
236
#define	_HE_NOT_ALLOWED		14
237
#define	_HE_BAD_PARAM		15
238
239
/* history_def_first():
240
 *	Default function to return the first event in the history.
241
 */
242
static int
243
history_def_first(void *p, TYPE(HistEvent) *ev)
244
{
245
	history_t *h = (history_t *) p;
246
247
	h->cursor = h->list.next;
248
	if (h->cursor != &h->list)
249
		*ev = h->cursor->ev;
250
	else {
251
		he_seterrev(ev, _HE_FIRST_NOTFOUND);
252
		return -1;
253
	}
254
255
	return 0;
256
}
257
258
259
/* history_def_last():
260
 *	Default function to return the last event in the history.
261
 */
262
static int
263
history_def_last(void *p, TYPE(HistEvent) *ev)
264
{
265
12
	history_t *h = (history_t *) p;
266
267
6
	h->cursor = h->list.prev;
268
6
	if (h->cursor != &h->list)
269
6
		*ev = h->cursor->ev;
270
	else {
271
		he_seterrev(ev, _HE_LAST_NOTFOUND);
272
		return -1;
273
	}
274
275
6
	return 0;
276
6
}
277
278
279
/* history_def_next():
280
 *	Default function to return the next event in the history.
281
 */
282
static int
283
history_def_next(void *p, TYPE(HistEvent) *ev)
284
{
285
24
	history_t *h = (history_t *) p;
286
287
12
	if (h->cursor == &h->list) {
288
		he_seterrev(ev, _HE_EMPTY_LIST);
289
		return -1;
290
	}
291
292
12
	if (h->cursor->next == &h->list) {
293
6
		he_seterrev(ev, _HE_END_REACHED);
294
6
		return -1;
295
	}
296
297
6
        h->cursor = h->cursor->next;
298
6
        *ev = h->cursor->ev;
299
300
6
	return 0;
301
12
}
302
303
304
/* history_def_prev():
305
 *	Default function to return the previous event in the history.
306
 */
307
static int
308
history_def_prev(void *p, TYPE(HistEvent) *ev)
309
{
310
36
	history_t *h = (history_t *) p;
311
312
18
	if (h->cursor == &h->list) {
313
		he_seterrev(ev,
314
		    (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST);
315
		return -1;
316
	}
317
318
18
	if (h->cursor->prev == &h->list) {
319
6
		he_seterrev(ev, _HE_START_REACHED);
320
6
		return -1;
321
	}
322
323
12
        h->cursor = h->cursor->prev;
324
12
        *ev = h->cursor->ev;
325
326
12
	return 0;
327
18
}
328
329
330
/* history_def_curr():
331
 *	Default function to return the current event in the history.
332
 */
333
static int
334
history_def_curr(void *p, TYPE(HistEvent) *ev)
335
{
336
228
	history_t *h = (history_t *) p;
337
338
114
	if (h->cursor != &h->list)
339
114
		*ev = h->cursor->ev;
340
	else {
341
		he_seterrev(ev,
342
		    (h->cur > 0) ? _HE_CURR_INVALID : _HE_EMPTY_LIST);
343
		return -1;
344
	}
345
346
114
	return 0;
347
114
}
348
349
350
/* history_def_set():
351
 *	Default function to set the current event in the history to the
352
 *	given one.
353
 */
354
static int
355
history_def_set(void *p, TYPE(HistEvent) *ev, const int n)
356
{
357
36
	history_t *h = (history_t *) p;
358
359
18
	if (h->cur == 0) {
360
		he_seterrev(ev, _HE_EMPTY_LIST);
361
		return -1;
362
	}
363

36
	if (h->cursor == &h->list || h->cursor->ev.num != n) {
364
12
		for (h->cursor = h->list.next; h->cursor != &h->list;
365
		    h->cursor = h->cursor->next)
366
6
			if (h->cursor->ev.num == n)
367
				break;
368
	}
369
18
	if (h->cursor == &h->list) {
370
		he_seterrev(ev, _HE_NOT_FOUND);
371
		return -1;
372
	}
373
18
	return 0;
374
18
}
375
376
377
/* history_set_nth():
378
 *	Default function to set the current event in the history to the
379
 *	n-th one.
380
 */
381
static int
382
history_set_nth(void *p, TYPE(HistEvent) *ev, int n)
383
{
384
132
	history_t *h = (history_t *) p;
385
386
66
	if (h->cur == 0) {
387
		he_seterrev(ev, _HE_EMPTY_LIST);
388
		return -1;
389
	}
390
240
	for (h->cursor = h->list.prev; h->cursor != &h->list;
391
54
	    h->cursor = h->cursor->prev)
392
120
		if (n-- <= 0)
393
			break;
394
66
	if (h->cursor == &h->list) {
395
		he_seterrev(ev, _HE_NOT_FOUND);
396
		return -1;
397
	}
398
66
	return 0;
399
66
}
400
401
402
/* history_def_add():
403
 *	Append string to element
404
 */
405
static int
406
history_def_add(void *p, TYPE(HistEvent) *ev, const Char *str)
407
{
408
	history_t *h = (history_t *) p;
409
	size_t len;
410
	Char *s;
411
	HistEventPrivate *evp = (void *)&h->cursor->ev;
412
413
	if (h->cursor == &h->list)
414
		return history_def_enter(p, ev, str);
415
	len = Strlen(evp->str) + Strlen(str) + 1;
416
	s = reallocarray(NULL, len, sizeof(*s));
417
	if (s == NULL) {
418
		he_seterrev(ev, _HE_MALLOC_FAILED);
419
		return -1;
420
	}
421
	(void) Strncpy(s, h->cursor->ev.str, len);
422
        s[len - 1] = '\0';
423
	(void) Strncat(s, str, len - Strlen(s) - 1);
424
	free(evp->str);
425
	evp->str = s;
426
	*ev = h->cursor->ev;
427
	return 0;
428
}
429
430
431
static int
432
history_deldata_nth(history_t *h, TYPE(HistEvent) *ev,
433
    int num, void **data)
434
{
435
132
	if (history_set_nth(h, ev, num) != 0)
436
		return -1;
437
	/* magic value to skip delete (just set to n-th history) */
438
66
	if (data == (void **)-1)
439
48
		return 0;
440
18
	ev->str = Strdup(h->cursor->ev.str);
441
18
	ev->num = h->cursor->ev.num;
442
18
	if (data)
443
18
		*data = h->cursor->data;
444
18
	history_def_delete(h, ev, h->cursor);
445
18
	return 0;
446
66
}
447
448
449
/* history_def_del():
450
 *	Delete element hp of the h list
451
 */
452
/* ARGSUSED */
453
static int
454
history_def_del(void *p, TYPE(HistEvent) *ev __attribute__((__unused__)),
455
    const int num)
456
{
457
	history_t *h = (history_t *) p;
458
	if (history_def_set(h, ev, num) != 0)
459
		return -1;
460
	ev->str = Strdup(h->cursor->ev.str);
461
	ev->num = h->cursor->ev.num;
462
	history_def_delete(h, ev, h->cursor);
463
	return 0;
464
}
465
466
467
/* history_def_delete():
468
 *	Delete element hp of the h list
469
 */
470
/* ARGSUSED */
471
static void
472
history_def_delete(history_t *h,
473
		   TYPE(HistEvent) *ev __attribute__((__unused__)), hentry_t *hp)
474
{
475
288
	HistEventPrivate *evp = (void *)&hp->ev;
476
144
	if (hp == &h->list)
477
		abort();
478
144
	if (h->cursor == hp) {
479
84
		h->cursor = hp->prev;
480
84
		if (h->cursor == &h->list)
481
48
			h->cursor = hp->next;
482
	}
483
144
	hp->prev->next = hp->next;
484
144
	hp->next->prev = hp->prev;
485
144
	free(evp->str);
486
144
	free(hp);
487
144
	h->cur--;
488
144
}
489
490
491
/* history_def_insert():
492
 *	Insert element with string str in the h list
493
 */
494
static int
495
history_def_insert(history_t *h, TYPE(HistEvent) *ev, const Char *str)
496
{
497
498
288
	h->cursor = (hentry_t *) malloc(sizeof(hentry_t));
499
144
	if (h->cursor == NULL)
500
		goto oomem;
501
144
	if ((h->cursor->ev.str = h_strdup(str)) == NULL) {
502
		free(h->cursor);
503
		goto oomem;
504
	}
505
144
	h->cursor->data = NULL;
506
144
	h->cursor->ev.num = ++h->eventid;
507
144
	h->cursor->next = h->list.next;
508
144
	h->cursor->prev = &h->list;
509
144
	h->list.next->prev = h->cursor;
510
144
	h->list.next = h->cursor;
511
144
	h->cur++;
512
513
144
	*ev = h->cursor->ev;
514
144
	return 0;
515
oomem:
516
	he_seterrev(ev, _HE_MALLOC_FAILED);
517
	return -1;
518
144
}
519
520
521
/* history_def_enter():
522
 *	Default function to enter an item in the history
523
 */
524
static int
525
history_def_enter(void *p, TYPE(HistEvent) *ev, const Char *str)
526
{
527
288
	history_t *h = (history_t *) p;
528
529

144
	if ((h->flags & H_UNIQUE) != 0 && h->list.next != &h->list &&
530
	    Strcmp(h->list.next->ev.str, str) == 0)
531
	    return 0;
532
533
144
	if (history_def_insert(h, ev, str) == -1)
534
		return -1;	/* error, keep error message */
535
536
	/*
537
         * Always keep at least one entry.
538
         * This way we don't have to check for the empty list.
539
         */
540

162
	while (h->cur > h->max && h->cur > 0)
541
6
		history_def_delete(h, ev, h->list.prev);
542
543
144
	return 1;
544
144
}
545
546
547
/* history_def_init():
548
 *	Default history initialization function
549
 */
550
/* ARGSUSED */
551
static int
552
history_def_init(void **p, TYPE(HistEvent) *ev __attribute__((__unused__)), int n)
553
{
554
12
	history_t *h = (history_t *) malloc(sizeof(history_t));
555
6
	if (h == NULL)
556
		return -1;
557
558
6
	if (n <= 0)
559
6
		n = 0;
560
6
	h->eventid = 0;
561
6
	h->cur = 0;
562
6
	h->max = n;
563
6
	h->list.next = h->list.prev = &h->list;
564
6
	h->list.ev.str = NULL;
565
6
	h->list.ev.num = 0;
566
6
	h->cursor = &h->list;
567
6
	h->flags = 0;
568
6
	*p = h;
569
6
	return 0;
570
6
}
571
572
573
/* history_def_clear():
574
 *	Default history cleanup function
575
 */
576
static void
577
history_def_clear(void *p, TYPE(HistEvent) *ev)
578
{
579
96
	history_t *h = (history_t *) p;
580
581
336
	while (h->list.prev != &h->list)
582
120
		history_def_delete(h, ev, h->list.prev);
583
48
	h->eventid = 0;
584
48
	h->cur = 0;
585
48
}
586
587
588
589
590
/************************************************************************/
591
592
/* history_init():
593
 *	Initialization function.
594
 */
595
TYPE(History) *
596
FUN(history,init)(void)
597
{
598
12
	TYPE(HistEvent) ev;
599
6
	TYPE(History) *h = (TYPE(History) *) malloc(sizeof(TYPE(History)));
600
6
	if (h == NULL)
601
		return NULL;
602
603
6
	if (history_def_init(&h->h_ref, &ev, 0) == -1) {
604
		free(h);
605
		return NULL;
606
	}
607
6
	h->h_ent = -1;
608
6
	h->h_next = history_def_next;
609
6
	h->h_first = history_def_first;
610
6
	h->h_last = history_def_last;
611
6
	h->h_prev = history_def_prev;
612
6
	h->h_curr = history_def_curr;
613
6
	h->h_set = history_def_set;
614
6
	h->h_clear = history_def_clear;
615
6
	h->h_enter = history_def_enter;
616
6
	h->h_add = history_def_add;
617
6
	h->h_del = history_def_del;
618
619
6
	return h;
620
6
}
621
622
623
/* history_end():
624
 *	clean up history;
625
 */
626
void
627
FUN(history,end)(TYPE(History) *h)
628
{
629
	TYPE(HistEvent) ev;
630
631
	if (h->h_next == history_def_next)
632
		history_def_clear(h->h_ref, &ev);
633
	free(h->h_ref);
634
	free(h);
635
}
636
637
638
639
/* history_setsize():
640
 *	Set history number of events
641
 */
642
static int
643
history_setsize(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
644
{
645
646
228
	if (h->h_next != history_def_next) {
647
		he_seterrev(ev, _HE_NOT_ALLOWED);
648
		return -1;
649
	}
650
114
	if (num < 0) {
651
		he_seterrev(ev, _HE_BAD_PARAM);
652
		return -1;
653
	}
654
114
	history_def_setsize(h->h_ref, num);
655
114
	return 0;
656
114
}
657
658
659
/* history_getsize():
660
 *      Get number of events currently in history
661
 */
662
static int
663
history_getsize(TYPE(History) *h, TYPE(HistEvent) *ev)
664
{
665
324
	if (h->h_next != history_def_next) {
666
		he_seterrev(ev, _HE_NOT_ALLOWED);
667
		return -1;
668
	}
669
162
	ev->num = history_def_getsize(h->h_ref);
670
162
	if (ev->num < -1) {
671
		he_seterrev(ev, _HE_SIZE_NEGATIVE);
672
		return -1;
673
	}
674
162
	return 0;
675
162
}
676
677
678
/* history_setunique():
679
 *	Set if adjacent equal events should not be entered in history.
680
 */
681
static int
682
history_setunique(TYPE(History) *h, TYPE(HistEvent) *ev, int uni)
683
{
684
685
	if (h->h_next != history_def_next) {
686
		he_seterrev(ev, _HE_NOT_ALLOWED);
687
		return -1;
688
	}
689
	history_def_setunique(h->h_ref, uni);
690
	return 0;
691
}
692
693
694
/* history_getunique():
695
 *	Get if adjacent equal events should not be entered in history.
696
 */
697
static int
698
history_getunique(TYPE(History) *h, TYPE(HistEvent) *ev)
699
{
700
	if (h->h_next != history_def_next) {
701
		he_seterrev(ev, _HE_NOT_ALLOWED);
702
		return -1;
703
	}
704
	ev->num = history_def_getunique(h->h_ref);
705
	return 0;
706
}
707
708
709
/* history_set_fun():
710
 *	Set history functions
711
 */
712
static int
713
history_set_fun(TYPE(History) *h, TYPE(History) *nh)
714
{
715
	TYPE(HistEvent) ev;
716
717
	if (nh->h_first == NULL || nh->h_next == NULL || nh->h_last == NULL ||
718
	    nh->h_prev == NULL || nh->h_curr == NULL || nh->h_set == NULL ||
719
	    nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL ||
720
	    nh->h_del == NULL || nh->h_ref == NULL) {
721
		if (h->h_next != history_def_next) {
722
			history_def_init(&h->h_ref, &ev, 0);
723
			h->h_first = history_def_first;
724
			h->h_next = history_def_next;
725
			h->h_last = history_def_last;
726
			h->h_prev = history_def_prev;
727
			h->h_curr = history_def_curr;
728
			h->h_set = history_def_set;
729
			h->h_clear = history_def_clear;
730
			h->h_enter = history_def_enter;
731
			h->h_add = history_def_add;
732
			h->h_del = history_def_del;
733
		}
734
		return -1;
735
	}
736
	if (h->h_next == history_def_next)
737
		history_def_clear(h->h_ref, &ev);
738
739
	h->h_ent = -1;
740
	h->h_first = nh->h_first;
741
	h->h_next = nh->h_next;
742
	h->h_last = nh->h_last;
743
	h->h_prev = nh->h_prev;
744
	h->h_curr = nh->h_curr;
745
	h->h_set = nh->h_set;
746
	h->h_clear = nh->h_clear;
747
	h->h_enter = nh->h_enter;
748
	h->h_add = nh->h_add;
749
	h->h_del = nh->h_del;
750
751
	return 0;
752
}
753
754
755
/* history_load():
756
 *	TYPE(History) load function
757
 */
758
static int
759
history_load(TYPE(History) *h, const char *fname)
760
{
761
	FILE *fp;
762
	char *line;
763
	size_t llen;
764
	ssize_t sz;
765
	size_t max_size;
766
	char *ptr;
767
	int i = -1;
768
	TYPE(HistEvent) ev;
769
#ifndef NARROWCHAR
770
	static ct_buffer_t conv;
771
#endif
772
773
	if ((fp = fopen(fname, "r")) == NULL)
774
		return i;
775
776
	line = NULL;
777
	llen = 0;
778
	if ((sz = getline(&line, &llen, fp)) == -1)
779
		goto done;
780
781
	if (strncmp(line, hist_cookie, sz) != 0)
782
		goto done;
783
784
	ptr = malloc(max_size = 1024);
785
	if (ptr == NULL)
786
		goto done;
787
	for (i = 0; (sz = getline(&line, &llen, fp)) != -1; i++) {
788
		if (sz > 0 && line[sz - 1] == '\n')
789
			line[--sz] = '\0';
790
		if (max_size < sz) {
791
			char *nptr;
792
			max_size = (sz + 1024) & ~1023;
793
			nptr = realloc(ptr, max_size);
794
			if (nptr == NULL) {
795
				i = -1;
796
				goto oomem;
797
			}
798
			ptr = nptr;
799
		}
800
		(void) strunvis(ptr, line);
801
		if (HENTER(h, &ev, ct_decode_string(ptr, &conv)) == -1) {
802
			i = -1;
803
			goto oomem;
804
		}
805
	}
806
oomem:
807
	free(ptr);
808
done:
809
	free(line);
810
	(void) fclose(fp);
811
	return i;
812
}
813
814
815
/* history_save_fp():
816
 *	TYPE(History) save function
817
 */
818
static int
819
history_save_fp(TYPE(History) *h, FILE *fp)
820
{
821
	TYPE(HistEvent) ev;
822
	int i = -1, retval;
823
	size_t len, max_size;
824
	char *ptr;
825
#ifndef NARROWCHAR
826
	static ct_buffer_t conv;
827
#endif
828
829
	if (fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1)
830
		goto done;
831
	if (fputs(hist_cookie, fp) == EOF)
832
		goto done;
833
	ptr = malloc(max_size = 1024);
834
	if (ptr == NULL)
835
		goto done;
836
	for (i = 0, retval = HLAST(h, &ev);
837
	    retval != -1;
838
	    retval = HPREV(h, &ev), i++) {
839
		len = Strlen(ev.str) * 4 + 1;
840
		if (len > max_size) {
841
			char *nptr;
842
			max_size = (len + 1024) & ~1023;
843
			nptr = realloc(ptr, max_size);
844
			if (nptr == NULL) {
845
				i = -1;
846
				goto oomem;
847
			}
848
			ptr = nptr;
849
		}
850
		(void) strnvis(ptr, ct_encode_string(ev.str, &conv), max_size,
851
		    VIS_WHITE);
852
		(void) fprintf(fp, "%s\n", ptr);
853
	}
854
oomem:
855
	free(ptr);
856
done:
857
	return i;
858
}
859
860
861
/* history_save():
862
 *    History save function
863
 */
864
static int
865
history_save(TYPE(History) *h, const char *fname)
866
{
867
	FILE *fp;
868
	int i;
869
870
	if ((fp = fopen(fname, "w")) == NULL)
871
		return -1;
872
873
	i = history_save_fp(h, fp);
874
875
	(void) fclose(fp);
876
	return i;
877
}
878
879
880
/* history_prev_event():
881
 *	Find the previous event, with number given
882
 */
883
static int
884
history_prev_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
885
{
886
	int retval;
887
888
	for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
889
		if (ev->num == num)
890
			return 0;
891
892
	he_seterrev(ev, _HE_NOT_FOUND);
893
	return -1;
894
}
895
896
897
static int
898
history_next_evdata(TYPE(History) *h, TYPE(HistEvent) *ev, int num, void **d)
899
{
900
	int retval;
901
902
54
	for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
903
18
		if (ev->num == num) {
904
18
			if (d)
905
18
				*d = ((history_t *)h->h_ref)->cursor->data;
906
18
			return 0;
907
		}
908
909
	he_seterrev(ev, _HE_NOT_FOUND);
910
	return -1;
911
18
}
912
913
914
/* history_next_event():
915
 *	Find the next event, with number given
916
 */
917
static int
918
history_next_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num)
919
{
920
	int retval;
921
922
	for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
923
		if (ev->num == num)
924
			return 0;
925
926
	he_seterrev(ev, _HE_NOT_FOUND);
927
	return -1;
928
}
929
930
931
/* history_prev_string():
932
 *	Find the previous event beginning with string
933
 */
934
static int
935
history_prev_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str)
936
{
937
	size_t len = Strlen(str);
938
	int retval;
939
940
	for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
941
		if (Strncmp(str, ev->str, len) == 0)
942
			return 0;
943
944
	he_seterrev(ev, _HE_NOT_FOUND);
945
	return -1;
946
}
947
948
949
/* history_next_string():
950
 *	Find the next event beginning with string
951
 */
952
static int
953
history_next_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str)
954
{
955
	size_t len = Strlen(str);
956
	int retval;
957
958
	for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
959
		if (Strncmp(str, ev->str, len) == 0)
960
			return 0;
961
962
	he_seterrev(ev, _HE_NOT_FOUND);
963
	return -1;
964
}
965
966
967
/* history():
968
 *	User interface to history functions.
969
 */
970
int
971
FUNW(history)(TYPE(History) *h, TYPE(HistEvent) *ev, int fun, ...)
972
{
973
1404
	va_list va;
974
	const Char *str;
975
	int retval;
976
977
702
	va_start(va, fun);
978
979
702
	he_seterrev(ev, _HE_OK);
980
981







702
	switch (fun) {
982
	case H_GETSIZE:
983
162
		retval = history_getsize(h, ev);
984
162
		break;
985
986
	case H_SETSIZE:
987
342
		retval = history_setsize(h, ev, va_arg(va, int));
988
114
		break;
989
990
	case H_GETUNIQUE:
991
		retval = history_getunique(h, ev);
992
		break;
993
994
	case H_SETUNIQUE:
995
		retval = history_setunique(h, ev, va_arg(va, int));
996
		break;
997
998
	case H_ADD:
999
		str = va_arg(va, const Char *);
1000
		retval = HADD(h, ev, str);
1001
		break;
1002
1003
	case H_DEL:
1004
		retval = HDEL(h, ev, va_arg(va, const int));
1005
		break;
1006
1007
	case H_ENTER:
1008
432
		str = va_arg(va, const Char *);
1009
144
		if ((retval = HENTER(h, ev, str)) != -1)
1010
144
			h->h_ent = ev->num;
1011
		break;
1012
1013
	case H_APPEND:
1014
		str = va_arg(va, const Char *);
1015
		if ((retval = HSET(h, ev, h->h_ent)) != -1)
1016
			retval = HADD(h, ev, str);
1017
		break;
1018
1019
	case H_FIRST:
1020
		retval = HFIRST(h, ev);
1021
		break;
1022
1023
	case H_NEXT:
1024
12
		retval = HNEXT(h, ev);
1025
12
		break;
1026
1027
	case H_LAST:
1028
6
		retval = HLAST(h, ev);
1029
6
		break;
1030
1031
	case H_PREV:
1032
18
		retval = HPREV(h, ev);
1033
18
		break;
1034
1035
	case H_CURR:
1036
96
		retval = HCURR(h, ev);
1037
96
		break;
1038
1039
	case H_SET:
1040
54
		retval = HSET(h, ev, va_arg(va, const int));
1041
18
		break;
1042
1043
	case H_CLEAR:
1044
48
		HCLEAR(h, ev);
1045
		retval = 0;
1046
48
		break;
1047
1048
	case H_LOAD:
1049
		retval = history_load(h, va_arg(va, const char *));
1050
		if (retval == -1)
1051
			he_seterrev(ev, _HE_HIST_READ);
1052
		break;
1053
1054
	case H_SAVE:
1055
		retval = history_save(h, va_arg(va, const char *));
1056
		if (retval == -1)
1057
			he_seterrev(ev, _HE_HIST_WRITE);
1058
		break;
1059
1060
	case H_SAVE_FP:
1061
		retval = history_save_fp(h, va_arg(va, FILE *));
1062
		if (retval == -1)
1063
		    he_seterrev(ev, _HE_HIST_WRITE);
1064
		break;
1065
1066
	case H_PREV_EVENT:
1067
		retval = history_prev_event(h, ev, va_arg(va, int));
1068
		break;
1069
1070
	case H_NEXT_EVENT:
1071
		retval = history_next_event(h, ev, va_arg(va, int));
1072
		break;
1073
1074
	case H_PREV_STR:
1075
		retval = history_prev_string(h, ev, va_arg(va, const Char *));
1076
		break;
1077
1078
	case H_NEXT_STR:
1079
		retval = history_next_string(h, ev, va_arg(va, const Char *));
1080
		break;
1081
1082
	case H_FUNC:
1083
	{
1084
		TYPE(History) hf;
1085
1086
		hf.h_ref = va_arg(va, void *);
1087
		h->h_ent = -1;
1088
		hf.h_first = va_arg(va, history_gfun_t);
1089
		hf.h_next = va_arg(va, history_gfun_t);
1090
		hf.h_last = va_arg(va, history_gfun_t);
1091
		hf.h_prev = va_arg(va, history_gfun_t);
1092
		hf.h_curr = va_arg(va, history_gfun_t);
1093
		hf.h_set = va_arg(va, history_sfun_t);
1094
		hf.h_clear = va_arg(va, history_vfun_t);
1095
		hf.h_enter = va_arg(va, history_efun_t);
1096
		hf.h_add = va_arg(va, history_efun_t);
1097
		hf.h_del = va_arg(va, history_sfun_t);
1098
1099
		if ((retval = history_set_fun(h, &hf)) == -1)
1100
			he_seterrev(ev, _HE_PARAM_MISSING);
1101
		break;
1102
	}
1103
1104
	case H_END:
1105
		FUN(history,end)(h);
1106
		retval = 0;
1107
		break;
1108
1109
	case H_NEXT_EVDATA:
1110
	{
1111
54
		int num = va_arg(va, int);
1112
54
		void **d = va_arg(va, void **);
1113
18
		retval = history_next_evdata(h, ev, num, d);
1114
		break;
1115
	}
1116
1117
	case H_DELDATA:
1118
	{
1119
198
		int num = va_arg(va, int);
1120
198
		void **d = va_arg(va, void **);
1121
66
		retval = history_deldata_nth((history_t *)h->h_ref, ev, num, d);
1122
		break;
1123
	}
1124
1125
	case H_REPLACE: /* only use after H_NEXT_EVDATA */
1126
	{
1127
		const Char *line = va_arg(va, const Char *);
1128
		void *d = va_arg(va, void *);
1129
		const Char *s;
1130
		if(!line || !(s = Strdup(line))) {
1131
			retval = -1;
1132
			break;
1133
		}
1134
		((history_t *)h->h_ref)->cursor->ev.str = s;
1135
		((history_t *)h->h_ref)->cursor->data = d;
1136
		retval = 0;
1137
		break;
1138
	}
1139
1140
	default:
1141
		retval = -1;
1142
		he_seterrev(ev, _HE_UNKNOWN);
1143
		break;
1144
	}
1145
702
	va_end(va);
1146
702
	return retval;
1147
702
}