source: trunk/ncurses/progs/dump_entry.c@ 3003

Last change on this file since 3003 was 2621, checked in by bird, 19 years ago

GNU ncurses 5.5

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