GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libcurses/tinfo/comp_parse.c Lines: 0 150 0.0 %
Date: 2017-11-07 Branches: 0 402 0.0 %

Line Branch Exec Source
1
/* $OpenBSD: comp_parse.c,v 1.12 2010/01/12 23:22:06 nicm Exp $ */
2
3
/****************************************************************************
4
 * Copyright (c) 1998-2007,2008 Free Software Foundation, Inc.              *
5
 *                                                                          *
6
 * Permission is hereby granted, free of charge, to any person obtaining a  *
7
 * copy of this software and associated documentation files (the            *
8
 * "Software"), to deal in the Software without restriction, including      *
9
 * without limitation the rights to use, copy, modify, merge, publish,      *
10
 * distribute, distribute with modifications, sublicense, and/or sell       *
11
 * copies of the Software, and to permit persons to whom the Software is    *
12
 * furnished to do so, subject to the following conditions:                 *
13
 *                                                                          *
14
 * The above copyright notice and this permission notice shall be included  *
15
 * in all copies or substantial portions of the Software.                   *
16
 *                                                                          *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
18
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
19
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
20
 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
21
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
22
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
23
 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
24
 *                                                                          *
25
 * Except as contained in this notice, the name(s) of the above copyright   *
26
 * holders shall not be used in advertising or otherwise to promote the     *
27
 * sale, use or other dealings in this Software without prior written       *
28
 * authorization.                                                           *
29
 ****************************************************************************/
30
31
/****************************************************************************
32
 *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
33
 *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
34
 *     and: Thomas E. Dickey                        1996-on                 *
35
 ****************************************************************************/
36
37
/*
38
 *	comp_parse.c -- parser driver loop and use handling.
39
 *
40
 *	_nc_read_entry_source(FILE *, literal, bool, bool (*hook)())
41
 *	_nc_resolve_uses2(void)
42
 *	_nc_free_entries(void)
43
 *
44
 *	Use this code by calling _nc_read_entry_source() on as many source
45
 *	files as you like (either terminfo or termcap syntax).  If you
46
 *	want use-resolution, call _nc_resolve_uses2().  To free the list
47
 *	storage, do _nc_free_entries().
48
 *
49
 */
50
51
#include <curses.priv.h>
52
53
#include <ctype.h>
54
55
#include <tic.h>
56
#include <term_entry.h>
57
58
MODULE_ID("$Id: comp_parse.c,v 1.12 2010/01/12 23:22:06 nicm Exp $")
59
60
static void sanity_check2(TERMTYPE *, bool);
61
NCURSES_IMPEXP void NCURSES_API(*_nc_check_termtype2) (TERMTYPE *, bool) = sanity_check2;
62
63
/* obsolete: 20040705 */
64
static void sanity_check(TERMTYPE *);
65
NCURSES_IMPEXP void NCURSES_API(*_nc_check_termtype) (TERMTYPE *) = sanity_check;
66
67
static void
68
enqueue(ENTRY * ep)
69
/* add an entry to the in-core list */
70
{
71
    ENTRY *newp = _nc_copy_entry(ep);
72
73
    if (newp == 0)
74
	_nc_err_abort(MSG_NO_MEMORY);
75
76
    newp->last = _nc_tail;
77
    _nc_tail = newp;
78
79
    newp->next = 0;
80
    if (newp->last)
81
	newp->last->next = newp;
82
}
83
84
static char *
85
force_bar(char *dst, char *src, size_t siz)
86
{
87
    if (strchr(src, '|') == 0) {
88
	    size_t len;
89
90
	    len = strlcpy(dst, src, siz);
91
	    if (len > siz - 2)
92
		len = siz - 2;
93
	    dst[len++] = '|';
94
	    dst[len] = '\0';
95
	    src = dst;
96
    }
97
    return src;
98
}
99
100
NCURSES_EXPORT(bool)
101
_nc_entry_match(char *n1, char *n2)
102
/* do any of the aliases in a pair of terminal names match? */
103
{
104
    char *pstart, *qstart, *pend, *qend;
105
    char nc1[MAX_NAME_SIZE + 2], nc2[MAX_NAME_SIZE + 2];
106
107
    n1 = force_bar(nc1, n1, sizeof(nc1));
108
    n2 = force_bar(nc2, n2, sizeof(nc2));
109
110
    for (pstart = n1; (pend = strchr(pstart, '|')); pstart = pend + 1)
111
	for (qstart = n2; (qend = strchr(qstart, '|')); qstart = qend + 1)
112
	    if ((pend - pstart == qend - qstart)
113
		&& memcmp(pstart, qstart, (size_t) (pend - pstart)) == 0)
114
		return (TRUE);
115
116
    return (FALSE);
117
}
118
119
/****************************************************************************
120
 *
121
 * Entry compiler and resolution logic
122
 *
123
 ****************************************************************************/
