Bug Summary

File:src/usr.bin/infocmp/infocmp.c
Warning:line 631, column 10
Array access results in a null pointer dereference

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name infocmp.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.bin/infocmp/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.bin/infocmp/../../lib/libcurses -I /usr/src/usr.bin/infocmp/../tic -I /usr/src/usr.bin/infocmp -I . -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/infocmp/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.bin/infocmp/infocmp.c
1/* $OpenBSD: infocmp.c,v 1.23 2016/08/03 16:32:08 krw 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 * infocmp.c -- decompile an entry, or compare two entries
39 * written by Eric S. Raymond
40 * and Thomas E Dickey
41 */
42
43#include <progs.priv.h>
44
45#include <dump_entry.h>
46
47MODULE_ID("$Id: infocmp.c,v 1.23 2016/08/03 16:32:08 krw Exp $")
48
49#define L_CURL"{" "{"
50#define R_CURL"}" "}"
51
52#define MAX_STRING1024 1024 /* maximum formatted string */
53
54const char *_nc_progname = "infocmp";
55
56typedef char path[PATH_MAX1024];
57
58/***************************************************************************
59 *
60 * The following control variables, together with the contents of the
61 * terminfo entries, completely determine the actions of the program.
62 *
63 ***************************************************************************/
64
65static ENTRY *entries; /* terminfo entries */
66static int termcount; /* count of terminal entries */
67
68static bool_Bool limited = TRUE1; /* "-r" option is not set */
69static bool_Bool quiet = FALSE0;
70static bool_Bool literal = FALSE0;
71static const char *bool_sep = ":";
72static const char *s_absent = "NULL";
73static const char *s_cancel = "NULL";
74static const char *tversion; /* terminfo version selected */
75static int itrace; /* trace flag for debugging */
76static int mwidth = 60;
77static int numbers = 0; /* format "%'char'" to/from "%{number}" */
78static int outform = F_TERMINFO0; /* output format */
79static int sortmode; /* sort_mode */
80
81/* main comparison mode */
82static int compare;
83#define C_DEFAULT0 0 /* don't force comparison mode */
84#define C_DIFFERENCE1 1 /* list differences between two terminals */
85#define C_COMMON2 2 /* list common capabilities */
86#define C_NAND3 3 /* list capabilities in neither terminal */
87#define C_USEALL4 4 /* generate relative use-form entry */
88static bool_Bool ignorepads; /* ignore pad prefixes when diffing */
89
90#if NO_LEAKS0
91#undef ExitProgram
92static void ExitProgram(int code)exit(int code) GCC_NORETURN__attribute__((__noreturn__));
93/* prototype is to get gcc to accept the noreturn attribute */
94static void
95ExitProgram(int code)exit(int code)
96{
97 while (termcount-- > 0)
98 _nc_free_termtype(&entries[termcount].tterm);
99 _nc_leaks_dump_entry();
100 free(entries);
101 _nc_free_tic(code);
102}
103#endif
104
105static char *
106canonical_name(char *ptr, char *buf, size_t bufl)
107/* extract the terminal type's primary name */
108{
109 char *bp;
110
111 (void) strlcpy(buf, ptr, bufl);
112 if ((bp = strchr(buf, '|')) != 0)
113 *bp = '\0';
114
115 return (buf);
116}
117
118/***************************************************************************
119 *
120 * Predicates for dump function
121 *
122 ***************************************************************************/
123
124static int
125capcmp(PredIdx idx, const char *s, const char *t)
126/* capability comparison function */
127{
128 if (!VALID_STRING(s)((s) != (char *)(-1) && (s) != (char *)0) && !VALID_STRING(t)((t) != (char *)(-1) && (t) != (char *)0))
129 return (s != t);
130 else if (!VALID_STRING(s)((s) != (char *)(-1) && (s) != (char *)0) || !VALID_STRING(t)((t) != (char *)(-1) && (t) != (char *)0))
131 return (1);
132
133 if ((idx == acs_chars_index146) || !ignorepads)
134 return (strcmp(s, t));
135 else
136 return (_nc_capcmp(s, t));
137}
138
139static int
140use_predicate(unsigned type, PredIdx idx)
141/* predicate function to use for use decompilation */
142{
143 ENTRY *ep;
144
145 switch (type) {
146 case BOOLEAN0:
147 {
148 int is_set = FALSE0;
149
150 /*
151 * This assumes that multiple use entries are supposed
152 * to contribute the logical or of their boolean capabilities.
153 * This is true if we take the semantics of multiple uses to
154 * be 'each capability gets the first non-default value found
155 * in the sequence of use entries'.
156 *
157 * Note that cancelled or absent booleans are stored as FALSE,
158 * unlike numbers and strings, whose cancelled/absent state is
159 * recorded in the terminfo database.
160 */
161 for (ep = &entries[1]; ep < entries + termcount; ep++)
162 if (ep->tterm.Booleans[idx] == TRUE1) {
163 is_set = entries[0].tterm.Booleans[idx];
164 break;
165 }
166 if (is_set != entries[0].tterm.Booleans[idx])
167 return (!is_set);
168 else
169 return (FAIL-1);
170 }
171
172 case NUMBER1:
173 {
174 int value = ABSENT_NUMERIC(-1);
175
176 /*
177 * We take the semantics of multiple uses to be 'each
178 * capability gets the first non-default value found
179 * in the sequence of use entries'.
180 */
181 for (ep = &entries[1]; ep < entries + termcount; ep++)
182 if (VALID_NUMERIC(ep->tterm.Numbers[idx])((ep->tterm.Numbers[idx]) >= 0)) {
183 value = ep->tterm.Numbers[idx];
184 break;
185 }
186
187 if (value != entries[0].tterm.Numbers[idx])
188 return (value != ABSENT_NUMERIC(-1));
189 else
190 return (FAIL-1);
191 }
192
193 case STRING2:
194 {
195 char *termstr, *usestr = ABSENT_STRING(char *)0;
196
197 termstr = entries[0].tterm.Strings[idx];
198
199 /*
200 * We take the semantics of multiple uses to be 'each
201 * capability gets the first non-default value found
202 * in the sequence of use entries'.
203 */
204 for (ep = &entries[1]; ep < entries + termcount; ep++)
205 if (ep->tterm.Strings[idx]) {
206 usestr = ep->tterm.Strings[idx];
207 break;
208 }
209
210 if (usestr == ABSENT_STRING(char *)0 && termstr == ABSENT_STRING(char *)0)
211 return (FAIL-1);
212 else if (!usestr || !termstr || capcmp(idx, usestr, termstr))
213 return (TRUE1);
214 else
215 return (FAIL-1);
216 }
217 }
218
219 return (FALSE0); /* pacify compiler */
220}
221
222static bool_Bool
223useeq(ENTRY * e1, ENTRY * e2)
224/* are the use references in two entries equivalent? */
225{
226 unsigned i, j;
227
228 if (e1->nuses != e2->nuses)
229 return (FALSE0);
230
231 /* Ugh...this is quadratic again */
232 for (i = 0; i < e1->nuses; i++) {
233 bool_Bool foundmatch = FALSE0;
234
235 /* search second entry for given use reference */
236 for (j = 0; j < e2->nuses; j++)
237 if (!strcmp(e1->uses[i].name, e2->uses[j].name)) {
238 foundmatch = TRUE1;
239 break;
240 }
241
242 if (!foundmatch)
243 return (FALSE0);
244 }
245
246 return (TRUE1);
247}
248
249static bool_Bool
250entryeq(TERMTYPE *t1, TERMTYPE *t2)
251/* are two entries equivalent? */
252{
253 unsigned i;
254
255 for (i = 0; i < NUM_BOOLEANS(t1)(t1)->num_Booleans; i++)
256 if (t1->Booleans[i] != t2->Booleans[i])
257 return (FALSE0);
258
259 for (i = 0; i < NUM_NUMBERS(t1)(t1)->num_Numbers; i++)
260 if (t1->Numbers[i] != t2->Numbers[i])
261 return (FALSE0);
262
263 for (i = 0; i < NUM_STRINGS(t1)(t1)->num_Strings; i++)
264 if (capcmp((PredIdx) i, t1->Strings[i], t2->Strings[i]))
265 return (FALSE0);
266
267 return (TRUE1);
268}
269
270#define TIC_EXPAND(result)_nc_tic_expand(result, outform==0, numbers) _nc_tic_expand(result, outform==F_TERMINFO0, numbers)
271
272static void
273print_uses(ENTRY * ep, FILE *fp)
274/* print an entry's use references */
275{
276 unsigned i;
277
278 if (!ep->nuses)
279 fputs("NULL", fp);
280 else
281 for (i = 0; i < ep->nuses; i++) {
282 fputs(ep->uses[i].name, fp);
283 if (i < ep->nuses - 1)
284 fputs(" ", fp);
285 }
286}
287
288static const char *
289dump_boolean(int val)
290/* display the value of a boolean capability */
291{
292 switch (val) {
293 case ABSENT_BOOLEAN((signed char)-1):
294 return (s_absent);
295 case CANCELLED_BOOLEAN((signed char)-2):
296 return (s_cancel);
297 case FALSE0:
298 return ("F");
299 case TRUE1:
300 return ("T");
301 default:
302 return ("?");
303 }
304}
305
306static void
307dump_numeric(int val, char *buf, size_t bufl)
308/* display the value of a boolean capability */
309{
310 switch (val) {
311 case ABSENT_NUMERIC(-1):
312 strlcpy(buf, s_absent, bufl);
313 break;
314 case CANCELLED_NUMERIC(-2):
315 strlcpy(buf, s_cancel, bufl);
316 break;
317 default:
318 snprintf(buf, bufl, "%d", val);
319 break;
320 }
321}
322
323static void
324dump_string(char *val, char *buf, size_t bufl)
325/* display the value of a string capability */
326{
327 if (val == ABSENT_STRING(char *)0)
328 strlcpy(buf, s_absent, bufl);
329 else if (val == CANCELLED_STRING(char *)(-1))
330 strlcpy(buf, s_cancel, bufl);
331 else {
332 snprintf(buf, bufl, "'%.*s'", MAX_STRING1024 - 3, TIC_EXPAND(val)_nc_tic_expand(val, outform==0, numbers));
333 }
334}
335
336static void
337compare_predicate(PredType type, PredIdx idx, const char *name)
338/* predicate function to use for entry difference reports */
339{
340 ENTRY *e1 = &entries[0];
341 ENTRY *e2 = &entries[1];
342 char buf1[MAX_STRING1024], buf2[MAX_STRING1024];
343 int b1, b2;
344 int n1, n2;
345 char *s1, *s2;
346
347 switch (type) {
348 case CMP_BOOLEAN0:
349 b1 = e1->tterm.Booleans[idx];
350 b2 = e2->tterm.Booleans[idx];
351 switch (compare) {
352 case C_DIFFERENCE1:
353 if (!(b1 == ABSENT_BOOLEAN((signed char)-1) && b2 == ABSENT_BOOLEAN((signed char)-1)) && b1 != b2)
354 (void) printf("\t%s: %s%s%s.\n",
355 name,
356 dump_boolean(b1),
357 bool_sep,
358 dump_boolean(b2));
359 break;
360
361 case C_COMMON2:
362 if (b1 == b2 && b1 != ABSENT_BOOLEAN((signed char)-1))
363 (void) printf("\t%s= %s.\n", name, dump_boolean(b1));
364 break;
365
366 case C_NAND3:
367 if (b1 == ABSENT_BOOLEAN((signed char)-1) && b2 == ABSENT_BOOLEAN((signed char)-1))
368 (void) printf("\t!%s.\n", name);
369 break;
370 }
371 break;
372
373 case CMP_NUMBER1:
374 n1 = e1->tterm.Numbers[idx];
375 n2 = e2->tterm.Numbers[idx];
376 dump_numeric(n1, buf1, sizeof buf1);
377 dump_numeric(n2, buf2, sizeof buf2);
378 switch (compare) {
379 case C_DIFFERENCE1:
380 if (!((n1 == ABSENT_NUMERIC(-1) && n2 == ABSENT_NUMERIC(-1))) && n1 != n2)
381 (void) printf("\t%s: %s, %s.\n", name, buf1, buf2);
382 break;
383
384 case C_COMMON2:
385 if (n1 != ABSENT_NUMERIC(-1) && n2 != ABSENT_NUMERIC(-1) && n1 == n2)
386 (void) printf("\t%s= %s.\n", name, buf1);
387 break;
388
389 case C_NAND3:
390 if (n1 == ABSENT_NUMERIC(-1) && n2 == ABSENT_NUMERIC(-1))
391 (void) printf("\t!%s.\n", name);
392 break;
393 }
394 break;
395
396 case CMP_STRING2:
397 s1 = e1->tterm.Strings[idx];
398 s2 = e2->tterm.Strings[idx];
399 switch (compare) {
400 case C_DIFFERENCE1:
401 if (capcmp(idx, s1, s2)) {
402 dump_string(s1, buf1, sizeof buf1);
403 dump_string(s2, buf2, sizeof buf2);
404 if (strcmp(buf1, buf2))
405 (void) printf("\t%s: %s, %s.\n", name, buf1, buf2);
406 }
407 break;
408
409 case C_COMMON2:
410 if (s1 && s2 && !capcmp(idx, s1, s2))
411 (void) printf("\t%s= '%s'.\n", name, TIC_EXPAND(s1)_nc_tic_expand(s1, outform==0, numbers));
412 break;
413
414 case C_NAND3:
415 if (!s1 && !s2)
416 (void) printf("\t!%s.\n", name);
417 break;
418 }
419 break;
420
421 case CMP_USE3:
422 /* unlike the other modes, this compares *all* use entries */
423 switch (compare) {
424 case C_DIFFERENCE1:
425 if (!useeq(e1, e2)) {
426 (void) fputs("\tuse: ", stdout(&__sF[1]));
427 print_uses(e1, stdout(&__sF[1]));
428 fputs(", ", stdout(&__sF[1]));
429 print_uses(e2, stdout(&__sF[1]));
430 fputs(".\n", stdout(&__sF[1]));
431 }
432 break;
433
434 case C_COMMON2:
435 if (e1->nuses && e2->nuses && useeq(e1, e2)) {
436 (void) fputs("\tuse: ", stdout(&__sF[1]));
437 print_uses(e1, stdout(&__sF[1]));
438 fputs(".\n", stdout(&__sF[1]));
439 }
440 break;
441
442 case C_NAND3:
443 if (!e1->nuses && !e2->nuses)
444 (void) printf("\t!use.\n");
445 break;
446 }
447 }
448}
449
450/***************************************************************************
451 *
452 * Init string analysis
453 *
454 ***************************************************************************/
455
456typedef struct {
457 const char *from;
458 const char *to;
459} assoc;
460
461static const assoc std_caps[] =
462{
463 /* these are specified by X.364 and iBCS2 */
464 {"\033c", "RIS"}, /* full reset */
465 {"\0337", "SC"}, /* save cursor */
466 {"\0338", "RC"}, /* restore cursor */
467 {"\033[r", "RSR"}, /* not an X.364 mnemonic */
468 {"\033[m", "SGR0"}, /* not an X.364 mnemonic */
469 {"\033[2J", "ED2"}, /* clear page */
470
471 /* this group is specified by ISO 2022 */
472 {"\033(0", "ISO DEC G0"}, /* enable DEC graphics for G0 */
473 {"\033(A", "ISO UK G0"}, /* enable UK chars for G0 */
474 {"\033(B", "ISO US G0"}, /* enable US chars for G0 */
475 {"\033)0", "ISO DEC G1"}, /* enable DEC graphics for G1 */
476 {"\033)A", "ISO UK G1"}, /* enable UK chars for G1 */
477 {"\033)B", "ISO US G1"}, /* enable US chars for G1 */
478
479 /* these are DEC private controls widely supported by emulators */
480 {"\033=", "DECPAM"}, /* application keypad mode */
481 {"\033>", "DECPNM"}, /* normal keypad mode */
482 {"\033<", "DECANSI"}, /* enter ANSI mode */
483 {"\033[!p", "DECSTR"}, /* soft reset */
484 {"\033 F", "S7C1T"}, /* 7-bit controls */
485
486 {(char *) 0, (char *) 0}
487};
488
489static const assoc std_modes[] =
490/* ECMA \E[ ... [hl] modes recognized by many emulators */
491{
492 {"2", "AM"}, /* keyboard action mode */
493 {"4", "IRM"}, /* insert/replace mode */
494 {"12", "SRM"}, /* send/receive mode */
495 {"20", "LNM"}, /* linefeed mode */
496 {(char *) 0, (char *) 0}
497};
498
499static const assoc private_modes[] =
500/* DEC \E[ ... [hl] modes recognized by many emulators */
501{
502 {"1", "CKM"}, /* application cursor keys */
503 {"2", "ANM"}, /* set VT52 mode */
504 {"3", "COLM"}, /* 132-column mode */
505 {"4", "SCLM"}, /* smooth scroll */
506 {"5", "SCNM"}, /* reverse video mode */
507 {"6", "OM"}, /* origin mode */
508 {"7", "AWM"}, /* wraparound mode */
509 {"8", "ARM"}, /* auto-repeat mode */
510 {(char *) 0, (char *) 0}
511};
512
513static const assoc ecma_highlights[] =
514/* recognize ECMA attribute sequences */
515{
516 {"0", "NORMAL"}, /* normal */
517 {"1", "+BOLD"}, /* bold on */
518 {"2", "+DIM"}, /* dim on */
519 {"3", "+ITALIC"}, /* italic on */
520 {"4", "+UNDERLINE"}, /* underline on */
521 {"5", "+BLINK"}, /* blink on */
522 {"6", "+FASTBLINK"}, /* fastblink on */
523 {"7", "+REVERSE"}, /* reverse on */
524 {"8", "+INVISIBLE"}, /* invisible on */
525 {"9", "+DELETED"}, /* deleted on */
526 {"10", "MAIN-FONT"}, /* select primary font */
527 {"11", "ALT-FONT-1"}, /* select alternate font 1 */
528 {"12", "ALT-FONT-2"}, /* select alternate font 2 */
529 {"13", "ALT-FONT-3"}, /* select alternate font 3 */
530 {"14", "ALT-FONT-4"}, /* select alternate font 4 */
531 {"15", "ALT-FONT-5"}, /* select alternate font 5 */
532 {"16", "ALT-FONT-6"}, /* select alternate font 6 */
533 {"17", "ALT-FONT-7"}, /* select alternate font 7 */
534 {"18", "ALT-FONT-1"}, /* select alternate font 1 */
535 {"19", "ALT-FONT-1"}, /* select alternate font 1 */
536 {"20", "FRAKTUR"}, /* Fraktur font */
537 {"21", "DOUBLEUNDER"}, /* double underline */
538 {"22", "-DIM"}, /* dim off */
539 {"23", "-ITALIC"}, /* italic off */
540 {"24", "-UNDERLINE"}, /* underline off */
541 {"25", "-BLINK"}, /* blink off */
542 {"26", "-FASTBLINK"}, /* fastblink off */
543 {"27", "-REVERSE"}, /* reverse off */
544 {"28", "-INVISIBLE"}, /* invisible off */
545 {"29", "-DELETED"}, /* deleted off */
546 {(char *) 0, (char *) 0}
547};
548
549static int
550skip_csi(const char *cap)
551{
552 int result = 0;
553 if (cap[0] == '\033' && cap[1] == '[')
554 result = 2;
555 else if (UChar(cap[0])((unsigned char)(cap[0])) == 0233)
556 result = 1;
557 return result;
558}
559
560static bool_Bool
561same_param(const char *table, const char *param, unsigned length)
562{
563 bool_Bool result = FALSE0;
564 if (strncmp(table, param, length) == 0) {
565 result = !isdigit(UChar(param[length])((unsigned char)(param[length])));
566 }
567 return result;
568}
569
570static char *
571lookup_params(const assoc * table, char *dst, char *src, size_t dstlen)
572{
573 char *result = 0;
574 const char *ep = strtok(src, ";");
575
576 if (ep != 0) {
577 const assoc *ap;
578
579 do {
580 bool_Bool found = FALSE0;
581
582 for (ap = table; ap->from; ap++) {
583 size_t tlen = strlen(ap->from);
584
585 if (same_param(ap->from, ep, tlen)) {
586 (void) strlcat(dst, ap->to, dstlen);
587 found = TRUE1;
588 break;
589 }
590 }
591
592 if (!found)
593 (void) strlcat(dst, ep, dstlen);
594 (void) strlcat(dst, ";", dstlen);
595 } while
596 ((ep = strtok((char *) 0, ";")));
597
598 if (dst[0] != '\0' && dst[strlen(dst) - 1] == ';')
599 dst[strlen(dst) - 1] = '\0';
600
601 result = dst;
602 }
603 return result;
604}
605
606static void
607analyze_string(const char *name, const char *cap, TERMTYPE *tp)
608{
609 char buf2[MAX_TERMINFO_LENGTH4096];
610 const char *sp;
611 const assoc *ap;
612 int tp_lines = tp->Numbers[2];
613
614 if (cap == ABSENT_STRING(char *)0 || cap == CANCELLED_STRING(char *)(-1))
28
Assuming 'cap' is not equal to ABSENT_STRING
29
Assuming the condition is false
30
Taking false branch
615 return;
616 (void) printf("%s: ", name);
617
618 for (sp = cap; *sp; sp++) {
31
Loop condition is true. Entering loop body
55
Loop condition is true. Entering loop body
619 int i;
620 int csi;
621 size_t len = 0;
622 size_t next;
623 const char *expansion = 0;
624 char buf3[MAX_TERMINFO_LENGTH4096];
625
626 /* first, check other capabilities in this entry */
627 for (i = 0; i < STRCOUNT414; i++) {
32
Loop condition is true. Entering loop body
56
The value 0 is assigned to 'i'
57
Loop condition is true. Entering loop body
628 char *cp = tp->Strings[i];
629
630 /* don't use soft-key capabilities */
631 if (strnames[i][0] == 'k' && strnames[i][1] == 'f')
33
Assuming the condition is false
58
Array access results in a null pointer dereference
632 continue;
633
634 if (cp != ABSENT_STRING(char *)0 && cp != CANCELLED_STRING(char *)(-1) && cp[0] && cp
34
Assuming 'cp' is not equal to ABSENT_STRING
35
Assuming the condition is true
36
Assuming the condition is true
37
Assuming 'cp' is not equal to 'cap'
38
Taking true branch
635 != cap) {
636 len = strlen(cp);
637 (void) strncpy(buf2, sp, len);
638 buf2[len] = '\0';
639
640 if (_nc_capcmp(cp, buf2))
39
Assigning value
40
Assuming the condition is false
41
Taking false branch
641 continue;
642
643#define ISRS(s) (!strncmp((s), "is", 2) || !strncmp((s), "rs", 2))
644 /*
645 * Theoretically we just passed the test for translation
646 * (equality once the padding is stripped). However, there
647 * are a few more hoops that need to be jumped so that
648 * identical pairs of initialization and reset strings
649 * don't just refer to each other.
650 */
651 if (ISRS(name) || ISRS(strnames[i]))
652 if (cap < cp)
42
Assuming 'cap' is >= 'cp'
43
Taking false branch
653 continue;
654#undef ISRS
655
656 expansion = strnames[i];
657 break;
44
Execution continues on line 662
658 }
659 }
660
661 /* now check the standard capabilities */
662 if (!expansion) {
45
Assuming 'expansion' is null
46
Taking true branch
663 csi = skip_csi(sp);
664 for (ap = std_caps; ap->from; ap++) {
47
Loop condition is true. Entering loop body
665 size_t adj = (size_t) (csi
47.1
'csi' is 0
? 2 : 0);
48
'?' condition is false
666
667 len = strlen(ap->from);
668 if (csi
48.1
'csi' is 0
&& skip_csi(ap->from) != csi)
669 continue;
670 if (len > adj
49
Assuming 'len' is > 'adj'
51
Taking true branch
671 && strncmp(ap->from + adj, sp + csi, len - adj) == 0) {
50
Assuming the condition is true
672 expansion = ap->to;
673 len -= adj;
674 len += (size_t) csi;
675 break;
52
Execution continues on line 681
676 }
677 }
678 }
679
680 /* now check for standard-mode sequences */
681 if (!expansion
53
Assuming 'expansion' is non-null
682 && (csi = skip_csi(sp)) != 0
683 && (len = strspn(sp + csi, "0123456789;"))
684 && (len < sizeof(buf3))
685 && (next = (size_t) csi + len)
686 && ((sp[next] == 'h') || (sp[next] == 'l'))) {
687
688 (void) strlcpy(buf2, (sp[next] == 'h') ? "ECMA+" : "ECMA-",
689 sizeof buf2);
690 (void) strncpy(buf3, sp + csi, len);
691 buf3[len] = '\0';
692 len += (size_t) csi + 1;
693
694 expansion = lookup_params(std_modes, buf2, buf3, sizeof buf2);
695 }
696
697 /* now check for private-mode sequences */
698 if (!expansion
53.1
'expansion' is non-null
699 && (csi = skip_csi(sp)) != 0 700 && sp[csi] == '?' 701 && (len = strspn(sp + csi + 1, "0123456789;")) 702 && (len < sizeof(buf3)) 703 && (next = (size_t) csi + 1 + len) 704 && ((sp[next] == 'h') || (sp[next] == 'l'))) { 705 706 (void) strlcpy(buf2, (sp[next] == 'h') ? "DEC+" : "DEC-", 707 sizeof buf2); 708 (void) strncpy(buf3, sp + csi + 1, len); 709 buf3[len] = '\0'; 710 len += (size_t) csi + 2; 711 712 expansion = lookup_params(private_modes, buf2, buf3, sizeof buf2); 713 } 714 715 /* now check for ECMA highlight sequences */ 716 if (!expansion
53.2
'expansion' is non-null
717 && (csi = skip_csi(sp)) != 0 718 && (len = strspn(sp + csi, "0123456789;")) != 0 719 && (len < sizeof(buf3)) 720 && (next = (size_t) csi + len) 721 && sp[next] == 'm') { 722 723 (void) strlcpy(buf2, "SGR:", sizeof buf2); 724 (void) strncpy(buf3, sp + csi, len); 725 buf3[len] = '\0'; 726 len += (size_t) csi + 1; 727 728 expansion = lookup_params(ecma_highlights, buf2, buf3, sizeof buf2); 729 } 730 731 if (!expansion
53.3
'expansion' is non-null
732 && (csi = skip_csi(sp)) != 0 733 && sp[csi] == 'm') { 734 len = (size_t) csi + 1; 735 (void) strlcpy(buf2, "SGR:", sizeof buf2); 736 strlcat(buf2, ecma_highlights[0].to, sizeof buf2); 737 expansion = buf2; 738 } 739 740 /* now check for scroll region reset */ 741 if (!expansion
53.4
'expansion' is non-null
742 && (csi = skip_csi(sp)) != 0) { 743 if (sp[csi] == 'r') { 744 expansion = "RSR"; 745 len = 1; 746 } else { 747 (void) snprintf(buf2, sizeof buf2, "1;%dr", tp_lines); 748 len = strlen(buf2); 749 if (strncmp(buf2, sp + csi, len) == 0) 750 expansion = "RSR"; 751 } 752 len += (size_t) csi; 753 } 754 755 /* now check for home-down */ 756 if (!expansion
53.5
'expansion' is non-null
757 && (csi = skip_csi(sp)) != 0) { 758 (void) snprintf(buf2, sizeof buf2, "%d;1H", tp_lines); 759 len = strlen(buf2); 760 if (strncmp(buf2, sp + csi, len) == 0) { 761 expansion = "LL"; 762 } else { 763 (void) snprintf(buf2, sizeof buf2, "%dH", tp_lines); 764 len = strlen(buf2); 765 if (strncmp(buf2, sp + csi, len) == 0) { 766 expansion = "LL"; 767 } 768 } 769 len += (size_t) csi; 770 } 771 772 /* now look at the expansion we got, if any */ 773 if (expansion
53.6
'expansion' is non-null
) {
54
Taking true branch
774 printf("{%s}", expansion); 775 sp += len - 1; 776 } else { 777 /* couldn't match anything */ 778 buf2[0] = *sp; 779 buf2[1] = '\0'; 780 fputs(TIC_EXPAND(buf2)_nc_tic_expand(buf2, outform==0, numbers), stdout(&__sF[1])); 781 } 782 } 783 putchar('\n')(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n',
(&__sF[1])))
; 784} 785 786/*************************************************************************** 787 * 788 * File comparison 789 * 790 ***************************************************************************/ 791 792static void 793file_comparison(int argc, char *argv[]) 794{ 795#define MAXCOMPARE2 2 796 /* someday we may allow comparisons on more files */ 797 int filecount = 0; 798 ENTRY *heads[MAXCOMPARE2]; 799 ENTRY *qp, *rp; 800 int i, n; 801 802 memset(heads, 0, sizeof(heads)); 803 dump_init((char *) 0, F_LITERAL4, S_TERMINFO2, 0, itrace, FALSE0); 804 805 for (n = 0; n < argc && n < MAXCOMPARE2; n++) { 806 if (freopen(argv[n], "r", stdin(&__sF[0])) == 0) 807 _nc_err_abort("Can't open %s", argv[n]); 808 809 _nc_head = _nc_tail = 0; 810 811 /* parse entries out of the source file */ 812 _nc_set_source(argv[n]); 813 _nc_read_entry_source(stdin(&__sF[0]), NULL((void *)0), TRUE1, literal, NULLHOOK(_Bool(*)(ENTRY *))0); 814 815 if (itrace) 816 (void) fprintf(stderr(&__sF[2]), "Resolving file %d...\n", n - 0); 817 818 /* maybe do use resolution */ 819 if (!_nc_resolve_uses2(!limited, literal)) { 820 (void) fprintf(stderr(&__sF[2]), 821 "There are unresolved use entries in %s:\n", 822 argv[n]); 823 for_entry_list(qp)for (qp = _nc_head; qp; qp = qp->next) { 824 if (qp->nuses) { 825 (void) fputs(qp->tterm.term_names, stderr(&__sF[2])); 826 (void) fputc('\n', stderr(&__sF[2])); 827 } 828 } 829 ExitProgram(EXIT_FAILURE)exit(1); 830 } 831 832 heads[filecount] = _nc_head; 833 filecount++; 834 } 835 836 /* OK, all entries are in core. Ready to do the comparison */ 837 if (itrace) 838 (void) fprintf(stderr(&__sF[2]), "Entries are now in core...\n"); 839 840 /* The entry-matching loop. Sigh, this is intrinsically quadratic. */ 841 for (qp = heads[0]; qp; qp = qp->next) { 842 for (rp = heads[1]; rp; rp = rp->next) 843 if (_nc_entry_match(qp->tterm.term_names, rp->tterm.term_names)) { 844 if (qp->ncrosslinks < MAX_CROSSLINKS16) 845 qp->crosslinks[qp->ncrosslinks] = rp; 846 qp->ncrosslinks++; 847 848 if (rp->ncrosslinks < MAX_CROSSLINKS16) 849 rp->crosslinks[rp->ncrosslinks] = qp; 850 rp->ncrosslinks++; 851 } 852 } 853 854 /* now we have two circular lists with crosslinks */ 855 if (itrace) 856 (void) fprintf(stderr(&__sF[2]), "Name matches are done...\n"); 857 858 for (qp = heads[0]; qp; qp = qp->next) { 859 if (qp->ncrosslinks > 1) { 860 (void) fprintf(stderr(&__sF[2]), 861 "%s in file 1 (%s) has %d matches in file 2 (%s):\n", 862 _nc_first_name(qp->tterm.term_names), 863 argv[0], 864 qp->ncrosslinks, 865 argv[1]); 866 for (i = 0; i < qp->ncrosslinks; i++) 867 (void) fprintf(stderr(&__sF[2]), 868 "\t%s\n", 869 _nc_first_name((qp->crosslinks[i])->tterm.term_names)); 870 } 871 } 872 873 for (rp = heads[1]; rp; rp = rp->next) { 874 if (rp->ncrosslinks > 1) { 875 (void) fprintf(stderr(&__sF[2]), 876 "%s in file 2 (%s) has %d matches in file 1 (%s):\n", 877 _nc_first_name(rp->tterm.term_names), 878 argv[1], 879 rp->ncrosslinks, 880 argv[0]); 881 for (i = 0; i < rp->ncrosslinks; i++) 882 (void) fprintf(stderr(&__sF[2]), 883 "\t%s\n", 884 _nc_first_name((rp->crosslinks[i])->tterm.term_names)); 885 } 886 } 887 888 (void) printf("In file 1 (%s) only:\n", argv[0]); 889 for (qp = heads[0]; qp; qp = qp->next) 890 if (qp->ncrosslinks == 0) 891 (void) printf("\t%s\n", 892 _nc_first_name(qp->tterm.term_names)); 893 894 (void) printf("In file 2 (%s) only:\n", argv[1]); 895 for (rp = heads[1]; rp; rp = rp->next) 896 if (rp->ncrosslinks == 0) 897 (void) printf("\t%s\n", 898 _nc_first_name(rp->tterm.term_names)); 899 900 (void) printf("The following entries are equivalent:\n"); 901 for (qp = heads[0]; qp; qp = qp->next) { 902 rp = qp->crosslinks[0]; 903 904 if (qp->ncrosslinks == 1) { 905 rp = qp->crosslinks[0]; 906 907 repair_acsc(&qp->tterm); 908 repair_acsc(&rp->tterm); 909#if NCURSES_XNAMES1 910 _nc_align_termtype(&qp->tterm, &rp->tterm); 911#endif 912 if (entryeq(&qp->tterm, &rp->tterm) && useeq(qp, rp)) { 913 char name1[NAMESIZE256], name2[NAMESIZE256]; 914 915 (void) canonical_name(qp->tterm.term_names, name1, sizeof name1); 916 (void) canonical_name(rp->tterm.term_names, name2, sizeof name2); 917 918 (void) printf("%s = %s\n", name1, name2); 919 } 920 } 921 } 922 923 (void) printf("Differing entries:\n"); 924 termcount = 2; 925 for (qp = heads[0]; qp; qp = qp->next) { 926 927 if (qp->ncrosslinks == 1) { 928 rp = qp->crosslinks[0]; 929#if NCURSES_XNAMES1 930 /* sorry - we have to do this on each pass */ 931 _nc_align_termtype(&qp->tterm, &rp->tterm); 932#endif 933 if (!(entryeq(&qp->tterm, &rp->tterm) && useeq(qp, rp))) { 934 char name1[NAMESIZE256], name2[NAMESIZE256]; 935 936 entries[0] = *qp; 937 entries[1] = *rp; 938 939 (void) canonical_name(qp->tterm.term_names, name1, sizeof name1); 940 (void) canonical_name(rp->tterm.term_names, name2, sizeof name2); 941 942 switch (compare) { 943 case C_DIFFERENCE1: 944 if (itrace) 945 (void) fprintf(stderr(&__sF[2]), 946 "%s: dumping differences\n", 947 _nc_progname); 948 (void) printf("comparing %s to %s.\n", name1, name2); 949 compare_entry(compare_predicate, &entries->tterm, quiet); 950 break; 951 952 case C_COMMON2: 953 if (itrace) 954 (void) fprintf(stderr(&__sF[2]), 955 "%s: dumping common capabilities\n", 956 _nc_progname); 957 (void) printf("comparing %s to %s.\n", name1, name2); 958 compare_entry(compare_predicate, &entries->tterm, quiet); 959 break; 960 961 case C_NAND3: 962 if (itrace) 963 (void) fprintf(stderr(&__sF[2]), 964 "%s: dumping differences\n", 965 _nc_progname); 966 (void) printf("comparing %s to %s.\n", name1, name2); 967 compare_entry(compare_predicate, &entries->tterm, quiet); 968 break; 969 970 } 971 } 972 } 973 } 974} 975 976static void 977usage(void) 978{ 979 static const char *tbl[] = 980 { 981 "Usage: infocmp [options] [-A directory] [-B directory] [termname...]" 982 ,"" 983 ,"Options:" 984 ," -1 print single-column" 985 ," -C use termcap-names" 986 ," -F compare terminfo-files" 987 ," -I use terminfo-names" 988 ," -L use long names" 989 ," -R subset (see manpage)" 990 ," -T eliminate size limits (test)" 991 ," -U eliminate post-processing of entries" 992 ," -V print version" 993#if NCURSES_XNAMES1 994 ," -a with -F, list commented-out caps" 995#endif 996 ," -c list common capabilities" 997 ," -d list different capabilities" 998 ," -e format output for C initializer" 999 ," -E format output as C tables" 1000 ," -f with -1, format complex strings" 1001 ," -G format %{number} to %'char'" 1002 ," -g format %'char' to %{number}" 1003 ," -i analyze initialization/reset" 1004 ," -l output terminfo names" 1005 ," -n list capabilities in neither" 1006 ," -p ignore padding specifiers" 1007 ," -q brief listing, removes headers" 1008 ," -r with -C, output in termcap form" 1009 ," -r with -F, resolve use-references" 1010 ," -s [d|i|l|c] sort fields" 1011#if NCURSES_XNAMES1 1012 ," -t suppress commented-out capabilities" 1013#endif 1014 ," -u produce source with 'use='" 1015 ," -v number (verbose)" 1016 ," -w number (width)" 1017#if NCURSES_XNAMES1 1018 ," -x treat unknown capabilities as user-defined" 1019#endif 1020 }; 1021 const size_t first = 3; 1022 const size_t last = SIZEOF(tbl)(sizeof(tbl)/sizeof(tbl[0])); 1023 const size_t left = (last - first + 1) / 2 + first; 1024 size_t n; 1025 1026 for (n = 0; n < left; n++) { 1027 size_t m = (n < first) ? last : n + left - first; 1028 if (m < last) 1029 fprintf(stderr(&__sF[2]), "%-40.40s%s\n", tbl[n], tbl[m]); 1030 else 1031 fprintf(stderr(&__sF[2]), "%s\n", tbl[n]); 1032 } 1033 ExitProgram(EXIT_FAILURE)exit(1); 1034} 1035 1036static char * 1037any_initializer(const char *fmt, const char *type) 1038{ 1039 static char *initializer; 1040 static size_t len; 1041 char *s; 1042 1043 if (initializer == 0) { 1044 len = strlen(entries->tterm.term_names) + strlen(type) + strlen(fmt); 1045 initializer = (char *) malloc(len); 1046 } 1047 1048 (void) strlcpy(initializer, entries->tterm.term_names, len); 1049 for (s = initializer; *s != 0 && *s != '|'; s++) { 1050 if (!isalnum(UChar(*s)((unsigned char)(*s)))) 1051 *s = '_'; 1052 } 1053 *s = 0; 1054 (void) snprintf(s, len - (s - initializer), fmt, type); 1055 return initializer; 1056} 1057 1058static char * 1059name_initializer(const char *type) 1060{ 1061 return any_initializer("_%s_data", type); 1062} 1063 1064static char * 1065string_variable(const char *type) 1066{ 1067 return any_initializer("_s_%s", type); 1068} 1069 1070/* dump C initializers for the terminal type */ 1071static void 1072dump_initializers(TERMTYPE *term) 1073{ 1074 unsigned n; 1075 const char *str = 0; 1076 1077 printf("\nstatic char %s[] = \"%s\";\n\n", 1078 name_initializer("alias"), entries->tterm.term_names); 1079 1080 for_each_string(n, term)for(n = 0; n < (term)->num_Strings; n++) { 1081 char buf[MAX_STRING1024], *sp, *tp; 1082 1083 if (VALID_STRING(term->Strings[n])((term->Strings[n]) != (char *)(-1) && (term->Strings
[n]) != (char *)0)
) { 1084 tp = buf; 1085 *tp++ = '"'; 1086 for (sp = term->Strings[n]; 1087 *sp != 0 && (tp - buf) < MAX_STRING1024 - 6; 1088 sp++) { 1089 if (isascii(UChar(*sp)((unsigned char)(*sp))) 1090 && isprint(UChar(*sp)((unsigned char)(*sp))) 1091 && *sp != '\\' 1092 && *sp != '"') 1093 *tp++ = *sp; 1094 else { 1095 (void) snprintf(tp, buf + sizeof buf - tp, "\\%03o", 1096 UChar(*sp)((unsigned char)(*sp))); 1097 tp += strlen(tp); 1098 } 1099 } 1100 *tp++ = '"'; 1101 *tp = '\0'; 1102 (void) printf("static char %-20s[] = %s;\n", 1103 string_variable(ExtStrname(term, n, strnames)(n >= 414) ? term->ext_Names[(n - (term->num_Strings
- term->ext_Strings)) + (term->ext_Numbers + term->
ext_Booleans)] : strnames[n]
), buf); 1104 } 1105 } 1106 printf("\n"); 1107 1108 (void) printf("static char %s[] = %s\n", name_initializer("bool"), L_CURL"{"); 1109 1110 for_each_boolean(n, term)for(n = 0; n < (term)->num_Booleans; n++) { 1111 switch ((int) (term->Booleans[n])) { 1112 case TRUE1: 1113 str = "TRUE"; 1114 break; 1115 1116 case FALSE0: 1117 str = "FALSE"; 1118 break; 1119 1120 case ABSENT_BOOLEAN((signed char)-1): 1121 str = "ABSENT_BOOLEAN"; 1122 break; 1123 1124 case CANCELLED_BOOLEAN((signed char)-2): 1125 str = "CANCELLED_BOOLEAN"; 1126 break; 1127 } 1128 (void) printf("\t/* %3u: %-8s */\t%s,\n", 1129 n, ExtBoolname(term, n, boolnames)(n >= 44) ? term->ext_Names[(n - (term->num_Booleans
- term->ext_Booleans))] : boolnames[n]
, str); 1130 } 1131 (void) printf("%s;\n", R_CURL"}"); 1132 1133 (void) printf("static short %s[] = %s\n", name_initializer("number"), L_CURL"{"); 1134 1135 for_each_number(n, term)for(n = 0; n < (term)->num_Numbers; n++) { 1136 char buf[BUFSIZ1024]; 1137 switch (term->Numbers[n]) { 1138 case ABSENT_NUMERIC(-1): 1139 str = "ABSENT_NUMERIC"; 1140 break; 1141 case CANCELLED_NUMERIC(-2): 1142 str = "CANCELLED_NUMERIC"; 1143 break; 1144 default: 1145 snprintf(buf, sizeof buf, "%d", term->Numbers[n]); 1146 str = buf; 1147 break; 1148 } 1149 (void) printf("\t/* %3u: %-8s */\t%s,\n", n, 1150 ExtNumname(term, n, numnames)(n >= 39) ? term->ext_Names[(n - (term->num_Numbers -
term->ext_Numbers)) + term->ext_Booleans] : numnames[n
]
, str); 1151 } 1152 (void) printf("%s;\n", R_CURL"}"); 1153 1154 (void) printf("static char * %s[] = %s\n", name_initializer("string"), L_CURL"{"); 1155 1156 for_each_string(n, term)for(n = 0; n < (term)->num_Strings; n++) { 1157 1158 if (term->Strings[n] == ABSENT_STRING(char *)0) 1159 str = "ABSENT_STRING"; 1160 else if (term->Strings[n] == CANCELLED_STRING(char *)(-1)) 1161 str = "CANCELLED_STRING"; 1162 else { 1163 str = string_variable(ExtStrname(term, n, strnames)(n >= 414) ? term->ext_Names[(n - (term->num_Strings
- term->ext_Strings)) + (term->ext_Numbers + term->
ext_Booleans)] : strnames[n]
); 1164 } 1165 (void) printf("\t/* %3u: %-8s */\t%s,\n", n, 1166 ExtStrname(term, n, strnames)(n >= 414) ? term->ext_Names[(n - (term->num_Strings
- term->ext_Strings)) + (term->ext_Numbers + term->
ext_Booleans)] : strnames[n]
, str); 1167 } 1168 (void) printf("%s;\n", R_CURL"}"); 1169 1170#if NCURSES_XNAMES1 1171 if ((NUM_BOOLEANS(term)(term)->num_Booleans != BOOLCOUNT44) 1172 || (NUM_NUMBERS(term)(term)->num_Numbers != NUMCOUNT39) 1173 || (NUM_STRINGS(term)(term)->num_Strings != STRCOUNT414)) { 1174 (void) printf("static char * %s[] = %s\n", 1175 name_initializer("string_ext"), L_CURL"{"); 1176 for (n = BOOLCOUNT44; n < NUM_BOOLEANS(term)(term)->num_Booleans; ++n) { 1177 (void) printf("\t/* %3u: bool */\t\"%s\",\n", 1178 n, ExtBoolname(term, n, boolnames)(n >= 44) ? term->ext_Names[(n - (term->num_Booleans
- term->ext_Booleans))] : boolnames[n]
); 1179 } 1180 for (n = NUMCOUNT39; n < NUM_NUMBERS(term)(term)->num_Numbers; ++n) { 1181 (void) printf("\t/* %3u: num */\t\"%s\",\n", 1182 n, ExtNumname(term, n, numnames)(n >= 39) ? term->ext_Names[(n - (term->num_Numbers -
term->ext_Numbers)) + term->ext_Booleans] : numnames[n
]
); 1183 } 1184 for (n = STRCOUNT414; n < NUM_STRINGS(term)(term)->num_Strings; ++n) { 1185 (void) printf("\t/* %3u: str */\t\"%s\",\n", 1186 n, ExtStrname(term, n, strnames)(n >= 414) ? term->ext_Names[(n - (term->num_Strings
- term->ext_Strings)) + (term->ext_Numbers + term->
ext_Booleans)] : strnames[n]
); 1187 } 1188 (void) printf("%s;\n", R_CURL"}"); 1189 } 1190#endif 1191} 1192 1193/* dump C initializers for the terminal type */ 1194static void 1195dump_termtype(TERMTYPE *term) 1196{ 1197 (void) printf("\t%s\n\t\t%s,\n", L_CURL"{", name_initializer("alias")); 1198 (void) printf("\t\t(char *)0,\t/* pointer to string table */\n"); 1199 1200 (void) printf("\t\t%s,\n", name_initializer("bool")); 1201 (void) printf("\t\t%s,\n", name_initializer("number")); 1202 1203 (void) printf("\t\t%s,\n", name_initializer("string")); 1204 1205#if NCURSES_XNAMES1 1206 (void) printf("#if NCURSES_XNAMES\n"); 1207 (void) printf("\t\t(char *)0,\t/* pointer to extended string table */\n"); 1208 (void) printf("\t\t%s,\t/* ...corresponding names */\n", 1209 ((NUM_BOOLEANS(term)(term)->num_Booleans != BOOLCOUNT44) 1210 || (NUM_NUMBERS(term)(term)->num_Numbers != NUMCOUNT39) 1211 || (NUM_STRINGS(term)(term)->num_Strings != STRCOUNT414)) 1212 ? name_initializer("string_ext") 1213 : "(char **)0"); 1214 1215 (void) printf("\t\t%d,\t\t/* count total Booleans */\n", NUM_BOOLEANS(term)(term)->num_Booleans); 1216 (void) printf("\t\t%d,\t\t/* count total Numbers */\n", NUM_NUMBERS(term)(term)->num_Numbers); 1217 (void) printf("\t\t%d,\t\t/* count total Strings */\n", NUM_STRINGS(term)(term)->num_Strings); 1218 1219 (void) printf("\t\t%d,\t\t/* count extensions to Booleans */\n", 1220 NUM_BOOLEANS(term)(term)->num_Booleans - BOOLCOUNT44); 1221 (void) printf("\t\t%d,\t\t/* count extensions to Numbers */\n", 1222 NUM_NUMBERS(term)(term)->num_Numbers - NUMCOUNT39); 1223 (void) printf("\t\t%d,\t\t/* count extensions to Strings */\n", 1224 NUM_STRINGS(term)(term)->num_Strings - STRCOUNT414); 1225 1226 (void) printf("#endif /* NCURSES_XNAMES */\n"); 1227#else 1228 (void) term; 1229#endif /* NCURSES_XNAMES */ 1230 (void) printf("\t%s\n", R_CURL"}"); 1231} 1232 1233static int 1234optarg_to_number(void) 1235{ 1236 char *temp = 0; 1237 long value = strtol(optarg, &temp, 0); 1238 1239 if (temp == 0 || temp == optarg || *temp != 0) { 1240 fprintf(stderr(&__sF[2]), "Expected a number, not \"%s\"\n", optarg); 1241 ExitProgram(EXIT_FAILURE)exit(1); 1242 } 1243 return (int) value; 1244} 1245 1246static char * 1247terminal_env(void) 1248{ 1249 char *terminal; 1250 1251 if ((terminal = getenv("TERM")) == 0) { 1252 (void) fprintf(stderr(&__sF[2]), 1253 "%s: environment variable TERM not set\n", 1254 _nc_progname); 1255 exit(EXIT_FAILURE1); 1256 } 1257 return terminal; 1258} 1259 1260/*************************************************************************** 1261 * 1262 * Main sequence 1263 * 1264 ***************************************************************************/ 1265 1266int 1267main(int argc, char *argv[]) 1268{ 1269 /* Avoid "local data >32k" error with mwcc */ 1270 /* Also avoid overflowing smaller stacks on systems like AmigaOS */ 1271 path *tfile = 0; 1272 char **tname = 0; 1273 int maxterms; 1274 1275 char **myargv; 1276 1277 char *firstdir, *restdir; 1278 int c, i, len; 1279 bool_Bool formatted = FALSE0; 1280 bool_Bool filecompare = FALSE0; 1281 int initdump = 0; 1282 bool_Bool init_analyze = FALSE0; 1283 bool_Bool suppress_untranslatable = FALSE0; 1284 1285 if (pledge("stdio rpath", NULL((void *)0)) == -1) {
1
Assuming the condition is false
2
Taking false branch
1286 perror("pledge"); 1287 exit(1); 1288 } 1289 1290 /* where is the terminfo database location going to default to? */ 1291 restdir = firstdir = 0; 1292 1293#if NCURSES_XNAMES1 1294 use_extended_names(FALSE0); 1295#endif 1296 1297 _nc_progname = _nc_rootname(argv[0]); 1298 1299 /* make sure we have enough space to add two terminal entries */ 1300 myargv = typeCalloc(char *, (size_t) (argc + 3))(char * *)calloc(((size_t) (argc + 3)),sizeof(char *)); 1301 memcpy(myargv, argv, (sizeof(char *) * (size_t) argc)); 1302 argv = myargv; 1303 1304 while ((c = getopt(argc,
3
Assuming the condition is true
4
Loop condition is true. Entering loop body
7
Assuming the condition is false
8
Loop condition is false. Execution continues on line 1469
1305 argv, 1306 "1A:aB:CcdEeFfGgIiLlnpqR:rs:TtUuVv:w:x")) != -1) { 1307 switch (c) {
5
Control jumps to 'case 105:' at line 1372
1308 case '1': 1309 mwidth = 0; 1310 break; 1311 1312 case 'A': 1313 firstdir = optarg; 1314 break; 1315 1316#if NCURSES_XNAMES1 1317 case 'a': 1318 _nc_disable_period = TRUE1; 1319 use_extended_names(TRUE1); 1320 break; 1321#endif 1322 case 'B': 1323 restdir = optarg; 1324 break; 1325 1326 case 'C': 1327 outform = F_TERMCAP2; 1328 tversion = "BSD"; 1329 if (sortmode == S_DEFAULT0) 1330 sortmode = S_TERMCAP4; 1331 break; 1332 1333 case 'c': 1334 compare = C_COMMON2; 1335 break; 1336 1337 case 'd': 1338 compare = C_DIFFERENCE1; 1339 break; 1340 1341 case 'E': 1342 initdump |= 2; 1343 break; 1344 1345 case 'e': 1346 initdump |= 1; 1347 break; 1348 1349 case 'F': 1350 filecompare = TRUE1; 1351 break; 1352 1353 case 'f': 1354 formatted = TRUE1; 1355 break; 1356 1357 case 'G': 1358 numbers = 1; 1359 break; 1360 1361 case 'g': 1362 numbers = -1; 1363 break; 1364 1365 case 'I': 1366 outform = F_TERMINFO0; 1367 if (sortmode == S_DEFAULT0) 1368 sortmode = S_VARIABLE3; 1369 tversion = 0; 1370 break; 1371 1372 case 'i': 1373 init_analyze = TRUE1; 1374 break;
6
Execution continues on line 1304
1375 1376 case 'L': 1377 outform = F_VARIABLE1; 1378 if (sortmode == S_DEFAULT0) 1379 sortmode = S_VARIABLE3; 1380 break; 1381 1382 case 'l': 1383 outform = F_TERMINFO0; 1384 break; 1385 1386 case 'n': 1387 compare = C_NAND3; 1388 break; 1389 1390 case 'p': 1391 ignorepads = TRUE1; 1392 break; 1393 1394 case 'q': 1395 quiet = TRUE1; 1396 s_absent = "-"; 1397 s_cancel = "@"; 1398 bool_sep = ", "; 1399 break; 1400 1401 case 'R': 1402 tversion = optarg; 1403 break; 1404 1405 case 'r': 1406 tversion = 0; 1407 break; 1408 1409 case 's': 1410 if (*optarg == 'd') 1411 sortmode = S_NOSORT1; 1412 else if (*optarg == 'i') 1413 sortmode = S_TERMINFO2; 1414 else if (*optarg == 'l') 1415 sortmode = S_VARIABLE3; 1416 else if (*optarg == 'c') 1417 sortmode = S_TERMCAP4; 1418 else { 1419 (void) fprintf(stderr(&__sF[2]), 1420 "%s: unknown sort mode\n", 1421 _nc_progname); 1422 ExitProgram(EXIT_FAILURE)exit(1); 1423 } 1424 break; 1425 1426 case 'T': 1427 limited = FALSE0; 1428 break; 1429 1430#if NCURSES_XNAMES1 1431 case 't': 1432 _nc_disable_period = FALSE0; 1433 suppress_untranslatable = TRUE1; 1434 break; 1435#endif 1436 1437 case 'U': 1438 literal = TRUE1; 1439 break; 1440 1441 case 'u': 1442 compare = C_USEALL4; 1443 break; 1444 1445 case 'V': 1446 puts(curses_version()); 1447 ExitProgram(EXIT_SUCCESS)exit(0); 1448 1449 case 'v': 1450 itrace = optarg_to_number(); 1451 set_trace_level(itrace)_nc_tracing &= ((15) << 13), _nc_tracing |= ((itrace
) << 13)
; 1452 break; 1453 1454 case 'w': 1455 mwidth = optarg_to_number(); 1456 break; 1457 1458#if NCURSES_XNAMES1 1459 case 'x': 1460 use_extended_names(TRUE1); 1461 break; 1462#endif 1463 1464 default: 1465 usage(); 1466 } 1467 } 1468 1469 maxterms = (argc + 2 - optind); 1470 tfile = typeMalloc(path, maxterms)(path *)malloc((maxterms)*sizeof(path)); 1471 tname = typeCalloc(char *, maxterms)(char * *)calloc((maxterms),sizeof(char *)); 1472 entries = typeCalloc(ENTRY, maxterms)(ENTRY *)calloc((maxterms),sizeof(ENTRY)); 1473 1474 if (tfile == 0
9
Assuming 'tfile' is not equal to null
12
Taking false branch
1475 || tname == 0
10
Assuming 'tname' is not equal to null
1476 || entries == 0) {
11
Assuming 'entries' is not equal to null
1477 fprintf(stderr(&__sF[2]), "%s: not enough memory\n", _nc_progname); 1478 ExitProgram(EXIT_FAILURE)exit(1); 1479 } 1480 1481 /* by default, sort by terminfo name */ 1482 if (sortmode == S_DEFAULT0)
13
Assuming 'sortmode' is not equal to S_DEFAULT
14
Taking false branch
1483 sortmode = S_TERMINFO2; 1484 1485 /* set up for display */ 1486 dump_init(tversion, outform, sortmode, mwidth, itrace, formatted); 1487 1488 /* make sure we have at least one terminal name to work with */ 1489 if (optind >= argc)
15
Assuming 'optind' is < 'argc'
16
Taking false branch
1490 argv[argc++] = terminal_env(); 1491 1492 /* if user is after a comparison, make sure we have two entries */ 1493 if (compare != C_DEFAULT0 && optind >= argc - 1)
17
Assuming 'compare' is not equal to C_DEFAULT
18
Assuming the condition is true
19
Taking true branch
1494 argv[argc++] = terminal_env(); 1495 1496 /* exactly two terminal names with no options means do -d */ 1497 if (argc - optind == 2 && compare == C_DEFAULT0)
20
Assuming the condition is false
1498 compare = C_DIFFERENCE1; 1499 1500 if (!filecompare
20.1
'filecompare' is false
) {
21
Taking true branch
1501 /* grab the entries */ 1502 termcount = 0; 1503 for (; optind < argc; optind++) {
22
Assuming 'optind' is >= 'argc'
23
Loop condition is false. Execution continues on line 1557
1504 const char *directory = termcount ? restdir : firstdir; 1505 int status; 1506 1507 tname[termcount] = argv[optind]; 1508 1509 if (directory) { 1510#if USE_DATABASE1 1511#if MIXEDCASE_FILENAMES1 1512#define LEAF_FMT"%c" "%c" 1513#else 1514#define LEAF_FMT"%c" "%02x" 1515#endif 1516 (void) snprintf(tfile[termcount], sizeof (path), 1517 "%s/" LEAF_FMT"%c" "/%s", directory, 1518 UChar(*argv[optind])((unsigned char)(*argv[optind])), argv[optind]); 1519 if (itrace) 1520 (void) fprintf(stderr(&__sF[2]), 1521 "%s: reading entry %s from file %s\n", 1522 _nc_progname, 1523 argv[optind], tfile[termcount]); 1524 1525 status = _nc_read_file_entry(tfile[termcount], 1526 &entries[termcount].tterm); 1527#else 1528 (void) fprintf(stderr(&__sF[2]), "%s: terminfo files not supported\n", 1529 _nc_progname); 1530 ExitProgram(EXIT_FAILURE)exit(1); 1531#endif 1532 } else { 1533 if (itrace) 1534 (void) fprintf(stderr(&__sF[2]), 1535 "%s: reading entry %s from database\n", 1536 _nc_progname, 1537 tname[termcount]); 1538 1539 status = _nc_read_entry(tname[termcount], 1540 tfile[termcount], 1541 &entries[termcount].tterm); 1542 directory = TERMINFO"/usr/share/terminfo"; /* for error message */ 1543 } 1544 1545 if (status <= 0) { 1546 (void) fprintf(stderr(&__sF[2]), 1547 "%s: couldn't open terminfo file %s.\n", 1548 _nc_progname, 1549 tfile[termcount]); 1550 ExitProgram(EXIT_FAILURE)exit(1); 1551 } 1552 repair_acsc(&entries[termcount].tterm); 1553 termcount++; 1554 } 1555 1556#if NCURSES_XNAMES1 1557 if (termcount
23.1
'termcount' is <= 1
> 1)
24
Taking false branch
1558 _nc_align_termtype(&entries[0].tterm, &entries[1].tterm); 1559#endif 1560 1561 /* dump as C initializer for the terminal type */ 1562 if (initdump
24.1
'initdump' is 0
) {
25
Taking false branch
1563 if (initdump & 1) 1564 dump_termtype(&entries[0].tterm); 1565 if (initdump & 2) 1566 dump_initializers(&entries[0].tterm); 1567 } 1568 1569 /* analyze the init strings */ 1570 else if (init_analyze
25.1
'init_analyze' is true
) {
26
Taking true branch
1571#undef CUR 1572#define CUR entries[0].tterm. 1573 analyze_string("is1", init_1stringCUR Strings[48], &entries[0].tterm);
27
Calling 'analyze_string'
1574 analyze_string("is2", init_2stringCUR Strings[49], &entries[0].tterm); 1575 analyze_string("is3", init_3stringCUR Strings[50], &entries[0].tterm); 1576 analyze_string("rs1", reset_1stringCUR Strings[122], &entries[0].tterm); 1577 analyze_string("rs2", reset_2stringCUR Strings[123], &entries[0].tterm); 1578 analyze_string("rs3", reset_3stringCUR Strings[124], &entries[0].tterm); 1579 analyze_string("smcup", enter_ca_modeCUR Strings[28], &entries[0].tterm); 1580 analyze_string("rmcup", exit_ca_modeCUR Strings[40], &entries[0].tterm); 1581#undef CUR 1582 } else { 1583 1584 /* 1585 * Here's where the real work gets done 1586 */ 1587 switch (compare) { 1588 case C_DEFAULT0: 1589 if (itrace) 1590 (void) fprintf(stderr(&__sF[2]), 1591 "%s: about to dump %s\n", 1592 _nc_progname, 1593 tname[0]); 1594 (void) printf("#\tReconstructed via infocmp from file: %s\n", 1595 tfile[0]); 1596 dump_entry(&entries[0].tterm, 1597 suppress_untranslatable, 1598 limited, 1599 numbers, 1600 NULL((void *)0)); 1601 len = show_entry(); 1602 if (itrace) 1603 (void) fprintf(stderr(&__sF[2]), "%s: length %d\n", _nc_progname, len); 1604 break; 1605 1606 case C_DIFFERENCE1: 1607 if (itrace) 1608 (void) fprintf(stderr(&__sF[2]), "%s: dumping differences\n", _nc_progname); 1609 (void) printf("comparing %s to %s.\n", tname[0], tname[1]); 1610 compare_entry(compare_predicate, &entries->tterm, quiet); 1611 break; 1612 1613 case C_COMMON2: 1614 if (itrace) 1615 (void) fprintf(stderr(&__sF[2]), 1616 "%s: dumping common capabilities\n", 1617 _nc_progname); 1618 (void) printf("comparing %s to %s.\n", tname[0], tname[1]); 1619 compare_entry(compare_predicate, &entries->tterm, quiet); 1620 break; 1621 1622 case C_NAND3: 1623 if (itrace) 1624 (void) fprintf(stderr(&__sF[2]), 1625 "%s: dumping differences\n", 1626 _nc_progname); 1627 (void) printf("comparing %s to %s.\n", tname[0], tname[1]); 1628 compare_entry(compare_predicate, &entries->tterm, quiet); 1629 break; 1630 1631 case C_USEALL4: 1632 if (itrace) 1633 (void) fprintf(stderr(&__sF[2]), "%s: dumping use entry\n", _nc_progname); 1634 dump_entry(&entries[0].tterm, 1635 suppress_untranslatable, 1636 limited, 1637 numbers, 1638 use_predicate); 1639 for (i = 1; i < termcount; i++) 1640 dump_uses(tname[i], !(outform == F_TERMCAP2 1641 || outform == F_TCONVERR3)); 1642 len = show_entry(); 1643 if (itrace) 1644 (void) fprintf(stderr(&__sF[2]), "%s: length %d\n", _nc_progname, len); 1645 break; 1646 } 1647 } 1648 } else if (compare == C_USEALL4) 1649 (void) fprintf(stderr(&__sF[2]), "Sorry, -u doesn't work with -F\n"); 1650 else if (compare == C_DEFAULT0) 1651 (void) fprintf(stderr(&__sF[2]), "Use `tic -[CI] <file>' for this.\n"); 1652 else if (argc - optind != 2) 1653 (void) fprintf(stderr(&__sF[2]), 1654 "File comparison needs exactly two file arguments.\n"); 1655 else 1656 file_comparison(argc - optind, argv + optind); 1657 1658#if NO_LEAKS0 1659 free(myargv); 1660 free(tfile); 1661 free(tname); 1662#endif 1663 ExitProgram(EXIT_SUCCESS)exit(0); 1664} 1665 1666/* infocmp.c ends here */