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 |
|
|
|
47 |
|
|
MODULE_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_STRING 1024 /* maximum formatted string */ |
53 |
|
|
|
54 |
|
|
const char *_nc_progname = "infocmp"; |
55 |
|
|
|
56 |
|
|
typedef char path[PATH_MAX]; |
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 |
|
|
|
65 |
|
|
static ENTRY *entries; /* terminfo entries */ |
66 |
|
|
static int termcount; /* count of terminal entries */ |
67 |
|
|
|
68 |
|
|
static bool limited = TRUE; /* "-r" option is not set */ |
69 |
|
|
static bool quiet = FALSE; |
70 |
|
|
static bool literal = FALSE; |
71 |
|
|
static const char *bool_sep = ":"; |
72 |
|
|
static const char *s_absent = "NULL"; |
73 |
|
|
static const char *s_cancel = "NULL"; |
74 |
|
|
static const char *tversion; /* terminfo version selected */ |
75 |
|
|
static int itrace; /* trace flag for debugging */ |
76 |
|
|
static int mwidth = 60; |
77 |
|
|
static int numbers = 0; /* format "%'char'" to/from "%{number}" */ |
78 |
|
|
static int outform = F_TERMINFO; /* output format */ |
79 |
|
|
static int sortmode; /* sort_mode */ |
80 |
|
|
|
81 |
|
|
/* main comparison mode */ |
82 |
|
|
static int compare; |
83 |
|
|
#define C_DEFAULT 0 /* don't force comparison mode */ |
84 |
|
|
#define C_DIFFERENCE 1 /* list differences between two terminals */ |
85 |
|
|
#define C_COMMON 2 /* list common capabilities */ |
86 |
|
|
#define C_NAND 3 /* list capabilities in neither terminal */ |
87 |
|
|
#define C_USEALL 4 /* generate relative use-form entry */ |
88 |
|
|
static bool ignorepads; /* ignore pad prefixes when diffing */ |
89 |
|
|
|
90 |
|
|
#if NO_LEAKS |
91 |
|
|
#undef ExitProgram |
92 |
|
|
static void ExitProgram(int code) GCC_NORETURN; |
93 |
|
|
/* prototype is to get gcc to accept the noreturn attribute */ |
94 |
|
|
static void |
95 |
|
|
ExitProgram(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 |
|
|
|
105 |
|
|
static char * |
106 |
|
|
canonical_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 |
|
|
|
124 |
|
|
static int |
125 |
|
|
capcmp(PredIdx idx, const char *s, const char *t) |
126 |
|
|
/* capability comparison function */ |
127 |
|
|
{ |
128 |
|
|
if (!VALID_STRING(s) && !VALID_STRING(t)) |
129 |
|
|
return (s != t); |
130 |
|
|
else if (!VALID_STRING(s) || !VALID_STRING(t)) |
131 |
|
|
return (1); |
132 |
|
|
|
133 |
|
|
if ((idx == acs_chars_index) || !ignorepads) |
134 |
|
|
return (strcmp(s, t)); |
135 |
|
|
else |
136 |
|
|
return (_nc_capcmp(s, t)); |
137 |
|
|
} |
138 |
|
|
|
139 |
|
|
static int |
140 |
|
|
use_predicate(unsigned type, PredIdx idx) |
141 |
|
|
/* predicate function to use for use decompilation */ |
142 |
|
|
{ |
143 |
|
|
ENTRY *ep; |
144 |
|
|
|
145 |
|
|
switch (type) { |
146 |
|
|
case BOOLEAN: |
147 |
|
|
{ |
148 |
|
|
int is_set = FALSE; |
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] == TRUE) { |
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); |
170 |
|
|
} |
171 |
|
|
|
172 |
|
|
case NUMBER: |
173 |
|
|
{ |
174 |
|
|
int value = ABSENT_NUMERIC; |
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])) { |
183 |
|
|
value = ep->tterm.Numbers[idx]; |
184 |
|
|
break; |
185 |
|
|
} |
186 |
|
|
|
187 |
|
|
if (value != entries[0].tterm.Numbers[idx]) |
188 |
|
|
return (value != ABSENT_NUMERIC); |
189 |
|
|
else |
190 |
|
|
return (FAIL); |
191 |
|
|
} |
192 |
|
|
|
193 |
|
|
case STRING: |
194 |
|
|
{ |
195 |
|
|
char *termstr, *usestr = ABSENT_STRING; |
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 && termstr == ABSENT_STRING) |
211 |
|
|
return (FAIL); |
212 |
|
|
else if (!usestr || !termstr || capcmp(idx, usestr, termstr)) |
213 |
|
|
return (TRUE); |
214 |
|
|
else |
215 |
|
|
return (FAIL); |
216 |
|
|
} |
217 |
|
|
} |
218 |
|
|
|
219 |
|
|
return (FALSE); /* pacify compiler */ |
220 |
|
|
} |
221 |
|
|
|
222 |
|
|
static bool |
223 |
|
|
useeq(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 (FALSE); |
230 |
|
|
|
231 |
|
|
/* Ugh...this is quadratic again */ |
232 |
|
|
for (i = 0; i < e1->nuses; i++) { |
233 |
|
|
bool foundmatch = FALSE; |
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 = TRUE; |
239 |
|
|
break; |
240 |
|
|
} |
241 |
|
|
|
242 |
|
|
if (!foundmatch) |
243 |
|
|
return (FALSE); |
244 |
|
|
} |
245 |
|
|
|
246 |
|
|
return (TRUE); |
247 |
|
|
} |
248 |
|
|
|
249 |
|
|
static bool |
250 |
|
|
entryeq(TERMTYPE *t1, TERMTYPE *t2) |
251 |
|
|
/* are two entries equivalent? */ |
252 |
|
|
{ |
253 |
|
|
unsigned i; |
254 |
|
|
|
255 |
|
|
for (i = 0; i < NUM_BOOLEANS(t1); i++) |
256 |
|
|
if (t1->Booleans[i] != t2->Booleans[i]) |
257 |
|
|
return (FALSE); |
258 |
|
|
|
259 |
|
|
for (i = 0; i < NUM_NUMBERS(t1); i++) |
260 |
|
|
if (t1->Numbers[i] != t2->Numbers[i]) |
261 |
|
|
return (FALSE); |
262 |
|
|
|
263 |
|
|
for (i = 0; i < NUM_STRINGS(t1); i++) |
264 |
|
|
if (capcmp((PredIdx) i, t1->Strings[i], t2->Strings[i])) |
265 |
|
|
return (FALSE); |
266 |
|
|
|
267 |
|
|
return (TRUE); |
268 |
|
|
} |
269 |
|
|
|
270 |
|
|
#define TIC_EXPAND(result) _nc_tic_expand(result, outform==F_TERMINFO, numbers) |
271 |
|
|
|
272 |
|
|
static void |
273 |
|
|
print_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 |
|
|
|
288 |
|
|
static const char * |
289 |
|
|
dump_boolean(int val) |
290 |
|
|
/* display the value of a boolean capability */ |
291 |
|
|
{ |
292 |
|
|
switch (val) { |
293 |
|
|
case ABSENT_BOOLEAN: |
294 |
|
|
return (s_absent); |
295 |
|
|
case CANCELLED_BOOLEAN: |
296 |
|
|
return (s_cancel); |
297 |
|
|
case FALSE: |
298 |
|
|
return ("F"); |
299 |
|
|
case TRUE: |
300 |
|
|
return ("T"); |
301 |
|
|
default: |
302 |
|
|
return ("?"); |
303 |
|
|
} |
304 |
|
|
} |
305 |
|
|
|
306 |
|
|
static void |
307 |
|
|
dump_numeric(int val, char *buf, size_t bufl) |
308 |
|
|
/* display the value of a boolean capability */ |
309 |
|
|
{ |
310 |
|
|
switch (val) { |
311 |
|
|
case ABSENT_NUMERIC: |
312 |
|
|
strlcpy(buf, s_absent, bufl); |
313 |
|
|
break; |
314 |
|
|
case CANCELLED_NUMERIC: |
315 |
|
|
strlcpy(buf, s_cancel, bufl); |
316 |
|
|
break; |
317 |
|
|
default: |
318 |
|
|
snprintf(buf, bufl, "%d", val); |
319 |
|
|
break; |
320 |
|
|
} |
321 |
|
|
} |
322 |
|
|
|
323 |
|
|
static void |
324 |
|
|
dump_string(char *val, char *buf, size_t bufl) |
325 |
|
|
/* display the value of a string capability */ |
326 |
|
|
{ |
327 |
|
|
if (val == ABSENT_STRING) |
328 |
|
|
strlcpy(buf, s_absent, bufl); |
329 |
|
|
else if (val == CANCELLED_STRING) |
330 |
|
|
strlcpy(buf, s_cancel, bufl); |
331 |
|
|
else { |
332 |
|
|
snprintf(buf, bufl, "'%.*s'", MAX_STRING - 3, TIC_EXPAND(val)); |
333 |
|
|
} |
334 |
|
|
} |
335 |
|
|
|
336 |
|
|
static void |
337 |
|
|
compare_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_STRING], buf2[MAX_STRING]; |
343 |
|
|
int b1, b2; |
344 |
|
|
int n1, n2; |
345 |
|
|
char *s1, *s2; |
346 |
|
|
|
347 |
|
|
switch (type) { |
348 |
|
|
case CMP_BOOLEAN: |
349 |
|
|
b1 = e1->tterm.Booleans[idx]; |
350 |
|
|
b2 = e2->tterm.Booleans[idx]; |
351 |
|
|
switch (compare) { |
352 |
|
|
case C_DIFFERENCE: |
353 |
|
|
if (!(b1 == ABSENT_BOOLEAN && b2 == ABSENT_BOOLEAN) && 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_COMMON: |
362 |
|
|
if (b1 == b2 && b1 != ABSENT_BOOLEAN) |
363 |
|
|
(void) printf("\t%s= %s.\n", name, dump_boolean(b1)); |
364 |
|
|
break; |
365 |
|
|
|
366 |
|
|
case C_NAND: |
367 |
|
|
if (b1 == ABSENT_BOOLEAN && b2 == ABSENT_BOOLEAN) |
368 |
|
|
(void) printf("\t!%s.\n", name); |
369 |
|
|
break; |
370 |
|
|
} |
371 |
|
|
break; |
372 |
|
|
|
373 |
|
|
case CMP_NUMBER: |
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_DIFFERENCE: |
380 |
|
|
if (!((n1 == ABSENT_NUMERIC && n2 == ABSENT_NUMERIC)) && n1 != n2) |
381 |
|
|
(void) printf("\t%s: %s, %s.\n", name, buf1, buf2); |
382 |
|
|
break; |
383 |
|
|
|
384 |
|
|
case C_COMMON: |
385 |
|
|
if (n1 != ABSENT_NUMERIC && n2 != ABSENT_NUMERIC && n1 == n2) |
386 |
|
|
(void) printf("\t%s= %s.\n", name, buf1); |
387 |
|
|
break; |
388 |
|
|
|
389 |
|
|
case C_NAND: |
390 |
|
|
if (n1 == ABSENT_NUMERIC && n2 == ABSENT_NUMERIC) |
391 |
|
|
(void) printf("\t!%s.\n", name); |
392 |
|
|
break; |
393 |
|
|
} |
394 |
|
|
break; |
395 |
|
|
|
396 |
|
|
case CMP_STRING: |
397 |
|
|
s1 = e1->tterm.Strings[idx]; |
398 |
|
|
s2 = e2->tterm.Strings[idx]; |
399 |
|
|
switch (compare) { |
400 |
|
|
case C_DIFFERENCE: |
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_COMMON: |
410 |
|
|
if (s1 && s2 && !capcmp(idx, s1, s2)) |
411 |
|
|
(void) printf("\t%s= '%s'.\n", name, TIC_EXPAND(s1)); |
412 |
|
|
break; |
413 |
|
|
|
414 |
|
|
case C_NAND: |
415 |
|
|
if (!s1 && !s2) |
416 |
|
|
(void) printf("\t!%s.\n", name); |
417 |
|
|
break; |
418 |
|
|
} |
419 |
|
|
break; |
420 |
|
|
|
421 |
|
|
case CMP_USE: |
422 |
|
|
/* unlike the other modes, this compares *all* use entries */ |
423 |
|
|
switch (compare) { |
424 |
|
|
case C_DIFFERENCE: |
425 |
|
|
if (!useeq(e1, e2)) { |
426 |
|
|
(void) fputs("\tuse: ", stdout); |
427 |
|
|
print_uses(e1, stdout); |
428 |
|
|
fputs(", ", stdout); |
429 |
|
|
print_uses(e2, stdout); |
430 |
|
|
fputs(".\n", stdout); |
431 |
|
|
} |
432 |
|
|
break; |
433 |
|
|
|
434 |
|
|
case C_COMMON: |
435 |
|
|
if (e1->nuses && e2->nuses && useeq(e1, e2)) { |
436 |
|
|
(void) fputs("\tuse: ", stdout); |
437 |
|
|
print_uses(e1, stdout); |
438 |
|
|
fputs(".\n", stdout); |
439 |
|
|
} |
440 |
|
|
break; |
441 |
|
|
|
442 |
|
|
case C_NAND: |
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 |
|
|
|
456 |
|
|
typedef struct { |
457 |
|
|
const char *from; |
458 |
|
|
const char *to; |
459 |
|
|
} assoc; |
460 |
|
|
|
461 |
|
|
static 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 |
|
|
|
489 |
|
|
static 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 |
|
|
|
499 |
|
|
static 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 |
|
|
|
513 |
|
|
static 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 |
|
|
|
549 |
|
|
static int |
550 |
|
|
skip_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]) == 0233) |
556 |
|
|
result = 1; |
557 |
|
|
return result; |
558 |
|
|
} |
559 |
|
|
|
560 |
|
|
static bool |
561 |
|
|
same_param(const char *table, const char *param, unsigned length) |
562 |
|
|
{ |
563 |
|
|
bool result = FALSE; |
564 |
|
|
if (strncmp(table, param, length) == 0) { |
565 |
|
|
result = !isdigit(UChar(param[length])); |
566 |
|
|
} |
567 |
|
|
return result; |
568 |
|
|
} |
569 |
|
|
|
570 |
|
|
static char * |
571 |
|
|
lookup_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 found = FALSE; |
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 = TRUE; |
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 |
|
|
|
606 |
|
|
static void |
607 |
|
|
analyze_string(const char *name, const char *cap, TERMTYPE *tp) |
608 |
|
|
{ |
609 |
|
|
char buf2[MAX_TERMINFO_LENGTH]; |
610 |
|
|
const char *sp; |
611 |
|
|
const assoc *ap; |
612 |
|
|
int tp_lines = tp->Numbers[2]; |
613 |
|
|
|
614 |
|
|
if (cap == ABSENT_STRING || cap == CANCELLED_STRING) |
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_LENGTH]; |
625 |
|
|
|
626 |
|
|
/* first, check other capabilities in this entry */ |
627 |
|
|
for (i = 0; i < STRCOUNT; 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 && cp != CANCELLED_STRING && 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), stdout); |
781 |
|
|
} |
782 |
|
|
} |
783 |
|
|
putchar('\n'); |
784 |
|
|
} |
785 |
|
|
|
786 |
|
|
/*************************************************************************** |
787 |
|
|
* |
788 |
|
|
* File comparison |
789 |
|
|
* |
790 |
|
|
***************************************************************************/ |
791 |
|
|
|
792 |
|
|
static void |
793 |
|
|
file_comparison(int argc, char *argv[]) |
794 |
|
|
{ |
795 |
|
|
#define MAXCOMPARE 2 |
796 |
|
|
/* someday we may allow comparisons on more files */ |
797 |
|
|
int filecount = 0; |
798 |
|
|
ENTRY *heads[MAXCOMPARE]; |
799 |
|
|
ENTRY *qp, *rp; |
800 |
|
|
int i, n; |
801 |
|
|
|
802 |
|
|
memset(heads, 0, sizeof(heads)); |
803 |
|
|
dump_init((char *) 0, F_LITERAL, S_TERMINFO, 0, itrace, FALSE); |
804 |
|
|
|
805 |
|
|
for (n = 0; n < argc && n < MAXCOMPARE; n++) { |
806 |
|
|
if (freopen(argv[n], "r", stdin) == 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, NULL, TRUE, literal, NULLHOOK); |
814 |
|
|
|
815 |
|
|
if (itrace) |
816 |
|
|
(void) fprintf(stderr, "Resolving file %d...\n", n - 0); |
817 |
|
|
|
818 |
|
|
/* maybe do use resolution */ |
819 |
|
|
if (!_nc_resolve_uses2(!limited, literal)) { |
820 |
|
|
(void) fprintf(stderr, |
821 |
|
|
"There are unresolved use entries in %s:\n", |
822 |
|
|
argv[n]); |
823 |
|
|
for_entry_list(qp) { |
824 |
|
|
if (qp->nuses) { |
825 |
|
|
(void) fputs(qp->tterm.term_names, stderr); |
826 |
|
|
(void) fputc('\n', stderr); |
827 |
|
|
} |
828 |
|
|
} |
829 |
|
|
ExitProgram(EXIT_FAILURE); |
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, "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_CROSSLINKS) |
845 |
|
|
qp->crosslinks[qp->ncrosslinks] = rp; |
846 |
|
|
qp->ncrosslinks++; |
847 |
|
|
|
848 |
|
|
if (rp->ncrosslinks < MAX_CROSSLINKS) |
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, "Name matches are done...\n"); |
857 |
|
|
|
858 |
|
|
for (qp = heads[0]; qp; qp = qp->next) { |
859 |
|
|
if (qp->ncrosslinks > 1) { |
860 |
|
|
(void) fprintf(stderr, |
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, |
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, |
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, |
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_XNAMES |
910 |
|
|
_nc_align_termtype(&qp->tterm, &rp->tterm); |
911 |
|
|
#endif |
912 |
|
|
if (entryeq(&qp->tterm, &rp->tterm) && useeq(qp, rp)) { |
913 |
|
|
char name1[NAMESIZE], name2[NAMESIZE]; |
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_XNAMES |
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[NAMESIZE], name2[NAMESIZE]; |
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_DIFFERENCE: |
944 |
|
|
if (itrace) |
945 |
|
|
(void) fprintf(stderr, |
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_COMMON: |
953 |
|
|
if (itrace) |
954 |
|
|
(void) fprintf(stderr, |
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_NAND: |
962 |
|
|
if (itrace) |
963 |
|
|
(void) fprintf(stderr, |
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 |
|
|
|
976 |
|
|
static void |
977 |
|
|
usage(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_XNAMES |
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_XNAMES |
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_XNAMES |
1018 |
|
|
," -x treat unknown capabilities as user-defined" |
1019 |
|
|
#endif |
1020 |
|
|
}; |
1021 |
|
|
const size_t first = 3; |
1022 |
|
|
const size_t last = SIZEOF(tbl); |
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, "%-40.40s%s\n", tbl[n], tbl[m]); |
1030 |
|
|
else |
1031 |
|
|
fprintf(stderr, "%s\n", tbl[n]); |
1032 |
|
|
} |
1033 |
|
|
ExitProgram(EXIT_FAILURE); |
1034 |
|
|
} |
1035 |
|
|
|
1036 |
|
|
static char * |
1037 |
|
|
any_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))) |
1051 |
|
|
*s = '_'; |
1052 |
|
|
} |
1053 |
|
|
*s = 0; |
1054 |
|
|
(void) snprintf(s, len - (s - initializer), fmt, type); |
1055 |
|
|
return initializer; |
1056 |
|
|
} |
1057 |
|
|
|
1058 |
|
|
static char * |
1059 |
|
|
name_initializer(const char *type) |
1060 |
|
|
{ |
1061 |
|
|
return any_initializer("_%s_data", type); |
1062 |
|
|
} |
1063 |
|
|
|
1064 |
|
|
static char * |
1065 |
|
|
string_variable(const char *type) |
1066 |
|
|
{ |
1067 |
|
|
return any_initializer("_s_%s", type); |
1068 |
|
|
} |
1069 |
|
|
|
1070 |
|
|
/* dump C initializers for the terminal type */ |
1071 |
|
|
static void |
1072 |
|
|
dump_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) { |
1081 |
|
|
char buf[MAX_STRING], *sp, *tp; |
1082 |
|
|
|
1083 |
|
|
if (VALID_STRING(term->Strings[n])) { |
1084 |
|
|
tp = buf; |
1085 |
|
|
*tp++ = '"'; |
1086 |
|
|
for (sp = term->Strings[n]; |
1087 |
|
|
*sp != 0 && (tp - buf) < MAX_STRING - 6; |
1088 |
|
|
sp++) { |
1089 |
|
|
if (isascii(UChar(*sp)) |
1090 |
|
|
&& isprint(UChar(*sp)) |
1091 |
|
|
&& *sp != '\\' |
1092 |
|
|
&& *sp != '"') |
1093 |
|
|
*tp++ = *sp; |
1094 |
|
|
else { |
1095 |
|
|
(void) snprintf(tp, buf + sizeof buf - tp, "\\%03o", |
1096 |
|
|
UChar(*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)), 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) { |
1111 |
|
|
switch ((int) (term->Booleans[n])) { |
1112 |
|
|
case TRUE: |
1113 |
|
|
str = "TRUE"; |
1114 |
|
|
break; |
1115 |
|
|
|
1116 |
|
|
case FALSE: |
1117 |
|
|
str = "FALSE"; |
1118 |
|
|
break; |
1119 |
|
|
|
1120 |
|
|
case ABSENT_BOOLEAN: |
1121 |
|
|
str = "ABSENT_BOOLEAN"; |
1122 |
|
|
break; |
1123 |
|
|
|
1124 |
|
|
case CANCELLED_BOOLEAN: |
1125 |
|
|
str = "CANCELLED_BOOLEAN"; |
1126 |
|
|
break; |
1127 |
|
|
} |
1128 |
|
|
(void) printf("\t/* %3u: %-8s */\t%s,\n", |
1129 |
|
|
n, ExtBoolname(term, n, boolnames), 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) { |
1136 |
|
|
char buf[BUFSIZ]; |
1137 |
|
|
switch (term->Numbers[n]) { |
1138 |
|
|
case ABSENT_NUMERIC: |
1139 |
|
|
str = "ABSENT_NUMERIC"; |
1140 |
|
|
break; |
1141 |
|
|
case CANCELLED_NUMERIC: |
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), 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) { |
1157 |
|
|
|
1158 |
|
|
if (term->Strings[n] == ABSENT_STRING) |
1159 |
|
|
str = "ABSENT_STRING"; |
1160 |
|
|
else if (term->Strings[n] == CANCELLED_STRING) |
1161 |
|
|
str = "CANCELLED_STRING"; |
1162 |
|
|
else { |
1163 |
|
|
str = string_variable(ExtStrname(term, n, strnames)); |
1164 |
|
|
} |
1165 |
|
|
(void) printf("\t/* %3u: %-8s */\t%s,\n", n, |
1166 |
|
|
ExtStrname(term, n, strnames), str); |
1167 |
|
|
} |
1168 |
|
|
(void) printf("%s;\n", R_CURL); |
1169 |
|
|
|
1170 |
|
|
#if NCURSES_XNAMES |
1171 |
|
|
if ((NUM_BOOLEANS(term) != BOOLCOUNT) |
1172 |
|
|
|| (NUM_NUMBERS(term) != NUMCOUNT) |
1173 |
|
|
|| (NUM_STRINGS(term) != STRCOUNT)) { |
1174 |
|
|
(void) printf("static char * %s[] = %s\n", |
1175 |
|
|
name_initializer("string_ext"), L_CURL); |
1176 |
|
|
for (n = BOOLCOUNT; n < NUM_BOOLEANS(term); ++n) { |
1177 |
|
|
(void) printf("\t/* %3u: bool */\t\"%s\",\n", |
1178 |
|
|
n, ExtBoolname(term, n, boolnames)); |
1179 |
|
|
} |
1180 |
|
|
for (n = NUMCOUNT; n < NUM_NUMBERS(term); ++n) { |
1181 |
|
|
(void) printf("\t/* %3u: num */\t\"%s\",\n", |
1182 |
|
|
n, ExtNumname(term, n, numnames)); |
1183 |
|
|
} |
1184 |
|
|
for (n = STRCOUNT; n < NUM_STRINGS(term); ++n) { |
1185 |
|
|
(void) printf("\t/* %3u: str */\t\"%s\",\n", |
1186 |
|
|
n, ExtStrname(term, n, strnames)); |
1187 |
|
|
} |
1188 |
|
|
(void) printf("%s;\n", R_CURL); |
1189 |
|
|
} |
1190 |
|
|
#endif |
1191 |
|
|
} |
1192 |
|
|
|
1193 |
|
|
/* dump C initializers for the terminal type */ |
1194 |
|
|
static void |
1195 |
|
|
dump_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_XNAMES |
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) != BOOLCOUNT) |
1210 |
|
|
|| (NUM_NUMBERS(term) != NUMCOUNT) |
1211 |
|
|
|| (NUM_STRINGS(term) != STRCOUNT)) |
1212 |
|
|
? name_initializer("string_ext") |
1213 |
|
|
: "(char **)0"); |
1214 |
|
|
|
1215 |
|
|
(void) printf("\t\t%d,\t\t/* count total Booleans */\n", NUM_BOOLEANS(term)); |
1216 |
|
|
(void) printf("\t\t%d,\t\t/* count total Numbers */\n", NUM_NUMBERS(term)); |
1217 |
|
|
(void) printf("\t\t%d,\t\t/* count total Strings */\n", NUM_STRINGS(term)); |
1218 |
|
|
|
1219 |
|
|
(void) printf("\t\t%d,\t\t/* count extensions to Booleans */\n", |
1220 |
|
|
NUM_BOOLEANS(term) - BOOLCOUNT); |
1221 |
|
|
(void) printf("\t\t%d,\t\t/* count extensions to Numbers */\n", |
1222 |
|
|
NUM_NUMBERS(term) - NUMCOUNT); |
1223 |
|
|
(void) printf("\t\t%d,\t\t/* count extensions to Strings */\n", |
1224 |
|
|
NUM_STRINGS(term) - STRCOUNT); |
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 |
|
|
|
1233 |
|
|
static int |
1234 |
|
|
optarg_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, "Expected a number, not \"%s\"\n", optarg); |
1241 |
|
|
ExitProgram(EXIT_FAILURE); |
1242 |
|
|
} |
1243 |
|
|
return (int) value; |
1244 |
|
|
} |
1245 |
|
|
|
1246 |
|
|
static char * |
1247 |
|
|
terminal_env(void) |
1248 |
|
|
{ |
1249 |
|
|
char *terminal; |
1250 |
|
|
|
1251 |
|
|
if ((terminal = getenv("TERM")) == 0) { |
1252 |
|
|
(void) fprintf(stderr, |
1253 |
|
|
"%s: environment variable TERM not set\n", |
1254 |
|
|
_nc_progname); |
1255 |
|
|
exit(EXIT_FAILURE); |
1256 |
|
|
} |
1257 |
|
|
return terminal; |
1258 |
|
|
} |
1259 |
|
|
|
1260 |
|
|
/*************************************************************************** |
1261 |
|
|
* |
1262 |
|
|
* Main sequence |
1263 |
|
|
* |
1264 |
|
|
***************************************************************************/ |
1265 |
|
|
|
1266 |
|
|
int |
1267 |
|
|
main(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 formatted = FALSE; |
1280 |
|
|
bool filecompare = FALSE; |
1281 |
|
|
int initdump = 0; |
1282 |
|
|
bool init_analyze = FALSE; |
1283 |
|
|
bool suppress_untranslatable = FALSE; |
1284 |
|
|
|
1285 |
|
|
if (pledge("stdio rpath flock cpath wpath", NULL) == -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_XNAMES |
1294 |
|
|
use_extended_names(FALSE); |
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)); |
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_XNAMES |
1317 |
|
|
case 'a': |
1318 |
|
|
_nc_disable_period = TRUE; |
1319 |
|
|
use_extended_names(TRUE); |
1320 |
|
|
break; |
1321 |
|
|
#endif |
1322 |
|
|
case 'B': |
1323 |
|
|
restdir = optarg; |
1324 |
|
|
break; |
1325 |
|
|
|
1326 |
|
|
case 'C': |
1327 |
|
|
outform = F_TERMCAP; |
1328 |
|
|
tversion = "BSD"; |
1329 |
|
|
if (sortmode == S_DEFAULT) |
1330 |
|
|
sortmode = S_TERMCAP; |
1331 |
|
|
break; |
1332 |
|
|
|
1333 |
|
|
case 'c': |
1334 |
|
|
compare = C_COMMON; |
1335 |
|
|
break; |
1336 |
|
|
|
1337 |
|
|
case 'd': |
1338 |
|
|
compare = C_DIFFERENCE; |
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 = TRUE; |
1351 |
|
|
break; |
1352 |
|
|
|
1353 |
|
|
case 'f': |
1354 |
|
|
formatted = TRUE; |
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_TERMINFO; |
1367 |
|
|
if (sortmode == S_DEFAULT) |
1368 |
|
|
sortmode = S_VARIABLE; |
1369 |
|
|
tversion = 0; |
1370 |
|
|
break; |
1371 |
|
|
|
1372 |
|
|
case 'i': |
1373 |
|
|
init_analyze = TRUE; |
1374 |
|
|
break; |
1375 |
|
|
|
1376 |
|
|
case 'L': |
1377 |
|
|
outform = F_VARIABLE; |
1378 |
|
|
if (sortmode == S_DEFAULT) |
1379 |
|
|
sortmode = S_VARIABLE; |
1380 |
|
|
break; |
1381 |
|
|
|
1382 |
|
|
case 'l': |
1383 |
|
|
outform = F_TERMINFO; |
1384 |
|
|
break; |
1385 |
|
|
|
1386 |
|
|
case 'n': |
1387 |
|
|
compare = C_NAND; |
1388 |
|
|
break; |
1389 |
|
|
|
1390 |
|
|
case 'p': |
1391 |
|
|
ignorepads = TRUE; |
1392 |
|
|
break; |
1393 |
|
|
|
1394 |
|
|
case 'q': |
1395 |
|
|
quiet = TRUE; |
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_NOSORT; |
1412 |
|
|
else if (*optarg == 'i') |
1413 |
|
|
sortmode = S_TERMINFO; |
1414 |
|
|
else if (*optarg == 'l') |
1415 |
|
|
sortmode = S_VARIABLE; |
1416 |
|
|
else if (*optarg == 'c') |
1417 |
|
|
sortmode = S_TERMCAP; |
1418 |
|
|
else { |
1419 |
|
|
(void) fprintf(stderr, |
1420 |
|
|
"%s: unknown sort mode\n", |
1421 |
|
|
_nc_progname); |
1422 |
|
|
ExitProgram(EXIT_FAILURE); |
1423 |
|
|
} |
1424 |
|
|
break; |
1425 |
|
|
|
1426 |
|
|
case 'T': |
1427 |
|
|
limited = FALSE; |
1428 |
|
|
break; |
1429 |
|
|
|
1430 |
|
|
#if NCURSES_XNAMES |
1431 |
|
|
case 't': |
1432 |
|
|
_nc_disable_period = FALSE; |
1433 |
|
|
suppress_untranslatable = TRUE; |
1434 |
|
|
break; |
1435 |
|
|
#endif |
1436 |
|
|
|
1437 |
|
|
case 'U': |
1438 |
|
|
literal = TRUE; |
1439 |
|
|
break; |
1440 |
|
|
|
1441 |
|
|
case 'u': |
1442 |
|
|
compare = C_USEALL; |
1443 |
|
|
break; |
1444 |
|
|
|
1445 |
|
|
case 'V': |
1446 |
|
|
puts(curses_version()); |
1447 |
|
|
ExitProgram(EXIT_SUCCESS); |
1448 |
|
|
|
1449 |
|
|
case 'v': |
1450 |
|
|
itrace = optarg_to_number(); |
1451 |
|
|
set_trace_level(itrace); |
1452 |
|
|
break; |
1453 |
|
|
|
1454 |
|
|
case 'w': |
1455 |
|
|
mwidth = optarg_to_number(); |
1456 |
|
|
break; |
1457 |
|
|
|
1458 |
|
|
#if NCURSES_XNAMES |
1459 |
|
|
case 'x': |
1460 |
|
|
use_extended_names(TRUE); |
1461 |
|
|
break; |
1462 |
|
|
#endif |
1463 |
|
|
|
1464 |
|
|
default: |
1465 |
|
|
usage(); |
1466 |
|
|
} |
1467 |
|
|
} |
1468 |
|
|
|
1469 |
|
|
maxterms = (argc + 2 - optind); |
1470 |
|
|
tfile = typeMalloc(path, maxterms); |
1471 |
|
|
tname = typeCalloc(char *, maxterms); |
1472 |
|
|
entries = typeCalloc(ENTRY, maxterms); |
1473 |
|
|
|
1474 |
|
|
if (tfile == 0 |
1475 |
|
|
|| tname == 0 |
1476 |
|
|
|| entries == 0) { |
1477 |
|
|
fprintf(stderr, "%s: not enough memory\n", _nc_progname); |
1478 |
|
|
ExitProgram(EXIT_FAILURE); |
1479 |
|
|
} |
1480 |
|
|
|
1481 |
|
|
/* by default, sort by terminfo name */ |
1482 |
|
|
if (sortmode == S_DEFAULT) |
1483 |
|
|
sortmode = S_TERMINFO; |
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_DEFAULT && 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_DEFAULT) |
1498 |
|
|
compare = C_DIFFERENCE; |
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_DATABASE |
1511 |
|
|
#if MIXEDCASE_FILENAMES |
1512 |
|
|
#define LEAF_FMT "%c" |
1513 |
|
|
#else |
1514 |
|
|
#define LEAF_FMT "%02x" |
1515 |
|
|
#endif |
1516 |
|
|
(void) snprintf(tfile[termcount], sizeof (path), |
1517 |
|
|
"%s/" LEAF_FMT "/%s", directory, |
1518 |
|
|
UChar(*argv[optind]), argv[optind]); |
1519 |
|
|
if (itrace) |
1520 |
|
|
(void) fprintf(stderr, |
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, "%s: terminfo files not supported\n", |
1529 |
|
|
_nc_progname); |
1530 |
|
|
ExitProgram(EXIT_FAILURE); |
1531 |
|
|
#endif |
1532 |
|
|
} else { |
1533 |
|
|
if (itrace) |
1534 |
|
|
(void) fprintf(stderr, |
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; /* for error message */ |
1543 |
|
|
} |
1544 |
|
|
|
1545 |
|
|
if (status <= 0) { |
1546 |
|
|
(void) fprintf(stderr, |
1547 |
|
|
"%s: couldn't open terminfo file %s.\n", |
1548 |
|
|
_nc_progname, |
1549 |
|
|
tfile[termcount]); |
1550 |
|
|
ExitProgram(EXIT_FAILURE); |
1551 |
|
|
} |
1552 |
|
|
repair_acsc(&entries[termcount].tterm); |
1553 |
|
|
termcount++; |
1554 |
|
|
} |
1555 |
|
|
|
1556 |
|
|
#if NCURSES_XNAMES |
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_1string, &entries[0].tterm); |
1574 |
|
|
analyze_string("is2", init_2string, &entries[0].tterm); |
1575 |
|
|
analyze_string("is3", init_3string, &entries[0].tterm); |
1576 |
|
|
analyze_string("rs1", reset_1string, &entries[0].tterm); |
1577 |
|
|
analyze_string("rs2", reset_2string, &entries[0].tterm); |
1578 |
|
|
analyze_string("rs3", reset_3string, &entries[0].tterm); |
1579 |
|
|
analyze_string("smcup", enter_ca_mode, &entries[0].tterm); |
1580 |
|
|
analyze_string("rmcup", exit_ca_mode, &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_DEFAULT: |
1589 |
|
|
if (itrace) |
1590 |
|
|
(void) fprintf(stderr, |
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); |
1601 |
|
|
len = show_entry(); |
1602 |
|
|
if (itrace) |
1603 |
|
|
(void) fprintf(stderr, "%s: length %d\n", _nc_progname, len); |
1604 |
|
|
break; |
1605 |
|
|
|
1606 |
|
|
case C_DIFFERENCE: |
1607 |
|
|
if (itrace) |
1608 |
|
|
(void) fprintf(stderr, "%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_COMMON: |
1614 |
|
|
if (itrace) |
1615 |
|
|
(void) fprintf(stderr, |
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_NAND: |
1623 |
|
|
if (itrace) |
1624 |
|
|
(void) fprintf(stderr, |
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_USEALL: |
1632 |
|
|
if (itrace) |
1633 |
|
|
(void) fprintf(stderr, "%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_TERMCAP |
1641 |
|
|
|| outform == F_TCONVERR)); |
1642 |
|
|
len = show_entry(); |
1643 |
|
|
if (itrace) |
1644 |
|
|
(void) fprintf(stderr, "%s: length %d\n", _nc_progname, len); |
1645 |
|
|
break; |
1646 |
|
|
} |
1647 |
|
|
} |
1648 |
|
|
} else if (compare == C_USEALL) |
1649 |
|
|
(void) fprintf(stderr, "Sorry, -u doesn't work with -F\n"); |
1650 |
|
|
else if (compare == C_DEFAULT) |
1651 |
|
|
(void) fprintf(stderr, "Use `tic -[CI] <file>' for this.\n"); |
1652 |
|
|
else if (argc - optind != 2) |
1653 |
|
|
(void) fprintf(stderr, |
1654 |
|
|
"File comparison needs exactly two file arguments.\n"); |
1655 |
|
|
else |
1656 |
|
|
file_comparison(argc - optind, argv + optind); |
1657 |
|
|
|
1658 |
|
|
#if NO_LEAKS |
1659 |
|
|
free(myargv); |
1660 |
|
|
free(tfile); |
1661 |
|
|
free(tname); |
1662 |
|
|
#endif |
1663 |
|
|
ExitProgram(EXIT_SUCCESS); |
1664 |
|
|
} |
1665 |
|
|
|
1666 |
|
|
/* infocmp.c ends here */ |