124
125
NCURSES_EXPORT(void)
126
_nc_read_entry_source(FILE *fp, char *buf,
127
		      int literal, bool silent,
128
		      bool(*hook) (ENTRY *))
129
/* slurp all entries in the given file into core */
130
{
131
    ENTRY thisentry;
132
    bool oldsuppress = _nc_suppress_warnings;
133
    int immediate = 0;
134
135
    if (silent)
136
	_nc_suppress_warnings = TRUE;	/* shut the lexer up, too */
137
138
    _nc_reset_input(fp, buf);
139
    for (;;) {
140
	memset(&thisentry, 0, sizeof(thisentry));
141
	if (_nc_parse_entry(&thisentry, literal, silent) == ERR)
142
	    break;
143
	if (!isalnum(UChar(thisentry.tterm.term_names[0])))
144
	    _nc_err_abort("terminal names must start with letter or digit");
145
146
	/*
147
	 * This can be used for immediate compilation of entries with no "use="
148
	 * references to disk.  That avoids consuming a lot of memory when the
149
	 * resolution code could fetch entries off disk.
150
	 */
151
	if (hook != NULLHOOK && (*hook) (&thisentry)) {
152
	    immediate++;
153
	} else {
154
	    enqueue(&thisentry);
155
	    /*
156
	     * The enqueued entry is copied with _nc_copy_termtype(), so we can
157
	     * free some of the data from thisentry, i.e., the arrays.
158
	     */
159
	    FreeIfNeeded(thisentry.tterm.Booleans);
160
	    FreeIfNeeded(thisentry.tterm.Numbers);
161
	    FreeIfNeeded(thisentry.tterm.Strings);
162
#if NCURSES_XNAMES
163
	    FreeIfNeeded(thisentry.tterm.ext_Names);
164
#endif
165
	}
166
    }
167
168
    if (_nc_tail) {
169
	/* set up the head pointer */
170
	for (_nc_head = _nc_tail; _nc_head->last; _nc_head = _nc_head->last)
171
	    continue;
172
173
	DEBUG(1, ("head = %s", _nc_head->tterm.term_names));
174
	DEBUG(1, ("tail = %s", _nc_tail->tterm.term_names));
175
    }
176
#ifdef TRACE
177
    else if (!immediate)
178
	DEBUG(1, ("no entries parsed"));
179
#endif
180
181
    _nc_suppress_warnings = oldsuppress;
182
}
183
184
NCURSES_EXPORT(int)
185
_nc_resolve_uses2(bool fullresolve, bool literal)
186
/* try to resolve all use capabilities */
187
{
188
    ENTRY *qp, *rp, *lastread = 0;
189
    bool keepgoing;
190
    unsigned i;
191
    int unresolved, total_unresolved, multiples;
192
193
    DEBUG(2, ("RESOLUTION BEGINNING"));
194
195
    /*
196
     * Check for multiple occurrences of the same name.
197
     */
198
    multiples = 0;
199
    for_entry_list(qp) {
200
	int matchcount = 0;
201
202
	for_entry_list(rp) {
203
	    if (qp > rp
204
		&& _nc_entry_match(qp->tterm.term_names, rp->tterm.term_names)) {
205
		matchcount++;
206
		if (matchcount == 1) {
207
		    (void) fprintf(stderr, "Name collision between %s",
208
				   _nc_first_name(qp->tterm.term_names));
209
		    multiples++;
210
		}
211
		if (matchcount >= 1)
212
		    (void) fprintf(stderr, " %s", _nc_first_name(rp->tterm.term_names));
213
	    }
214
	}
215
	if (matchcount >= 1)
216
	    (void) putc('\n', stderr);
217
    }
218
    if (multiples > 0)
219
	return (FALSE);
220
221
    DEBUG(2, ("NO MULTIPLE NAME OCCURRENCES"));
222
223
    /*
224
     * First resolution stage: compute link pointers corresponding to names.
225
     */
226
    total_unresolved = 0;
227
    _nc_curr_col = -1;
228
    for_entry_list(qp) {
229
	unresolved = 0;
230
	for (i = 0; i < qp->nuses; i++) {
231
	    bool foundit;
232
	    char *child = _nc_first_name(qp->tterm.term_names);
233
	    char *lookfor = qp->uses[i].name;
234
	    long lookline = qp->uses[i].line;
235
236
	    foundit = FALSE;
237
238
	    _nc_set_type(child);
239
240
	    /* first, try to resolve from in-core records */
241
	    for_entry_list(rp) {
242
		if (rp != qp
243
		    && _nc_name_match(rp->tterm.term_names, lookfor, "|")) {
244
		    DEBUG(2, ("%s: resolving use=%s (in core)",
245
			      child, lookfor));
246
247
		    qp->uses[i].link = rp;
248
		    foundit = TRUE;
249
		}
250
	    }
251
252
	    /* if that didn't work, try to merge in a compiled entry */
253
	    if (!foundit) {
254
		TERMTYPE thisterm;
255
		char filename[PATH_MAX];
256
257
		memset(&thisterm, 0, sizeof(thisterm));
258
		if (_nc_read_entry(lookfor, filename, &thisterm) == 1) {
259
		    DEBUG(2, ("%s: resolving use=%s (compiled)",
260
			      child, lookfor));
261
262
		    rp = typeMalloc(ENTRY, 1);
263
		    if (rp == 0)
264
			_nc_err_abort(MSG_NO_MEMORY);
265
		    rp->tterm = thisterm;
266
		    rp->nuses = 0;
267
		    rp->next = lastread;
268
		    lastread = rp;
269
270
		    qp->uses[i].link = rp;
271
		    foundit = TRUE;
272
		}
273
	    }
274
275
	    /* no good, mark this one unresolvable and complain */
276
	    if (!foundit) {
277
		unresolved++;
278
		total_unresolved++;
279
280
		_nc_curr_line = lookline;
281
		_nc_warning("resolution of use=%s failed", lookfor);
282
		qp->uses[i].link = 0;
283
	    }
284
	}
285
    }
286
    if (total_unresolved) {
287
	/* free entries read in off disk */
288
	_nc_free_entries(lastread);
289
	return (FALSE);
290
    }
291
292
    DEBUG(2, ("NAME RESOLUTION COMPLETED OK"));
293
294
    /*
295
     * OK, at this point all (char *) references in `name' members
296
     * have been successfully converted to (ENTRY *) pointers in
297
     * `link' members.  Time to do the actual merges.
298
     */
299
    if (fullresolve) {
300
	do {
301
	    TERMTYPE merged;
302
303
	    keepgoing = FALSE;
304
305
	    for_entry_list(qp) {
306
		if (qp->nuses > 0) {
307
		    DEBUG(2, ("%s: attempting merge",
308
			      _nc_first_name(qp->tterm.term_names)));
309
		    /*
310
		     * If any of the use entries we're looking for is
311
		     * incomplete, punt.  We'll catch this entry on a
312
		     * subsequent pass.
313
		     */
314
		    for (i = 0; i < qp->nuses; i++)
315
			if (qp->uses[i].link->nuses) {
316
			    DEBUG(2, ("%s: use entry %d unresolved",
317
				      _nc_first_name(qp->tterm.term_names), i));
318
			    goto incomplete;
319
			}
320
321
		    /*
322
		     * First, make sure there is no garbage in the
323
		     * merge block.  As a side effect, copy into
324
		     * the merged entry the name field and string
325
		     * table pointer.
326
		     */
327
		    _nc_copy_termtype(&merged, &(qp->tterm));
328
329
		    /*
330
		     * Now merge in each use entry in the proper
331
		     * (reverse) order.
332
		     */
333
		    for (; qp->nuses; qp->nuses--)
334
			_nc_merge_entry(&merged,
335
					&qp->uses[qp->nuses - 1].link->tterm);
336
337
		    /*
338
		     * Now merge in the original entry.
339
		     */
340
		    _nc_merge_entry(&merged, &qp->tterm);
341
342
		    /*
343
		     * Replace the original entry with the merged one.
344
		     */
345
		    FreeIfNeeded(qp->tterm.Booleans);
346
		    FreeIfNeeded(qp->tterm.Numbers);
347
		    FreeIfNeeded(qp->tterm.Strings);
348
#if NCURSES_XNAMES
349
		    FreeIfNeeded(qp->tterm.ext_Names);
350
#endif
351
		    qp->tterm = merged;
352
		    _nc_wrap_entry(qp, TRUE);
353
354
		    /*
355
		     * We know every entry is resolvable because name resolution
356
		     * didn't bomb.  So go back for another pass.
357
		     */
358
		    /* FALLTHRU */
359
		  incomplete:
360
		    keepgoing = TRUE;
361
		}
362
	    }
363
	} while
364
	    (keepgoing);
365
366
	DEBUG(2, ("MERGES COMPLETED OK"));
367
    }
368
369
    /*
370
     * We'd like to free entries read in off disk at this point, but can't.
371
     * The merge_entry() code doesn't copy the strings in the use entries,
372
     * it just aliases them.  If this ever changes, do a
373
     * free_entries(lastread) here.
374
     */
375
376
    DEBUG(2, ("RESOLUTION FINISHED"));
377
378
    if (fullresolve)
379
	if (_nc_check_termtype != 0) {
380
	    _nc_curr_col = -1;
381
	    for_entry_list(qp) {
382
		_nc_curr_line = qp->startline;
383
		_nc_set_type(_nc_first_name(qp->tterm.term_names));
384
		_nc_check_termtype2(&qp->tterm, literal);
385
	    }
386
	    DEBUG(2, ("SANITY CHECK FINISHED"));
387
	}
388
389
    return (TRUE);
390
}
391
392
/* obsolete: 20040705 */
393
NCURSES_EXPORT(int)
394
_nc_resolve_uses(bool fullresolve)
395
{
396
    return _nc_resolve_uses2(fullresolve, FALSE);
397
}
398
399
/*
400
 * This bit of legerdemain turns all the terminfo variable names into
401
 * references to locations in the arrays Booleans, Numbers, and Strings ---
402
 * precisely what's needed.
403
 */
