8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / captoinfo / captoinfo.c
blobfc26e626d6b0e5f8befa32f7ce4d594a4f217216
1 /*
2 * CDDL HEADER START
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
7 * with the License.
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]
20 * CDDL HEADER END
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 */
30 #pragma ident "%Z%%M% %I% %E% SMI"
33 * NAME
34 * captoinfo - convert a termcap description to a terminfo description
36 * SYNOPSIS
37 * captoinfo [-1vV] [-w width] [ filename ... ]
39 * AUTHOR
40 * Tony Hansen, January 22, 1984.
43 #include "curses.h"
44 #include <ctype.h>
45 #include <stdlib.h>
46 #include <unistd.h>
47 #include <string.h>
48 #include "otermcap.h"
49 #include "print.h"
51 #define trace stderr /* send trace messages to stderr */
53 /* extra termcap variables no longer in terminfo */
54 char *oboolcodes[] =
56 "bs", /* Terminal can backspace with "^H" */
57 "nc", /* No correctly working carriage return (DM2500,H2000) */
58 "ns", /* Terminal is a CRT but does not scroll. */
59 "pt", /* Has hardware tabs (may need to be set with "is") */
60 "MT", /* Has meta key, alternate code. */
61 "xr", /* Return acts like ce \r \n (Delta Data) */
64 int cap_bs = 0, cap_nc = 1, cap_ns = 2, cap_pt = 3, cap_MT = 4, cap_xr = 5;
65 char *onumcodes[] =
67 "dB", /* Number of millisec of bs delay needed */
68 "dC", /* Number of millisec of cr delay needed */
69 "dF", /* Number of millisec of ff delay needed */
70 "dN", /* Number of millisec of nl delay needed */
71 "dT", /* Number of millisec of tab delay needed */
72 "ug", /* Number of blank chars left by us or ue */
73 /* Ignore the 'kn' number. It was ill-defined and never used. */
74 "kn", /* Number of "other" keys */
77 int cap_dB = 0, cap_dC = 1, cap_dF = 2, cap_dN = 3, cap_dT = 4, cap_ug = 5;
79 char *ostrcodes[] =
81 "bc", /* Backspace if not "^H" */
82 "ko", /* Termcap entries for other non-function keys */
83 "ma", /* Arrow key map, used by vi version 2 only */
84 "nl", /* Newline character (default "\n") */
85 "rs", /* undocumented reset string, like is (info is2) */
86 /* Ignore the 'ml' and 'mu' strings. */
87 "ml", /* Memory lock on above cursor. */
88 "mu", /* Memory unlock (turn off memory lock). */
91 int cap_bc = 0, cap_ko = 1, cap_ma = 2, cap_nl = 3, cap_rs = 4;
93 #define numelements(x) (sizeof (x)/sizeof (x[0]))
94 char oboolval[2][numelements(oboolcodes)];
95 short onumval[2][numelements(onumcodes)];
96 char *ostrval[2][numelements(ostrcodes)];
98 /* externs from libcurses.a */
99 extern char *boolnames[], *boolcodes[];
100 extern char *numnames[], *numcodes[];
101 extern char *strnames[], *strcodes[];
103 /* globals for this file */
104 char *progname; /* argv [0], the name of the program */
105 static char *term_name; /* the name of the terminal being worked on */
106 static int uselevel; /* whether we're dealing with use= info */
107 static int boolcount, /* the maximum numbers of each name array */
108 numcount,
109 strcount;
111 /* globals dealing with the environment */
112 extern char **environ;
113 static char TERM[100];
114 #if defined(SYSV) || defined(USG) /* handle both Sys Vr2 and Vr3 curses */
115 static char dirname[BUFSIZ];
116 #else
117 #include <sys/param.h>
118 static char dirname[MAXPATHLEN];
119 #endif /* SYSV || USG */
120 static char TERMCAP[BUFSIZ+15];
121 static char *newenviron[] = { &TERM[0], &TERMCAP[0], 0 };
123 /* dynamic arrays */
124 static char *boolval[2]; /* dynamic array of boolean values */
125 static short *numval[2]; /* dynamic array of numeric values */
126 static char **strval[2]; /* dynamic array of string pointers */
128 /* data buffers */
129 static char *capbuffer; /* string table, pointed at by strval */
130 static char *nextstring; /* pointer into string table */
131 static char *bp; /* termcap raw string table */
132 static char *buflongname; /* place to copy the long names */
134 /* flags */
135 static int verbose = 0; /* debugging printing level */
136 static int copycomments = 0; /* copy comments from tercap source */
138 #define ispadchar(c) (isdigit(c) || (c) == '.' || (c) == '*')
140 static void getlongname(void);
141 static void handleko(void);
142 static void handlema(void);
143 static void print_no_use_entry(void);
144 static void print_use_entry(char *);
145 static void captoinfo(void);
146 static void use_etc_termcap(void);
147 static void initdirname(void);
148 static void setfilename(char *);
149 static void setterm_name(void);
150 static void use_file(char *);
151 static void sorttable(char *[], char *[]);
152 static void inittables(void);
155 * Verify that the names given in the termcap entry are all valid.
159 capsearch(char *codes[], char *ocodes[], char *cap)
161 for (; *codes; codes++)
162 if (((*codes)[0] == cap[0]) && ((*codes)[1] == cap[1]))
163 return (1);
165 for (; *ocodes; ocodes++)
166 if (((*ocodes)[0] == cap[0]) && ((*ocodes)[1] == cap[1]))
167 return (1);
169 return (0);
172 void
173 checktermcap()
175 char *tbuf = bp;
176 enum { tbool, tnum, tstr, tcancel, tunknown } type;
178 for (;;) {
179 tbuf = tskip(tbuf);
180 while (*tbuf == '\t' || *tbuf == ' ' || *tbuf == ':')
181 tbuf++;
183 if (*tbuf == 0)
184 return;
186 /* commented out entry? */
187 if (*tbuf == '.') {
188 if (verbose)
189 (void) fprintf(trace, "termcap string '%c%c' "
190 "commented out.\n", tbuf[1], tbuf[2]);
191 if (!capsearch(boolcodes, oboolcodes, tbuf + 1) &&
192 !capsearch(numcodes, onumcodes, tbuf + 1) &&
193 !capsearch(strcodes, ostrcodes, tbuf + 1))
194 (void) fprintf(stderr,
195 "%s: TERM=%s: commented out code '%.2s' "
196 "is unknown.\n", progname, term_name,
197 tbuf+1);
198 continue;
201 if (verbose)
202 (void) fprintf(trace, "looking at termcap string "
203 "'%.2s'.\n", tbuf);
205 switch (tbuf[2]) {
206 case ':': case '\0': type = tbool; break;
207 case '#': type = tnum; break;
208 case '=': type = tstr; break;
209 case '@': type = tcancel; break;
210 default:
211 (void) fprintf(stderr,
212 "%s: TERM=%s: unknown type given for the "
213 "termcap code '%.2s'.\n", progname,
214 term_name, tbuf);
215 type = tunknown;
218 if (verbose > 1)
219 (void) fprintf(trace, "type of '%.2s' is %s.\n", tbuf,
220 (type == tbool) ? "boolean" :
221 (type == tnum) ? "numeric" :
222 (type = tstr) ? "string" :
223 (type = tcancel) ? "canceled" : "unknown");
225 /* look for the name in bools */
226 if (capsearch(boolcodes, oboolcodes, tbuf)) {
227 if (type != tbool && type != tcancel)
228 (void) fprintf(stderr,
229 "%s: TERM=%s: wrong type given for the "
230 "boolean termcap code '%.2s'.\n", progname,
231 term_name, tbuf);
232 continue;
235 /* look for the name in nums */
236 if (capsearch(numcodes, onumcodes, tbuf)) {
237 if (type != tnum && type != tcancel)
238 (void) fprintf(stderr,
239 "%s: TERM=%s: wrong type given for the "
240 "numeric termcap code '%.2s'.\n", progname,
241 term_name, tbuf);
242 continue;
245 /* look for the name in strs */
246 if (capsearch(strcodes, ostrcodes, tbuf)) {
247 if (type != tstr && type != tcancel)
248 (void) fprintf(stderr,
249 "%s: TERM=%s: wrong type given for the "
250 "string termcap code '%.2s'.\n", progname,
251 term_name, tbuf);
252 continue;
255 (void) fprintf(stderr,
256 "%s: TERM=%s: the %s termcap code '%.2s' is not a valid "
257 "name.\n", progname, term_name,
258 (type == tbool) ? "boolean" :
259 (type == tnum) ? "numeric" :
260 (type = tstr) ? "string" :
261 (type = tcancel) ? "canceled" : "(unknown type)", tbuf);
266 * Fill up the termcap tables.
269 filltables(void)
271 int i, tret;
273 /* Retrieve the termcap entry. */
274 if ((tret = otgetent(bp, term_name)) != 1) {
275 (void) fprintf(stderr,
276 "%s: TERM=%s: tgetent failed with return code %d (%s).\n",
277 progname, term_name, tret,
278 (tret == 0) ? "non-existent or invalid entry" :
279 (tret == -1) ? "cannot open $TERMCAP" : "unknown reason");
280 return (0);
283 if (verbose) {
284 (void) fprintf(trace, "bp=");
285 (void) cpr(trace, bp);
286 (void) fprintf(trace, ".\n");
289 if (uselevel == 0)
290 checktermcap();
292 /* Retrieve the values that are in terminfo. */
294 /* booleans */
295 for (i = 0; boolcodes[i]; i++) {
296 boolval[uselevel][i] = otgetflag(boolcodes[i]);
297 if (verbose > 1) {
298 (void) fprintf(trace, "boolcodes=%s, ", boolcodes[i]);
299 (void) fprintf(trace, "boolnames=%s, ", boolnames[i]);
300 (void) fprintf(trace,
301 "flag=%d.\n", boolval[uselevel][i]);
305 /* numbers */
306 for (i = 0; numcodes[i]; i++) {
307 numval[uselevel][i] = otgetnum(numcodes[i]);
308 if (verbose > 1) {
309 (void) fprintf(trace, "numcodes=%s, ", numcodes[i]);
310 (void) fprintf(trace, "numnames=%s, ", numnames[i]);
311 (void) fprintf(trace, "num=%d.\n", numval[uselevel][i]);
315 if (uselevel == 0)
316 nextstring = capbuffer;
318 /* strings */
319 for (i = 0; strcodes[i]; i++) {
320 strval[uselevel][i] = otgetstr(strcodes[i], &nextstring);
321 if (verbose > 1) {
322 (void) fprintf(trace, "strcodes=%s, ", strcodes [i]);
323 (void) fprintf(trace, "strnames=%s, ", strnames [i]);
324 if (strval[uselevel][i]) {
325 (void) fprintf(trace, "str=");
326 tpr(trace, strval[uselevel][i]);
327 (void) fprintf(trace, ".\n");
329 else
330 (void) fprintf(trace, "str=NULL.\n");
332 /* remove zero length strings */
333 if (strval[uselevel][i] && (strval[uselevel][i][0] == '\0')) {
334 (void) fprintf(stderr,
335 "%s: TERM=%s: cap %s (info %s) is NULL: REMOVED\n",
336 progname, term_name, strcodes[i], strnames[i]);
337 strval[uselevel][i] = NULL;
341 /* Retrieve the values not found in terminfo anymore. */
343 /* booleans */
344 for (i = 0; oboolcodes[i]; i++) {
345 oboolval[uselevel][i] = otgetflag(oboolcodes[i]);
346 if (verbose > 1) {
347 (void) fprintf(trace, "oboolcodes=%s, ",
348 oboolcodes[i]);
349 (void) fprintf(trace, "flag=%d.\n",
350 oboolval[uselevel][i]);
354 /* numbers */
355 for (i = 0; onumcodes[i]; i++) {
356 onumval[uselevel][i] = otgetnum(onumcodes[i]);
357 if (verbose > 1) {
358 (void) fprintf(trace, "onumcodes=%s, ", onumcodes[i]);
359 (void) fprintf(trace, "num=%d.\n",
360 onumval[uselevel][i]);
364 /* strings */
365 for (i = 0; ostrcodes[i]; i++) {
366 ostrval[uselevel][i] = otgetstr(ostrcodes[i], &nextstring);
367 if (verbose > 1) {
368 (void) fprintf(trace, "ostrcodes=%s, ", ostrcodes[i]);
369 if (ostrval[uselevel][i]) {
370 (void) fprintf(trace, "ostr=");
371 tpr(trace, ostrval[uselevel][i]);
372 (void) fprintf(trace, ".\n");
374 else
375 (void) fprintf(trace, "ostr=NULL.\n");
377 /* remove zero length strings */
378 if (ostrval[uselevel][i] && (ostrval[uselevel][i][0] == '\0')) {
379 (void) fprintf(stderr,
380 "%s: TERM=%s: cap %s (no terminfo name) is NULL: "
381 "REMOVED\n", progname, term_name, ostrcodes[i]);
382 ostrval[uselevel][i] = NULL;
385 return (1);
389 * This routine copies the set of names from the termcap entry into
390 * a separate buffer, getting rid of the old obsolete two character
391 * names.
393 static void
394 getlongname(void)
396 char *b = &bp[0], *l = buflongname;
398 /* Skip the two character name */
399 if (bp[2] == '|')
400 b = &bp[3];
402 /* Copy the rest of the names */
403 while (*b && *b != ':')
404 *l++ = *b++;
405 *l = '\0';
407 if (b != &bp[0]) {
408 (void) fprintf(stderr, "%s: obsolete 2 character name "
409 "'%2.2s' removed.\n", progname, bp);
410 (void) fprintf(stderr, "\tsynonyms are: '%s'\n", buflongname);
415 * Return the value of the termcap string 'capname' as stored in our list.
417 char *
418 getcapstr(char *capname)
420 int i;
422 if (verbose > 1)
423 (void) fprintf(trace, "looking for termcap value of %s.\n",
424 capname);
426 /* Check the old termcap list. */
427 for (i = 0; ostrcodes[i]; i++)
428 if (strcmp(ostrcodes[i], capname) == 0) {
429 if (verbose > 1) {
430 (void) fprintf(trace, "\tvalue is:");
431 tpr(trace, ostrval[uselevel][i]);
432 (void) fprintf(trace, ".\n");
434 return (ostrval[uselevel][i]);
437 if (verbose > 1)
438 (void) fprintf(trace, "termcap name '%s' not found in "
439 "ostrcodes.\n", capname);
441 /* Check the terminfo list. */
442 for (i = 0; strcodes[i]; i++)
443 if (strcmp(strcodes[i], capname) == 0) {
444 if (verbose > 1) {
445 (void) fprintf(trace, "\tvalue is:");
446 tpr(trace, strval[uselevel][i]);
447 (void) fprintf(trace, ".\n");
449 return (strval[uselevel][i]);
452 (void) fprintf(stderr, "%s: TERM=%s: termcap name '%s' not found.\n",
453 progname, term_name, capname);
455 return ((char *)NULL);
459 * Search for a name in the given table and
460 * return the index.
461 * Someday I'll redo this to use bsearch().
463 /* ARGSUSED */
465 search(char *names[], int max, char *infoname)
467 #ifndef BSEARCH
468 int i;
469 for (i = 0; names [i] != NULL; i++)
470 if (strcmp(names [i], infoname) == 0)
471 return (i);
472 return (-1);
473 #else /* this doesn't work for some reason */
474 char **bret;
476 bret = (char **)bsearch(infoname, (char *)names, max,
477 sizeof (char *), strcmp);
478 (void) fprintf(trace, "search looking for %s.\n", infoname);
479 (void) fprintf(trace, "base=%#x, bret=%#x, nel=%d.\n", names,
480 bret, max);
481 (void) fprintf(trace, "returning %d.\n", bret == NULL ? -1 :
482 bret - names);
483 if (bret == NULL)
484 return (-1);
485 else
486 return (bret - names);
487 #endif /* OLD */
491 * return the value of the terminfo string 'infoname'
493 char *
494 getinfostr(char *infoname)
496 int i;
498 if (verbose > 1)
499 (void) fprintf(trace, "looking for terminfo value of %s.\n",
500 infoname);
502 i = search(strnames, strcount, infoname);
503 if (i != -1) {
504 if (verbose > 1) {
505 (void) fprintf(trace, "\tvalue is:");
506 tpr(trace, strval[uselevel][i]);
507 (void) fprintf(trace, ".\n");
509 return (strval[uselevel][i]);
512 if (verbose > 1)
513 (void) fprintf(trace, "terminfo name '%s' not found.\n",
514 infoname);
516 return ((char *)NULL);
520 * Replace the value stored for the terminfo boolean
521 * capability 'infoname' with the newvalue.
523 void
524 putbool(char *infoname, int newvalue)
526 int i;
528 if (verbose > 1)
529 (void) fprintf(trace, "changing value for %s to %d.\n",
530 infoname, newvalue);
532 i = search(boolnames, boolcount, infoname);
533 if (i != -1) {
534 if (verbose > 1)
535 (void) fprintf(trace, "value was: %d.\n",
536 boolval[uselevel][i]);
538 boolval[uselevel][i] = newvalue;
539 return;
542 (void) fprintf(stderr, "%s: TERM=%s: the boolean name '%s' was not "
543 "found!\n", progname, term_name, infoname);
547 * Replace the value stored for the terminfo number
548 * capability 'infoname' with the newvalue.
550 void
551 putnum(char *infoname, int newvalue)
553 int i;
555 if (verbose > 1)
556 (void) fprintf(trace, "changing value for %s to %d.\n",
557 infoname, newvalue);
559 i = search(numnames, numcount, infoname);
560 if (i != -1) {
561 if (verbose > 1)
562 (void) fprintf(trace, "value was: %d.\n",
563 numval[uselevel][i]);
565 numval[uselevel][i] = newvalue;
566 return;
569 (void) fprintf(stderr, "%s: TERM=%s: the numeric name '%s' was not "
570 "found!\n",
571 progname, term_name, infoname);
575 * replace the value stored for the terminfo string capability 'infoname'
576 * with the newvalue.
578 void
579 putstr(char *infoname, char *newvalue)
581 int i;
583 if (verbose > 1) {
584 (void) fprintf(trace, "changing value for %s to ", infoname);
585 tpr(trace, newvalue);
586 (void) fprintf(trace, ".\n");
589 i = search(strnames, strcount, infoname);
590 if (i != -1) {
591 if (verbose > 1) {
592 (void) fprintf(trace, "value was:");
593 tpr(trace, strval[uselevel][i]);
594 (void) fprintf(trace, ".\n");
596 strval[uselevel][i] = nextstring;
597 while (*newvalue)
598 *nextstring++ = *newvalue++;
599 *nextstring++ = '\0';
600 return;
603 (void) fprintf(stderr, "%s: TERM=%s: the string name '%s' was not "
604 "found!\n",
605 progname, term_name, infoname);
609 * Add in extra delays if they are not recorded already.
610 * This is done before the padding information has been modified by
611 * changecalculations() below, so the padding information, if there
612 * already, is still at the beginning of the string in termcap format.
614 void
615 addpadding(int cappadding, char *infostr)
617 char *cap;
618 char tempbuffer [100];
620 /* Is there padding to add? */
621 if (cappadding > 0)
622 /* Is there a string to add it to? */
623 if (cap = getinfostr(infostr))
624 /* Is there any padding info already? */
625 if (ispadchar(*cap)) {
626 /* EMPTY */;
627 /* Assume that the padding info that is there is correct. */
628 } else {
629 /* Add the padding at the end of the present string. */
630 (void) snprintf(tempbuffer, sizeof (tempbuffer),
631 "%s$<%d>", cap, cappadding);
632 putstr(infostr, tempbuffer);
633 } else {
634 /* Create a new string that only has the padding. */
635 (void) sprintf(tempbuffer, "$<%d>", cappadding);
636 putstr(infostr, tempbuffer);
640 struct
642 char *capname;
643 char *keyedinfoname;
644 } ko_map[] = {
645 "al", "kil1",
646 "bs", "kbs", /* special addition */
647 "bt", "kcbt",
648 "cd", "ked",
649 "ce", "kel",
650 "cl", "kclr",
651 "ct", "ktbc",
652 "dc", "kdch1",
653 "dl", "kdl1",
654 "do", "kcud1",
655 "ei", "krmir",
656 "ho", "khome",
657 "ic", "kich1",
658 "im", "kich1", /* special addition */
659 "le", "kcub1",
660 "ll", "kll",
661 "nd", "kcuf1",
662 "sf", "kind",
663 "sr", "kri",
664 "st", "khts",
665 "up", "kcuu1",
666 /* "", "kctab", */
667 /* "", "knp", */
668 /* "", "kpp", */
669 0, 0
673 * Work with the ko string. It is a comma separated list of keys for which
674 * the keyboard has a key by the same name that emits the same sequence.
675 * For example, ko = dc, im, ei means that there are keys called
676 * delete-character, enter-insert-mode and exit-insert-mode on the keyboard,
677 * and they emit the same sequences as specified in the dc, im and ei
678 * capabilities.
680 static void
681 handleko(void)
683 char capname[3];
684 char *capstr;
685 int i, j, found;
686 char *infostr;
688 if (verbose > 1)
689 (void) fprintf(trace, "working on termcap ko string.\n");
691 if (ostrval[uselevel][cap_ko] == NULL)
692 return;
694 capname[2] = '\0';
695 for (i = 0; ostrval[uselevel][cap_ko][i] != '\0'; ) {
696 /* isolate the termcap name */
697 capname[0] = ostrval[uselevel][cap_ko][i++];
698 if (ostrval[uselevel][cap_ko][i] == '\0')
699 break;
700 capname[1] = ostrval[uselevel][cap_ko][i++];
701 if (ostrval[uselevel][cap_ko][i] == ',')
702 i++;
704 if (verbose > 1) {
705 (void) fprintf(trace, "key termcap name is '");
706 tpr(trace, capname);
707 (void) fprintf(trace, "'.\n");
710 /* match it up into our list */
711 found = 0;
712 for (j = 0; !found && ko_map[j].keyedinfoname != NULL; j++) {
713 if (verbose > 1)
714 (void) fprintf(trace, "looking at termcap name %s.\n",
715 ko_map[j].capname);
716 if (capname[0] == ko_map[j].capname[0] &&
717 capname[1] == ko_map[j].capname[1]) {
718 /* add the value to our database */
719 if ((capstr = getcapstr(capname)) != NULL) {
720 infostr = getinfostr
721 (ko_map[j].keyedinfoname);
722 if (infostr == NULL) {
723 /* skip any possible padding */
724 /* information */
725 while (ispadchar(*capstr))
726 capstr++;
727 putstr(ko_map[j].keyedinfoname, capstr);
728 } else
729 if (strcmp(capstr, infostr) != 0) {
730 (void) fprintf(stderr,
731 "%s: TERM=%s: a function "
732 "key for '%s' was "
733 "specified with the "
734 "value ", progname,
735 term_name, capname);
736 tpr(stderr, capstr);
737 (void) fprintf(stderr,
738 ", but it already has the "
739 "value '");
740 tpr(stderr, infostr);
741 (void) fprintf(stderr, "'.\n");
744 found = 1;
748 if (!found) {
749 (void) fprintf(stderr, "%s: TERM=%s: the unknown "
750 "termcap name '%s' was\n", progname, term_name,
751 capname);
752 (void) fprintf(stderr, "specified in the 'ko' "
753 "termcap capability.\n");
758 #define CONTROL(x) ((x) & 037)
759 struct
761 char vichar;
762 char *keyedinfoname;
763 } ma_map[] = {
764 CONTROL('J'), "kcud1", /* down */
765 CONTROL('N'), "kcud1",
766 'j', "kcud1",
767 CONTROL('P'), "kcuu1", /* up */
768 'k', "kcuu1",
769 'h', "kcub1", /* left */
770 CONTROL('H'), "kcub1",
771 ' ', "kcuf1", /* right */
772 'l', "kcuf1",
773 'H', "khome", /* home */
774 CONTROL('L'), "kclr", /* clear */
775 0, 0
779 * Work with the ma string. This is a list of pairs of characters.
780 * The first character is the what a function key sends. The second
781 * character is the equivalent vi function that should be done when
782 * it receives that character. Note that only function keys that send
783 * a single character could be defined by this list.
786 void
787 prchar(FILE *stream, int c)
789 char xbuf[2];
790 xbuf[0] = c;
791 xbuf[1] = '\0';
792 (void) fprintf(stream, "%s", iexpand(xbuf));
795 static void
796 handlema(void)
798 char vichar;
799 char cap[2];
800 int i, j, found;
801 char *infostr;
803 if (verbose > 1)
804 (void) fprintf(trace, "working on termcap ma string.\n");
806 if (ostrval[uselevel][cap_ma] == NULL)
807 return;
809 cap[1] = '\0';
810 for (i = 0; ostrval[uselevel][cap_ma][i] != '\0'; ) {
811 /* isolate the key's value */
812 cap[0] = ostrval[uselevel][cap_ma][i++];
813 if (verbose > 1) {
814 (void) fprintf(trace, "key value is '");
815 tpr(trace, cap);
816 (void) fprintf(trace, "'.\n");
819 if (ostrval[uselevel][cap_ma][i] == '\0')
820 break;
822 /* isolate the vi key name */
823 vichar = ostrval[uselevel][cap_ma][i++];
824 if (verbose > 1) {
825 (void) fprintf(trace, "the vi key is '");
826 prchar(trace, vichar);
827 (void) fprintf(trace, "'.\n");
830 /* match up the vi name in our list */
831 found = 0;
832 for (j = 0; !found && ma_map[j].keyedinfoname != NULL; j++) {
833 if (verbose > 1) {
834 (void) fprintf(trace, "looking at vi "
835 "character '");
836 prchar(trace, ma_map[j].vichar);
837 (void) fprintf(trace, "'\n");
839 if (vichar == ma_map[j].vichar) {
840 infostr = getinfostr(ma_map[j].keyedinfoname);
841 if (infostr == NULL)
842 putstr(ma_map[j].keyedinfoname, cap);
843 else if (strcmp(cap, infostr) != 0) {
844 (void) fprintf(stderr, "%s: TERM=%s: "
845 "the vi character '", progname,
846 term_name);
847 prchar(stderr, vichar);
848 (void) fprintf(stderr,
849 "' (info '%s') has the value '",
850 ma_map[j].keyedinfoname);
851 tpr(stderr, infostr);
852 (void) fprintf(stderr, "', but 'ma' "
853 "gives '");
854 prchar(stderr, cap[0]);
855 (void) fprintf(stderr, "'.\n");
857 found = 1;
861 if (!found) {
862 (void) fprintf(stderr, "%s: the unknown vi key '",
863 progname);
864 prchar(stderr, vichar);
865 (void) fprintf(stderr, "' was\n");
866 (void) fprintf(stderr, "specified in the 'ma' termcap "
867 "capability.\n");
873 * Many capabilities were defaulted in termcap which must now be explicitly
874 * given. We'll assume that the defaults are in effect for this terminal.
876 void
877 adddefaults(void)
879 char *cap;
880 int sg;
882 if (verbose > 1)
883 (void) fprintf(trace, "assigning defaults.\n");
885 /* cr was assumed to be ^M, unless nc was given, */
886 /* which meant it could not be done. */
887 /* Also, xr meant that ^M acted strangely. */
888 if ((getinfostr("cr") == NULL) && !oboolval[uselevel][cap_nc] &&
889 !oboolval[uselevel][cap_xr])
890 if ((cap = getcapstr("cr")) == NULL)
891 putstr("cr", "\r");
892 else
893 putstr("cr", cap);
895 /* cursor down was assumed to be ^J if not specified by nl */
896 if (getinfostr("cud1") == NULL)
897 if (ostrval[uselevel][cap_nl] != NULL)
898 putstr("cud1", ostrval[uselevel][cap_nl]);
899 else
900 putstr("cud1", "\n");
902 /* ind was assumed to be ^J, unless ns was given, */
903 /* which meant it could not be done. */
904 if ((getinfostr("ind") == NULL) && !oboolval[uselevel][cap_ns])
905 if (ostrval[uselevel][cap_nl] == NULL)
906 putstr("ind", "\n");
907 else
908 putstr("ind", ostrval[uselevel][cap_nl]);
910 /* bel was assumed to be ^G */
911 if (getinfostr("bel") == NULL)
912 putstr("bel", "\07");
914 /* if bs, then could do backspacing, */
915 /* with value of bc, default of ^H */
916 if ((getinfostr("cub1") == NULL) && oboolval[uselevel][cap_bs])
917 if (ostrval[uselevel][cap_bc] != NULL)
918 putstr("cub1", ostrval[uselevel][cap_bc]);
919 else
920 putstr("cub1", "\b");
922 /* default xon to true */
923 if (!otgetflag("xo"))
924 putbool("xon", 1);
926 /* if pt, then hardware tabs are allowed, */
927 /* with value of ta, default of ^I */
928 if ((getinfostr("ht") == NULL) && oboolval[uselevel][cap_pt])
929 if ((cap = getcapstr("ta")) == NULL)
930 putstr("ht", "\t");
931 else
932 putstr("ht", cap);
934 /* The dX numbers are now stored as padding */
935 /* in the appropriate terminfo string. */
936 addpadding(onumval[uselevel][cap_dB], "cub1");
937 addpadding(onumval[uselevel][cap_dC], "cr");
938 addpadding(onumval[uselevel][cap_dF], "ff");
939 addpadding(onumval[uselevel][cap_dN], "cud1");
940 addpadding(onumval[uselevel][cap_dT], "ht");
942 /* The ug and sg caps were essentially identical, */
943 /* so ug almost never got used. We set sg from ug */
944 /* if it hasn't already been set. */
945 if (onumval[uselevel][cap_ug] >= 0 && (sg = otgetnum("sg")) < 0)
946 putnum("xmc", onumval[uselevel][cap_ug]);
947 else if ((onumval[uselevel][cap_ug] >= 0) &&
948 (sg >= 0) && (onumval[uselevel][cap_ug] != sg))
949 (void) fprintf(stderr,
950 "%s: TERM=%s: Warning: termcap sg and ug had different "
951 "values (%d<->%d).\n", progname, term_name, sg,
952 onumval[uselevel][cap_ug]);
954 /* The MT boolean was never really part of termcap, */
955 /* but we can check for it anyways. */
956 if (oboolval[uselevel][cap_MT] && !otgetflag("km"))
957 putbool("km", 1);
959 /* the rs string was renamed r2 (info rs2) */
960 if ((ostrval[uselevel][cap_rs] != NULL) &&
961 (ostrval[uselevel][cap_rs][0] != NULL))
962 putstr("rs2", ostrval[uselevel][cap_rs]);
964 handleko();
965 handlema();
968 #define caddch(x) *to++ = (x)
971 * add the string to the string table
973 char *
974 caddstr(char *to, char *str)
976 while (*str)
977 *to++ = *str++;
978 return (to);
981 /* If there is no padding info or parmed strings, */
982 /* then we do not need to copy the string. */
984 needscopying(char *string)
986 /* any string at all? */
987 if (string == NULL)
988 return (0);
990 /* any padding info? */
991 if (ispadchar(*string))
992 return (1);
994 /* any parmed info? */
995 while (*string)
996 if (*string++ == '%')
997 return (1);
999 return (0);
1003 * Certain manipulations of the stack require strange manipulations of the
1004 * values that are on the stack. To handle these, we save the values of the
1005 * parameters in registers at the very beginning and make the changes in
1006 * the registers. We don't want to do this in the general case because of the
1007 * potential performance loss.
1010 fancycap(char *string)
1012 int parmset = 0;
1014 while (*string)
1015 if (*string++ == '%') {
1016 switch (*string) {
1017 /* These manipulate just the top value on */
1018 /* the stack, so we only have to do */
1019 /* something strange if a %r follows. */
1020 case '>': case 'B': case 'D':
1021 parmset = 1;
1022 break;
1023 /* If the parm has already been been */
1024 /* pushed onto the stack by %>, then we */
1025 /* can not reverse the parms and must get */
1026 /* them from the registers. */
1027 case 'r':
1028 if (parmset)
1029 return (1);
1030 break;
1031 /* This manipulates both parameters, so we */
1032 /* cannot just do one and leave the value */
1033 /* on the stack like we can with %>, */
1034 /* %B or %D. */
1035 case 'n':
1036 return (1);
1038 string++;
1040 return (0);
1044 * Change old style of doing calculations to the new stack style.
1045 * Note that this will not necessarily produce the most efficient string,
1046 * but it will work.
1048 void
1049 changecalculations()
1051 int i, currentparm;
1052 char *from, *to = nextstring;
1053 int ch;
1054 int parmset, parmsaved;
1055 char padding[100], *saveto;
1057 for (i = 0; strnames[i]; i++)
1058 if (needscopying(strval[uselevel][i])) {
1059 if (verbose) {
1060 (void) fprintf(trace, "%s needs copying, "
1061 "was:", strnames [i]);
1062 tpr(trace, strval[uselevel][i]);
1063 (void) fprintf(trace, ".\n");
1066 from = strval[uselevel][i];
1067 strval[uselevel][i] = to;
1068 currentparm = 1;
1069 parmset = 0;
1071 /* Handle padding information. Save it so that it can be */
1072 /* placed at the end of the string where it should */
1073 /* have been in the first place. */
1074 if (ispadchar(*from)) {
1075 saveto = to;
1076 to = padding;
1077 to = caddstr(to, "$<");
1078 while (isdigit(*from) || *from == '.')
1079 caddch(*from++);
1080 if (*from == '*')
1081 caddch(*from++);
1082 caddch('>');
1083 caddch('\0');
1084 to = saveto;
1085 } else
1086 padding[0] = '\0';
1088 if (fancycap(from)) {
1089 to = caddstr(to, "%p1%Pa%p2%Pb");
1090 parmsaved = 1;
1091 (void) fprintf(stderr,
1092 "%s: TERM=%s: Warning: the string "
1093 "produced for '%s' may be inefficient.\n",
1094 progname, term_name, strnames[i]);
1095 (void) fprintf(stderr, "It should be "
1096 "looked at by hand.\n");
1097 } else
1098 parmsaved = 0;
1100 while ((ch = *from++) != '\0')
1101 if (ch != '%')
1102 caddch(ch);
1103 else
1104 switch (ch = *from++) {
1105 case '.': /* %. -> %p1%c */
1106 case 'd': /* %d -> %p1%d */
1107 case '2': /* %2 -> %p1%2.2d */
1108 case '3': /* %3 -> %p1%3.3d */
1109 case '+':
1110 /* %+x -> %p1%'x'%+%c */
1112 case '>':
1113 /* %>xy -> %p1%Pc%?%'x'%> */
1114 /* %t%gc%'y'%+ */
1115 /* if current value > x, then add y. */
1116 /* No output. */
1118 case 'B':
1119 /* %B: BCD */
1120 /* (16*(x/10))+(x%10) */
1121 /* No output. */
1122 /* (Adds Regent 100) */
1124 case 'D':
1125 /* %D: Reverse coding */
1126 /* (x-2*(x%16)) */
1127 /* No output. */
1128 /* (Delta Data) */
1130 if (!parmset)
1131 if (parmsaved) {
1132 to = caddstr(to, "%g");
1133 if (currentparm == 1)
1134 caddch('a');
1135 else
1136 caddch('b');
1137 } else {
1138 to = caddstr(to, "%p");
1139 if (currentparm == 1)
1140 caddch('1');
1141 else
1142 caddch('2');
1144 currentparm = 3 - currentparm;
1145 parmset = 0;
1146 switch (ch) {
1147 case '.':
1148 to = caddstr(to, "%c");
1149 break;
1150 case 'd':
1151 to = caddstr(to, "%d");
1152 break;
1153 case '2': case '3':
1154 #ifdef USG /* Vr2==USG, Vr3==SYSV. Use %02d for Vr2, %2.2d for Vr3 */
1155 caddch('%');
1156 caddch('0');
1157 #else
1158 caddch('%');
1159 caddch(ch);
1160 caddch('.');
1161 #endif /* USG vs. SYSV */
1162 caddch(ch);
1163 caddch('d');
1164 break;
1165 case '+':
1166 to = caddstr(to, "%'");
1167 caddch(*from++);
1168 to = caddstr(to,
1169 "'%+%c");
1170 break;
1171 case '>':
1172 to = caddstr(to,
1173 "%Pc%?%'");
1174 caddch(*from++);
1175 to = caddstr(to,
1176 "'%>%t%gc%'");
1177 caddch(*from++);
1178 to = caddstr(to,
1179 "'%+");
1180 parmset = 1;
1181 break;
1182 case 'B':
1183 to = caddstr(to,
1184 "%Pc%gc%{10}%/%{16}%*%gc%{10}%m%+");
1185 parmset = 1;
1186 break;
1188 case 'D':
1189 to = caddstr(to,
1190 "%Pc%gc%gc%{16}%m%{2}%*%-");
1191 parmset = 1;
1192 break;
1194 break;
1196 /* %r reverses current parameter */
1197 case 'r':
1198 currentparm = 3 - currentparm;
1199 break;
1201 /* %n: exclusive-or row AND column */
1202 /* with 0140, 96 decimal, no output */
1203 /* (Datamedia 2500, Exidy Sorceror) */
1204 case 'n':
1205 to = caddstr(to,
1206 "%ga%'`'%^%Pa");
1207 to = caddstr(to,
1208 "%gb%'`'%^%Pb");
1209 break;
1211 /* assume %x means %x */
1212 /* this includes %i and %% */
1213 default:
1214 caddch('%');
1215 caddch(ch);
1217 to = caddstr(to, padding);
1218 caddch('\0');
1220 if (verbose) {
1221 (void) fprintf(trace, "and has become:");
1222 tpr(trace, strval[uselevel][i]);
1223 (void) fprintf(trace, ".\n");
1226 nextstring = to;
1229 static void
1230 print_no_use_entry(void)
1232 int i;
1234 pr_heading("", buflongname);
1235 pr_bheading();
1237 for (i = 0; boolcodes[i]; i++)
1238 if (boolval[0][i])
1239 pr_boolean(boolnames[i], (char *)0, (char *)0, 1);
1241 pr_bfooting();
1242 pr_sheading();
1244 for (i = 0; numcodes[i]; i++)
1245 if (numval[0][i] > -1)
1246 pr_number(numnames[i], (char *)0, (char *)0,
1247 numval[0][i]);
1249 pr_nfooting();
1250 pr_sheading();
1252 for (i = 0; strcodes[i]; i++)
1253 if (strval[0][i])
1254 pr_string(strnames[i], (char *)0, (char *)0,
1255 strval[0][i]);
1257 pr_sfooting();
1260 static void
1261 print_use_entry(char *usename)
1263 int i;
1265 pr_heading("", buflongname);
1266 pr_bheading();
1268 for (i = 0; boolcodes[i]; i++)
1269 if (boolval[0][i] && !boolval[1][i])
1270 pr_boolean(boolnames[i], (char *)0, (char *)0, 1);
1271 else if (!boolval[0][i] && boolval[1][i])
1272 pr_boolean(boolnames[i], (char *)0, (char *)0, -1);
1274 pr_bfooting();
1275 pr_nheading();
1277 for (i = 0; numcodes[i]; i++)
1278 if ((numval[0][i] > -1) && (numval[0][i] != numval[1][i]))
1279 pr_number(numnames[i], (char *)0, (char *)0,
1280 numval[0][i]);
1281 else if ((numval [0] [i] == -1) && (numval [1] [i] > -1))
1282 pr_number(numnames[i], (char *)0, (char *)0, -1);
1284 pr_nfooting();
1285 pr_sheading();
1287 for (i = 0; strcodes[i]; i++)
1288 /* print out str[0] if: */
1289 /* str[0] != NULL and str[1] == NULL, or str[0] != str[1] */
1290 if (strval[0][i] && ((strval[1][i] == NULL) ||
1291 (strcmp(strval[0][i], strval[1][i]) != 0)))
1292 pr_string(strnames[i], (char *)0, (char *)0,
1293 strval[0][i]);
1294 /* print out @ if str[0] == NULL and str[1] != NULL */
1295 else if (strval[0][i] == NULL && strval[1][i] != NULL)
1296 pr_string(strnames[i], (char *)0, (char *)0,
1297 (char *)0);
1299 pr_sfooting();
1301 (void) printf("\tuse=%s,\n", usename);
1304 static void
1305 captoinfo(void)
1307 char usename[512];
1308 char *sterm_name;
1310 if (term_name == NULL) {
1311 (void) fprintf(stderr, "%s: Null term_name given.\n",
1312 progname);
1313 return;
1316 if (verbose)
1317 (void) fprintf(trace, "changing cap to info, TERM=%s.\n",
1318 term_name);
1320 uselevel = 0;
1321 if (filltables() == 0)
1322 return;
1323 getlongname();
1324 adddefaults();
1325 changecalculations();
1326 if (TLHtcfound != 0) {
1327 uselevel = 1;
1328 if (verbose)
1329 (void) fprintf(trace, "use= found, %s uses %s.\n",
1330 term_name, TLHtcname);
1331 (void) strcpy(usename, TLHtcname);
1332 sterm_name = term_name;
1333 term_name = usename;
1334 if (filltables() == 0)
1335 return;
1336 adddefaults();
1337 changecalculations();
1338 term_name = sterm_name;
1339 print_use_entry(usename);
1340 } else
1341 print_no_use_entry();
1345 #include <signal.h> /* use this file to determine if this is SVR4.0 system */
1347 static void
1348 use_etc_termcap(void)
1350 if (verbose)
1351 #ifdef SIGSTOP
1352 (void) fprintf(trace, "reading from /usr/share/lib/termcap\n");
1353 #else /* SIGSTOP */
1354 (void) fprintf(trace, "reading from /etc/termcap\n");
1355 #endif /* SIGSTOP */
1356 term_name = getenv("TERM");
1357 captoinfo();
1360 static void
1361 initdirname(void)
1363 #if defined(SYSV) || defined(USG) /* handle both Sys Vr2 and Vr3 curses */
1364 (void) getcwd(dirname, BUFSIZ-2);
1365 #else
1366 (void) getwd(dirname);
1367 #endif /* SYSV || USG */
1368 if (verbose)
1369 (void) fprintf(trace, "current directory name=%s.\n", dirname);
1370 environ = newenviron;
1373 static void
1374 setfilename(char *capfile)
1376 if (capfile [0] == '/')
1377 (void) snprintf(TERMCAP, sizeof (TERMCAP),
1378 "TERMCAP=%s", capfile);
1379 else
1380 (void) snprintf(TERMCAP, sizeof (TERMCAP),
1381 "TERMCAP=%s/%s", dirname, capfile);
1382 if (verbose)
1383 (void) fprintf(trace, "setting the environment for %s.\n",
1384 TERMCAP);
1387 static void
1388 setterm_name(void)
1390 if (verbose)
1391 (void) fprintf(trace, "setting the environment "
1392 "for TERM=%s.\n", term_name);
1393 (void) snprintf(TERM, sizeof (TERM), "TERM=%s", term_name);
1396 /* Look at the current line to see if it is a list of names. */
1397 /* If it is, return the first name in the list, else NULL. */
1398 /* As a side-effect, comment lines and blank lines */
1399 /* are copied to standard output. */
1401 char *
1402 getterm_name(char *line)
1404 char *lineptr = line;
1406 if (verbose)
1407 (void) fprintf(trace, "extracting name from '%s'.\n", line);
1409 /* Copy comment lines out. */
1410 if (*line == '#') {
1411 if (copycomments)
1412 (void) printf("%s", line);
1414 /* Blank lines get copied too. */
1415 else if (isspace (*line)) {
1416 if (copycomments) {
1417 for (; *lineptr; lineptr++)
1418 if (!isspace(*lineptr))
1419 break;
1420 if (*lineptr == '\0')
1421 (void) printf("\n");
1424 else
1425 for (; *lineptr; lineptr++)
1426 if (*lineptr == '|' || *lineptr == ':') {
1427 *lineptr = '\0';
1428 if (verbose)
1429 (void) fprintf(trace,
1430 "returning %s.\n", line);
1431 return (line);
1433 if (verbose)
1434 (void) fprintf(trace, "returning NULL.\n");
1435 return (NULL);
1438 static void
1439 use_file(char *filename)
1441 FILE *termfile;
1442 char buffer[BUFSIZ];
1444 if (verbose)
1445 (void) fprintf(trace, "reading from %s.\n", filename);
1447 if ((termfile = fopen(filename, "r")) == NULL) {
1448 (void) fprintf(stderr, "%s: cannot open %s for reading.\n",
1449 progname, filename);
1450 return;
1453 copycomments++;
1454 setfilename(filename);
1456 while (fgets(buffer, BUFSIZ, termfile) != NULL) {
1457 if ((term_name = getterm_name(buffer)) != NULL) {
1458 setterm_name();
1459 captoinfo();
1465 * Sort a name and code table pair according to the name table.
1466 * Use a simple bubble sort for now. Too bad I can't call qsort(3).
1467 * At least I only have to do it once for each table.
1469 static void
1470 sorttable(char *nametable[], char *codetable[])
1472 int i, j;
1473 char *c;
1475 for (i = 0; nametable[i]; i++)
1476 for (j = 0; j < i; j++)
1477 if (strcmp(nametable[i], nametable[j]) < 0) {
1478 c = nametable[i];
1479 nametable[i] = nametable[j];
1480 nametable[j] = c;
1481 c = codetable[i];
1482 codetable[i] = codetable[j];
1483 codetable[j] = c;
1488 * Initialize and sort the name and code tables. Allocate space for the
1489 * value tables.
1491 static void
1492 inittables(void)
1494 unsigned int i;
1496 for (i = 0; boolnames [i]; i++)
1498 boolval[0] = (char *)malloc(i * sizeof (char));
1499 boolval[1] = (char *)malloc(i * sizeof (char));
1500 boolcount = i;
1501 sorttable(boolnames, boolcodes);
1503 for (i = 0; numcodes [i]; i++)
1505 numval[0] = (short *)malloc(i * sizeof (short));
1506 numval[1] = (short *)malloc(i * sizeof (short));
1507 numcount = i;
1508 sorttable(numnames, numcodes);
1510 for (i = 0; strcodes [i]; i++)
1512 strval[0] = (char **)malloc(i * sizeof (char *));
1513 strval[1] = (char **)malloc(i * sizeof (char *));
1514 strcount = i;
1515 sorttable(strnames, strcodes);
1519 main(int argc, char **argv)
1521 int c;
1522 char _capbuffer [8192];
1523 char _bp [TBUFSIZE];
1524 char _buflongname [128];
1526 capbuffer = &_capbuffer[0];
1527 bp = &_bp[0];
1528 buflongname = &_buflongname[0];
1529 progname = argv[0];
1531 while ((c = getopt(argc, argv, "1vVw:")) != EOF)
1532 switch (c) {
1533 case '1':
1534 pr_onecolumn(1);
1535 break;
1536 case 'w':
1537 pr_width(atoi(optarg));
1538 break;
1539 case 'v':
1540 verbose++;
1541 break;
1542 case 'V':
1543 (void) printf("%s: version %s\n", progname,
1544 "@(#)curses:screen/captoinfo.c 1.12");
1545 (void) fflush(stdout);
1546 exit(0);
1547 /* FALLTHROUGH (not really) */
1548 case '?':
1549 (void) fprintf(stderr,
1550 "usage: %s [-1Vv] [-w width] "
1551 "[filename ...]\n", progname);
1552 (void) fprintf(stderr, "\t-1\tsingle column "
1553 "output\n");
1554 (void) fprintf(stderr,
1555 "\t-v\tverbose debugging output\n");
1556 (void) fprintf(stderr,
1557 "\t-V\tprint program version\n");
1558 exit(-1);
1561 /* initialize */
1562 pr_init(pr_terminfo);
1563 inittables();
1565 if (optind >= argc)
1566 use_etc_termcap();
1567 else {
1568 initdirname();
1569 for (; optind < argc; optind++)
1570 use_file(argv [optind]);
1573 return (0);
1576 /* fake out the modules in print.c so we don't have to load in */
1577 /* cexpand.c and infotocap.c */
1578 /* ARGSUSED */
1580 cpr(FILE *stream, char *string)
1582 return (0);