tic.c 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522
  1. /****************************************************************************
  2. * Copyright (c) 1998-2007,2008 Free Software Foundation, Inc. *
  3. * *
  4. * Permission is hereby granted, free of charge, to any person obtaining a *
  5. * copy of this software and associated documentation files (the *
  6. * "Software"), to deal in the Software without restriction, including *
  7. * without limitation the rights to use, copy, modify, merge, publish, *
  8. * distribute, distribute with modifications, sublicense, and/or sell *
  9. * copies of the Software, and to permit persons to whom the Software is *
  10. * furnished to do so, subject to the following conditions: *
  11. * *
  12. * The above copyright notice and this permission notice shall be included *
  13. * in all copies or substantial portions of the Software. *
  14. * *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
  16. * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
  17. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
  18. * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
  19. * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
  20. * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
  21. * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
  22. * *
  23. * Except as contained in this notice, the name(s) of the above copyright *
  24. * holders shall not be used in advertising or otherwise to promote the *
  25. * sale, use or other dealings in this Software without prior written *
  26. * authorization. *
  27. ****************************************************************************/
  28. /****************************************************************************
  29. * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 *
  30. * and: Eric S. Raymond <esr@snark.thyrsus.com> *
  31. * and: Thomas E. Dickey 1996 on *
  32. ****************************************************************************/
  33. /*
  34. * tic.c --- Main program for terminfo compiler
  35. * by Eric S. Raymond
  36. *
  37. */
  38. #include <progs.priv.h>
  39. #include <sys/stat.h>
  40. #include <dump_entry.h>
  41. #include <transform.h>
  42. MODULE_ID("$Id: tic.c,v 1.137 2008/09/13 16:59:24 tom Exp $")
  43. const char *_nc_progname = "tic";
  44. static FILE *log_fp;
  45. static FILE *tmp_fp;
  46. static bool capdump = FALSE; /* running as infotocap? */
  47. static bool infodump = FALSE; /* running as captoinfo? */
  48. static bool showsummary = FALSE;
  49. static const char *to_remove;
  50. static void (*save_check_termtype) (TERMTYPE *, bool);
  51. static void check_termtype(TERMTYPE *tt, bool);
  52. static const char usage_string[] = "\
  53. [-e names] \
  54. [-o dir] \
  55. [-R name] \
  56. [-v[n]] \
  57. [-V] \
  58. [-w[n]] \
  59. [-\
  60. 1\
  61. a\
  62. C\
  63. c\
  64. f\
  65. G\
  66. g\
  67. I\
  68. L\
  69. N\
  70. r\
  71. s\
  72. T\
  73. t\
  74. U\
  75. x\
  76. ] \
  77. source-file\n";
  78. #if NO_LEAKS
  79. static void
  80. free_namelist(char **src)
  81. {
  82. if (src != 0) {
  83. int n;
  84. for (n = 0; src[n] != 0; ++n)
  85. free(src[n]);
  86. free(src);
  87. }
  88. }
  89. #endif
  90. static void
  91. cleanup(char **namelst GCC_UNUSED)
  92. {
  93. #if NO_LEAKS
  94. free_namelist(namelst);
  95. #endif
  96. if (tmp_fp != 0)
  97. fclose(tmp_fp);
  98. if (to_remove != 0) {
  99. #if HAVE_REMOVE
  100. remove(to_remove);
  101. #else
  102. unlink(to_remove);
  103. #endif
  104. }
  105. }
  106. static void
  107. failed(const char *msg)
  108. {
  109. perror(msg);
  110. cleanup((char **) 0);
  111. ExitProgram(EXIT_FAILURE);
  112. }
  113. static void
  114. usage(void)
  115. {
  116. static const char *const tbl[] =
  117. {
  118. "Options:",
  119. " -1 format translation output one capability per line",
  120. #if NCURSES_XNAMES
  121. " -a retain commented-out capabilities (sets -x also)",
  122. #endif
  123. " -C translate entries to termcap source form",
  124. " -c check only, validate input without compiling or translating",
  125. " -e<names> translate/compile only entries named by comma-separated list",
  126. " -f format complex strings for readability",
  127. " -G format %{number} to %'char'",
  128. " -g format %'char' to %{number}",
  129. " -I translate entries to terminfo source form",
  130. " -L translate entries to full terminfo source form",
  131. " -N disable smart defaults for source translation",
  132. " -o<dir> set output directory for compiled entry writes",
  133. " -R<name> restrict translation to given terminfo/termcap version",
  134. " -r force resolution of all use entries in source translation",
  135. " -s print summary statistics",
  136. " -T remove size-restrictions on compiled description",
  137. #if NCURSES_XNAMES
  138. " -t suppress commented-out capabilities",
  139. #endif
  140. " -U suppress post-processing of entries",
  141. " -V print version",
  142. " -v[n] set verbosity level",
  143. " -w[n] set format width for translation output",
  144. #if NCURSES_XNAMES
  145. " -x treat unknown capabilities as user-defined",
  146. #endif
  147. "",
  148. "Parameters:",
  149. " <file> file to translate or compile"
  150. };
  151. size_t j;
  152. fprintf(stderr, "Usage: %s %s\n", _nc_progname, usage_string);
  153. for (j = 0; j < SIZEOF(tbl); j++) {
  154. fputs(tbl[j], stderr);
  155. putc('\n', stderr);
  156. }
  157. ExitProgram(EXIT_FAILURE);
  158. }
  159. #define L_BRACE '{'
  160. #define R_BRACE '}'
  161. #define S_QUOTE '\'';
  162. static void
  163. write_it(ENTRY * ep)
  164. {
  165. unsigned n;
  166. int ch;
  167. char *s, *d, *t;
  168. char result[MAX_ENTRY_SIZE];
  169. /*
  170. * Look for strings that contain %{number}, convert them to %'char',
  171. * which is shorter and runs a little faster.
  172. */
  173. for (n = 0; n < STRCOUNT; n++) {
  174. s = ep->tterm.Strings[n];
  175. if (VALID_STRING(s)
  176. && strchr(s, L_BRACE) != 0) {
  177. d = result;
  178. t = s;
  179. while ((ch = *t++) != 0) {
  180. *d++ = (char) ch;
  181. if (ch == '\\') {
  182. *d++ = *t++;
  183. } else if ((ch == '%')
  184. && (*t == L_BRACE)) {
  185. char *v = 0;
  186. long value = strtol(t + 1, &v, 0);
  187. if (v != 0
  188. && *v == R_BRACE
  189. && value > 0
  190. && value != '\\' /* FIXME */
  191. && value < 127
  192. && isprint((int) value)) {
  193. *d++ = S_QUOTE;
  194. *d++ = (char) value;
  195. *d++ = S_QUOTE;
  196. t = (v + 1);
  197. }
  198. }
  199. }
  200. *d = 0;
  201. if (strlen(result) < strlen(s))
  202. strcpy(s, result);
  203. }
  204. }
  205. _nc_set_type(_nc_first_name(ep->tterm.term_names));
  206. _nc_curr_line = ep->startline;
  207. _nc_write_entry(&ep->tterm);
  208. }
  209. static bool
  210. immedhook(ENTRY * ep GCC_UNUSED)
  211. /* write out entries with no use capabilities immediately to save storage */
  212. {
  213. #if !HAVE_BIG_CORE
  214. /*
  215. * This is strictly a core-economy kluge. The really clean way to handle
  216. * compilation is to slurp the whole file into core and then do all the
  217. * name-collision checks and entry writes in one swell foop. But the
  218. * terminfo master file is large enough that some core-poor systems swap
  219. * like crazy when you compile it this way...there have been reports of
  220. * this process taking *three hours*, rather than the twenty seconds or
  221. * less typical on my development box.
  222. *
  223. * So. This hook *immediately* writes out the referenced entry if it
  224. * has no use capabilities. The compiler main loop refrains from
  225. * adding the entry to the in-core list when this hook fires. If some
  226. * other entry later needs to reference an entry that got written
  227. * immediately, that's OK; the resolution code will fetch it off disk
  228. * when it can't find it in core.
  229. *
  230. * Name collisions will still be detected, just not as cleanly. The
  231. * write_entry() code complains before overwriting an entry that
  232. * postdates the time of tic's first call to write_entry(). Thus
  233. * it will complain about overwriting entries newly made during the
  234. * tic run, but not about overwriting ones that predate it.
  235. *
  236. * The reason this is a hook, and not in line with the rest of the
  237. * compiler code, is that the support for termcap fallback cannot assume
  238. * it has anywhere to spool out these entries!
  239. *
  240. * The _nc_set_type() call here requires a compensating one in
  241. * _nc_parse_entry().
  242. *
  243. * If you define HAVE_BIG_CORE, you'll disable this kluge. This will
  244. * make tic a bit faster (because the resolution code won't have to do
  245. * disk I/O nearly as often).
  246. */
  247. if (ep->nuses == 0) {
  248. int oldline = _nc_curr_line;
  249. write_it(ep);
  250. _nc_curr_line = oldline;
  251. free(ep->tterm.str_table);
  252. return (TRUE);
  253. }
  254. #endif /* HAVE_BIG_CORE */
  255. return (FALSE);
  256. }
  257. static void
  258. put_translate(int c)
  259. /* emit a comment char, translating terminfo names to termcap names */
  260. {
  261. static bool in_name = FALSE;
  262. static size_t have, used;
  263. static char *namebuf, *suffix;
  264. if (in_name) {
  265. if (used + 1 >= have) {
  266. have += 132;
  267. namebuf = typeRealloc(char, have, namebuf);
  268. suffix = typeRealloc(char, have, suffix);
  269. }
  270. if (c == '\n' || c == '@') {
  271. namebuf[used++] = '\0';
  272. (void) putchar('<');
  273. (void) fputs(namebuf, stdout);
  274. putchar(c);
  275. in_name = FALSE;
  276. } else if (c != '>') {
  277. namebuf[used++] = (char) c;
  278. } else { /* ah! candidate name! */
  279. char *up;
  280. NCURSES_CONST char *tp;
  281. namebuf[used++] = '\0';
  282. in_name = FALSE;
  283. suffix[0] = '\0';
  284. if ((up = strchr(namebuf, '#')) != 0
  285. || (up = strchr(namebuf, '=')) != 0
  286. || ((up = strchr(namebuf, '@')) != 0 && up[1] == '>')) {
  287. (void) strcpy(suffix, up);
  288. *up = '\0';
  289. }
  290. if ((tp = nametrans(namebuf)) != 0) {
  291. (void) putchar(':');
  292. (void) fputs(tp, stdout);
  293. (void) fputs(suffix, stdout);
  294. (void) putchar(':');
  295. } else {
  296. /* couldn't find a translation, just dump the name */
  297. (void) putchar('<');
  298. (void) fputs(namebuf, stdout);
  299. (void) fputs(suffix, stdout);
  300. (void) putchar('>');
  301. }
  302. }
  303. } else {
  304. used = 0;
  305. if (c == '<') {
  306. in_name = TRUE;
  307. } else {
  308. putchar(c);
  309. }
  310. }
  311. }
  312. /* Returns a string, stripped of leading/trailing whitespace */
  313. static char *
  314. stripped(char *src)
  315. {
  316. while (isspace(UChar(*src)))
  317. src++;
  318. if (*src != '\0') {
  319. char *dst = strcpy((char *) malloc(strlen(src) + 1), src);
  320. size_t len = strlen(dst);
  321. while (--len != 0 && isspace(UChar(dst[len])))
  322. dst[len] = '\0';
  323. return dst;
  324. }
  325. return 0;
  326. }
  327. static FILE *
  328. open_input(const char *filename)
  329. {
  330. FILE *fp = fopen(filename, "r");
  331. struct stat sb;
  332. if (fp == 0) {
  333. fprintf(stderr, "%s: Can't open %s\n", _nc_progname, filename);
  334. ExitProgram(EXIT_FAILURE);
  335. }
  336. if (fstat(fileno(fp), &sb) < 0
  337. || (sb.st_mode & S_IFMT) != S_IFREG) {
  338. fprintf(stderr, "%s: %s is not a file\n", _nc_progname, filename);
  339. ExitProgram(EXIT_FAILURE);
  340. }
  341. return fp;
  342. }
  343. /* Parse the "-e" option-value into a list of names */
  344. static char **
  345. make_namelist(char *src)
  346. {
  347. char **dst = 0;
  348. char *s, *base;
  349. unsigned pass, n, nn;
  350. char buffer[BUFSIZ];
  351. if (src == 0) {
  352. /* EMPTY */ ;
  353. } else if (strchr(src, '/') != 0) { /* a filename */
  354. FILE *fp = open_input(src);
  355. for (pass = 1; pass <= 2; pass++) {
  356. nn = 0;
  357. while (fgets(buffer, sizeof(buffer), fp) != 0) {
  358. if ((s = stripped(buffer)) != 0) {
  359. if (dst != 0)
  360. dst[nn] = s;
  361. else
  362. free(s);
  363. nn++;
  364. }
  365. }
  366. if (pass == 1) {
  367. dst = typeCalloc(char *, nn + 1);
  368. rewind(fp);
  369. }
  370. }
  371. fclose(fp);
  372. } else { /* literal list of names */
  373. for (pass = 1; pass <= 2; pass++) {
  374. for (n = nn = 0, base = src;; n++) {
  375. int mark = src[n];
  376. if (mark == ',' || mark == '\0') {
  377. if (pass == 1) {
  378. nn++;
  379. } else {
  380. src[n] = '\0';
  381. if ((s = stripped(base)) != 0)
  382. dst[nn++] = s;
  383. base = &src[n + 1];
  384. }
  385. }
  386. if (mark == '\0')
  387. break;
  388. }
  389. if (pass == 1)
  390. dst = typeCalloc(char *, nn + 1);
  391. }
  392. }
  393. if (showsummary && (dst != 0)) {
  394. fprintf(log_fp, "Entries that will be compiled:\n");
  395. for (n = 0; dst[n] != 0; n++)
  396. fprintf(log_fp, "%u:%s\n", n + 1, dst[n]);
  397. }
  398. return dst;
  399. }
  400. static bool
  401. matches(char **needle, const char *haystack)
  402. /* does entry in needle list match |-separated field in haystack? */
  403. {
  404. bool code = FALSE;
  405. size_t n;
  406. if (needle != 0) {
  407. for (n = 0; needle[n] != 0; n++) {
  408. if (_nc_name_match(haystack, needle[n], "|")) {
  409. code = TRUE;
  410. break;
  411. }
  412. }
  413. } else
  414. code = TRUE;
  415. return (code);
  416. }
  417. static FILE *
  418. open_tempfile(char *name)
  419. {
  420. FILE *result = 0;
  421. #if HAVE_MKSTEMP
  422. int fd = mkstemp(name);
  423. if (fd >= 0)
  424. result = fdopen(fd, "w");
  425. #else
  426. if (tmpnam(name) != 0)
  427. result = fopen(name, "w");
  428. #endif
  429. return result;
  430. }
  431. int
  432. main(int argc, char *argv[])
  433. {
  434. char my_tmpname[PATH_MAX];
  435. int v_opt = -1, debug_level;
  436. int smart_defaults = TRUE;
  437. char *termcap;
  438. ENTRY *qp;
  439. int this_opt, last_opt = '?';
  440. int outform = F_TERMINFO; /* output format */
  441. int sortmode = S_TERMINFO; /* sort_mode */
  442. int width = 60;
  443. bool formatted = FALSE; /* reformat complex strings? */
  444. bool literal = FALSE; /* suppress post-processing? */
  445. int numbers = 0; /* format "%'char'" to/from "%{number}" */
  446. bool forceresolve = FALSE; /* force resolution */
  447. bool limited = TRUE;
  448. char *tversion = (char *) NULL;
  449. const char *source_file = "terminfo";
  450. char **namelst = 0;
  451. char *outdir = (char *) NULL;
  452. bool check_only = FALSE;
  453. bool suppress_untranslatable = FALSE;
  454. log_fp = stderr;
  455. _nc_progname = _nc_rootname(argv[0]);
  456. if ((infodump = (strcmp(_nc_progname, PROG_CAPTOINFO) == 0)) != FALSE) {
  457. outform = F_TERMINFO;
  458. sortmode = S_TERMINFO;
  459. }
  460. if ((capdump = (strcmp(_nc_progname, PROG_INFOTOCAP) == 0)) != FALSE) {
  461. outform = F_TERMCAP;
  462. sortmode = S_TERMCAP;
  463. }
  464. #if NCURSES_XNAMES
  465. use_extended_names(FALSE);
  466. #endif
  467. /*
  468. * Processing arguments is a little complicated, since someone made a
  469. * design decision to allow the numeric values for -w, -v options to
  470. * be optional.
  471. */
  472. while ((this_opt = getopt(argc, argv,
  473. "0123456789CILNR:TUVace:fGgo:rstvwx")) != -1) {
  474. if (isdigit(this_opt)) {
  475. switch (last_opt) {
  476. case 'v':
  477. v_opt = (v_opt * 10) + (this_opt - '0');
  478. break;
  479. case 'w':
  480. width = (width * 10) + (this_opt - '0');
  481. break;
  482. default:
  483. if (this_opt != '1')
  484. usage();
  485. last_opt = this_opt;
  486. width = 0;
  487. }
  488. continue;
  489. }
  490. switch (this_opt) {
  491. case 'C':
  492. capdump = TRUE;
  493. outform = F_TERMCAP;
  494. sortmode = S_TERMCAP;
  495. break;
  496. case 'I':
  497. infodump = TRUE;
  498. outform = F_TERMINFO;
  499. sortmode = S_TERMINFO;
  500. break;
  501. case 'L':
  502. infodump = TRUE;
  503. outform = F_VARIABLE;
  504. sortmode = S_VARIABLE;
  505. break;
  506. case 'N':
  507. smart_defaults = FALSE;
  508. literal = TRUE;
  509. break;
  510. case 'R':
  511. tversion = optarg;
  512. break;
  513. case 'T':
  514. limited = FALSE;
  515. break;
  516. case 'U':
  517. literal = TRUE;
  518. break;
  519. case 'V':
  520. puts(curses_version());
  521. cleanup(namelst);
  522. ExitProgram(EXIT_SUCCESS);
  523. case 'c':
  524. check_only = TRUE;
  525. break;
  526. case 'e':
  527. namelst = make_namelist(optarg);
  528. break;
  529. case 'f':
  530. formatted = TRUE;
  531. break;
  532. case 'G':
  533. numbers = 1;
  534. break;
  535. case 'g':
  536. numbers = -1;
  537. break;
  538. case 'o':
  539. outdir = optarg;
  540. break;
  541. case 'r':
  542. forceresolve = TRUE;
  543. break;
  544. case 's':
  545. showsummary = TRUE;
  546. break;
  547. case 'v':
  548. v_opt = 0;
  549. break;
  550. case 'w':
  551. width = 0;
  552. break;
  553. #if NCURSES_XNAMES
  554. case 't':
  555. _nc_disable_period = FALSE;
  556. suppress_untranslatable = TRUE;
  557. break;
  558. case 'a':
  559. _nc_disable_period = TRUE;
  560. /* FALLTHRU */
  561. case 'x':
  562. use_extended_names(TRUE);
  563. break;
  564. #endif
  565. default:
  566. usage();
  567. }
  568. last_opt = this_opt;
  569. }
  570. debug_level = (v_opt > 0) ? v_opt : (v_opt == 0);
  571. set_trace_level(debug_level);
  572. if (_nc_tracing) {
  573. save_check_termtype = _nc_check_termtype2;
  574. _nc_check_termtype2 = check_termtype;
  575. }
  576. #if !HAVE_BIG_CORE
  577. /*
  578. * Aaargh! immedhook seriously hoses us!
  579. *
  580. * One problem with immedhook is it means we can't do -e. Problem
  581. * is that we can't guarantee that for each terminal listed, all the
  582. * terminals it depends on will have been kept in core for reference
  583. * resolution -- in fact it's certain the primitive types at the end
  584. * of reference chains *won't* be in core unless they were explicitly
  585. * in the select list themselves.
  586. */
  587. if (namelst && (!infodump && !capdump)) {
  588. (void) fprintf(stderr,
  589. "Sorry, -e can't be used without -I or -C\n");
  590. cleanup(namelst);
  591. ExitProgram(EXIT_FAILURE);
  592. }
  593. #endif /* HAVE_BIG_CORE */
  594. if (optind < argc) {
  595. source_file = argv[optind++];
  596. if (optind < argc) {
  597. fprintf(stderr,
  598. "%s: Too many file names. Usage:\n\t%s %s",
  599. _nc_progname,
  600. _nc_progname,
  601. usage_string);
  602. ExitProgram(EXIT_FAILURE);
  603. }
  604. } else {
  605. if (infodump == TRUE) {
  606. /* captoinfo's no-argument case */
  607. source_file = "/etc/termcap";
  608. if ((termcap = getenv("TERMCAP")) != 0
  609. && (namelst = make_namelist(getenv("TERM"))) != 0) {
  610. if (access(termcap, F_OK) == 0) {
  611. /* file exists */
  612. source_file = termcap;
  613. } else if ((tmp_fp = open_tempfile(strcpy(my_tmpname,
  614. "/tmp/XXXXXX")))
  615. != 0) {
  616. source_file = my_tmpname;
  617. fprintf(tmp_fp, "%s\n", termcap);
  618. fclose(tmp_fp);
  619. tmp_fp = open_input(source_file);
  620. to_remove = source_file;
  621. } else {
  622. failed("tmpnam");
  623. }
  624. }
  625. } else {
  626. /* tic */
  627. fprintf(stderr,
  628. "%s: File name needed. Usage:\n\t%s %s",
  629. _nc_progname,
  630. _nc_progname,
  631. usage_string);
  632. cleanup(namelst);
  633. ExitProgram(EXIT_FAILURE);
  634. }
  635. }
  636. if (tmp_fp == 0)
  637. tmp_fp = open_input(source_file);
  638. if (infodump)
  639. dump_init(tversion,
  640. smart_defaults
  641. ? outform
  642. : F_LITERAL,
  643. sortmode, width, debug_level, formatted);
  644. else if (capdump)
  645. dump_init(tversion,
  646. outform,
  647. sortmode, width, debug_level, FALSE);
  648. /* parse entries out of the source file */
  649. _nc_set_source(source_file);
  650. #if !HAVE_BIG_CORE
  651. if (!(check_only || infodump || capdump))
  652. _nc_set_writedir(outdir);
  653. #endif /* HAVE_BIG_CORE */
  654. _nc_read_entry_source(tmp_fp, (char *) NULL,
  655. !smart_defaults || literal, FALSE,
  656. ((check_only || infodump || capdump)
  657. ? NULLHOOK
  658. : immedhook));
  659. /* do use resolution */
  660. if (check_only || (!infodump && !capdump) || forceresolve) {
  661. if (!_nc_resolve_uses2(TRUE, literal) && !check_only) {
  662. cleanup(namelst);
  663. ExitProgram(EXIT_FAILURE);
  664. }
  665. }
  666. /* length check */
  667. if (check_only && (capdump || infodump)) {
  668. for_entry_list(qp) {
  669. if (matches(namelst, qp->tterm.term_names)) {
  670. int len = fmt_entry(&qp->tterm, NULL, FALSE, TRUE, infodump, numbers);
  671. if (len > (infodump ? MAX_TERMINFO_LENGTH : MAX_TERMCAP_LENGTH))
  672. (void) fprintf(stderr,
  673. "warning: resolved %s entry is %d bytes long\n",
  674. _nc_first_name(qp->tterm.term_names),
  675. len);
  676. }
  677. }
  678. }
  679. /* write or dump all entries */
  680. if (!check_only) {
  681. if (!infodump && !capdump) {
  682. _nc_set_writedir(outdir);
  683. for_entry_list(qp) {
  684. if (matches(namelst, qp->tterm.term_names))
  685. write_it(qp);
  686. }
  687. } else {
  688. /* this is in case infotocap() generates warnings */
  689. _nc_curr_col = _nc_curr_line = -1;
  690. for_entry_list(qp) {
  691. if (matches(namelst, qp->tterm.term_names)) {
  692. int j = qp->cend - qp->cstart;
  693. int len = 0;
  694. /* this is in case infotocap() generates warnings */
  695. _nc_set_type(_nc_first_name(qp->tterm.term_names));
  696. (void) fseek(tmp_fp, qp->cstart, SEEK_SET);
  697. while (j-- > 0) {
  698. if (infodump)
  699. (void) putchar(fgetc(tmp_fp));
  700. else
  701. put_translate(fgetc(tmp_fp));
  702. }
  703. dump_entry(&qp->tterm, suppress_untranslatable,
  704. limited, numbers, NULL);
  705. for (j = 0; j < (int) qp->nuses; j++)
  706. dump_uses(qp->uses[j].name, !capdump);
  707. len = show_entry();
  708. if (debug_level != 0 && !limited)
  709. printf("# length=%d\n", len);
  710. }
  711. }
  712. if (!namelst && _nc_tail) {
  713. int c, oldc = '\0';
  714. bool in_comment = FALSE;
  715. bool trailing_comment = FALSE;
  716. (void) fseek(tmp_fp, _nc_tail->cend, SEEK_SET);
  717. while ((c = fgetc(tmp_fp)) != EOF) {
  718. if (oldc == '\n') {
  719. if (c == '#') {
  720. trailing_comment = TRUE;
  721. in_comment = TRUE;
  722. } else {
  723. in_comment = FALSE;
  724. }
  725. }
  726. if (trailing_comment
  727. && (in_comment || (oldc == '\n' && c == '\n')))
  728. putchar(c);
  729. oldc = c;
  730. }
  731. }
  732. }
  733. }
  734. /* Show the directory into which entries were written, and the total
  735. * number of entries
  736. */
  737. if (showsummary
  738. && (!(check_only || infodump || capdump))) {
  739. int total = _nc_tic_written();
  740. if (total != 0)
  741. fprintf(log_fp, "%d entries written to %s\n",
  742. total,
  743. _nc_tic_dir((char *) 0));
  744. else
  745. fprintf(log_fp, "No entries written\n");
  746. }
  747. cleanup(namelst);
  748. ExitProgram(EXIT_SUCCESS);
  749. }
  750. /*
  751. * This bit of legerdemain turns all the terminfo variable names into
  752. * references to locations in the arrays Booleans, Numbers, and Strings ---
  753. * precisely what's needed (see comp_parse.c).
  754. */
  755. #undef CUR
  756. #define CUR tp->
  757. /*
  758. * Check if the alternate character-set capabilities are consistent.
  759. */
  760. static void
  761. check_acs(TERMTYPE *tp)
  762. {
  763. if (VALID_STRING(acs_chars)) {
  764. const char *boxes = "lmkjtuvwqxn";
  765. char mapped[256];
  766. char missing[256];
  767. const char *p;
  768. char *q;
  769. memset(mapped, 0, sizeof(mapped));
  770. for (p = acs_chars; *p != '\0'; p += 2) {
  771. if (p[1] == '\0') {
  772. _nc_warning("acsc has odd number of characters");
  773. break;
  774. }
  775. mapped[UChar(p[0])] = p[1];
  776. }
  777. if (mapped[UChar('I')] && !mapped[UChar('i')]) {
  778. _nc_warning("acsc refers to 'I', which is probably an error");
  779. }
  780. for (p = boxes, q = missing; *p != '\0'; ++p) {
  781. if (!mapped[UChar(p[0])]) {
  782. *q++ = p[0];
  783. }
  784. }
  785. *q = '\0';
  786. assert(strlen(missing) <= strlen(boxes));
  787. if (*missing != '\0' && strcmp(missing, boxes)) {
  788. _nc_warning("acsc is missing some line-drawing mapping: %s", missing);
  789. }
  790. }
  791. }
  792. /*
  793. * Check if the color capabilities are consistent
  794. */
  795. static void
  796. check_colors(TERMTYPE *tp)
  797. {
  798. if ((max_colors > 0) != (max_pairs > 0)
  799. || ((max_colors > max_pairs) && (initialize_pair == 0)))
  800. _nc_warning("inconsistent values for max_colors (%d) and max_pairs (%d)",
  801. max_colors, max_pairs);
  802. PAIRED(set_foreground, set_background);
  803. PAIRED(set_a_foreground, set_a_background);
  804. PAIRED(set_color_pair, initialize_pair);
  805. if (VALID_STRING(set_foreground)
  806. && VALID_STRING(set_a_foreground)
  807. && !_nc_capcmp(set_foreground, set_a_foreground))
  808. _nc_warning("expected setf/setaf to be different");
  809. if (VALID_STRING(set_background)
  810. && VALID_STRING(set_a_background)
  811. && !_nc_capcmp(set_background, set_a_background))
  812. _nc_warning("expected setb/setab to be different");
  813. /* see: has_colors() */
  814. if (VALID_NUMERIC(max_colors) && VALID_NUMERIC(max_pairs)
  815. && (((set_foreground != NULL)
  816. && (set_background != NULL))
  817. || ((set_a_foreground != NULL)
  818. && (set_a_background != NULL))
  819. || set_color_pair)) {
  820. if (!VALID_STRING(orig_pair) && !VALID_STRING(orig_colors))
  821. _nc_warning("expected either op/oc string for resetting colors");
  822. }
  823. }
  824. static char
  825. keypad_final(const char *string)
  826. {
  827. char result = '\0';
  828. if (VALID_STRING(string)
  829. && *string++ == '\033'
  830. && *string++ == 'O'
  831. && strlen(string) == 1) {
  832. result = *string;
  833. }
  834. return result;
  835. }
  836. static int
  837. keypad_index(const char *string)
  838. {
  839. char *test;
  840. const char *list = "PQRSwxymtuvlqrsPpn"; /* app-keypad except "Enter" */
  841. int ch;
  842. int result = -1;
  843. if ((ch = keypad_final(string)) != '\0') {
  844. test = strchr(list, ch);
  845. if (test != 0)
  846. result = (test - list);
  847. }
  848. return result;
  849. }
  850. #define MAX_KP 5
  851. /*
  852. * Do a quick sanity-check for vt100-style keypads to see if the 5-key keypad
  853. * is mapped inconsistently.
  854. */
  855. static void
  856. check_keypad(TERMTYPE *tp)
  857. {
  858. char show[80];
  859. if (VALID_STRING(key_a1) &&
  860. VALID_STRING(key_a3) &&
  861. VALID_STRING(key_b2) &&
  862. VALID_STRING(key_c1) &&
  863. VALID_STRING(key_c3)) {
  864. char final[MAX_KP + 1];
  865. int list[MAX_KP];
  866. int increase = 0;
  867. int j, k, kk;
  868. int last;
  869. int test;
  870. final[0] = keypad_final(key_a1);
  871. final[1] = keypad_final(key_a3);
  872. final[2] = keypad_final(key_b2);
  873. final[3] = keypad_final(key_c1);
  874. final[4] = keypad_final(key_c3);
  875. final[5] = '\0';
  876. /* special case: legacy coding using 1,2,3,0,. on the bottom */
  877. assert(strlen(final) <= MAX_KP);
  878. if (!strcmp(final, "qsrpn"))
  879. return;
  880. list[0] = keypad_index(key_a1);
  881. list[1] = keypad_index(key_a3);
  882. list[2] = keypad_index(key_b2);
  883. list[3] = keypad_index(key_c1);
  884. list[4] = keypad_index(key_c3);
  885. /* check that they're all vt100 keys */
  886. for (j = 0; j < MAX_KP; ++j) {
  887. if (list[j] < 0) {
  888. return;
  889. }
  890. }
  891. /* check if they're all in increasing order */
  892. for (j = 1; j < MAX_KP; ++j) {
  893. if (list[j] > list[j - 1]) {
  894. ++increase;
  895. }
  896. }
  897. if (increase != (MAX_KP - 1)) {
  898. show[0] = '\0';
  899. for (j = 0, last = -1; j < MAX_KP; ++j) {
  900. for (k = 0, kk = -1, test = 100; k < 5; ++k) {
  901. if (list[k] > last &&
  902. list[k] < test) {
  903. test = list[k];
  904. kk = k;
  905. }
  906. }
  907. last = test;
  908. assert(strlen(show) < (MAX_KP * 4));
  909. switch (kk) {
  910. case 0:
  911. strcat(show, " ka1");
  912. break;
  913. case 1:
  914. strcat(show, " ka3");
  915. break;
  916. case 2:
  917. strcat(show, " kb2");
  918. break;
  919. case 3:
  920. strcat(show, " kc1");
  921. break;
  922. case 4:
  923. strcat(show, " kc3");
  924. break;
  925. }
  926. }
  927. _nc_warning("vt100 keypad order inconsistent: %s", show);
  928. }
  929. } else if (VALID_STRING(key_a1) ||
  930. VALID_STRING(key_a3) ||
  931. VALID_STRING(key_b2) ||
  932. VALID_STRING(key_c1) ||
  933. VALID_STRING(key_c3)) {
  934. show[0] = '\0';
  935. if (keypad_index(key_a1) >= 0)
  936. strcat(show, " ka1");
  937. if (keypad_index(key_a3) >= 0)
  938. strcat(show, " ka3");
  939. if (keypad_index(key_b2) >= 0)
  940. strcat(show, " kb2");
  941. if (keypad_index(key_c1) >= 0)
  942. strcat(show, " kc1");
  943. if (keypad_index(key_c3) >= 0)
  944. strcat(show, " kc3");
  945. if (*show != '\0')
  946. _nc_warning("vt100 keypad map incomplete:%s", show);
  947. }
  948. }
  949. /*
  950. * Returns the expected number of parameters for the given capability.
  951. */
  952. static int
  953. expected_params(const char *name)
  954. {
  955. /* *INDENT-OFF* */
  956. static const struct {
  957. const char *name;
  958. int count;
  959. } table[] = {
  960. { "S0", 1 }, /* 'screen' extension */
  961. { "birep", 2 },
  962. { "chr", 1 },
  963. { "colornm", 1 },
  964. { "cpi", 1 },
  965. { "csnm", 1 },
  966. { "csr", 2 },
  967. { "cub", 1 },
  968. { "cud", 1 },
  969. { "cuf", 1 },
  970. { "cup", 2 },
  971. { "cuu", 1 },
  972. { "cvr", 1 },
  973. { "cwin", 5 },
  974. { "dch", 1 },
  975. { "defc", 3 },
  976. { "dial", 1 },
  977. { "dispc", 1 },
  978. { "dl", 1 },
  979. { "ech", 1 },
  980. { "getm", 1 },
  981. { "hpa", 1 },
  982. { "ich", 1 },
  983. { "il", 1 },
  984. { "indn", 1 },
  985. { "initc", 4 },
  986. { "initp", 7 },
  987. { "lpi", 1 },
  988. { "mc5p", 1 },
  989. { "mrcup", 2 },
  990. { "mvpa", 1 },
  991. { "pfkey", 2 },
  992. { "pfloc", 2 },
  993. { "pfx", 2 },
  994. { "pfxl", 3 },
  995. { "pln", 2 },
  996. { "qdial", 1 },
  997. { "rcsd", 1 },
  998. { "rep", 2 },
  999. { "rin", 1 },
  1000. { "sclk", 3 },
  1001. { "scp", 1 },
  1002. { "scs", 1 },
  1003. { "scsd", 2 },
  1004. { "setab", 1 },
  1005. { "setaf", 1 },
  1006. { "setb", 1 },
  1007. { "setcolor", 1 },
  1008. { "setf", 1 },
  1009. { "sgr", 9 },
  1010. { "sgr1", 6 },
  1011. { "slength", 1 },
  1012. { "slines", 1 },
  1013. { "smgbp", 1 }, /* 2 if smgtp is not given */
  1014. { "smglp", 1 },
  1015. { "smglr", 2 },
  1016. { "smgrp", 1 },
  1017. { "smgtb", 2 },
  1018. { "smgtp", 1 },
  1019. { "tsl", 1 },
  1020. { "u6", -1 },
  1021. { "vpa", 1 },
  1022. { "wind", 4 },
  1023. { "wingo", 1 },
  1024. };
  1025. /* *INDENT-ON* */
  1026. unsigned n;
  1027. int result = 0; /* function-keys, etc., use none */
  1028. for (n = 0; n < SIZEOF(table); n++) {
  1029. if (!strcmp(name, table[n].name)) {
  1030. result = table[n].count;
  1031. break;
  1032. }
  1033. }
  1034. return result;
  1035. }
  1036. /*
  1037. * Make a quick sanity check for the parameters which are used in the given
  1038. * strings. If there are no "%p" tokens, then there should be no other "%"
  1039. * markers.
  1040. */
  1041. static void
  1042. check_params(TERMTYPE *tp, const char *name, char *value)
  1043. {
  1044. int expected = expected_params(name);
  1045. int actual = 0;
  1046. int n;
  1047. bool params[10];
  1048. char *s = value;
  1049. #ifdef set_top_margin_parm
  1050. if (!strcmp(name, "smgbp")
  1051. && set_top_margin_parm == 0)
  1052. expected = 2;
  1053. #endif
  1054. for (n = 0; n < 10; n++)
  1055. params[n] = FALSE;
  1056. while (*s != 0) {
  1057. if (*s == '%') {
  1058. if (*++s == '\0') {
  1059. _nc_warning("expected character after %% in %s", name);
  1060. break;
  1061. } else if (*s == 'p') {
  1062. if (*++s == '\0' || !isdigit((int) *s)) {
  1063. _nc_warning("expected digit after %%p in %s", name);
  1064. return;
  1065. } else {
  1066. n = (*s - '0');
  1067. if (n > actual)
  1068. actual = n;
  1069. params[n] = TRUE;
  1070. }
  1071. }
  1072. }
  1073. s++;
  1074. }
  1075. if (params[0]) {
  1076. _nc_warning("%s refers to parameter 0 (%%p0), which is not allowed", name);
  1077. }
  1078. if (value == set_attributes || expected < 0) {
  1079. ;
  1080. } else if (expected != actual) {
  1081. _nc_warning("%s uses %d parameters, expected %d", name,
  1082. actual, expected);
  1083. for (n = 1; n < actual; n++) {
  1084. if (!params[n])
  1085. _nc_warning("%s omits parameter %d", name, n);
  1086. }
  1087. }
  1088. }
  1089. static char *
  1090. skip_delay(char *s)
  1091. {
  1092. while (*s == '/' || isdigit(UChar(*s)))
  1093. ++s;
  1094. return s;
  1095. }
  1096. /*
  1097. * Skip a delay altogether, e.g., when comparing a simple string to sgr,
  1098. * the latter may have a worst-case delay on the end.
  1099. */
  1100. static char *
  1101. ignore_delays(char *s)
  1102. {
  1103. int delaying = 0;
  1104. do {
  1105. switch (*s) {
  1106. case '$':
  1107. if (delaying == 0)
  1108. delaying = 1;
  1109. break;
  1110. case '<':
  1111. if (delaying == 1)
  1112. delaying = 2;
  1113. break;
  1114. case '\0':
  1115. delaying = 0;
  1116. break;
  1117. default:
  1118. if (delaying) {
  1119. s = skip_delay(s);
  1120. if (*s == '>')
  1121. ++s;
  1122. delaying = 0;
  1123. }
  1124. break;
  1125. }
  1126. if (delaying)
  1127. ++s;
  1128. } while (delaying);
  1129. return s;
  1130. }
  1131. /*
  1132. * An sgr string may contain several settings other than the one we're
  1133. * interested in, essentially sgr0 + rmacs + whatever. As long as the
  1134. * "whatever" is contained in the sgr string, that is close enough for our
  1135. * sanity check.
  1136. */
  1137. static bool
  1138. similar_sgr(int num, char *a, char *b)
  1139. {
  1140. static const char *names[] =
  1141. {
  1142. "none"
  1143. ,"standout"
  1144. ,"underline"
  1145. ,"reverse"
  1146. ,"blink"
  1147. ,"dim"
  1148. ,"bold"
  1149. ,"invis"
  1150. ,"protect"
  1151. ,"altcharset"
  1152. };
  1153. char *base_a = a;
  1154. char *base_b = b;
  1155. int delaying = 0;
  1156. while (*b != 0) {
  1157. while (*a != *b) {
  1158. if (*a == 0) {
  1159. if (b[0] == '$'
  1160. && b[1] == '<') {
  1161. _nc_warning("Did not find delay %s", _nc_visbuf(b));
  1162. } else {
  1163. _nc_warning("checking sgr(%s) %s\n\tcompare to %s\n\tunmatched %s",
  1164. names[num], _nc_visbuf2(1, base_a),
  1165. _nc_visbuf2(2, base_b),
  1166. _nc_visbuf2(3, b));
  1167. }
  1168. return FALSE;
  1169. } else if (delaying) {
  1170. a = skip_delay(a);
  1171. b = skip_delay(b);
  1172. } else {
  1173. a++;
  1174. }
  1175. }
  1176. switch (*a) {
  1177. case '$':
  1178. if (delaying == 0)
  1179. delaying = 1;
  1180. break;
  1181. case '<':
  1182. if (delaying == 1)
  1183. delaying = 2;
  1184. break;
  1185. default:
  1186. delaying = 0;
  1187. break;
  1188. }
  1189. a++;
  1190. b++;
  1191. }
  1192. /* ignore delays on the end of the string */
  1193. a = ignore_delays(a);
  1194. return ((num != 0) || (*a == 0));
  1195. }
  1196. static char *
  1197. check_sgr(TERMTYPE *tp, char *zero, int num, char *cap, const char *name)
  1198. {
  1199. char *test;
  1200. _nc_tparm_err = 0;
  1201. test = TPARM_9(set_attributes,
  1202. num == 1,
  1203. num == 2,
  1204. num == 3,
  1205. num == 4,
  1206. num == 5,
  1207. num == 6,
  1208. num == 7,
  1209. num == 8,
  1210. num == 9);
  1211. if (test != 0) {
  1212. if (PRESENT(cap)) {
  1213. if (!similar_sgr(num, test, cap)) {
  1214. _nc_warning("%s differs from sgr(%d)\n\t%s=%s\n\tsgr(%d)=%s",
  1215. name, num,
  1216. name, _nc_visbuf2(1, cap),
  1217. num, _nc_visbuf2(2, test));
  1218. }
  1219. } else if (_nc_capcmp(test, zero)) {
  1220. _nc_warning("sgr(%d) present, but not %s", num, name);
  1221. }
  1222. } else if (PRESENT(cap)) {
  1223. _nc_warning("sgr(%d) missing, but %s present", num, name);
  1224. }
  1225. if (_nc_tparm_err)
  1226. _nc_warning("stack error in sgr(%d) string", num);
  1227. return test;
  1228. }
  1229. #define CHECK_SGR(num,name) check_sgr(tp, zero, num, name, #name)
  1230. #ifdef TRACE
  1231. /*
  1232. * If tic is compiled with TRACE, we'll be able to see the output from the
  1233. * DEBUG() macro. But since it doesn't use traceon(), it always goes to
  1234. * the standard error. Use this function to make it simpler to follow the
  1235. * resulting debug traces.
  1236. */
  1237. static void
  1238. show_where(unsigned level)
  1239. {
  1240. if (_nc_tracing >= DEBUG_LEVEL(level)) {
  1241. char my_name[256];
  1242. _nc_get_type(my_name);
  1243. fprintf(stderr, "\"%s\", line %d, '%s' ",
  1244. _nc_get_source(),
  1245. _nc_curr_line, my_name);
  1246. }
  1247. }
  1248. #else
  1249. #define show_where(level) /* nothing */
  1250. #endif
  1251. /* other sanity-checks (things that we don't want in the normal
  1252. * logic that reads a terminfo entry)
  1253. */
  1254. static void
  1255. check_termtype(TERMTYPE *tp, bool literal)
  1256. {
  1257. bool conflict = FALSE;
  1258. unsigned j, k;
  1259. char fkeys[STRCOUNT];
  1260. /*
  1261. * A terminal entry may contain more than one keycode assigned to
  1262. * a given string (e.g., KEY_END and KEY_LL). But curses will only
  1263. * return one (the last one assigned).
  1264. */
  1265. if (!(_nc_syntax == SYN_TERMCAP && capdump)) {
  1266. memset(fkeys, 0, sizeof(fkeys));
  1267. for (j = 0; _nc_tinfo_fkeys[j].code; j++) {
  1268. char *a = tp->Strings[_nc_tinfo_fkeys[j].offset];
  1269. bool first = TRUE;
  1270. if (!VALID_STRING(a))
  1271. continue;
  1272. for (k = j + 1; _nc_tinfo_fkeys[k].code; k++) {
  1273. char *b = tp->Strings[_nc_tinfo_fkeys[k].offset];
  1274. if (!VALID_STRING(b)
  1275. || fkeys[k])
  1276. continue;
  1277. if (!_nc_capcmp(a, b)) {
  1278. fkeys[j] = 1;
  1279. fkeys[k] = 1;
  1280. if (first) {
  1281. if (!conflict) {
  1282. _nc_warning("Conflicting key definitions (using the last)");
  1283. conflict = TRUE;
  1284. }
  1285. fprintf(stderr, "... %s is the same as %s",
  1286. keyname((int) _nc_tinfo_fkeys[j].code),
  1287. keyname((int) _nc_tinfo_fkeys[k].code));
  1288. first = FALSE;
  1289. } else {
  1290. fprintf(stderr, ", %s",
  1291. keyname((int) _nc_tinfo_fkeys[k].code));
  1292. }
  1293. }
  1294. }
  1295. if (!first)
  1296. fprintf(stderr, "\n");
  1297. }
  1298. }
  1299. for (j = 0; j < NUM_STRINGS(tp); j++) {
  1300. char *a = tp->Strings[j];
  1301. if (VALID_STRING(a))
  1302. check_params(tp, ExtStrname(tp, j, strnames), a);
  1303. }
  1304. check_acs(tp);
  1305. check_colors(tp);
  1306. check_keypad(tp);
  1307. /*
  1308. * These may be mismatched because the terminal description relies on
  1309. * restoring the cursor visibility by resetting it.
  1310. */
  1311. ANDMISSING(cursor_invisible, cursor_normal);
  1312. ANDMISSING(cursor_visible, cursor_normal);
  1313. if (PRESENT(cursor_visible) && PRESENT(cursor_normal)
  1314. && !_nc_capcmp(cursor_visible, cursor_normal))
  1315. _nc_warning("cursor_visible is same as cursor_normal");
  1316. /*
  1317. * From XSI & O'Reilly, we gather that sc/rc are required if csr is
  1318. * given, because the cursor position after the scrolling operation is
  1319. * performed is undefined.
  1320. */
  1321. ANDMISSING(change_scroll_region, save_cursor);
  1322. ANDMISSING(change_scroll_region, restore_cursor);
  1323. if (PRESENT(set_attributes)) {
  1324. char *zero = 0;
  1325. _nc_tparm_err = 0;
  1326. if (PRESENT(exit_attribute_mode)) {
  1327. zero = strdup(CHECK_SGR(0, exit_attribute_mode));
  1328. } else {
  1329. zero = strdup(TPARM_9(set_attributes, 0, 0, 0, 0, 0, 0, 0, 0, 0));
  1330. }
  1331. if (_nc_tparm_err)
  1332. _nc_warning("stack error in sgr(0) string");
  1333. if (zero != 0) {
  1334. CHECK_SGR(1, enter_standout_mode);
  1335. CHECK_SGR(2, enter_underline_mode);
  1336. CHECK_SGR(3, enter_reverse_mode);
  1337. CHECK_SGR(4, enter_blink_mode);
  1338. CHECK_SGR(5, enter_dim_mode);
  1339. CHECK_SGR(6, enter_bold_mode);
  1340. CHECK_SGR(7, enter_secure_mode);
  1341. CHECK_SGR(8, enter_protected_mode);
  1342. CHECK_SGR(9, enter_alt_charset_mode);
  1343. free(zero);
  1344. } else {
  1345. _nc_warning("sgr(0) did not return a value");
  1346. }
  1347. } else if (PRESENT(exit_attribute_mode) &&
  1348. set_attributes != CANCELLED_STRING) {
  1349. if (_nc_syntax == SYN_TERMINFO)
  1350. _nc_warning("missing sgr string");
  1351. }
  1352. if (PRESENT(exit_attribute_mode)) {
  1353. char *check_sgr0 = _nc_trim_sgr0(tp);
  1354. if (check_sgr0 == 0 || *check_sgr0 == '\0') {
  1355. _nc_warning("trimmed sgr0 is empty");
  1356. } else {
  1357. show_where(2);
  1358. if (check_sgr0 != exit_attribute_mode) {
  1359. DEBUG(2,
  1360. ("will trim sgr0\n\toriginal sgr0=%s\n\ttrimmed sgr0=%s",
  1361. _nc_visbuf2(1, exit_attribute_mode),
  1362. _nc_visbuf2(2, check_sgr0)));
  1363. free(check_sgr0);
  1364. } else {
  1365. DEBUG(2,
  1366. ("will not trim sgr0\n\toriginal sgr0=%s",
  1367. _nc_visbuf(exit_attribute_mode)));
  1368. }
  1369. }
  1370. }
  1371. #ifdef TRACE
  1372. show_where(2);
  1373. if (!auto_right_margin) {
  1374. DEBUG(2,
  1375. ("can write to lower-right directly"));
  1376. } else if (PRESENT(enter_am_mode) && PRESENT(exit_am_mode)) {
  1377. DEBUG(2,
  1378. ("can write to lower-right by suppressing automargin"));
  1379. } else if ((PRESENT(enter_insert_mode) && PRESENT(exit_insert_mode))
  1380. || PRESENT(insert_character) || PRESENT(parm_ich)) {
  1381. DEBUG(2,
  1382. ("can write to lower-right by using inserts"));
  1383. } else {
  1384. DEBUG(2,
  1385. ("cannot write to lower-right"));
  1386. }
  1387. #endif
  1388. /*
  1389. * Some standard applications (e.g., vi) and some non-curses
  1390. * applications (e.g., jove) get confused if we have both ich1 and
  1391. * smir/rmir. Let's be nice and warn about that, too, even though
  1392. * ncurses handles it.
  1393. */
  1394. if ((PRESENT(enter_insert_mode) || PRESENT(exit_insert_mode))
  1395. && PRESENT(parm_ich)) {
  1396. _nc_warning("non-curses applications may be confused by ich1 with smir/rmir");
  1397. }
  1398. /*
  1399. * Finally, do the non-verbose checks
  1400. */
  1401. if (save_check_termtype != 0)
  1402. save_check_termtype(tp, literal);
  1403. }