404
405
#undef CUR
406
#define CUR tp->
407
408
static void
409
sanity_check2(TERMTYPE *tp, bool literal)
410
{
411
    if (!PRESENT(exit_attribute_mode)) {
412
#ifdef __UNUSED__		/* this casts too wide a net */
413
	bool terminal_entry = !strchr(tp->term_names, '+');
414
	if (terminal_entry &&
415
	    (PRESENT(set_attributes)
416
	     || PRESENT(enter_standout_mode)
417
	     || PRESENT(enter_underline_mode)
418
	     || PRESENT(enter_blink_mode)
419
	     || PRESENT(enter_bold_mode)
420
	     || PRESENT(enter_dim_mode)
421
	     || PRESENT(enter_secure_mode)
422
	     || PRESENT(enter_protected_mode)
423
	     || PRESENT(enter_reverse_mode)))
424
	    _nc_warning("no exit_attribute_mode");
425
#endif /* __UNUSED__ */
426
	PAIRED(enter_standout_mode, exit_standout_mode);
427
	PAIRED(enter_underline_mode, exit_underline_mode);
428
    }
429
430
    /* we do this check/fix in postprocess_termcap(), but some packagers
431
     * prefer to bypass it...
432
     */
433
    if (!literal) {
434
	if (acs_chars == 0
435
	    && enter_alt_charset_mode != 0
436
	    && exit_alt_charset_mode != 0)
437
	    acs_chars = strdup(VT_ACSC);
438
	ANDMISSING(enter_alt_charset_mode, acs_chars);
439
	ANDMISSING(exit_alt_charset_mode, acs_chars);
440
    }
441
442
    /* listed in structure-member order of first argument */
443
    PAIRED(enter_alt_charset_mode, exit_alt_charset_mode);
444
    ANDMISSING(enter_blink_mode, exit_attribute_mode);
445
    ANDMISSING(enter_bold_mode, exit_attribute_mode);
446
    PAIRED(exit_ca_mode, enter_ca_mode);
447
    PAIRED(enter_delete_mode, exit_delete_mode);
448
    ANDMISSING(enter_dim_mode, exit_attribute_mode);
449
    PAIRED(enter_insert_mode, exit_insert_mode);
450
    ANDMISSING(enter_secure_mode, exit_attribute_mode);
451
    ANDMISSING(enter_protected_mode, exit_attribute_mode);
452
    ANDMISSING(enter_reverse_mode, exit_attribute_mode);
453
    PAIRED(from_status_line, to_status_line);
454
    PAIRED(meta_off, meta_on);
455
456
    PAIRED(prtr_on, prtr_off);
457
    PAIRED(save_cursor, restore_cursor);
458
    PAIRED(enter_xon_mode, exit_xon_mode);
459
    PAIRED(enter_am_mode, exit_am_mode);
460
    ANDMISSING(label_off, label_on);
461
#ifdef remove_clock
462
    PAIRED(display_clock, remove_clock);
463
#endif
464
    ANDMISSING(set_color_pair, initialize_pair);
465
}
466
467
/* obsolete: 20040705 */
468
static void
469
sanity_check(TERMTYPE *tp)
470
{
471
    sanity_check2(tp, FALSE);
472
}
473
474
#if NO_LEAKS
475
NCURSES_EXPORT(void)
476
_nc_leaks_tic(void)
477
{
478
    _nc_alloc_entry_leaks();
479
    _nc_captoinfo_leaks();
480
    _nc_comp_captab_leaks();
481
    _nc_comp_scan_leaks();
482
#if BROKEN_LINKER || USE_REENTRANT
483
    _nc_names_leaks();
484
    _nc_codes_leaks();
485
#endif
486
    _nc_tic_expand(0, FALSE, 0);
487
}
488
489
NCURSES_EXPORT(void)
490
_nc_free_tic(int code)
491
{
492
    _nc_leaks_tic();
493
    _nc_free_tinfo(code);
494
}
495
#endif