Bug Summary

File:src/usr.bin/infocmp/infocmp.c
Warning:line 902, column 2
Value stored to 'rp' is never read

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))
615 return;
616 (void) printf("%s: ", name);
617
618 for (sp = cap; *sp; sp++) {
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++) {
628 char *cp = tp->Strings[i];
629
630 /* don't use soft-key capabilities */
631 if (strnames[i][0] == 'k' && strnames[i][1] == 'f')
632 continue;
633
634 if (cp != ABSENT_STRING(char *)0 && cp != CANCELLED_STRING(char *)(-1) && cp[0] && cp
635 != cap) {
636 len = strlen(cp);
637 (void) strncpy(buf2, sp, len);
638 buf2[len] = '\0';
639
640 if (_nc_capcmp(cp, buf2))
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)
653 continue;
654#undef ISRS
655
656 expansion = strnames[i];
657 break;
658 }
659 }
660
661 /* now check the standard capabilities */
662 if (!expansion) {
663 csi = skip_csi(sp);
664 for (ap = std_caps; ap->from; ap++) {
665 size_t adj = (size_t) (csi ? 2 : 0);
666
667 len = strlen(ap->from);
668 if (csi && skip_csi(ap->from) != csi)
669 continue;
670 if (len > adj
671 && strncmp(ap->from + adj, sp + csi, len - adj) == 0) {
672 expansion = ap->to;
673 len -= adj;
674 len += (size_t) csi;
675 break;
676 }
677 }
678 }
679
680 /* now check for standard-mode sequences */
681 if (!expansion
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
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
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
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
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
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) {
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];
Value stored to 'rp' is never read
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) {
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,
1305 argv,
1306 "1A:aB:CcdEeFfGgIiLlnpqR:rs:TtUuVv:w:x")) != -1) {
1307 switch (c) {
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;
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
1475 || tname == 0
1476 || entries == 0) {
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)
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)
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)
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)
1498 compare = C_DIFFERENCE1;
1499
1500 if (!filecompare) {
1501 /* grab the entries */
1502 termcount = 0;
1503 for (; optind < argc; optind++) {
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 > 1)
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) {
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) {
1571#undef CUR
1572#define CUR entries[0].tterm.
1573 analyze_string("is1", init_1stringCUR Strings[48], &entries[0].tterm);
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 */