ncurses 4.1
[ncurses.git] / progs / dump_entry.c
1
2 /***************************************************************************
3 *                            COPYRIGHT NOTICE                              *
4 ****************************************************************************
5 *                ncurses is copyright (C) 1992-1995                        *
6 *                          Zeyd M. Ben-Halim                               *
7 *                          zmbenhal@netcom.com                             *
8 *                          Eric S. Raymond                                 *
9 *                          esr@snark.thyrsus.com                           *
10 *                                                                          *
11 *        Permission is hereby granted to reproduce and distribute ncurses  *
12 *        by any means and for any fee, whether alone or as part of a       *
13 *        larger distribution, in source or in binary form, PROVIDED        *
14 *        this notice is included with any such distribution, and is not    *
15 *        removed from any of its header files. Mention of ncurses in any   *
16 *        applications linked with it is highly appreciated.                *
17 *                                                                          *
18 *        ncurses comes AS IS with no warranty, implied or expressed.       *
19 *                                                                          *
20 ***************************************************************************/
21
22 #define __INTERNAL_CAPS_VISIBLE
23 #include <progs.priv.h>
24
25 #include <ctype.h>
26 #include "dump_entry.h"
27 #include "termsort.c"           /* this C file is generated */
28 #include "parametrized.h"       /* so is this */
29
30 MODULE_ID("$Id: dump_entry.c,v 1.17 1997/05/10 17:35:30 tom Exp $")
31
32 #define INDENT                  8
33
34 static int tversion;            /* terminfo version */
35 static int outform;             /* output format to use */
36 static int sortmode;            /* sort mode to use */
37 static int width = 60;          /* max line width for listings */
38 static int column;              /* current column, limited by 'width' */
39 static int oldcol;              /* last value of column before wrap */
40 static int tracelevel;          /* level of debug output */
41
42 static char *outbuf;            /* the output-buffer */
43 static size_t out_used;         /* ...its current length */
44 static size_t out_size;         /* ...and its allocated length */
45
46 /* indirection pointers for implementing sort and display modes */
47 static const int *bool_indirect, *num_indirect, *str_indirect;
48 static char * const *bool_names, * const *num_names, * const *str_names;
49
50 static const char *separator, *trailer;
51
52 /* cover various ports and variants of terminfo */
53 #define V_ALLCAPS       0       /* all capabilities (SVr4, XSI, ncurses) */
54 #define V_SVR1          1       /* SVR1, Ultrix */
55 #define V_HPUX          2       /* HP/UX */
56 #define V_AIX           3       /* AIX */
57 #define V_BSD           4       /* BSD */
58
59 #define OBSOLETE(n) (n[0] == 'O' && n[1] == 'T')
60
61 #if NO_LEAKS
62 void _nc_leaks_dump_entry(void)
63 {
64         if (outbuf != 0) {
65                 free(outbuf);
66                 outbuf = 0;
67         }
68 }
69 #endif
70
71 char *nametrans(const char *name)
72 /* translate a capability name from termcap to terminfo */
73 {
74     const struct name_table_entry       *np;
75
76     if ((np = _nc_find_entry(name, _nc_info_hash_table)) != NULL)
77         switch(np->nte_type)
78         {
79         case BOOLEAN:
80             if (bool_from_termcap[np->nte_index])
81                 return(boolcodes[np->nte_index]);
82             break;
83
84         case NUMBER:
85             if (num_from_termcap[np->nte_index])
86                 return(numcodes[np->nte_index]);
87             break;
88
89         case STRING:
90             if (str_from_termcap[np->nte_index])
91                 return(strcodes[np->nte_index]);
92             break;
93         }
94
95     return((char *)NULL);
96 }
97
98 void dump_init(const char *version, int mode, int sort, int twidth, int traceval)
99 /* set up for entry display */
100 {
101     width = twidth;
102     tracelevel = traceval;
103
104     /* versions */
105     if (version == (char *)NULL)
106         tversion = V_ALLCAPS;
107     else if (!strcmp(version, "SVr1") || !strcmp(version, "SVR1")
108                                         || !strcmp(version, "Ultrix"))
109         tversion = V_SVR1;
110     else if (!strcmp(version, "HP"))
111         tversion = V_HPUX;
112     else if (!strcmp(version, "AIX"))
113         tversion = V_AIX;
114     else if (!strcmp(version, "BSD"))
115         tversion = V_BSD;
116     else
117         tversion = V_ALLCAPS;
118
119     /* implement display modes */
120     switch (outform = mode)
121     {
122     case F_LITERAL:
123     case F_TERMINFO:
124         bool_names = boolnames;
125         num_names = numnames;
126         str_names = strnames;
127         separator = twidth ? ", " : ",";
128         trailer = "\n\t";
129         break;
130
131     case F_VARIABLE:
132         bool_names = boolfnames;
133         num_names = numfnames;
134         str_names = strfnames;
135         separator = twidth ? ", " : ",";
136         trailer = "\n\t";
137         break;
138
139     case F_TERMCAP:
140     case F_TCONVERR:
141         bool_names = boolcodes;
142         num_names = numcodes;
143         str_names = strcodes;
144         separator = ":";
145         trailer = "\\\n\t:";
146         break;
147     }
148
149     /* implement sort modes */
150     switch(sortmode = sort)
151     { 
152     case S_NOSORT:
153         if (traceval)
154             (void) fprintf(stderr,
155                            "%s: sorting by term structure order\n", _nc_progname);
156         break;
157
158     case S_TERMINFO:
159         if (traceval)
160             (void) fprintf(stderr,
161                            "%s: sorting by terminfo name order\n", _nc_progname);
162         bool_indirect = bool_terminfo_sort;
163         num_indirect = num_terminfo_sort;
164         str_indirect = str_terminfo_sort;
165         break;
166
167     case S_VARIABLE:
168         if (traceval)
169             (void) fprintf(stderr,
170                            "%s: sorting by C variable order\n", _nc_progname);
171         bool_indirect = bool_variable_sort;
172         num_indirect = num_variable_sort;
173         str_indirect = str_variable_sort;
174         break;
175
176     case S_TERMCAP:
177         if (traceval)
178             (void) fprintf(stderr,
179                            "%s: sorting by termcap name order\n", _nc_progname);
180         bool_indirect = bool_termcap_sort;
181         num_indirect = num_termcap_sort;
182         str_indirect = str_termcap_sort;
183         break;
184     }
185
186     if (traceval)
187         (void) fprintf(stderr,
188                        "%s: width = %d, tversion = %d, outform = %d\n",
189                        _nc_progname, width, tversion, outform);
190 }
191
192 static int trailing_spaces(const char *src)
193 {
194         while (*src == ' ')
195                 src++;
196         return *src == 0;
197 }
198
199 /* this deals with differences over whether 0x7f and 0x80..0x9f are controls */
200 #define CHAR_OF(s) (*(unsigned const char *)(s))
201 #define REALCTL(s) (CHAR_OF(s) < 127 && iscntrl(CHAR_OF(s)))
202 #define REALPRINT(s) (CHAR_OF(s) < 127 && isprint(CHAR_OF(s)))
203
204 char *expand(char *srcp)
205 {
206 static char     buffer[1024];
207 int             bufp;
208 const char      *ptr, *str = (srcp == ABSENT_STRING
209                            || srcp == CANCELLED_STRING) ? "" : srcp;
210 bool            islong = (strlen(str) > 3);
211
212         bufp = 0;
213         ptr = str;
214         while (*str) {
215                 if (*str == '%' && REALPRINT(str+1)) {
216                         buffer[bufp++] = *str++;
217                         buffer[bufp++] = *str;
218                 }
219                 else if (*str == '\033') {
220                         buffer[bufp++] = '\\';
221                         buffer[bufp++] = 'E';
222                 }
223                 else if (*str == '\\' && (outform==F_TERMINFO) && (str == srcp || str[-1] != '^')) {
224                         buffer[bufp++] = '\\';
225                         buffer[bufp++] = '\\';
226                 }
227                 else if (*str == ' ' && (outform==F_TERMINFO) && (str == srcp || trailing_spaces(str))) {
228                         buffer[bufp++] = '\\';
229                         buffer[bufp++] = 's';
230                 }
231                 else if ((*str == ',' || *str == ':' || *str == '^') && (outform==F_TERMINFO)) {
232                         buffer[bufp++] = '\\';
233                         buffer[bufp++] = *str;
234                 }
235                 else if (REALPRINT(str) && (*str != ',' && *str != ':' && !(*str == '!' && outform!=F_TERMINFO) && *str != '^'))
236                         buffer[bufp++] = *str;
237 #if 0           /* FIXME: this would be more readable */
238                 else if (*str == '\b') {
239                         buffer[bufp++] = '\\';
240                         buffer[bufp++] = 'b';
241                 }
242                 else if (*str == '\f') {
243                         buffer[bufp++] = '\\';
244                         buffer[bufp++] = 'f';
245                 }
246                 else if (*str == '\t' && islong) {
247                         buffer[bufp++] = '\\';
248                         buffer[bufp++] = 't';
249                 }
250 #endif
251                 else if (*str == '\r' && (islong || (strlen(srcp) > 2 && str[1] == '\0'))) {
252                         buffer[bufp++] = '\\';
253                         buffer[bufp++] = 'r';
254                 }
255                 else if (*str == '\n' && islong) {
256                         buffer[bufp++] = '\\';
257                         buffer[bufp++] = 'n';
258                 }
259 #define UnCtl(c) ((0xff & (c)) + '@')
260                 else if (REALCTL(str) && *str != '\\' && (!islong || isdigit(str[1])))
261                 {
262                         (void) sprintf(&buffer[bufp], "^%c", UnCtl(*str));
263                         bufp += 2;
264                 }
265                 else
266                 {
267                         (void) sprintf(&buffer[bufp], "\\%03o", 0xff & *str);
268                         bufp += 4;
269                 }
270
271                 str++;
272         }
273
274         buffer[bufp] = '\0';
275         return(buffer);
276 }
277
278 static TERMTYPE *cur_type;
279
280 static int dump_predicate(int type, int idx)
281 /* predicate function to use for ordinary decompilation */
282 {
283         switch(type) {
284         case BOOLEAN:
285                 return (cur_type->Booleans[idx] == FALSE)
286                     ? FAIL : cur_type->Booleans[idx];
287
288         case NUMBER:
289                 return (cur_type->Numbers[idx] == ABSENT_NUMERIC)
290                     ? FAIL : cur_type->Numbers[idx];
291
292         case STRING:
293                 return (cur_type->Strings[idx] != ABSENT_STRING)
294                     ? (int)TRUE : FAIL;
295         }
296
297         return(FALSE);  /* pacify compiler */
298 }
299
300 static void set_obsolete_termcaps(TERMTYPE *tp);
301
302 /* is this the index of a function key string? */
303 #define FNKEY(i)        (((i)<= 65 && (i)>= 75) || ((i)<= 216 && (i)>= 268))
304
305 static bool version_filter(int type, int idx)
306 /* filter out capabilities we may want to suppress */
307 {
308     switch (tversion)
309     {
310     case V_ALLCAPS:     /* SVr4, XSI Curses */
311         return(TRUE);
312
313     case V_SVR1:        /* System V Release 1, Ultrix */
314         switch (type)
315         {
316         case BOOLEAN:
317             return (idx <= 20); /* below and including xon_xoff */
318         case NUMBER:
319             return (idx <= 7);  /* below and including width_status_line */
320         case STRING:
321             return (idx <= 144);        /* below and including prtr_non */
322         }
323         break;
324
325     case V_HPUX:                /* Hewlett-Packard */
326         switch (type)
327         {
328         case BOOLEAN:
329             return (idx <= 20); /* below and including xon_xoff */
330         case NUMBER:
331             return (idx <= 10); /* below and including label_width */
332         case STRING:
333             if (idx <= 144)     /* below and including prtr_non */
334                 return(TRUE);
335             else if (FNKEY(idx))        /* function keys */
336                 return(TRUE);
337             else if (idx==147||idx==156||idx==157) /* plab_norm,label_on,label_off */
338                 return(TRUE);
339             else
340                 return(FALSE);
341         }
342         break;
343
344     case V_AIX:         /* AIX */
345         switch (type)
346         {
347         case BOOLEAN:
348             return (idx <= 20); /* below and including xon_xoff */
349         case NUMBER:
350             return (idx <= 7);  /* below and including width_status_line */
351         case STRING:
352             if (idx <= 144)     /* below and including prtr_non */
353                 return(TRUE);
354             else if (FNKEY(idx))        /* function keys */
355                 return(TRUE);
356             else
357                 return(FALSE);
358         }
359         break;
360
361     case V_BSD:         /* BSD */
362         switch (type)
363         {
364         case BOOLEAN:
365             return bool_from_termcap[idx];
366         case NUMBER:
367             return num_from_termcap[idx];
368         case STRING:
369             return str_from_termcap[idx];
370         }
371         break;
372     }
373
374     return(FALSE);      /* pacify the compiler */
375 }
376
377 static
378 void append_output (const char *src)
379 {
380         if (src == 0) {
381                 out_used = 0;
382                 append_output("");
383         } else {
384                 size_t need = strlen(src);
385                 size_t want = need + out_used + 1;
386                 if (want > out_size) {
387                         out_size += want;       /* be generous */
388                         if (outbuf == 0)
389                                 outbuf = malloc(out_size);
390                         else
391                                 outbuf = realloc(outbuf, out_size);
392                 }
393                 (void)strcpy(outbuf + out_used, src);
394                 out_used += need;
395         }
396 }
397
398 static
399 void force_wrap(void)
400 {
401         oldcol = column;
402         append_output(trailer);
403         column = INDENT;
404 }
405
406 static
407 void wrap_concat(const char *src)
408 {
409         int need = strlen(src);
410         int want = strlen(separator) + need;
411
412         if (column > INDENT
413          && column + want > width) {
414                 force_wrap();
415         }
416         append_output(src);
417         append_output(separator);
418         column += need;
419 }
420
421 #define IGNORE_SEP_TRAIL(first,last,sep_trail) \
422         if ((size_t)(last - first) > sizeof(sep_trail)-1 \
423          && !strncmp(first, sep_trail, sizeof(sep_trail)-1)) \
424                 first += sizeof(sep_trail)-2
425
426 /* Returns the nominal length of the buffer assuming it is termcap format,
427  * i.e., the continuation sequence is treated as a single character ":".
428  *
429  * There are several implementations of termcap which read the text into a
430  * fixed-size buffer.  Generally they strip the newlines from the text, but may
431  * not do it until after the buffer is read.  Also, "tc=" resolution may be
432  * expanded in the same buffer.  This function is useful for measuring the size
433  * of the best fixed-buffer implementation; the worst case may be much worse.
434  */
435 #ifdef TEST_TERMCAP_LENGTH
436 static int termcap_length(const char *src)
437 {
438         static const char pattern[] = ":\\\n\t:";
439
440         int len = 0;
441         const char *const t = src + strlen(src);
442
443         while (*src != '\0') {
444                 IGNORE_SEP_TRAIL(src, t, pattern);
445                 src++;
446                 len++;
447         }
448         return len;
449 }
450 #else
451 #define termcap_length(src) strlen(src)
452 #endif
453
454 int fmt_entry(TERMTYPE *tterm,
455                            int (*pred)(int type, int idx),
456                            bool suppress_untranslatable,
457                            bool infodump)
458 {
459 int     i, j;
460 char    buffer[MAX_TERMINFO_LENGTH];
461 int     predval, len;
462 int     num_bools = 0;
463 int     num_values = 0;
464 int     num_strings = 0;
465 bool    outcount = 0;
466
467 #define WRAP_CONCAT     \
468         wrap_concat(buffer); \
469         outcount = TRUE
470
471     len = 12;                   /* terminfo file-header */
472
473     if (pred == NULL) {
474         cur_type = tterm;
475         pred = dump_predicate;
476     }
477
478     append_output(NULL);
479     append_output(tterm->term_names);
480     append_output(separator);
481     column = out_used;
482     force_wrap();
483
484     for (j=0; j < BOOLCOUNT; j++) {
485         if (sortmode == S_NOSORT)
486             i = j;
487         else
488             i = bool_indirect[j];
489
490         if (!version_filter(BOOLEAN, i))
491             continue;
492         else if ((outform == F_LITERAL || outform == F_TERMINFO || outform == F_VARIABLE)
493                  && (OBSOLETE(bool_names[i]) && outform != F_LITERAL))
494             continue;
495
496         predval = pred(BOOLEAN, i);
497         if (predval != FAIL) {
498             (void) strcpy(buffer, bool_names[i]);
499             if (predval <= 0)
500                 (void) strcat(buffer, "@");
501             else if (i + 1 > num_bools)
502                 num_bools = i + 1;
503             WRAP_CONCAT;
504         }
505     }
506
507     if (column != INDENT)
508         force_wrap();
509
510     for (j=0; j < NUMCOUNT; j++) {
511         if (sortmode == S_NOSORT)
512             i = j;
513         else
514             i = num_indirect[j];
515
516         if (!version_filter(NUMBER, i))
517             continue;
518         else if ((outform == F_LITERAL || outform == F_TERMINFO || outform == F_VARIABLE)
519                  && (OBSOLETE(num_names[i]) && outform != F_LITERAL))
520             continue;
521
522         predval = pred(NUMBER, i);
523         if (predval != FAIL) {
524             if (tterm->Numbers[i] < 0) {
525                 sprintf(buffer, "%s@", num_names[i]);
526             } else {
527                 sprintf(buffer, "%s#%d", num_names[i], tterm->Numbers[i]);
528                 if (i + 1 > num_values)
529                     num_values = i + 1;
530             }
531             WRAP_CONCAT;
532         }
533     }
534
535     if (column != INDENT)
536         force_wrap();
537
538     len += num_bools
539         + num_values * 2
540         + strlen(tterm->term_names) + 1;
541     if (len & 1)
542         len++;
543
544     for (j=0; j < STRCOUNT; j++) {
545         if (sortmode == S_NOSORT)
546             i = j;
547         else
548             i = str_indirect[j];
549
550         if (!version_filter(STRING, i))
551             continue;
552         else if ((outform == F_LITERAL || outform == F_TERMINFO || outform == F_VARIABLE)
553                  && (OBSOLETE(str_names[i]) && outform != F_LITERAL))
554             continue;
555
556         /*
557          * Some older versions of vi want rmir/smir to be defined
558          * for ich/ich1 to work.  If they're not defined, force
559          * them to be output as defined and empty.
560          */
561         if (outform==F_TERMCAP)
562 #undef CUR
563 #define CUR tterm->
564             if (insert_character || parm_ich)
565             {
566                 if (&tterm->Strings[i] == &enter_insert_mode
567                     && enter_insert_mode == ABSENT_STRING)
568                 {
569                     (void) strcpy(buffer, "im=");
570                     goto catenate;
571                 }
572
573                 if (&tterm->Strings[i] == &exit_insert_mode
574                     && exit_insert_mode == ABSENT_STRING)
575                 {
576                     (void) strcpy(buffer, "ei=");
577                     goto catenate;
578                 }
579             }
580
581         predval = pred(STRING, i);
582         buffer[0] = '\0';
583         if (predval != FAIL) {
584             if (tterm->Strings[i] != ABSENT_STRING
585              && i + 1 > num_strings)
586                 num_strings = i + 1;
587             if (tterm->Strings[i] == ABSENT_STRING
588              || tterm->Strings[i] == CANCELLED_STRING)
589                 sprintf(buffer, "%s@", str_names[i]);
590             else if (outform == F_TERMCAP || outform == F_TCONVERR)
591             {
592                 char *srccap = expand(tterm->Strings[i]);
593                 char *cv = _nc_infotocap(str_names[i], srccap,parametrized[i]);
594
595                 if (cv == (char *)NULL)
596                 {
597                     if (outform == F_TCONVERR)
598                         sprintf(buffer, "%s=!!! %s WILL NOT CONVERT !!!", str_names[i], srccap);
599                     else if (suppress_untranslatable)
600                         continue;
601                     else
602                         sprintf(buffer, "..%s=%s", str_names[i], srccap);
603                 }
604                 else
605                     sprintf(buffer, "%s=%s", str_names[i], cv);
606                 len += strlen(tterm->Strings[i]) + 1;
607             }
608             else
609             {
610                 sprintf(buffer,"%s=%s",str_names[i],expand(tterm->Strings[i]));
611                 len += strlen(tterm->Strings[i]) + 1;
612             }
613
614         catenate:
615             WRAP_CONCAT;
616         }
617     }
618     len += num_strings * 2;
619
620     /*
621      * This piece of code should be an effective inverse of the functions
622      * postprocess_terminfo and postprocess_terminfo in parse_entry.c.
623      * Much more work should be done on this to support dumping termcaps.
624      */
625     if (tversion == V_HPUX)
626     {
627         if (memory_lock)
628         {
629             (void) sprintf(buffer, "meml=%s", memory_lock);
630             WRAP_CONCAT;
631         }
632         if (memory_unlock)
633         {
634             (void) sprintf(buffer, "memu=%s", memory_unlock);
635             WRAP_CONCAT;
636         }
637     }
638     else if (tversion == V_AIX)
639     {
640         if (acs_chars)
641         {
642             bool        box_ok = TRUE;
643             const char  *acstrans = "lqkxjmwuvtn";
644             const char  *cp;
645             char        *tp, *sp, boxchars[11];
646
647             tp = boxchars;
648             for (cp = acstrans; *cp; cp++)
649             {
650                 sp = strchr(acs_chars, *cp);
651                 if (sp)
652                     *tp++ = sp[1];
653                 else
654                 {
655                     box_ok = FALSE;
656                     break;
657                 }
658             }
659             tp[0] = '\0';
660
661             if (box_ok)
662             {
663                 (void) strcpy(buffer, "box1=");
664                 (void) strcat(buffer, expand(boxchars));
665                 WRAP_CONCAT;
666             }
667         }
668     }
669
670     /*
671      * kludge: trim off trailer to avoid an extra blank line
672      * in infocmp -u output when there are no string differences
673      */
674     if (outcount)
675     {
676         j = out_used;
677         if (j >= 2
678          && outbuf[j-1] == '\t'
679          && outbuf[j-2] == '\n') {
680             out_used -= 2;
681         } else if (j >= 4
682          && outbuf[j-1] == ':'
683          && outbuf[j-2] == '\t'
684          && outbuf[j-3] == '\n'
685          && outbuf[j-4] == '\\') {
686             out_used -= 4;
687         }
688         outbuf[out_used] = '\0';
689         column = oldcol;
690     }
691
692 #if 0
693     fprintf(stderr, "num_bools = %d\n", num_bools);
694     fprintf(stderr, "num_values = %d\n", num_values);
695     fprintf(stderr, "num_strings = %d\n", num_strings);
696     fprintf(stderr, "term_names=%s, len=%d, strlen(outbuf)=%d, outbuf=%s\n",
697             tterm->term_names, len, out_used, outbuf);
698 #endif
699     /*
700      * Here's where we use infodump to trigger a more stringent length check
701      * for termcap-translation purposes.
702      * Return the length of the raw entry, without tc= expansions,
703      * It gives an idea of which entries are deadly to even *scan past*,
704      * as opposed to *use*.
705      */
706     return(infodump ? len : termcap_length(outbuf));
707 }
708
709 int dump_entry(TERMTYPE *tterm, bool limited, int (*pred)(int type, int idx))
710 /* dump a single entry */
711 {
712     int len, critlen;
713     const char  *legend;
714     bool        infodump;
715
716     if (outform==F_TERMCAP || outform==F_TCONVERR)
717     {
718         critlen = MAX_TERMCAP_LENGTH;
719         legend = "older termcap";
720         infodump = FALSE;
721         set_obsolete_termcaps(tterm);
722     }
723     else
724     {
725         critlen = MAX_TERMINFO_LENGTH;
726         legend = "terminfo";
727         infodump = TRUE;
728     }
729
730     if (((len = fmt_entry(tterm, pred, FALSE, infodump)) > critlen) && limited)
731     {
732         (void) printf("# (untranslatable capabilities removed to fit entry within %d bytes)\n",
733                       critlen);
734         if ((len = fmt_entry(tterm, pred, TRUE, infodump)) > critlen)
735         {
736             /*
737              * We pick on sgr because it's a nice long string capability that
738              * is really just an optimization hack.
739              */
740             char *oldsgr = set_attributes;
741             set_attributes = ABSENT_STRING; 
742             (void) printf("# (sgr removed to fit entry within %d bytes)\n",
743                           critlen);
744             if ((len = fmt_entry(tterm, pred, TRUE, infodump)) > critlen)
745             {
746                 int oldversion = tversion;
747
748                 tversion = V_BSD;
749                 (void) printf("# (terminfo-only capabilities suppressed to fit entry within %d bytes)\n",
750                               critlen);
751
752                 if ((len = fmt_entry(tterm, pred, TRUE, infodump)) > critlen)
753                 {
754                     (void) fprintf(stderr,
755                                "warning: %s entry is %d bytes long\n",
756                                _nc_first_name(tterm->term_names),
757                                len);
758                     (void) printf(
759                               "# WARNING: this entry, %d bytes long, may core-dump %s libraries!\n",
760                               len, legend);
761                 }
762                 tversion = oldversion;
763             }
764             set_attributes = oldsgr;
765         }
766     }
767
768     (void) fputs(outbuf, stdout);
769     return len;
770 }
771
772 int dump_uses(const char *name, bool infodump)
773 /* dump "use=" clauses in the appropriate format */
774 {
775     char buffer[MAX_TERMINFO_LENGTH];
776
777     append_output(NULL);
778     (void)sprintf(buffer, "%s%s", infodump ? "use=" : "tc=", name);
779     wrap_concat(buffer);
780     (void) fputs(outbuf, stdout);
781     return out_used;
782 }
783
784 void compare_entry(void (*hook)(int t, int i, const char *name))
785 /* compare two entries */
786 {
787     int i, j;
788
789     (void) fputs("    comparing booleans.\n", stdout);
790     for (j=0; j < BOOLCOUNT; j++)
791     {
792         if (sortmode == S_NOSORT)
793             i = j;
794         else
795             i = bool_indirect[j];
796
797         if ((outform == F_LITERAL || outform == F_TERMINFO || outform == F_VARIABLE)
798                  && (OBSOLETE(bool_names[i]) && outform != F_LITERAL))
799             continue;
800
801         (*hook)(BOOLEAN, i, bool_names[i]);
802     }
803
804     (void) fputs("    comparing numbers.\n", stdout);
805     for (j=0; j < NUMCOUNT; j++)
806     {
807         if (sortmode == S_NOSORT)
808             i = j;
809         else
810             i = num_indirect[j];
811
812         if ((outform==F_LITERAL || outform==F_TERMINFO || outform==F_VARIABLE)
813                  && (OBSOLETE(num_names[i]) && outform != F_LITERAL))
814             continue;
815
816         (*hook)(NUMBER, i, num_names[i]);
817     }
818
819     (void) fputs("    comparing strings.\n", stdout);
820     for (j=0; j < STRCOUNT; j++)
821     {
822         if (sortmode == S_NOSORT)
823             i = j;
824         else
825             i = str_indirect[j];
826
827         if ((outform==F_LITERAL || outform==F_TERMINFO || outform==F_VARIABLE)
828                  && (OBSOLETE(str_names[i]) && outform != F_LITERAL))
829             continue;
830
831         (*hook)(STRING, i, str_names[i]);
832     }
833 }
834
835 #define NOTSET(s)       ((s) == (char *)NULL)
836
837 /*
838  * This bit of legerdemain turns all the terminfo variable names into
839  * references to locations in the arrays Booleans, Numbers, and Strings ---
840  * precisely what's needed.
841  */
842 #undef CUR
843 #define CUR tp->
844
845 static void set_obsolete_termcaps(TERMTYPE *tp)
846 {
847 #include "capdefaults.c"
848 }