4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1988 AT&T */
28 /* All Rights Reserved */
32 * captoinfo - convert a termcap description to a terminfo description
35 * captoinfo [-1vV] [-w width] [ filename ... ]
38 * Tony Hansen, January 22, 1984.
49 #define trace stderr /* send trace messages to stderr */
51 /* extra termcap variables no longer in terminfo */
54 "bs", /* Terminal can backspace with "^H" */
55 "nc", /* No correctly working carriage return (DM2500,H2000) */
56 "ns", /* Terminal is a CRT but does not scroll. */
57 "pt", /* Has hardware tabs (may need to be set with "is") */
58 "MT", /* Has meta key, alternate code. */
59 "xr", /* Return acts like ce \r \n (Delta Data) */
62 int cap_bs
= 0, cap_nc
= 1, cap_ns
= 2, cap_pt
= 3, cap_MT
= 4, cap_xr
= 5;
65 "dB", /* Number of millisec of bs delay needed */
66 "dC", /* Number of millisec of cr delay needed */
67 "dF", /* Number of millisec of ff delay needed */
68 "dN", /* Number of millisec of nl delay needed */
69 "dT", /* Number of millisec of tab delay needed */
70 "ug", /* Number of blank chars left by us or ue */
71 /* Ignore the 'kn' number. It was ill-defined and never used. */
72 "kn", /* Number of "other" keys */
75 int cap_dB
= 0, cap_dC
= 1, cap_dF
= 2, cap_dN
= 3, cap_dT
= 4, cap_ug
= 5;
79 "bc", /* Backspace if not "^H" */
80 "ko", /* Termcap entries for other non-function keys */
81 "ma", /* Arrow key map, used by vi version 2 only */
82 "nl", /* Newline character (default "\n") */
83 "rs", /* undocumented reset string, like is (info is2) */
84 /* Ignore the 'ml' and 'mu' strings. */
85 "ml", /* Memory lock on above cursor. */
86 "mu", /* Memory unlock (turn off memory lock). */
89 int cap_bc
= 0, cap_ko
= 1, cap_ma
= 2, cap_nl
= 3, cap_rs
= 4;
91 #define numelements(x) (sizeof (x)/sizeof (x[0]))
92 char oboolval
[2][numelements(oboolcodes
)];
93 short onumval
[2][numelements(onumcodes
)];
94 char *ostrval
[2][numelements(ostrcodes
)];
96 /* externs from libcurses.a */
97 extern char *boolnames
[], *boolcodes
[];
98 extern char *numnames
[], *numcodes
[];
99 extern char *strnames
[], *strcodes
[];
101 /* globals for this file */
102 char *progname
; /* argv [0], the name of the program */
103 static char *term_name
; /* the name of the terminal being worked on */
104 static int uselevel
; /* whether we're dealing with use= info */
105 static int boolcount
, /* the maximum numbers of each name array */
109 /* globals dealing with the environment */
110 extern char **environ
;
111 static char TERM
[100];
112 #if defined(SYSV) || defined(USG) /* handle both Sys Vr2 and Vr3 curses */
113 static char dirname
[BUFSIZ
];
115 #include <sys/param.h>
116 static char dirname
[MAXPATHLEN
];
117 #endif /* SYSV || USG */
118 static char TERMCAP
[BUFSIZ
+15];
119 static char *newenviron
[] = { &TERM
[0], &TERMCAP
[0], 0 };
122 static char *boolval
[2]; /* dynamic array of boolean values */
123 static short *numval
[2]; /* dynamic array of numeric values */
124 static char **strval
[2]; /* dynamic array of string pointers */
127 static char *capbuffer
; /* string table, pointed at by strval */
128 static char *nextstring
; /* pointer into string table */
129 static char *bp
; /* termcap raw string table */
130 static char *buflongname
; /* place to copy the long names */
133 static int verbose
= 0; /* debugging printing level */
134 static int copycomments
= 0; /* copy comments from tercap source */
136 #define ispadchar(c) (isdigit(c) || (c) == '.' || (c) == '*')
138 static void getlongname(void);
139 static void handleko(void);
140 static void handlema(void);
141 static void print_no_use_entry(void);
142 static void print_use_entry(char *);
143 static void captoinfo(void);
144 static void use_etc_termcap(void);
145 static void initdirname(void);
146 static void setfilename(char *);
147 static void setterm_name(void);
148 static void use_file(char *);
149 static void sorttable(char *[], char *[]);
150 static void inittables(void);
153 * Verify that the names given in the termcap entry are all valid.
157 capsearch(char *codes
[], char *ocodes
[], char *cap
)
159 for (; *codes
; codes
++)
160 if (((*codes
)[0] == cap
[0]) && ((*codes
)[1] == cap
[1]))
163 for (; *ocodes
; ocodes
++)
164 if (((*ocodes
)[0] == cap
[0]) && ((*ocodes
)[1] == cap
[1]))
174 enum { tbool
, tnum
, tstr
, tcancel
, tunknown
} type
;
178 while (*tbuf
== '\t' || *tbuf
== ' ' || *tbuf
== ':')
184 /* commented out entry? */
187 (void) fprintf(trace
, "termcap string '%c%c' "
188 "commented out.\n", tbuf
[1], tbuf
[2]);
189 if (!capsearch(boolcodes
, oboolcodes
, tbuf
+ 1) &&
190 !capsearch(numcodes
, onumcodes
, tbuf
+ 1) &&
191 !capsearch(strcodes
, ostrcodes
, tbuf
+ 1))
192 (void) fprintf(stderr
,
193 "%s: TERM=%s: commented out code '%.2s' "
194 "is unknown.\n", progname
, term_name
,
200 (void) fprintf(trace
, "looking at termcap string "
204 case ':': case '\0': type
= tbool
; break;
205 case '#': type
= tnum
; break;
206 case '=': type
= tstr
; break;
207 case '@': type
= tcancel
; break;
209 (void) fprintf(stderr
,
210 "%s: TERM=%s: unknown type given for the "
211 "termcap code '%.2s'.\n", progname
,
217 (void) fprintf(trace
, "type of '%.2s' is %s.\n", tbuf
,
218 (type
== tbool
) ? "boolean" :
219 (type
== tnum
) ? "numeric" :
220 (type
= tstr
) ? "string" :
221 (type
= tcancel
) ? "canceled" : "unknown");
223 /* look for the name in bools */
224 if (capsearch(boolcodes
, oboolcodes
, tbuf
)) {
225 if (type
!= tbool
&& type
!= tcancel
)
226 (void) fprintf(stderr
,
227 "%s: TERM=%s: wrong type given for the "
228 "boolean termcap code '%.2s'.\n", progname
,
233 /* look for the name in nums */
234 if (capsearch(numcodes
, onumcodes
, tbuf
)) {
235 if (type
!= tnum
&& type
!= tcancel
)
236 (void) fprintf(stderr
,
237 "%s: TERM=%s: wrong type given for the "
238 "numeric termcap code '%.2s'.\n", progname
,
243 /* look for the name in strs */
244 if (capsearch(strcodes
, ostrcodes
, tbuf
)) {
245 if (type
!= tstr
&& type
!= tcancel
)
246 (void) fprintf(stderr
,
247 "%s: TERM=%s: wrong type given for the "
248 "string termcap code '%.2s'.\n", progname
,
253 (void) fprintf(stderr
,
254 "%s: TERM=%s: the %s termcap code '%.2s' is not a valid "
255 "name.\n", progname
, term_name
,
256 (type
== tbool
) ? "boolean" :
257 (type
== tnum
) ? "numeric" :
258 (type
= tstr
) ? "string" :
259 (type
= tcancel
) ? "canceled" : "(unknown type)", tbuf
);
264 * Fill up the termcap tables.
271 /* Retrieve the termcap entry. */
272 if ((tret
= otgetent(bp
, term_name
)) != 1) {
273 (void) fprintf(stderr
,
274 "%s: TERM=%s: tgetent failed with return code %d (%s).\n",
275 progname
, term_name
, tret
,
276 (tret
== 0) ? "non-existent or invalid entry" :
277 (tret
== -1) ? "cannot open $TERMCAP" : "unknown reason");
282 (void) fprintf(trace
, "bp=");
283 (void) cpr(trace
, bp
);
284 (void) fprintf(trace
, ".\n");
290 /* Retrieve the values that are in terminfo. */
293 for (i
= 0; boolcodes
[i
]; i
++) {
294 boolval
[uselevel
][i
] = otgetflag(boolcodes
[i
]);
296 (void) fprintf(trace
, "boolcodes=%s, ", boolcodes
[i
]);
297 (void) fprintf(trace
, "boolnames=%s, ", boolnames
[i
]);
298 (void) fprintf(trace
,
299 "flag=%d.\n", boolval
[uselevel
][i
]);
304 for (i
= 0; numcodes
[i
]; i
++) {
305 numval
[uselevel
][i
] = otgetnum(numcodes
[i
]);
307 (void) fprintf(trace
, "numcodes=%s, ", numcodes
[i
]);
308 (void) fprintf(trace
, "numnames=%s, ", numnames
[i
]);
309 (void) fprintf(trace
, "num=%d.\n", numval
[uselevel
][i
]);
314 nextstring
= capbuffer
;
317 for (i
= 0; strcodes
[i
]; i
++) {
318 strval
[uselevel
][i
] = otgetstr(strcodes
[i
], &nextstring
);
320 (void) fprintf(trace
, "strcodes=%s, ", strcodes
[i
]);
321 (void) fprintf(trace
, "strnames=%s, ", strnames
[i
]);
322 if (strval
[uselevel
][i
]) {
323 (void) fprintf(trace
, "str=");
324 tpr(trace
, strval
[uselevel
][i
]);
325 (void) fprintf(trace
, ".\n");
328 (void) fprintf(trace
, "str=NULL.\n");
330 /* remove zero length strings */
331 if (strval
[uselevel
][i
] && (strval
[uselevel
][i
][0] == '\0')) {
332 (void) fprintf(stderr
,
333 "%s: TERM=%s: cap %s (info %s) is NULL: REMOVED\n",
334 progname
, term_name
, strcodes
[i
], strnames
[i
]);
335 strval
[uselevel
][i
] = NULL
;
339 /* Retrieve the values not found in terminfo anymore. */
342 for (i
= 0; oboolcodes
[i
]; i
++) {
343 oboolval
[uselevel
][i
] = otgetflag(oboolcodes
[i
]);
345 (void) fprintf(trace
, "oboolcodes=%s, ",
347 (void) fprintf(trace
, "flag=%d.\n",
348 oboolval
[uselevel
][i
]);
353 for (i
= 0; onumcodes
[i
]; i
++) {
354 onumval
[uselevel
][i
] = otgetnum(onumcodes
[i
]);
356 (void) fprintf(trace
, "onumcodes=%s, ", onumcodes
[i
]);
357 (void) fprintf(trace
, "num=%d.\n",
358 onumval
[uselevel
][i
]);
363 for (i
= 0; ostrcodes
[i
]; i
++) {
364 ostrval
[uselevel
][i
] = otgetstr(ostrcodes
[i
], &nextstring
);
366 (void) fprintf(trace
, "ostrcodes=%s, ", ostrcodes
[i
]);
367 if (ostrval
[uselevel
][i
]) {
368 (void) fprintf(trace
, "ostr=");
369 tpr(trace
, ostrval
[uselevel
][i
]);
370 (void) fprintf(trace
, ".\n");
373 (void) fprintf(trace
, "ostr=NULL.\n");
375 /* remove zero length strings */
376 if (ostrval
[uselevel
][i
] && (ostrval
[uselevel
][i
][0] == '\0')) {
377 (void) fprintf(stderr
,
378 "%s: TERM=%s: cap %s (no terminfo name) is NULL: "
379 "REMOVED\n", progname
, term_name
, ostrcodes
[i
]);
380 ostrval
[uselevel
][i
] = NULL
;
387 * This routine copies the set of names from the termcap entry into
388 * a separate buffer, getting rid of the old obsolete two character
394 char *b
= &bp
[0], *l
= buflongname
;
396 /* Skip the two character name */
400 /* Copy the rest of the names */
401 while (*b
&& *b
!= ':')
406 (void) fprintf(stderr
, "%s: obsolete 2 character name "
407 "'%2.2s' removed.\n", progname
, bp
);
408 (void) fprintf(stderr
, "\tsynonyms are: '%s'\n", buflongname
);
413 * Return the value of the termcap string 'capname' as stored in our list.
416 getcapstr(char *capname
)
421 (void) fprintf(trace
, "looking for termcap value of %s.\n",
424 /* Check the old termcap list. */
425 for (i
= 0; ostrcodes
[i
]; i
++)
426 if (strcmp(ostrcodes
[i
], capname
) == 0) {
428 (void) fprintf(trace
, "\tvalue is:");
429 tpr(trace
, ostrval
[uselevel
][i
]);
430 (void) fprintf(trace
, ".\n");
432 return (ostrval
[uselevel
][i
]);
436 (void) fprintf(trace
, "termcap name '%s' not found in "
437 "ostrcodes.\n", capname
);
439 /* Check the terminfo list. */
440 for (i
= 0; strcodes
[i
]; i
++)
441 if (strcmp(strcodes
[i
], capname
) == 0) {
443 (void) fprintf(trace
, "\tvalue is:");
444 tpr(trace
, strval
[uselevel
][i
]);
445 (void) fprintf(trace
, ".\n");
447 return (strval
[uselevel
][i
]);
450 (void) fprintf(stderr
, "%s: TERM=%s: termcap name '%s' not found.\n",
451 progname
, term_name
, capname
);
453 return ((char *)NULL
);
457 * Search for a name in the given table and
459 * Someday I'll redo this to use bsearch().
463 search(char *names
[], int max
, char *infoname
)
467 for (i
= 0; names
[i
] != NULL
; i
++)
468 if (strcmp(names
[i
], infoname
) == 0)
471 #else /* this doesn't work for some reason */
474 bret
= (char **)bsearch(infoname
, (char *)names
, max
,
475 sizeof (char *), strcmp
);
476 (void) fprintf(trace
, "search looking for %s.\n", infoname
);
477 (void) fprintf(trace
, "base=%#x, bret=%#x, nel=%d.\n", names
,
479 (void) fprintf(trace
, "returning %d.\n", bret
== NULL
? -1 :
484 return (bret
- names
);
489 * return the value of the terminfo string 'infoname'
492 getinfostr(char *infoname
)
497 (void) fprintf(trace
, "looking for terminfo value of %s.\n",
500 i
= search(strnames
, strcount
, infoname
);
503 (void) fprintf(trace
, "\tvalue is:");
504 tpr(trace
, strval
[uselevel
][i
]);
505 (void) fprintf(trace
, ".\n");
507 return (strval
[uselevel
][i
]);
511 (void) fprintf(trace
, "terminfo name '%s' not found.\n",
514 return ((char *)NULL
);
518 * Replace the value stored for the terminfo boolean
519 * capability 'infoname' with the newvalue.
522 putbool(char *infoname
, int newvalue
)
527 (void) fprintf(trace
, "changing value for %s to %d.\n",
530 i
= search(boolnames
, boolcount
, infoname
);
533 (void) fprintf(trace
, "value was: %d.\n",
534 boolval
[uselevel
][i
]);
536 boolval
[uselevel
][i
] = newvalue
;
540 (void) fprintf(stderr
, "%s: TERM=%s: the boolean name '%s' was not "
541 "found!\n", progname
, term_name
, infoname
);
545 * Replace the value stored for the terminfo number
546 * capability 'infoname' with the newvalue.
549 putnum(char *infoname
, int newvalue
)
554 (void) fprintf(trace
, "changing value for %s to %d.\n",
557 i
= search(numnames
, numcount
, infoname
);
560 (void) fprintf(trace
, "value was: %d.\n",
561 numval
[uselevel
][i
]);
563 numval
[uselevel
][i
] = newvalue
;
567 (void) fprintf(stderr
, "%s: TERM=%s: the numeric name '%s' was not "
569 progname
, term_name
, infoname
);
573 * replace the value stored for the terminfo string capability 'infoname'
577 putstr(char *infoname
, char *newvalue
)
582 (void) fprintf(trace
, "changing value for %s to ", infoname
);
583 tpr(trace
, newvalue
);
584 (void) fprintf(trace
, ".\n");
587 i
= search(strnames
, strcount
, infoname
);
590 (void) fprintf(trace
, "value was:");
591 tpr(trace
, strval
[uselevel
][i
]);
592 (void) fprintf(trace
, ".\n");
594 strval
[uselevel
][i
] = nextstring
;
596 *nextstring
++ = *newvalue
++;
597 *nextstring
++ = '\0';
601 (void) fprintf(stderr
, "%s: TERM=%s: the string name '%s' was not "
603 progname
, term_name
, infoname
);
607 * Add in extra delays if they are not recorded already.
608 * This is done before the padding information has been modified by
609 * changecalculations() below, so the padding information, if there
610 * already, is still at the beginning of the string in termcap format.
613 addpadding(int cappadding
, char *infostr
)
616 char tempbuffer
[100];
618 /* Is there padding to add? */
620 /* Is there a string to add it to? */
621 if (cap
= getinfostr(infostr
))
622 /* Is there any padding info already? */
623 if (ispadchar(*cap
)) {
625 /* Assume that the padding info that is there is correct. */
627 /* Add the padding at the end of the present string. */
628 (void) snprintf(tempbuffer
, sizeof (tempbuffer
),
629 "%s$<%d>", cap
, cappadding
);
630 putstr(infostr
, tempbuffer
);
632 /* Create a new string that only has the padding. */
633 (void) sprintf(tempbuffer
, "$<%d>", cappadding
);
634 putstr(infostr
, tempbuffer
);
644 "bs", "kbs", /* special addition */
656 "im", "kich1", /* special addition */
671 * Work with the ko string. It is a comma separated list of keys for which
672 * the keyboard has a key by the same name that emits the same sequence.
673 * For example, ko = dc, im, ei means that there are keys called
674 * delete-character, enter-insert-mode and exit-insert-mode on the keyboard,
675 * and they emit the same sequences as specified in the dc, im and ei
687 (void) fprintf(trace
, "working on termcap ko string.\n");
689 if (ostrval
[uselevel
][cap_ko
] == NULL
)
693 for (i
= 0; ostrval
[uselevel
][cap_ko
][i
] != '\0'; ) {
694 /* isolate the termcap name */
695 capname
[0] = ostrval
[uselevel
][cap_ko
][i
++];
696 if (ostrval
[uselevel
][cap_ko
][i
] == '\0')
698 capname
[1] = ostrval
[uselevel
][cap_ko
][i
++];
699 if (ostrval
[uselevel
][cap_ko
][i
] == ',')
703 (void) fprintf(trace
, "key termcap name is '");
705 (void) fprintf(trace
, "'.\n");
708 /* match it up into our list */
710 for (j
= 0; !found
&& ko_map
[j
].keyedinfoname
!= NULL
; j
++) {
712 (void) fprintf(trace
, "looking at termcap name %s.\n",
714 if (capname
[0] == ko_map
[j
].capname
[0] &&
715 capname
[1] == ko_map
[j
].capname
[1]) {
716 /* add the value to our database */
717 if ((capstr
= getcapstr(capname
)) != NULL
) {
719 (ko_map
[j
].keyedinfoname
);
720 if (infostr
== NULL
) {
721 /* skip any possible padding */
723 while (ispadchar(*capstr
))
725 putstr(ko_map
[j
].keyedinfoname
, capstr
);
727 if (strcmp(capstr
, infostr
) != 0) {
728 (void) fprintf(stderr
,
729 "%s: TERM=%s: a function "
731 "specified with the "
735 (void) fprintf(stderr
,
736 ", but it already has the "
738 tpr(stderr
, infostr
);
739 (void) fprintf(stderr
, "'.\n");
747 (void) fprintf(stderr
, "%s: TERM=%s: the unknown "
748 "termcap name '%s' was\n", progname
, term_name
,
750 (void) fprintf(stderr
, "specified in the 'ko' "
751 "termcap capability.\n");
756 #define CONTROL(x) ((x) & 037)
762 CONTROL('J'), "kcud1", /* down */
763 CONTROL('N'), "kcud1",
765 CONTROL('P'), "kcuu1", /* up */
767 'h', "kcub1", /* left */
768 CONTROL('H'), "kcub1",
769 ' ', "kcuf1", /* right */
771 'H', "khome", /* home */
772 CONTROL('L'), "kclr", /* clear */
777 * Work with the ma string. This is a list of pairs of characters.
778 * The first character is the what a function key sends. The second
779 * character is the equivalent vi function that should be done when
780 * it receives that character. Note that only function keys that send
781 * a single character could be defined by this list.
785 prchar(FILE *stream
, int c
)
790 (void) fprintf(stream
, "%s", iexpand(xbuf
));
802 (void) fprintf(trace
, "working on termcap ma string.\n");
804 if (ostrval
[uselevel
][cap_ma
] == NULL
)
808 for (i
= 0; ostrval
[uselevel
][cap_ma
][i
] != '\0'; ) {
809 /* isolate the key's value */
810 cap
[0] = ostrval
[uselevel
][cap_ma
][i
++];
812 (void) fprintf(trace
, "key value is '");
814 (void) fprintf(trace
, "'.\n");
817 if (ostrval
[uselevel
][cap_ma
][i
] == '\0')
820 /* isolate the vi key name */
821 vichar
= ostrval
[uselevel
][cap_ma
][i
++];
823 (void) fprintf(trace
, "the vi key is '");
824 prchar(trace
, vichar
);
825 (void) fprintf(trace
, "'.\n");
828 /* match up the vi name in our list */
830 for (j
= 0; !found
&& ma_map
[j
].keyedinfoname
!= NULL
; j
++) {
832 (void) fprintf(trace
, "looking at vi "
834 prchar(trace
, ma_map
[j
].vichar
);
835 (void) fprintf(trace
, "'\n");
837 if (vichar
== ma_map
[j
].vichar
) {
838 infostr
= getinfostr(ma_map
[j
].keyedinfoname
);
840 putstr(ma_map
[j
].keyedinfoname
, cap
);
841 else if (strcmp(cap
, infostr
) != 0) {
842 (void) fprintf(stderr
, "%s: TERM=%s: "
843 "the vi character '", progname
,
845 prchar(stderr
, vichar
);
846 (void) fprintf(stderr
,
847 "' (info '%s') has the value '",
848 ma_map
[j
].keyedinfoname
);
849 tpr(stderr
, infostr
);
850 (void) fprintf(stderr
, "', but 'ma' "
852 prchar(stderr
, cap
[0]);
853 (void) fprintf(stderr
, "'.\n");
860 (void) fprintf(stderr
, "%s: the unknown vi key '",
862 prchar(stderr
, vichar
);
863 (void) fprintf(stderr
, "' was\n");
864 (void) fprintf(stderr
, "specified in the 'ma' termcap "
871 * Many capabilities were defaulted in termcap which must now be explicitly
872 * given. We'll assume that the defaults are in effect for this terminal.
881 (void) fprintf(trace
, "assigning defaults.\n");
883 /* cr was assumed to be ^M, unless nc was given, */
884 /* which meant it could not be done. */
885 /* Also, xr meant that ^M acted strangely. */
886 if ((getinfostr("cr") == NULL
) && !oboolval
[uselevel
][cap_nc
] &&
887 !oboolval
[uselevel
][cap_xr
])
888 if ((cap
= getcapstr("cr")) == NULL
)
893 /* cursor down was assumed to be ^J if not specified by nl */
894 if (getinfostr("cud1") == NULL
)
895 if (ostrval
[uselevel
][cap_nl
] != NULL
)
896 putstr("cud1", ostrval
[uselevel
][cap_nl
]);
898 putstr("cud1", "\n");
900 /* ind was assumed to be ^J, unless ns was given, */
901 /* which meant it could not be done. */
902 if ((getinfostr("ind") == NULL
) && !oboolval
[uselevel
][cap_ns
])
903 if (ostrval
[uselevel
][cap_nl
] == NULL
)
906 putstr("ind", ostrval
[uselevel
][cap_nl
]);
908 /* bel was assumed to be ^G */
909 if (getinfostr("bel") == NULL
)
910 putstr("bel", "\07");
912 /* if bs, then could do backspacing, */
913 /* with value of bc, default of ^H */
914 if ((getinfostr("cub1") == NULL
) && oboolval
[uselevel
][cap_bs
])
915 if (ostrval
[uselevel
][cap_bc
] != NULL
)
916 putstr("cub1", ostrval
[uselevel
][cap_bc
]);
918 putstr("cub1", "\b");
920 /* default xon to true */
921 if (!otgetflag("xo"))
924 /* if pt, then hardware tabs are allowed, */
925 /* with value of ta, default of ^I */
926 if ((getinfostr("ht") == NULL
) && oboolval
[uselevel
][cap_pt
])
927 if ((cap
= getcapstr("ta")) == NULL
)
932 /* The dX numbers are now stored as padding */
933 /* in the appropriate terminfo string. */
934 addpadding(onumval
[uselevel
][cap_dB
], "cub1");
935 addpadding(onumval
[uselevel
][cap_dC
], "cr");
936 addpadding(onumval
[uselevel
][cap_dF
], "ff");
937 addpadding(onumval
[uselevel
][cap_dN
], "cud1");
938 addpadding(onumval
[uselevel
][cap_dT
], "ht");
940 /* The ug and sg caps were essentially identical, */
941 /* so ug almost never got used. We set sg from ug */
942 /* if it hasn't already been set. */
943 if (onumval
[uselevel
][cap_ug
] >= 0 && (sg
= otgetnum("sg")) < 0)
944 putnum("xmc", onumval
[uselevel
][cap_ug
]);
945 else if ((onumval
[uselevel
][cap_ug
] >= 0) &&
946 (sg
>= 0) && (onumval
[uselevel
][cap_ug
] != sg
))
947 (void) fprintf(stderr
,
948 "%s: TERM=%s: Warning: termcap sg and ug had different "
949 "values (%d<->%d).\n", progname
, term_name
, sg
,
950 onumval
[uselevel
][cap_ug
]);
952 /* The MT boolean was never really part of termcap, */
953 /* but we can check for it anyways. */
954 if (oboolval
[uselevel
][cap_MT
] && !otgetflag("km"))
957 /* the rs string was renamed r2 (info rs2) */
958 if ((ostrval
[uselevel
][cap_rs
] != NULL
) &&
959 (ostrval
[uselevel
][cap_rs
][0] != NULL
))
960 putstr("rs2", ostrval
[uselevel
][cap_rs
]);
966 #define caddch(x) *to++ = (x)
969 * add the string to the string table
972 caddstr(char *to
, char *str
)
979 /* If there is no padding info or parmed strings, */
980 /* then we do not need to copy the string. */
982 needscopying(char *string
)
984 /* any string at all? */
988 /* any padding info? */
989 if (ispadchar(*string
))
992 /* any parmed info? */
994 if (*string
++ == '%')
1001 * Certain manipulations of the stack require strange manipulations of the
1002 * values that are on the stack. To handle these, we save the values of the
1003 * parameters in registers at the very beginning and make the changes in
1004 * the registers. We don't want to do this in the general case because of the
1005 * potential performance loss.
1008 fancycap(char *string
)
1013 if (*string
++ == '%') {
1015 /* These manipulate just the top value on */
1016 /* the stack, so we only have to do */
1017 /* something strange if a %r follows. */
1018 case '>': case 'B': case 'D':
1021 /* If the parm has already been been */
1022 /* pushed onto the stack by %>, then we */
1023 /* can not reverse the parms and must get */
1024 /* them from the registers. */
1029 /* This manipulates both parameters, so we */
1030 /* cannot just do one and leave the value */
1031 /* on the stack like we can with %>, */
1042 * Change old style of doing calculations to the new stack style.
1043 * Note that this will not necessarily produce the most efficient string,
1047 changecalculations()
1050 char *from
, *to
= nextstring
;
1052 int parmset
, parmsaved
;
1053 char padding
[100], *saveto
;
1055 for (i
= 0; strnames
[i
]; i
++)
1056 if (needscopying(strval
[uselevel
][i
])) {
1058 (void) fprintf(trace
, "%s needs copying, "
1059 "was:", strnames
[i
]);
1060 tpr(trace
, strval
[uselevel
][i
]);
1061 (void) fprintf(trace
, ".\n");
1064 from
= strval
[uselevel
][i
];
1065 strval
[uselevel
][i
] = to
;
1069 /* Handle padding information. Save it so that it can be */
1070 /* placed at the end of the string where it should */
1071 /* have been in the first place. */
1072 if (ispadchar(*from
)) {
1075 to
= caddstr(to
, "$<");
1076 while (isdigit(*from
) || *from
== '.')
1086 if (fancycap(from
)) {
1087 to
= caddstr(to
, "%p1%Pa%p2%Pb");
1089 (void) fprintf(stderr
,
1090 "%s: TERM=%s: Warning: the string "
1091 "produced for '%s' may be inefficient.\n",
1092 progname
, term_name
, strnames
[i
]);
1093 (void) fprintf(stderr
, "It should be "
1094 "looked at by hand.\n");
1098 while ((ch
= *from
++) != '\0')
1102 switch (ch
= *from
++) {
1103 case '.': /* %. -> %p1%c */
1104 case 'd': /* %d -> %p1%d */
1105 case '2': /* %2 -> %p1%2.2d */
1106 case '3': /* %3 -> %p1%3.3d */
1108 /* %+x -> %p1%'x'%+%c */
1111 /* %>xy -> %p1%Pc%?%'x'%> */
1113 /* if current value > x, then add y. */
1118 /* (16*(x/10))+(x%10) */
1120 /* (Adds Regent 100) */
1123 /* %D: Reverse coding */
1130 to
= caddstr(to
, "%g");
1131 if (currentparm
== 1)
1136 to
= caddstr(to
, "%p");
1137 if (currentparm
== 1)
1142 currentparm
= 3 - currentparm
;
1146 to
= caddstr(to
, "%c");
1149 to
= caddstr(to
, "%d");
1152 #ifdef USG /* Vr2==USG, Vr3==SYSV. Use %02d for Vr2, %2.2d for Vr3 */
1159 #endif /* USG vs. SYSV */
1164 to
= caddstr(to
, "%'");
1182 "%Pc%gc%{10}%/%{16}%*%gc%{10}%m%+");
1188 "%Pc%gc%gc%{16}%m%{2}%*%-");
1194 /* %r reverses current parameter */
1196 currentparm
= 3 - currentparm
;
1199 /* %n: exclusive-or row AND column */
1200 /* with 0140, 96 decimal, no output */
1201 /* (Datamedia 2500, Exidy Sorceror) */
1209 /* assume %x means %x */
1210 /* this includes %i and %% */
1215 to
= caddstr(to
, padding
);
1219 (void) fprintf(trace
, "and has become:");
1220 tpr(trace
, strval
[uselevel
][i
]);
1221 (void) fprintf(trace
, ".\n");
1228 print_no_use_entry(void)
1232 pr_heading("", buflongname
);
1235 for (i
= 0; boolcodes
[i
]; i
++)
1237 pr_boolean(boolnames
[i
], (char *)0, (char *)0, 1);
1242 for (i
= 0; numcodes
[i
]; i
++)
1243 if (numval
[0][i
] > -1)
1244 pr_number(numnames
[i
], (char *)0, (char *)0,
1250 for (i
= 0; strcodes
[i
]; i
++)
1252 pr_string(strnames
[i
], (char *)0, (char *)0,
1259 print_use_entry(char *usename
)
1263 pr_heading("", buflongname
);
1266 for (i
= 0; boolcodes
[i
]; i
++)
1267 if (boolval
[0][i
] && !boolval
[1][i
])
1268 pr_boolean(boolnames
[i
], (char *)0, (char *)0, 1);
1269 else if (!boolval
[0][i
] && boolval
[1][i
])
1270 pr_boolean(boolnames
[i
], (char *)0, (char *)0, -1);
1275 for (i
= 0; numcodes
[i
]; i
++)
1276 if ((numval
[0][i
] > -1) && (numval
[0][i
] != numval
[1][i
]))
1277 pr_number(numnames
[i
], (char *)0, (char *)0,
1279 else if ((numval
[0] [i
] == -1) && (numval
[1] [i
] > -1))
1280 pr_number(numnames
[i
], (char *)0, (char *)0, -1);
1285 for (i
= 0; strcodes
[i
]; i
++)
1286 /* print out str[0] if: */
1287 /* str[0] != NULL and str[1] == NULL, or str[0] != str[1] */
1288 if (strval
[0][i
] && ((strval
[1][i
] == NULL
) ||
1289 (strcmp(strval
[0][i
], strval
[1][i
]) != 0)))
1290 pr_string(strnames
[i
], (char *)0, (char *)0,
1292 /* print out @ if str[0] == NULL and str[1] != NULL */
1293 else if (strval
[0][i
] == NULL
&& strval
[1][i
] != NULL
)
1294 pr_string(strnames
[i
], (char *)0, (char *)0,
1299 (void) printf("\tuse=%s,\n", usename
);
1308 if (term_name
== NULL
) {
1309 (void) fprintf(stderr
, "%s: Null term_name given.\n",
1315 (void) fprintf(trace
, "changing cap to info, TERM=%s.\n",
1319 if (filltables() == 0)
1323 changecalculations();
1324 if (TLHtcfound
!= 0) {
1327 (void) fprintf(trace
, "use= found, %s uses %s.\n",
1328 term_name
, TLHtcname
);
1329 (void) strcpy(usename
, TLHtcname
);
1330 sterm_name
= term_name
;
1331 term_name
= usename
;
1332 if (filltables() == 0)
1335 changecalculations();
1336 term_name
= sterm_name
;
1337 print_use_entry(usename
);
1339 print_no_use_entry();
1343 #include <signal.h> /* use this file to determine if this is SVR4.0 system */
1346 use_etc_termcap(void)
1350 (void) fprintf(trace
, "reading from /usr/share/lib/termcap\n");
1352 (void) fprintf(trace
, "reading from /etc/termcap\n");
1353 #endif /* SIGSTOP */
1354 term_name
= getenv("TERM");
1361 #if defined(SYSV) || defined(USG) /* handle both Sys Vr2 and Vr3 curses */
1362 (void) getcwd(dirname
, BUFSIZ
-2);
1364 (void) getwd(dirname
);
1365 #endif /* SYSV || USG */
1367 (void) fprintf(trace
, "current directory name=%s.\n", dirname
);
1368 environ
= newenviron
;
1372 setfilename(char *capfile
)
1374 if (capfile
[0] == '/')
1375 (void) snprintf(TERMCAP
, sizeof (TERMCAP
),
1376 "TERMCAP=%s", capfile
);
1378 (void) snprintf(TERMCAP
, sizeof (TERMCAP
),
1379 "TERMCAP=%s/%s", dirname
, capfile
);
1381 (void) fprintf(trace
, "setting the environment for %s.\n",
1389 (void) fprintf(trace
, "setting the environment "
1390 "for TERM=%s.\n", term_name
);
1391 (void) snprintf(TERM
, sizeof (TERM
), "TERM=%s", term_name
);
1394 /* Look at the current line to see if it is a list of names. */
1395 /* If it is, return the first name in the list, else NULL. */
1396 /* As a side-effect, comment lines and blank lines */
1397 /* are copied to standard output. */
1400 getterm_name(char *line
)
1402 char *lineptr
= line
;
1405 (void) fprintf(trace
, "extracting name from '%s'.\n", line
);
1407 /* Copy comment lines out. */
1410 (void) printf("%s", line
);
1412 /* Blank lines get copied too. */
1413 else if (isspace (*line
)) {
1415 for (; *lineptr
; lineptr
++)
1416 if (!isspace(*lineptr
))
1418 if (*lineptr
== '\0')
1419 (void) printf("\n");
1423 for (; *lineptr
; lineptr
++)
1424 if (*lineptr
== '|' || *lineptr
== ':') {
1427 (void) fprintf(trace
,
1428 "returning %s.\n", line
);
1432 (void) fprintf(trace
, "returning NULL.\n");
1437 use_file(char *filename
)
1440 char buffer
[BUFSIZ
];
1443 (void) fprintf(trace
, "reading from %s.\n", filename
);
1445 if ((termfile
= fopen(filename
, "r")) == NULL
) {
1446 (void) fprintf(stderr
, "%s: cannot open %s for reading.\n",
1447 progname
, filename
);
1452 setfilename(filename
);
1454 while (fgets(buffer
, BUFSIZ
, termfile
) != NULL
) {
1455 if ((term_name
= getterm_name(buffer
)) != NULL
) {
1463 * Sort a name and code table pair according to the name table.
1464 * Use a simple bubble sort for now. Too bad I can't call qsort(3).
1465 * At least I only have to do it once for each table.
1468 sorttable(char *nametable
[], char *codetable
[])
1473 for (i
= 0; nametable
[i
]; i
++)
1474 for (j
= 0; j
< i
; j
++)
1475 if (strcmp(nametable
[i
], nametable
[j
]) < 0) {
1477 nametable
[i
] = nametable
[j
];
1480 codetable
[i
] = codetable
[j
];
1486 * Initialize and sort the name and code tables. Allocate space for the
1494 for (i
= 0; boolnames
[i
]; i
++)
1496 boolval
[0] = (char *)malloc(i
* sizeof (char));
1497 boolval
[1] = (char *)malloc(i
* sizeof (char));
1499 sorttable(boolnames
, boolcodes
);
1501 for (i
= 0; numcodes
[i
]; i
++)
1503 numval
[0] = (short *)malloc(i
* sizeof (short));
1504 numval
[1] = (short *)malloc(i
* sizeof (short));
1506 sorttable(numnames
, numcodes
);
1508 for (i
= 0; strcodes
[i
]; i
++)
1510 strval
[0] = (char **)malloc(i
* sizeof (char *));
1511 strval
[1] = (char **)malloc(i
* sizeof (char *));
1513 sorttable(strnames
, strcodes
);
1517 main(int argc
, char **argv
)
1520 char _capbuffer
[8192];
1521 char _bp
[TBUFSIZE
];
1522 char _buflongname
[128];
1524 capbuffer
= &_capbuffer
[0];
1526 buflongname
= &_buflongname
[0];
1529 while ((c
= getopt(argc
, argv
, "1vVw:")) != EOF
)
1535 pr_width(atoi(optarg
));
1541 (void) printf("%s: version %s\n", progname
,
1542 "@(#)curses:screen/captoinfo.c 1.12");
1543 (void) fflush(stdout
);
1545 /* FALLTHROUGH (not really) */
1547 (void) fprintf(stderr
,
1548 "usage: %s [-1Vv] [-w width] "
1549 "[filename ...]\n", progname
);
1550 (void) fprintf(stderr
, "\t-1\tsingle column "
1552 (void) fprintf(stderr
,
1553 "\t-v\tverbose debugging output\n");
1554 (void) fprintf(stderr
,
1555 "\t-V\tprint program version\n");
1560 pr_init(pr_terminfo
);
1567 for (; optind
< argc
; optind
++)
1568 use_file(argv
[optind
]);
1574 /* fake out the modules in print.c so we don't have to load in */
1575 /* cexpand.c and infotocap.c */
1578 cpr(FILE *stream
, char *string
)