dump_entry.c 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274
  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. #define __INTERNAL_CAPS_VISIBLE
  34. #include <progs.priv.h>
  35. #include "dump_entry.h"
  36. #include "termsort.c" /* this C file is generated */
  37. #include <parametrized.h> /* so is this */
  38. MODULE_ID("$Id: dump_entry.c,v 1.88 2008/08/04 12:36:12 tom Exp $")
  39. #define INDENT 8
  40. #define DISCARD(string) string = ABSENT_STRING
  41. #define PRINTF (void) printf
  42. #define OkIndex(index,array) ((int)(index) >= 0 && (int)(index) < (int) SIZEOF(array))
  43. typedef struct {
  44. char *text;
  45. size_t used;
  46. size_t size;
  47. } DYNBUF;
  48. static int tversion; /* terminfo version */
  49. static int outform; /* output format to use */
  50. static int sortmode; /* sort mode to use */
  51. static int width = 60; /* max line width for listings */
  52. static int column; /* current column, limited by 'width' */
  53. static int oldcol; /* last value of column before wrap */
  54. static bool pretty; /* true if we format if-then-else strings */
  55. static char *save_sgr;
  56. static DYNBUF outbuf;
  57. static DYNBUF tmpbuf;
  58. /* indirection pointers for implementing sort and display modes */
  59. static const PredIdx *bool_indirect, *num_indirect, *str_indirect;
  60. static NCURSES_CONST char *const *bool_names;
  61. static NCURSES_CONST char *const *num_names;
  62. static NCURSES_CONST char *const *str_names;
  63. static const char *separator, *trailer;
  64. /* cover various ports and variants of terminfo */
  65. #define V_ALLCAPS 0 /* all capabilities (SVr4, XSI, ncurses) */
  66. #define V_SVR1 1 /* SVR1, Ultrix */
  67. #define V_HPUX 2 /* HP/UX */
  68. #define V_AIX 3 /* AIX */
  69. #define V_BSD 4 /* BSD */
  70. #if NCURSES_XNAMES
  71. #define OBSOLETE(n) (!_nc_user_definable && (n[0] == 'O' && n[1] == 'T'))
  72. #else
  73. #define OBSOLETE(n) (n[0] == 'O' && n[1] == 'T')
  74. #endif
  75. #define isObsolete(f,n) ((f == F_TERMINFO || f == F_VARIABLE) && OBSOLETE(n))
  76. #if NCURSES_XNAMES
  77. #define BoolIndirect(j) ((j >= BOOLCOUNT) ? (j) : ((sortmode == S_NOSORT) ? j : bool_indirect[j]))
  78. #define NumIndirect(j) ((j >= NUMCOUNT) ? (j) : ((sortmode == S_NOSORT) ? j : num_indirect[j]))
  79. #define StrIndirect(j) ((j >= STRCOUNT) ? (j) : ((sortmode == S_NOSORT) ? j : str_indirect[j]))
  80. #else
  81. #define BoolIndirect(j) ((sortmode == S_NOSORT) ? (j) : bool_indirect[j])
  82. #define NumIndirect(j) ((sortmode == S_NOSORT) ? (j) : num_indirect[j])
  83. #define StrIndirect(j) ((sortmode == S_NOSORT) ? (j) : str_indirect[j])
  84. #endif
  85. static void
  86. strncpy_DYN(DYNBUF * dst, const char *src, size_t need)
  87. {
  88. size_t want = need + dst->used + 1;
  89. if (want > dst->size) {
  90. dst->size += (want + 1024); /* be generous */
  91. dst->text = typeRealloc(char, dst->size, dst->text);
  92. }
  93. (void) strncpy(dst->text + dst->used, src, need);
  94. dst->used += need;
  95. dst->text[dst->used] = 0;
  96. }
  97. static void
  98. strcpy_DYN(DYNBUF * dst, const char *src)
  99. {
  100. if (src == 0) {
  101. dst->used = 0;
  102. strcpy_DYN(dst, "");
  103. } else {
  104. strncpy_DYN(dst, src, strlen(src));
  105. }
  106. }
  107. #if NO_LEAKS
  108. static void
  109. free_DYN(DYNBUF * p)
  110. {
  111. if (p->text != 0)
  112. free(p->text);
  113. p->text = 0;
  114. p->size = 0;
  115. p->used = 0;
  116. }
  117. void
  118. _nc_leaks_dump_entry(void)
  119. {
  120. free_DYN(&outbuf);
  121. free_DYN(&tmpbuf);
  122. }
  123. #endif
  124. #define NameTrans(check,result) \
  125. if (OkIndex(np->nte_index, check) \
  126. && check[np->nte_index]) \
  127. return (result[np->nte_index])
  128. NCURSES_CONST char *
  129. nametrans(const char *name)
  130. /* translate a capability name from termcap to terminfo */
  131. {
  132. const struct name_table_entry *np;
  133. if ((np = _nc_find_entry(name, _nc_get_hash_table(0))) != 0)
  134. switch (np->nte_type) {
  135. case BOOLEAN:
  136. NameTrans(bool_from_termcap, boolcodes);
  137. break;
  138. case NUMBER:
  139. NameTrans(num_from_termcap, numcodes);
  140. break;
  141. case STRING:
  142. NameTrans(str_from_termcap, strcodes);
  143. break;
  144. }
  145. return (0);
  146. }
  147. void
  148. dump_init(const char *version, int mode, int sort, int twidth, int traceval,
  149. bool formatted)
  150. /* set up for entry display */
  151. {
  152. width = twidth;
  153. pretty = formatted;
  154. /* versions */
  155. if (version == 0)
  156. tversion = V_ALLCAPS;
  157. else if (!strcmp(version, "SVr1") || !strcmp(version, "SVR1")
  158. || !strcmp(version, "Ultrix"))
  159. tversion = V_SVR1;
  160. else if (!strcmp(version, "HP"))
  161. tversion = V_HPUX;
  162. else if (!strcmp(version, "AIX"))
  163. tversion = V_AIX;
  164. else if (!strcmp(version, "BSD"))
  165. tversion = V_BSD;
  166. else
  167. tversion = V_ALLCAPS;
  168. /* implement display modes */
  169. switch (outform = mode) {
  170. case F_LITERAL:
  171. case F_TERMINFO:
  172. bool_names = boolnames;
  173. num_names = numnames;
  174. str_names = strnames;
  175. separator = twidth ? ", " : ",";
  176. trailer = "\n\t";
  177. break;
  178. case F_VARIABLE:
  179. bool_names = boolfnames;
  180. num_names = numfnames;
  181. str_names = strfnames;
  182. separator = twidth ? ", " : ",";
  183. trailer = "\n\t";
  184. break;
  185. case F_TERMCAP:
  186. case F_TCONVERR:
  187. bool_names = boolcodes;
  188. num_names = numcodes;
  189. str_names = strcodes;
  190. separator = ":";
  191. trailer = "\\\n\t:";
  192. break;
  193. }
  194. /* implement sort modes */
  195. switch (sortmode = sort) {
  196. case S_NOSORT:
  197. if (traceval)
  198. (void) fprintf(stderr,
  199. "%s: sorting by term structure order\n", _nc_progname);
  200. break;
  201. case S_TERMINFO:
  202. if (traceval)
  203. (void) fprintf(stderr,
  204. "%s: sorting by terminfo name order\n", _nc_progname);
  205. bool_indirect = bool_terminfo_sort;
  206. num_indirect = num_terminfo_sort;
  207. str_indirect = str_terminfo_sort;
  208. break;
  209. case S_VARIABLE:
  210. if (traceval)
  211. (void) fprintf(stderr,
  212. "%s: sorting by C variable order\n", _nc_progname);
  213. bool_indirect = bool_variable_sort;
  214. num_indirect = num_variable_sort;
  215. str_indirect = str_variable_sort;
  216. break;
  217. case S_TERMCAP:
  218. if (traceval)
  219. (void) fprintf(stderr,
  220. "%s: sorting by termcap name order\n", _nc_progname);
  221. bool_indirect = bool_termcap_sort;
  222. num_indirect = num_termcap_sort;
  223. str_indirect = str_termcap_sort;
  224. break;
  225. }
  226. if (traceval)
  227. (void) fprintf(stderr,
  228. "%s: width = %d, tversion = %d, outform = %d\n",
  229. _nc_progname, width, tversion, outform);
  230. }
  231. static TERMTYPE *cur_type;
  232. static int
  233. dump_predicate(PredType type, PredIdx idx)
  234. /* predicate function to use for ordinary decompilation */
  235. {
  236. switch (type) {
  237. case BOOLEAN:
  238. return (cur_type->Booleans[idx] == FALSE)
  239. ? FAIL : cur_type->Booleans[idx];
  240. case NUMBER:
  241. return (cur_type->Numbers[idx] == ABSENT_NUMERIC)
  242. ? FAIL : cur_type->Numbers[idx];
  243. case STRING:
  244. return (cur_type->Strings[idx] != ABSENT_STRING)
  245. ? (int) TRUE : FAIL;
  246. }
  247. return (FALSE); /* pacify compiler */
  248. }
  249. static void set_obsolete_termcaps(TERMTYPE *tp);
  250. /* is this the index of a function key string? */
  251. #define FNKEY(i) (((i)<= 65 && (i)>= 75) || ((i)<= 216 && (i)>= 268))
  252. /*
  253. * If we configure with a different Caps file, the offsets into the arrays
  254. * will change. So we use an address expression.
  255. */
  256. #define BOOL_IDX(name) (PredType) (&(name) - &(CUR Booleans[0]))
  257. #define NUM_IDX(name) (PredType) (&(name) - &(CUR Numbers[0]))
  258. #define STR_IDX(name) (PredType) (&(name) - &(CUR Strings[0]))
  259. static bool
  260. version_filter(PredType type, PredIdx idx)
  261. /* filter out capabilities we may want to suppress */
  262. {
  263. switch (tversion) {
  264. case V_ALLCAPS: /* SVr4, XSI Curses */
  265. return (TRUE);
  266. case V_SVR1: /* System V Release 1, Ultrix */
  267. switch (type) {
  268. case BOOLEAN:
  269. return ((idx <= BOOL_IDX(xon_xoff)) ? TRUE : FALSE);
  270. case NUMBER:
  271. return ((idx <= NUM_IDX(width_status_line)) ? TRUE : FALSE);
  272. case STRING:
  273. return ((idx <= STR_IDX(prtr_non)) ? TRUE : FALSE);
  274. }
  275. break;
  276. case V_HPUX: /* Hewlett-Packard */
  277. switch (type) {
  278. case BOOLEAN:
  279. return ((idx <= BOOL_IDX(xon_xoff)) ? TRUE : FALSE);
  280. case NUMBER:
  281. return ((idx <= NUM_IDX(label_width)) ? TRUE : FALSE);
  282. case STRING:
  283. if (idx <= STR_IDX(prtr_non))
  284. return (TRUE);
  285. else if (FNKEY(idx)) /* function keys */
  286. return (TRUE);
  287. else if (idx == STR_IDX(plab_norm)
  288. || idx == STR_IDX(label_on)
  289. || idx == STR_IDX(label_off))
  290. return (TRUE);
  291. else
  292. return (FALSE);
  293. }
  294. break;
  295. case V_AIX: /* AIX */
  296. switch (type) {
  297. case BOOLEAN:
  298. return ((idx <= BOOL_IDX(xon_xoff)) ? TRUE : FALSE);
  299. case NUMBER:
  300. return ((idx <= NUM_IDX(width_status_line)) ? TRUE : FALSE);
  301. case STRING:
  302. if (idx <= STR_IDX(prtr_non))
  303. return (TRUE);
  304. else if (FNKEY(idx)) /* function keys */
  305. return (TRUE);
  306. else
  307. return (FALSE);
  308. }
  309. break;
  310. #define is_termcap(type) (OkIndex(idx, type##_from_termcap) && \
  311. type##_from_termcap[idx])
  312. case V_BSD: /* BSD */
  313. switch (type) {
  314. case BOOLEAN:
  315. return is_termcap(bool);
  316. case NUMBER:
  317. return is_termcap(num);
  318. case STRING:
  319. return is_termcap(str);
  320. }
  321. break;
  322. }
  323. return (FALSE); /* pacify the compiler */
  324. }
  325. static void
  326. trim_trailing(void)
  327. {
  328. while (outbuf.used > 0 && outbuf.text[outbuf.used - 1] == ' ')
  329. outbuf.text[--outbuf.used] = '\0';
  330. }
  331. static void
  332. force_wrap(void)
  333. {
  334. oldcol = column;
  335. trim_trailing();
  336. strcpy_DYN(&outbuf, trailer);
  337. column = INDENT;
  338. }
  339. static void
  340. wrap_concat(const char *src)
  341. {
  342. unsigned need = strlen(src);
  343. unsigned want = strlen(separator) + need;
  344. if (column > INDENT
  345. && column + (int) want > width) {
  346. force_wrap();
  347. }
  348. strcpy_DYN(&outbuf, src);
  349. strcpy_DYN(&outbuf, separator);
  350. column += (int) need;
  351. }
  352. #define IGNORE_SEP_TRAIL(first,last,sep_trail) \
  353. if ((size_t)(last - first) > sizeof(sep_trail)-1 \
  354. && !strncmp(first, sep_trail, sizeof(sep_trail)-1)) \
  355. first += sizeof(sep_trail)-2
  356. /* Returns the nominal length of the buffer assuming it is termcap format,
  357. * i.e., the continuation sequence is treated as a single character ":".
  358. *
  359. * There are several implementations of termcap which read the text into a
  360. * fixed-size buffer. Generally they strip the newlines from the text, but may
  361. * not do it until after the buffer is read. Also, "tc=" resolution may be
  362. * expanded in the same buffer. This function is useful for measuring the size
  363. * of the best fixed-buffer implementation; the worst case may be much worse.
  364. */
  365. #ifdef TEST_TERMCAP_LENGTH
  366. static int
  367. termcap_length(const char *src)
  368. {
  369. static const char pattern[] = ":\\\n\t:";
  370. int len = 0;
  371. const char *const t = src + strlen(src);
  372. while (*src != '\0') {
  373. IGNORE_SEP_TRAIL(src, t, pattern);
  374. src++;
  375. len++;
  376. }
  377. return len;
  378. }
  379. #else
  380. #define termcap_length(src) strlen(src)
  381. #endif
  382. static void
  383. indent_DYN(DYNBUF * buffer, int level)
  384. {
  385. int n;
  386. for (n = 0; n < level; n++)
  387. strncpy_DYN(buffer, "\t", 1);
  388. }
  389. static bool
  390. has_params(const char *src)
  391. {
  392. bool result = FALSE;
  393. int len = (int) strlen(src);
  394. int n;
  395. bool ifthen = FALSE;
  396. bool params = FALSE;
  397. for (n = 0; n < len - 1; ++n) {
  398. if (!strncmp(src + n, "%p", 2)) {
  399. params = TRUE;
  400. } else if (!strncmp(src + n, "%;", 2)) {
  401. ifthen = TRUE;
  402. result = params;
  403. break;
  404. }
  405. }
  406. if (!ifthen) {
  407. result = ((len > 50) && params);
  408. }
  409. return result;
  410. }
  411. static char *
  412. fmt_complex(char *src, int level)
  413. {
  414. bool percent = FALSE;
  415. bool params = has_params(src);
  416. while (*src != '\0') {
  417. switch (*src) {
  418. case '\\':
  419. percent = FALSE;
  420. strncpy_DYN(&tmpbuf, src++, 1);
  421. break;
  422. case '%':
  423. percent = TRUE;
  424. break;
  425. case '?': /* "if" */
  426. case 't': /* "then" */
  427. case 'e': /* "else" */
  428. if (percent) {
  429. percent = FALSE;
  430. tmpbuf.text[tmpbuf.used - 1] = '\n';
  431. /* treat a "%e" as else-if, on the same level */
  432. if (*src == 'e') {
  433. indent_DYN(&tmpbuf, level);
  434. strncpy_DYN(&tmpbuf, "%", 1);
  435. strncpy_DYN(&tmpbuf, src, 1);
  436. src++;
  437. params = has_params(src);
  438. if (!params && *src != '\0' && *src != '%') {
  439. strncpy_DYN(&tmpbuf, "\n", 1);
  440. indent_DYN(&tmpbuf, level + 1);
  441. }
  442. } else {
  443. indent_DYN(&tmpbuf, level + 1);
  444. strncpy_DYN(&tmpbuf, "%", 1);
  445. strncpy_DYN(&tmpbuf, src, 1);
  446. if (*src++ == '?') {
  447. src = fmt_complex(src, level + 1);
  448. if (*src != '\0' && *src != '%') {
  449. strncpy_DYN(&tmpbuf, "\n", 1);
  450. indent_DYN(&tmpbuf, level + 1);
  451. }
  452. } else if (level == 1) {
  453. _nc_warning("%%%c without %%?", *src);
  454. }
  455. }
  456. continue;
  457. }
  458. break;
  459. case ';': /* "endif" */
  460. if (percent) {
  461. percent = FALSE;
  462. if (level > 1) {
  463. tmpbuf.text[tmpbuf.used - 1] = '\n';
  464. indent_DYN(&tmpbuf, level);
  465. strncpy_DYN(&tmpbuf, "%", 1);
  466. strncpy_DYN(&tmpbuf, src++, 1);
  467. return src;
  468. }
  469. _nc_warning("%%; without %%?");
  470. }
  471. break;
  472. case 'p':
  473. if (percent && params) {
  474. tmpbuf.text[tmpbuf.used - 1] = '\n';
  475. indent_DYN(&tmpbuf, level + 1);
  476. strncpy_DYN(&tmpbuf, "%", 1);
  477. }
  478. params = FALSE;
  479. percent = FALSE;
  480. break;
  481. case ' ':
  482. strncpy_DYN(&tmpbuf, "\\s", 2);
  483. ++src;
  484. continue;
  485. default:
  486. percent = FALSE;
  487. break;
  488. }
  489. strncpy_DYN(&tmpbuf, src++, 1);
  490. }
  491. return src;
  492. }
  493. #define SAME_CAP(n,cap) (&tterm->Strings[n] == &cap)
  494. #define EXTRA_CAP 20
  495. int
  496. fmt_entry(TERMTYPE *tterm,
  497. PredFunc pred,
  498. bool content_only,
  499. bool suppress_untranslatable,
  500. bool infodump,
  501. int numbers)
  502. {
  503. PredIdx i, j;
  504. char buffer[MAX_TERMINFO_LENGTH + EXTRA_CAP];
  505. char *capability;
  506. NCURSES_CONST char *name;
  507. int predval, len;
  508. PredIdx num_bools = 0;
  509. PredIdx num_values = 0;
  510. PredIdx num_strings = 0;
  511. bool outcount = 0;
  512. #define WRAP_CONCAT \
  513. wrap_concat(buffer); \
  514. outcount = TRUE
  515. len = 12; /* terminfo file-header */
  516. if (pred == 0) {
  517. cur_type = tterm;
  518. pred = dump_predicate;
  519. }
  520. strcpy_DYN(&outbuf, 0);
  521. if (content_only) {
  522. column = INDENT; /* FIXME: workaround to prevent empty lines */
  523. } else {
  524. strcpy_DYN(&outbuf, tterm->term_names);
  525. strcpy_DYN(&outbuf, separator);
  526. column = (int) outbuf.used;
  527. force_wrap();
  528. }
  529. for_each_boolean(j, tterm) {
  530. i = BoolIndirect(j);
  531. name = ExtBoolname(tterm, i, bool_names);
  532. assert(strlen(name) < sizeof(buffer) - EXTRA_CAP);
  533. if (!version_filter(BOOLEAN, i))
  534. continue;
  535. else if (isObsolete(outform, name))
  536. continue;
  537. predval = pred(BOOLEAN, i);
  538. if (predval != FAIL) {
  539. (void) strcpy(buffer, name);
  540. if (predval <= 0)
  541. (void) strcat(buffer, "@");
  542. else if (i + 1 > num_bools)
  543. num_bools = i + 1;
  544. WRAP_CONCAT;
  545. }
  546. }
  547. if (column != INDENT)
  548. force_wrap();
  549. for_each_number(j, tterm) {
  550. i = NumIndirect(j);
  551. name = ExtNumname(tterm, i, num_names);
  552. assert(strlen(name) < sizeof(buffer) - EXTRA_CAP);
  553. if (!version_filter(NUMBER, i))
  554. continue;
  555. else if (isObsolete(outform, name))
  556. continue;
  557. predval = pred(NUMBER, i);
  558. if (predval != FAIL) {
  559. if (tterm->Numbers[i] < 0) {
  560. sprintf(buffer, "%s@", name);
  561. } else {
  562. sprintf(buffer, "%s#%d", name, tterm->Numbers[i]);
  563. if (i + 1 > num_values)
  564. num_values = i + 1;
  565. }
  566. WRAP_CONCAT;
  567. }
  568. }
  569. if (column != INDENT)
  570. force_wrap();
  571. len += (int) (num_bools
  572. + num_values * 2
  573. + strlen(tterm->term_names) + 1);
  574. if (len & 1)
  575. len++;
  576. #undef CUR
  577. #define CUR tterm->
  578. if (outform == F_TERMCAP) {
  579. if (termcap_reset != ABSENT_STRING) {
  580. if (init_3string != ABSENT_STRING
  581. && !strcmp(init_3string, termcap_reset))
  582. DISCARD(init_3string);
  583. if (reset_2string != ABSENT_STRING
  584. && !strcmp(reset_2string, termcap_reset))
  585. DISCARD(reset_2string);
  586. }
  587. }
  588. for_each_string(j, tterm) {
  589. i = StrIndirect(j);
  590. name = ExtStrname(tterm, i, str_names);
  591. assert(strlen(name) < sizeof(buffer) - EXTRA_CAP);
  592. capability = tterm->Strings[i];
  593. if (!version_filter(STRING, i))
  594. continue;
  595. else if (isObsolete(outform, name))
  596. continue;
  597. #if NCURSES_XNAMES
  598. /*
  599. * Extended names can be longer than 2 characters, but termcap programs
  600. * cannot read those (filter them out).
  601. */
  602. if (outform == F_TERMCAP && (strlen(name) > 2))
  603. continue;
  604. #endif
  605. if (outform == F_TERMCAP) {
  606. /*
  607. * Some older versions of vi want rmir/smir to be defined
  608. * for ich/ich1 to work. If they're not defined, force
  609. * them to be output as defined and empty.
  610. */
  611. if (PRESENT(insert_character) || PRESENT(parm_ich)) {
  612. if (SAME_CAP(i, enter_insert_mode)
  613. && enter_insert_mode == ABSENT_STRING) {
  614. (void) strcpy(buffer, "im=");
  615. WRAP_CONCAT;
  616. continue;
  617. }
  618. if (SAME_CAP(i, exit_insert_mode)
  619. && exit_insert_mode == ABSENT_STRING) {
  620. (void) strcpy(buffer, "ei=");
  621. WRAP_CONCAT;
  622. continue;
  623. }
  624. }
  625. /*
  626. * termcap applications such as screen will be confused if sgr0
  627. * is translated to a string containing rmacs. Filter that out.
  628. */
  629. if (PRESENT(exit_attribute_mode)) {
  630. if (SAME_CAP(i, exit_attribute_mode)) {
  631. char *trimmed_sgr0;
  632. char *my_sgr = set_attributes;
  633. set_attributes = save_sgr;
  634. trimmed_sgr0 = _nc_trim_sgr0(tterm);
  635. if (strcmp(capability, trimmed_sgr0))
  636. capability = trimmed_sgr0;
  637. set_attributes = my_sgr;
  638. }
  639. }
  640. }
  641. predval = pred(STRING, i);
  642. buffer[0] = '\0';
  643. if (predval != FAIL) {
  644. if (capability != ABSENT_STRING
  645. && i + 1 > num_strings)
  646. num_strings = i + 1;
  647. if (!VALID_STRING(capability)) {
  648. sprintf(buffer, "%s@", name);
  649. WRAP_CONCAT;
  650. } else if (outform == F_TERMCAP || outform == F_TCONVERR) {
  651. int params = ((i < (int) SIZEOF(parametrized))
  652. ? parametrized[i]
  653. : 0);
  654. char *srccap = _nc_tic_expand(capability, TRUE, numbers);
  655. char *cv = _nc_infotocap(name, srccap, params);
  656. if (cv == 0) {
  657. if (outform == F_TCONVERR) {
  658. sprintf(buffer, "%s=!!! %s WILL NOT CONVERT !!!",
  659. name, srccap);
  660. } else if (suppress_untranslatable) {
  661. continue;
  662. } else {
  663. char *s = srccap, *d = buffer;
  664. sprintf(d, "..%s=", name);
  665. d += strlen(d);
  666. while ((*d = *s++) != 0) {
  667. if (*d == ':') {
  668. *d++ = '\\';
  669. *d = ':';
  670. } else if (*d == '\\') {
  671. *++d = *s++;
  672. }
  673. d++;
  674. }
  675. }
  676. } else {
  677. sprintf(buffer, "%s=%s", name, cv);
  678. }
  679. len += (int) strlen(capability) + 1;
  680. WRAP_CONCAT;
  681. } else {
  682. char *src = _nc_tic_expand(capability,
  683. outform == F_TERMINFO, numbers);
  684. strcpy_DYN(&tmpbuf, 0);
  685. strcpy_DYN(&tmpbuf, name);
  686. strcpy_DYN(&tmpbuf, "=");
  687. if (pretty
  688. && (outform == F_TERMINFO
  689. || outform == F_VARIABLE)) {
  690. fmt_complex(src, 1);
  691. } else {
  692. strcpy_DYN(&tmpbuf, src);
  693. }
  694. len += (int) strlen(capability) + 1;
  695. wrap_concat(tmpbuf.text);
  696. outcount = TRUE;
  697. }
  698. }
  699. /* e.g., trimmed_sgr0 */
  700. if (capability != tterm->Strings[i])
  701. free(capability);
  702. }
  703. len += (int) (num_strings * 2);
  704. /*
  705. * This piece of code should be an effective inverse of the functions
  706. * postprocess_terminfo() and postprocess_terminfo() in parse_entry.c.
  707. * Much more work should be done on this to support dumping termcaps.
  708. */
  709. if (tversion == V_HPUX) {
  710. if (VALID_STRING(memory_lock)) {
  711. (void) sprintf(buffer, "meml=%s", memory_lock);
  712. WRAP_CONCAT;
  713. }
  714. if (VALID_STRING(memory_unlock)) {
  715. (void) sprintf(buffer, "memu=%s", memory_unlock);
  716. WRAP_CONCAT;
  717. }
  718. } else if (tversion == V_AIX) {
  719. if (VALID_STRING(acs_chars)) {
  720. bool box_ok = TRUE;
  721. const char *acstrans = "lqkxjmwuvtn";
  722. const char *cp;
  723. char *tp, *sp, boxchars[11];
  724. tp = boxchars;
  725. for (cp = acstrans; *cp; cp++) {
  726. sp = strchr(acs_chars, *cp);
  727. if (sp)
  728. *tp++ = sp[1];
  729. else {
  730. box_ok = FALSE;
  731. break;
  732. }
  733. }
  734. tp[0] = '\0';
  735. if (box_ok) {
  736. (void) strcpy(buffer, "box1=");
  737. (void) strcat(buffer, _nc_tic_expand(boxchars,
  738. outform == F_TERMINFO, numbers));
  739. WRAP_CONCAT;
  740. }
  741. }
  742. }
  743. /*
  744. * kludge: trim off trailer to avoid an extra blank line
  745. * in infocmp -u output when there are no string differences
  746. */
  747. if (outcount) {
  748. bool trimmed = FALSE;
  749. j = outbuf.used;
  750. if (j >= 2
  751. && outbuf.text[j - 1] == '\t'
  752. && outbuf.text[j - 2] == '\n') {
  753. outbuf.used -= 2;
  754. trimmed = TRUE;
  755. } else if (j >= 4
  756. && outbuf.text[j - 1] == ':'
  757. && outbuf.text[j - 2] == '\t'
  758. && outbuf.text[j - 3] == '\n'
  759. && outbuf.text[j - 4] == '\\') {
  760. outbuf.used -= 4;
  761. trimmed = TRUE;
  762. }
  763. if (trimmed) {
  764. outbuf.text[outbuf.used] = '\0';
  765. column = oldcol;
  766. strcpy_DYN(&outbuf, " ");
  767. }
  768. }
  769. #if 0
  770. fprintf(stderr, "num_bools = %d\n", num_bools);
  771. fprintf(stderr, "num_values = %d\n", num_values);
  772. fprintf(stderr, "num_strings = %d\n", num_strings);
  773. fprintf(stderr, "term_names=%s, len=%d, strlen(outbuf)=%d, outbuf=%s\n",
  774. tterm->term_names, len, outbuf.used, outbuf.text);
  775. #endif
  776. /*
  777. * Here's where we use infodump to trigger a more stringent length check
  778. * for termcap-translation purposes.
  779. * Return the length of the raw entry, without tc= expansions,
  780. * It gives an idea of which entries are deadly to even *scan past*,
  781. * as opposed to *use*.
  782. */
  783. return (infodump ? len : (int) termcap_length(outbuf.text));
  784. }
  785. static bool
  786. kill_string(TERMTYPE *tterm, char *cap)
  787. {
  788. unsigned n;
  789. for (n = 0; n < NUM_STRINGS(tterm); ++n) {
  790. if (cap == tterm->Strings[n]) {
  791. tterm->Strings[n] = ABSENT_STRING;
  792. return TRUE;
  793. }
  794. }
  795. return FALSE;
  796. }
  797. static char *
  798. find_string(TERMTYPE *tterm, char *name)
  799. {
  800. PredIdx n;
  801. for (n = 0; n < NUM_STRINGS(tterm); ++n) {
  802. if (version_filter(STRING, n)
  803. && !strcmp(name, strnames[n])) {
  804. char *cap = tterm->Strings[n];
  805. if (VALID_STRING(cap)) {
  806. return cap;
  807. }
  808. break;
  809. }
  810. }
  811. return ABSENT_STRING;
  812. }
  813. /*
  814. * This is used to remove function-key labels from a termcap entry to
  815. * make it smaller.
  816. */
  817. static int
  818. kill_labels(TERMTYPE *tterm, int target)
  819. {
  820. int n;
  821. int result = 0;
  822. char *cap;
  823. char name[10];
  824. for (n = 0; n <= 10; ++n) {
  825. sprintf(name, "lf%d", n);
  826. if ((cap = find_string(tterm, name)) != ABSENT_STRING
  827. && kill_string(tterm, cap)) {
  828. target -= (int) (strlen(cap) + 5);
  829. ++result;
  830. if (target < 0)
  831. break;
  832. }
  833. }
  834. return result;
  835. }
  836. /*
  837. * This is used to remove function-key definitions from a termcap entry to
  838. * make it smaller.
  839. */
  840. static int
  841. kill_fkeys(TERMTYPE *tterm, int target)
  842. {
  843. int n;
  844. int result = 0;
  845. char *cap;
  846. char name[10];
  847. for (n = 60; n >= 0; --n) {
  848. sprintf(name, "kf%d", n);
  849. if ((cap = find_string(tterm, name)) != ABSENT_STRING
  850. && kill_string(tterm, cap)) {
  851. target -= (int) (strlen(cap) + 5);
  852. ++result;
  853. if (target < 0)
  854. break;
  855. }
  856. }
  857. return result;
  858. }
  859. /*
  860. * Check if the given acsc string is a 1-1 mapping, i.e., just-like-vt100.
  861. * Also, since this is for termcap, we only care about the line-drawing map.
  862. */
  863. #define isLine(c) (strchr("lmkjtuvwqxn", c) != 0)
  864. static bool
  865. one_one_mapping(const char *mapping)
  866. {
  867. bool result = TRUE;
  868. if (mapping != ABSENT_STRING) {
  869. int n = 0;
  870. while (mapping[n] != '\0') {
  871. if (isLine(mapping[n]) &&
  872. mapping[n] != mapping[n + 1]) {
  873. result = FALSE;
  874. break;
  875. }
  876. n += 2;
  877. }
  878. }
  879. return result;
  880. }
  881. #define FMT_ENTRY() \
  882. fmt_entry(tterm, pred, \
  883. 0, \
  884. suppress_untranslatable, \
  885. infodump, numbers)
  886. #define SHOW_WHY PRINTF
  887. static bool
  888. purged_acs(TERMTYPE *tterm)
  889. {
  890. bool result = FALSE;
  891. if (VALID_STRING(acs_chars)) {
  892. if (!one_one_mapping(acs_chars)) {
  893. enter_alt_charset_mode = ABSENT_STRING;
  894. exit_alt_charset_mode = ABSENT_STRING;
  895. SHOW_WHY("# (rmacs/smacs removed for consistency)\n");
  896. }
  897. result = TRUE;
  898. }
  899. return result;
  900. }
  901. /*
  902. * Dump a single entry.
  903. */
  904. void
  905. dump_entry(TERMTYPE *tterm,
  906. bool suppress_untranslatable,
  907. bool limited,
  908. int numbers,
  909. PredFunc pred)
  910. {
  911. TERMTYPE save_tterm;
  912. int len, critlen;
  913. const char *legend;
  914. bool infodump;
  915. if (outform == F_TERMCAP || outform == F_TCONVERR) {
  916. critlen = MAX_TERMCAP_LENGTH;
  917. legend = "older termcap";
  918. infodump = FALSE;
  919. set_obsolete_termcaps(tterm);
  920. } else {
  921. critlen = MAX_TERMINFO_LENGTH;
  922. legend = "terminfo";
  923. infodump = TRUE;
  924. }
  925. save_sgr = set_attributes;
  926. if (((len = FMT_ENTRY()) > critlen)
  927. && limited) {
  928. save_tterm = *tterm;
  929. if (!suppress_untranslatable) {
  930. SHOW_WHY("# (untranslatable capabilities removed to fit entry within %d bytes)\n",
  931. critlen);
  932. suppress_untranslatable = TRUE;
  933. }
  934. if ((len = FMT_ENTRY()) > critlen) {
  935. /*
  936. * We pick on sgr because it's a nice long string capability that
  937. * is really just an optimization hack. Another good candidate is
  938. * acsc since it is both long and unused by BSD termcap.
  939. */
  940. bool changed = FALSE;
  941. #if NCURSES_XNAMES
  942. /*
  943. * Extended names are most likely function-key definitions. Drop
  944. * those first.
  945. */
  946. unsigned n;
  947. for (n = STRCOUNT; n < NUM_STRINGS(tterm); n++) {
  948. const char *name = ExtStrname(tterm, n, strnames);
  949. if (VALID_STRING(tterm->Strings[n])) {
  950. set_attributes = ABSENT_STRING;
  951. /* we remove long names anyway - only report the short */
  952. if (strlen(name) <= 2) {
  953. SHOW_WHY("# (%s removed to fit entry within %d bytes)\n",
  954. name,
  955. critlen);
  956. }
  957. changed = TRUE;
  958. if ((len = FMT_ENTRY()) <= critlen)
  959. break;
  960. }
  961. }
  962. #endif
  963. if (VALID_STRING(set_attributes)) {
  964. set_attributes = ABSENT_STRING;
  965. SHOW_WHY("# (sgr removed to fit entry within %d bytes)\n",
  966. critlen);
  967. changed = TRUE;
  968. }
  969. if (!changed || ((len = FMT_ENTRY()) > critlen)) {
  970. if (purged_acs(tterm)) {
  971. acs_chars = ABSENT_STRING;
  972. SHOW_WHY("# (acsc removed to fit entry within %d bytes)\n",
  973. critlen);
  974. changed = TRUE;
  975. }
  976. }
  977. if (!changed || ((len = FMT_ENTRY()) > critlen)) {
  978. int oldversion = tversion;
  979. tversion = V_BSD;
  980. SHOW_WHY("# (terminfo-only capabilities suppressed to fit entry within %d bytes)\n",
  981. critlen);
  982. len = FMT_ENTRY();
  983. if (len > critlen
  984. && kill_labels(tterm, len - critlen)) {
  985. SHOW_WHY("# (some labels capabilities suppressed to fit entry within %d bytes)\n",
  986. critlen);
  987. len = FMT_ENTRY();
  988. }
  989. if (len > critlen
  990. && kill_fkeys(tterm, len - critlen)) {
  991. SHOW_WHY("# (some function-key capabilities suppressed to fit entry within %d bytes)\n",
  992. critlen);
  993. len = FMT_ENTRY();
  994. }
  995. if (len > critlen) {
  996. (void) fprintf(stderr,
  997. "warning: %s entry is %d bytes long\n",
  998. _nc_first_name(tterm->term_names),
  999. len);
  1000. SHOW_WHY("# WARNING: this entry, %d bytes long, may core-dump %s libraries!\n",
  1001. len, legend);
  1002. }
  1003. tversion = oldversion;
  1004. }
  1005. set_attributes = save_sgr;
  1006. *tterm = save_tterm;
  1007. }
  1008. } else if (!version_filter(STRING, STR_IDX(acs_chars))) {
  1009. save_tterm = *tterm;
  1010. if (purged_acs(tterm)) {
  1011. len = FMT_ENTRY();
  1012. }
  1013. *tterm = save_tterm;
  1014. }
  1015. }
  1016. void
  1017. dump_uses(const char *name, bool infodump)
  1018. /* dump "use=" clauses in the appropriate format */
  1019. {
  1020. char buffer[MAX_TERMINFO_LENGTH];
  1021. if (outform == F_TERMCAP || outform == F_TCONVERR)
  1022. trim_trailing();
  1023. (void) sprintf(buffer, "%s%s", infodump ? "use=" : "tc=", name);
  1024. wrap_concat(buffer);
  1025. }
  1026. int
  1027. show_entry(void)
  1028. {
  1029. trim_trailing();
  1030. (void) fputs(outbuf.text, stdout);
  1031. putchar('\n');
  1032. return (int) outbuf.used;
  1033. }
  1034. void
  1035. compare_entry(void (*hook) (PredType t, PredIdx i, const char *name),
  1036. TERMTYPE *tp GCC_UNUSED,
  1037. bool quiet)
  1038. /* compare two entries */
  1039. {
  1040. PredIdx i, j;
  1041. NCURSES_CONST char *name;
  1042. if (!quiet)
  1043. fputs(" comparing booleans.\n", stdout);
  1044. for_each_boolean(j, tp) {
  1045. i = BoolIndirect(j);
  1046. name = ExtBoolname(tp, i, bool_names);
  1047. if (isObsolete(outform, name))
  1048. continue;
  1049. (*hook) (CMP_BOOLEAN, i, name);
  1050. }
  1051. if (!quiet)
  1052. fputs(" comparing numbers.\n", stdout);
  1053. for_each_number(j, tp) {
  1054. i = NumIndirect(j);
  1055. name = ExtNumname(tp, i, num_names);
  1056. if (isObsolete(outform, name))
  1057. continue;
  1058. (*hook) (CMP_NUMBER, i, name);
  1059. }
  1060. if (!quiet)
  1061. fputs(" comparing strings.\n", stdout);
  1062. for_each_string(j, tp) {
  1063. i = StrIndirect(j);
  1064. name = ExtStrname(tp, i, str_names);
  1065. if (isObsolete(outform, name))
  1066. continue;
  1067. (*hook) (CMP_STRING, i, name);
  1068. }
  1069. /* (void) fputs(" comparing use entries.\n", stdout); */
  1070. (*hook) (CMP_USE, 0, "use");
  1071. }
  1072. #define NOTSET(s) ((s) == 0)
  1073. /*
  1074. * This bit of legerdemain turns all the terminfo variable names into
  1075. * references to locations in the arrays Booleans, Numbers, and Strings ---
  1076. * precisely what's needed.
  1077. */
  1078. #undef CUR
  1079. #define CUR tp->
  1080. static void
  1081. set_obsolete_termcaps(TERMTYPE *tp)
  1082. {
  1083. #include "capdefaults.c"
  1084. }
  1085. /*
  1086. * Convert an alternate-character-set string to canonical form: sorted and
  1087. * unique.
  1088. */
  1089. void
  1090. repair_acsc(TERMTYPE *tp)
  1091. {
  1092. if (VALID_STRING(acs_chars)) {
  1093. size_t n, m;
  1094. char mapped[256];
  1095. char extra = 0;
  1096. unsigned source;
  1097. unsigned target;
  1098. bool fix_needed = FALSE;
  1099. for (n = 0, source = 0; acs_chars[n] != 0; n++) {
  1100. target = UChar(acs_chars[n]);
  1101. if (source >= target) {
  1102. fix_needed = TRUE;
  1103. break;
  1104. }
  1105. source = target;
  1106. if (acs_chars[n + 1])
  1107. n++;
  1108. }
  1109. if (fix_needed) {
  1110. memset(mapped, 0, sizeof(mapped));
  1111. for (n = 0; acs_chars[n] != 0; n++) {
  1112. source = UChar(acs_chars[n]);
  1113. if ((target = (unsigned char) acs_chars[n + 1]) != 0) {
  1114. mapped[source] = (char) target;
  1115. n++;
  1116. } else {
  1117. extra = (char) source;
  1118. }
  1119. }
  1120. for (n = m = 0; n < sizeof(mapped); n++) {
  1121. if (mapped[n]) {
  1122. acs_chars[m++] = (char) n;
  1123. acs_chars[m++] = mapped[n];
  1124. }
  1125. }
  1126. if (extra)
  1127. acs_chars[m++] = extra; /* garbage in, garbage out */
  1128. acs_chars[m] = 0;
  1129. }
  1130. }
  1131. }