8196 captoinfo: misleading-indentation
[unleashed.git] / usr / src / cmd / captoinfo / captoinfo.c
blob3a7fc5b3e81f5a8baf2fed69cb1aa4578c7402c3
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 */
31 * NAME
32 * captoinfo - convert a termcap description to a terminfo description
34 * SYNOPSIS
35 * captoinfo [-1vV] [-w width] [ filename ... ]
37 * AUTHOR
38 * Tony Hansen, January 22, 1984.
41 #include "curses.h"
42 #include <ctype.h>
43 #include <stdlib.h>
44 #include <unistd.h>
45 #include <string.h>
46 #include "otermcap.h"
47 #include "print.h"
49 #define trace stderr /* send trace messages to stderr */
51 /* extra termcap variables no longer in terminfo */
52 char *oboolcodes[] =
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;
63 char *onumcodes[] =
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;
77 char *ostrcodes[] =
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 */
106 numcount,
107 strcount;
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];
114 #else
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 };
121 /* dynamic arrays */
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 */
126 /* data buffers */
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 */
132 /* flags */
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]))
161 return (1);
163 for (; *ocodes; ocodes++)
164 if (((*ocodes)[0] == cap[0]) && ((*ocodes)[1] == cap[1]))
165 return (1);
167 return (0);
170 void
171 checktermcap()
173 char *tbuf = bp;
174 enum { tbool, tnum, tstr, tcancel, tunknown } type;
176 for (;;) {
177 tbuf = tskip(tbuf);
178 while (*tbuf == '\t' || *tbuf == ' ' || *tbuf == ':')
179 tbuf++;
181 if (*tbuf == 0)
182 return;
184 /* commented out entry? */
185 if (*tbuf == '.') {
186 if (verbose)
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,
195 tbuf+1);
196 continue;
199 if (verbose)
200 (void) fprintf(trace, "looking at termcap string "
201 "'%.2s'.\n", tbuf);
203 switch (tbuf[2]) {
204 case ':': case '\0': type = tbool; break;
205 case '#': type = tnum; break;
206 case '=': type = tstr; break;
207 case '@': type = tcancel; break;
208 default:
209 (void) fprintf(stderr,
210 "%s: TERM=%s: unknown type given for the "
211 "termcap code '%.2s'.\n", progname,
212 term_name, tbuf);
213 type = tunknown;
216 if (verbose > 1)
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,
229 term_name, tbuf);
230 continue;
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,
239 term_name, tbuf);
240 continue;
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,
249 term_name, tbuf);
250 continue;
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.
267 filltables(void)
269 int i, tret;
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");
278 return (0);
281 if (verbose) {
282 (void) fprintf(trace, "bp=");
283 (void) cpr(trace, bp);
284 (void) fprintf(trace, ".\n");
287 if (uselevel == 0)
288 checktermcap();
290 /* Retrieve the values that are in terminfo. */
292 /* booleans */
293 for (i = 0; boolcodes[i]; i++) {
294 boolval[uselevel][i] = otgetflag(boolcodes[i]);
295 if (verbose > 1) {
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]);
303 /* numbers */
304 for (i = 0; numcodes[i]; i++) {
305 numval[uselevel][i] = otgetnum(numcodes[i]);
306 if (verbose > 1) {
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]);
313 if (uselevel == 0)
314 nextstring = capbuffer;
316 /* strings */
317 for (i = 0; strcodes[i]; i++) {
318 strval[uselevel][i] = otgetstr(strcodes[i], &nextstring);
319 if (verbose > 1) {
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");
327 else
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. */
341 /* booleans */
342 for (i = 0; oboolcodes[i]; i++) {
343 oboolval[uselevel][i] = otgetflag(oboolcodes[i]);
344 if (verbose > 1) {
345 (void) fprintf(trace, "oboolcodes=%s, ",
346 oboolcodes[i]);
347 (void) fprintf(trace, "flag=%d.\n",
348 oboolval[uselevel][i]);
352 /* numbers */
353 for (i = 0; onumcodes[i]; i++) {
354 onumval[uselevel][i] = otgetnum(onumcodes[i]);
355 if (verbose > 1) {
356 (void) fprintf(trace, "onumcodes=%s, ", onumcodes[i]);
357 (void) fprintf(trace, "num=%d.\n",
358 onumval[uselevel][i]);
362 /* strings */
363 for (i = 0; ostrcodes[i]; i++) {
364 ostrval[uselevel][i] = otgetstr(ostrcodes[i], &nextstring);
365 if (verbose > 1) {
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");
372 else
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;
383 return (1);
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
389 * names.
391 static void
392 getlongname(void)
394 char *b = &bp[0], *l = buflongname;
396 /* Skip the two character name */
397 if (bp[2] == '|')
398 b = &bp[3];
400 /* Copy the rest of the names */
401 while (*b && *b != ':')
402 *l++ = *b++;
403 *l = '\0';
405 if (b != &bp[0]) {
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.
415 char *
416 getcapstr(char *capname)
418 int i;
420 if (verbose > 1)
421 (void) fprintf(trace, "looking for termcap value of %s.\n",
422 capname);
424 /* Check the old termcap list. */
425 for (i = 0; ostrcodes[i]; i++)
426 if (strcmp(ostrcodes[i], capname) == 0) {
427 if (verbose > 1) {
428 (void) fprintf(trace, "\tvalue is:");
429 tpr(trace, ostrval[uselevel][i]);
430 (void) fprintf(trace, ".\n");
432 return (ostrval[uselevel][i]);
435 if (verbose > 1)
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) {
442 if (verbose > 1) {
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
458 * return the index.
459 * Someday I'll redo this to use bsearch().
461 /* ARGSUSED */
463 search(char *names[], int max, char *infoname)
465 #ifndef BSEARCH
466 int i;
467 for (i = 0; names [i] != NULL; i++)
468 if (strcmp(names [i], infoname) == 0)
469 return (i);
470 return (-1);
471 #else /* this doesn't work for some reason */
472 char **bret;
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,
478 bret, max);
479 (void) fprintf(trace, "returning %d.\n", bret == NULL ? -1 :
480 bret - names);
481 if (bret == NULL)
482 return (-1);
483 else
484 return (bret - names);
485 #endif /* OLD */
489 * return the value of the terminfo string 'infoname'
491 char *
492 getinfostr(char *infoname)
494 int i;
496 if (verbose > 1)
497 (void) fprintf(trace, "looking for terminfo value of %s.\n",
498 infoname);
500 i = search(strnames, strcount, infoname);
501 if (i != -1) {
502 if (verbose > 1) {
503 (void) fprintf(trace, "\tvalue is:");
504 tpr(trace, strval[uselevel][i]);
505 (void) fprintf(trace, ".\n");
507 return (strval[uselevel][i]);
510 if (verbose > 1)
511 (void) fprintf(trace, "terminfo name '%s' not found.\n",
512 infoname);
514 return ((char *)NULL);
518 * Replace the value stored for the terminfo boolean
519 * capability 'infoname' with the newvalue.
521 void
522 putbool(char *infoname, int newvalue)
524 int i;
526 if (verbose > 1)
527 (void) fprintf(trace, "changing value for %s to %d.\n",
528 infoname, newvalue);
530 i = search(boolnames, boolcount, infoname);
531 if (i != -1) {
532 if (verbose > 1)
533 (void) fprintf(trace, "value was: %d.\n",
534 boolval[uselevel][i]);
536 boolval[uselevel][i] = newvalue;
537 return;
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.
548 void
549 putnum(char *infoname, int newvalue)
551 int i;
553 if (verbose > 1)
554 (void) fprintf(trace, "changing value for %s to %d.\n",
555 infoname, newvalue);
557 i = search(numnames, numcount, infoname);
558 if (i != -1) {
559 if (verbose > 1)
560 (void) fprintf(trace, "value was: %d.\n",
561 numval[uselevel][i]);
563 numval[uselevel][i] = newvalue;
564 return;
567 (void) fprintf(stderr, "%s: TERM=%s: the numeric name '%s' was not "
568 "found!\n",
569 progname, term_name, infoname);
573 * replace the value stored for the terminfo string capability 'infoname'
574 * with the newvalue.
576 void
577 putstr(char *infoname, char *newvalue)
579 int i;
581 if (verbose > 1) {
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);
588 if (i != -1) {
589 if (verbose > 1) {
590 (void) fprintf(trace, "value was:");
591 tpr(trace, strval[uselevel][i]);
592 (void) fprintf(trace, ".\n");
594 strval[uselevel][i] = nextstring;
595 while (*newvalue)
596 *nextstring++ = *newvalue++;
597 *nextstring++ = '\0';
598 return;
601 (void) fprintf(stderr, "%s: TERM=%s: the string name '%s' was not "
602 "found!\n",
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.
612 void
613 addpadding(int cappadding, char *infostr)
615 char *cap;
616 char tempbuffer [100];
618 /* Is there padding to add? */
619 if (cappadding > 0)
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)) {
624 /* EMPTY */;
625 /* Assume that the padding info that is there is correct. */
626 } else {
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);
631 } else {
632 /* Create a new string that only has the padding. */
633 (void) sprintf(tempbuffer, "$<%d>", cappadding);
634 putstr(infostr, tempbuffer);
638 struct
640 char *capname;
641 char *keyedinfoname;
642 } ko_map[] = {
643 "al", "kil1",
644 "bs", "kbs", /* special addition */
645 "bt", "kcbt",
646 "cd", "ked",
647 "ce", "kel",
648 "cl", "kclr",
649 "ct", "ktbc",
650 "dc", "kdch1",
651 "dl", "kdl1",
652 "do", "kcud1",
653 "ei", "krmir",
654 "ho", "khome",
655 "ic", "kich1",
656 "im", "kich1", /* special addition */
657 "le", "kcub1",
658 "ll", "kll",
659 "nd", "kcuf1",
660 "sf", "kind",
661 "sr", "kri",
662 "st", "khts",
663 "up", "kcuu1",
664 /* "", "kctab", */
665 /* "", "knp", */
666 /* "", "kpp", */
667 0, 0
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
676 * capabilities.
678 static void
679 handleko(void)
681 char capname[3];
682 char *capstr;
683 int i, j, found;
684 char *infostr;
686 if (verbose > 1)
687 (void) fprintf(trace, "working on termcap ko string.\n");
689 if (ostrval[uselevel][cap_ko] == NULL)
690 return;
692 capname[2] = '\0';
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')
697 break;
698 capname[1] = ostrval[uselevel][cap_ko][i++];
699 if (ostrval[uselevel][cap_ko][i] == ',')
700 i++;
702 if (verbose > 1) {
703 (void) fprintf(trace, "key termcap name is '");
704 tpr(trace, capname);
705 (void) fprintf(trace, "'.\n");
708 /* match it up into our list */
709 found = 0;
710 for (j = 0; !found && ko_map[j].keyedinfoname != NULL; j++) {
711 if (verbose > 1)
712 (void) fprintf(trace, "looking at termcap name %s.\n",
713 ko_map[j].capname);
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) {
718 infostr = getinfostr
719 (ko_map[j].keyedinfoname);
720 if (infostr == NULL) {
721 /* skip any possible padding */
722 /* information */
723 while (ispadchar(*capstr))
724 capstr++;
725 putstr(ko_map[j].keyedinfoname, capstr);
726 } else
727 if (strcmp(capstr, infostr) != 0) {
728 (void) fprintf(stderr,
729 "%s: TERM=%s: a function "
730 "key for '%s' was "
731 "specified with the "
732 "value ", progname,
733 term_name, capname);
734 tpr(stderr, capstr);
735 (void) fprintf(stderr,
736 ", but it already has the "
737 "value '");
738 tpr(stderr, infostr);
739 (void) fprintf(stderr, "'.\n");
742 found = 1;
746 if (!found) {
747 (void) fprintf(stderr, "%s: TERM=%s: the unknown "
748 "termcap name '%s' was\n", progname, term_name,
749 capname);
750 (void) fprintf(stderr, "specified in the 'ko' "
751 "termcap capability.\n");
756 #define CONTROL(x) ((x) & 037)
757 struct
759 char vichar;
760 char *keyedinfoname;
761 } ma_map[] = {
762 CONTROL('J'), "kcud1", /* down */
763 CONTROL('N'), "kcud1",
764 'j', "kcud1",
765 CONTROL('P'), "kcuu1", /* up */
766 'k', "kcuu1",
767 'h', "kcub1", /* left */
768 CONTROL('H'), "kcub1",
769 ' ', "kcuf1", /* right */
770 'l', "kcuf1",
771 'H', "khome", /* home */
772 CONTROL('L'), "kclr", /* clear */
773 0, 0
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.
784 void
785 prchar(FILE *stream, int c)
787 char xbuf[2];
788 xbuf[0] = c;
789 xbuf[1] = '\0';
790 (void) fprintf(stream, "%s", iexpand(xbuf));
793 static void
794 handlema(void)
796 char vichar;
797 char cap[2];
798 int i, j, found;
799 char *infostr;
801 if (verbose > 1)
802 (void) fprintf(trace, "working on termcap ma string.\n");
804 if (ostrval[uselevel][cap_ma] == NULL)
805 return;
807 cap[1] = '\0';
808 for (i = 0; ostrval[uselevel][cap_ma][i] != '\0'; ) {
809 /* isolate the key's value */
810 cap[0] = ostrval[uselevel][cap_ma][i++];
811 if (verbose > 1) {
812 (void) fprintf(trace, "key value is '");
813 tpr(trace, cap);
814 (void) fprintf(trace, "'.\n");
817 if (ostrval[uselevel][cap_ma][i] == '\0')
818 break;
820 /* isolate the vi key name */
821 vichar = ostrval[uselevel][cap_ma][i++];
822 if (verbose > 1) {
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 */
829 found = 0;
830 for (j = 0; !found && ma_map[j].keyedinfoname != NULL; j++) {
831 if (verbose > 1) {
832 (void) fprintf(trace, "looking at vi "
833 "character '");
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);
839 if (infostr == NULL)
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,
844 term_name);
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' "
851 "gives '");
852 prchar(stderr, cap[0]);
853 (void) fprintf(stderr, "'.\n");
855 found = 1;
859 if (!found) {
860 (void) fprintf(stderr, "%s: the unknown vi key '",
861 progname);
862 prchar(stderr, vichar);
863 (void) fprintf(stderr, "' was\n");
864 (void) fprintf(stderr, "specified in the 'ma' termcap "
865 "capability.\n");
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.
874 void
875 adddefaults(void)
877 char *cap;
878 int sg;
880 if (verbose > 1)
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)
889 putstr("cr", "\r");
890 else
891 putstr("cr", cap);
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]);
897 else
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)
904 putstr("ind", "\n");
905 else
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]);
917 else
918 putstr("cub1", "\b");
920 /* default xon to true */
921 if (!otgetflag("xo"))
922 putbool("xon", 1);
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)
928 putstr("ht", "\t");
929 else
930 putstr("ht", cap);
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"))
955 putbool("km", 1);
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]);
962 handleko();
963 handlema();
966 #define caddch(x) *to++ = (x)
969 * add the string to the string table
971 char *
972 caddstr(char *to, char *str)
974 while (*str)
975 *to++ = *str++;
976 return (to);
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? */
985 if (string == NULL)
986 return (0);
988 /* any padding info? */
989 if (ispadchar(*string))
990 return (1);
992 /* any parmed info? */
993 while (*string)
994 if (*string++ == '%')
995 return (1);
997 return (0);
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)
1010 int parmset = 0;
1012 while (*string)
1013 if (*string++ == '%') {
1014 switch (*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':
1019 parmset = 1;
1020 break;
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. */
1025 case 'r':
1026 if (parmset)
1027 return (1);
1028 break;
1029 /* This manipulates both parameters, so we */
1030 /* cannot just do one and leave the value */
1031 /* on the stack like we can with %>, */
1032 /* %B or %D. */
1033 case 'n':
1034 return (1);
1036 string++;
1038 return (0);
1042 * Change old style of doing calculations to the new stack style.
1043 * Note that this will not necessarily produce the most efficient string,
1044 * but it will work.
1046 void
1047 changecalculations()
1049 int i, currentparm;
1050 char *from, *to = nextstring;
1051 int ch;
1052 int parmset, parmsaved;
1053 char padding[100], *saveto;
1055 for (i = 0; strnames[i]; i++)
1056 if (needscopying(strval[uselevel][i])) {
1057 if (verbose) {
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;
1066 currentparm = 1;
1067 parmset = 0;
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)) {
1073 saveto = to;
1074 to = padding;
1075 to = caddstr(to, "$<");
1076 while (isdigit(*from) || *from == '.')
1077 caddch(*from++);
1078 if (*from == '*')
1079 caddch(*from++);
1080 caddch('>');
1081 caddch('\0');
1082 to = saveto;
1083 } else
1084 padding[0] = '\0';
1086 if (fancycap(from)) {
1087 to = caddstr(to, "%p1%Pa%p2%Pb");
1088 parmsaved = 1;
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");
1095 } else
1096 parmsaved = 0;
1098 while ((ch = *from++) != '\0')
1099 if (ch != '%')
1100 caddch(ch);
1101 else
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 */
1107 case '+':
1108 /* %+x -> %p1%'x'%+%c */
1110 case '>':
1111 /* %>xy -> %p1%Pc%?%'x'%> */
1112 /* %t%gc%'y'%+ */
1113 /* if current value > x, then add y. */
1114 /* No output. */
1116 case 'B':
1117 /* %B: BCD */
1118 /* (16*(x/10))+(x%10) */
1119 /* No output. */
1120 /* (Adds Regent 100) */
1122 case 'D':
1123 /* %D: Reverse coding */
1124 /* (x-2*(x%16)) */
1125 /* No output. */
1126 /* (Delta Data) */
1128 if (!parmset)
1129 if (parmsaved) {
1130 to = caddstr(to, "%g");
1131 if (currentparm == 1)
1132 caddch('a');
1133 else
1134 caddch('b');
1135 } else {
1136 to = caddstr(to, "%p");
1137 if (currentparm == 1)
1138 caddch('1');
1139 else
1140 caddch('2');
1142 currentparm = 3 - currentparm;
1143 parmset = 0;
1144 switch (ch) {
1145 case '.':
1146 to = caddstr(to, "%c");
1147 break;
1148 case 'd':
1149 to = caddstr(to, "%d");
1150 break;
1151 case '2': case '3':
1152 #ifdef USG /* Vr2==USG, Vr3==SYSV. Use %02d for Vr2, %2.2d for Vr3 */
1153 caddch('%');
1154 caddch('0');
1155 #else
1156 caddch('%');
1157 caddch(ch);
1158 caddch('.');
1159 #endif /* USG vs. SYSV */
1160 caddch(ch);
1161 caddch('d');
1162 break;
1163 case '+':
1164 to = caddstr(to, "%'");
1165 caddch(*from++);
1166 to = caddstr(to,
1167 "'%+%c");
1168 break;
1169 case '>':
1170 to = caddstr(to,
1171 "%Pc%?%'");
1172 caddch(*from++);
1173 to = caddstr(to,
1174 "'%>%t%gc%'");
1175 caddch(*from++);
1176 to = caddstr(to,
1177 "'%+");
1178 parmset = 1;
1179 break;
1180 case 'B':
1181 to = caddstr(to,
1182 "%Pc%gc%{10}%/%{16}%*%gc%{10}%m%+");
1183 parmset = 1;
1184 break;
1186 case 'D':
1187 to = caddstr(to,
1188 "%Pc%gc%gc%{16}%m%{2}%*%-");
1189 parmset = 1;
1190 break;
1192 break;
1194 /* %r reverses current parameter */
1195 case 'r':
1196 currentparm = 3 - currentparm;
1197 break;
1199 /* %n: exclusive-or row AND column */
1200 /* with 0140, 96 decimal, no output */
1201 /* (Datamedia 2500, Exidy Sorceror) */
1202 case 'n':
1203 to = caddstr(to,
1204 "%ga%'`'%^%Pa");
1205 to = caddstr(to,
1206 "%gb%'`'%^%Pb");
1207 break;
1209 /* assume %x means %x */
1210 /* this includes %i and %% */
1211 default:
1212 caddch('%');
1213 caddch(ch);
1215 to = caddstr(to, padding);
1216 caddch('\0');
1218 if (verbose) {
1219 (void) fprintf(trace, "and has become:");
1220 tpr(trace, strval[uselevel][i]);
1221 (void) fprintf(trace, ".\n");
1224 nextstring = to;
1227 static void
1228 print_no_use_entry(void)
1230 int i;
1232 pr_heading("", buflongname);
1233 pr_bheading();
1235 for (i = 0; boolcodes[i]; i++)
1236 if (boolval[0][i])
1237 pr_boolean(boolnames[i], (char *)0, (char *)0, 1);
1239 pr_bfooting();
1240 pr_sheading();
1242 for (i = 0; numcodes[i]; i++)
1243 if (numval[0][i] > -1)
1244 pr_number(numnames[i], (char *)0, (char *)0,
1245 numval[0][i]);
1247 pr_nfooting();
1248 pr_sheading();
1250 for (i = 0; strcodes[i]; i++)
1251 if (strval[0][i])
1252 pr_string(strnames[i], (char *)0, (char *)0,
1253 strval[0][i]);
1255 pr_sfooting();
1258 static void
1259 print_use_entry(char *usename)
1261 int i;
1263 pr_heading("", buflongname);
1264 pr_bheading();
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);
1272 pr_bfooting();
1273 pr_nheading();
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,
1278 numval[0][i]);
1279 else if ((numval [0] [i] == -1) && (numval [1] [i] > -1))
1280 pr_number(numnames[i], (char *)0, (char *)0, -1);
1282 pr_nfooting();
1283 pr_sheading();
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,
1291 strval[0][i]);
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,
1295 (char *)0);
1297 pr_sfooting();
1299 (void) printf("\tuse=%s,\n", usename);
1302 static void
1303 captoinfo(void)
1305 char usename[512];
1306 char *sterm_name;
1308 if (term_name == NULL) {
1309 (void) fprintf(stderr, "%s: Null term_name given.\n",
1310 progname);
1311 return;
1314 if (verbose)
1315 (void) fprintf(trace, "changing cap to info, TERM=%s.\n",
1316 term_name);
1318 uselevel = 0;
1319 if (filltables() == 0)
1320 return;
1321 getlongname();
1322 adddefaults();
1323 changecalculations();
1324 if (TLHtcfound != 0) {
1325 uselevel = 1;
1326 if (verbose)
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)
1333 return;
1334 adddefaults();
1335 changecalculations();
1336 term_name = sterm_name;
1337 print_use_entry(usename);
1338 } else
1339 print_no_use_entry();
1343 #include <signal.h> /* use this file to determine if this is SVR4.0 system */
1345 static void
1346 use_etc_termcap(void)
1348 if (verbose)
1349 #ifdef SIGSTOP
1350 (void) fprintf(trace, "reading from /usr/share/lib/termcap\n");
1351 #else /* SIGSTOP */
1352 (void) fprintf(trace, "reading from /etc/termcap\n");
1353 #endif /* SIGSTOP */
1354 term_name = getenv("TERM");
1355 captoinfo();
1358 static void
1359 initdirname(void)
1361 #if defined(SYSV) || defined(USG) /* handle both Sys Vr2 and Vr3 curses */
1362 (void) getcwd(dirname, BUFSIZ-2);
1363 #else
1364 (void) getwd(dirname);
1365 #endif /* SYSV || USG */
1366 if (verbose)
1367 (void) fprintf(trace, "current directory name=%s.\n", dirname);
1368 environ = newenviron;
1371 static void
1372 setfilename(char *capfile)
1374 if (capfile [0] == '/')
1375 (void) snprintf(TERMCAP, sizeof (TERMCAP),
1376 "TERMCAP=%s", capfile);
1377 else
1378 (void) snprintf(TERMCAP, sizeof (TERMCAP),
1379 "TERMCAP=%s/%s", dirname, capfile);
1380 if (verbose)
1381 (void) fprintf(trace, "setting the environment for %s.\n",
1382 TERMCAP);
1385 static void
1386 setterm_name(void)
1388 if (verbose)
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. */
1399 char *
1400 getterm_name(char *line)
1402 char *lineptr = line;
1404 if (verbose)
1405 (void) fprintf(trace, "extracting name from '%s'.\n", line);
1407 /* Copy comment lines out. */
1408 if (*line == '#') {
1409 if (copycomments)
1410 (void) printf("%s", line);
1412 /* Blank lines get copied too. */
1413 else if (isspace (*line)) {
1414 if (copycomments) {
1415 for (; *lineptr; lineptr++)
1416 if (!isspace(*lineptr))
1417 break;
1418 if (*lineptr == '\0')
1419 (void) printf("\n");
1422 else
1423 for (; *lineptr; lineptr++)
1424 if (*lineptr == '|' || *lineptr == ':') {
1425 *lineptr = '\0';
1426 if (verbose)
1427 (void) fprintf(trace,
1428 "returning %s.\n", line);
1429 return (line);
1431 if (verbose)
1432 (void) fprintf(trace, "returning NULL.\n");
1433 return (NULL);
1436 static void
1437 use_file(char *filename)
1439 FILE *termfile;
1440 char buffer[BUFSIZ];
1442 if (verbose)
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);
1448 return;
1451 copycomments++;
1452 setfilename(filename);
1454 while (fgets(buffer, BUFSIZ, termfile) != NULL) {
1455 if ((term_name = getterm_name(buffer)) != NULL) {
1456 setterm_name();
1457 captoinfo();
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.
1467 static void
1468 sorttable(char *nametable[], char *codetable[])
1470 int i, j;
1471 char *c;
1473 for (i = 0; nametable[i]; i++)
1474 for (j = 0; j < i; j++)
1475 if (strcmp(nametable[i], nametable[j]) < 0) {
1476 c = nametable[i];
1477 nametable[i] = nametable[j];
1478 nametable[j] = c;
1479 c = codetable[i];
1480 codetable[i] = codetable[j];
1481 codetable[j] = c;
1486 * Initialize and sort the name and code tables. Allocate space for the
1487 * value tables.
1489 static void
1490 inittables(void)
1492 unsigned int i;
1494 for (i = 0; boolnames [i]; i++)
1496 boolval[0] = (char *)malloc(i * sizeof (char));
1497 boolval[1] = (char *)malloc(i * sizeof (char));
1498 boolcount = i;
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));
1505 numcount = i;
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 *));
1512 strcount = i;
1513 sorttable(strnames, strcodes);
1517 main(int argc, char **argv)
1519 int c;
1520 char _capbuffer [8192];
1521 char _bp [TBUFSIZE];
1522 char _buflongname [128];
1524 capbuffer = &_capbuffer[0];
1525 bp = &_bp[0];
1526 buflongname = &_buflongname[0];
1527 progname = argv[0];
1529 while ((c = getopt(argc, argv, "1vVw:")) != EOF)
1530 switch (c) {
1531 case '1':
1532 pr_onecolumn(1);
1533 break;
1534 case 'w':
1535 pr_width(atoi(optarg));
1536 break;
1537 case 'v':
1538 verbose++;
1539 break;
1540 case 'V':
1541 (void) printf("%s: version %s\n", progname,
1542 "@(#)curses:screen/captoinfo.c 1.12");
1543 (void) fflush(stdout);
1544 exit(0);
1545 /* FALLTHROUGH (not really) */
1546 case '?':
1547 (void) fprintf(stderr,
1548 "usage: %s [-1Vv] [-w width] "
1549 "[filename ...]\n", progname);
1550 (void) fprintf(stderr, "\t-1\tsingle column "
1551 "output\n");
1552 (void) fprintf(stderr,
1553 "\t-v\tverbose debugging output\n");
1554 (void) fprintf(stderr,
1555 "\t-V\tprint program version\n");
1556 exit(-1);
1559 /* initialize */
1560 pr_init(pr_terminfo);
1561 inittables();
1563 if (optind >= argc)
1564 use_etc_termcap();
1565 else {
1566 initdirname();
1567 for (; optind < argc; optind++)
1568 use_file(argv [optind]);
1571 return (0);
1574 /* fake out the modules in print.c so we don't have to load in */
1575 /* cexpand.c and infotocap.c */
1576 /* ARGSUSED */
1578 cpr(FILE *stream, char *string)
1580 return (0);