8 * tconv [-b] [-c [-OUGd]] [-i] [-B [-D dir]] [-I] [-k] [-V] [-t term] [file]
10 * -c convert from termcap
11 * -i convert from terminfo source
12 * -b convert from terminfo binary
13 * -B convert to terminfo binary
14 * -I convert to terminfo source
15 * -V print version info
17 * The following switches are available when converting from termcap:
18 * -d don't supply any defaults for missing capabilities
19 * -O include obsolete termcap capabilities
20 * -G include GNU capabilities
21 * -U include UW capabilities
24 * -D dir directory to put terminfo binaries in
26 * -t term name of terminal to translate
27 * file filename of termcap/terminfo database to use
29 * If a file is specifed and no terminal is given the entire file we be
31 * If no terminal and no file is specified then the terminal name will be
32 * taken from the environment variable TERM.
33 * Unless compiling to a terminfo binary, output is to stdout.
45 #include <sys/types.h>
58 static const char SCCSid[] =
59 "@(#) mytinfo tconv.c 3.2 92/02/01 public domain, By Ross Ridge";
60 static const char rcsid[] =
64 /* the right margin of the output */
67 struct term_path *path; /* returned from _buildpath */
70 char buf[MAX_BUF+1]; /* buffer for the termcap entry */
72 int noOT = 1; /* -O */
73 int noGNU = 1; /* -G */
74 int noUW = 1; /* -W */
75 int dodefault = 1; /* -d */
76 int keepcomments = 0; /* -k */
77 int compile = 0; /* -B */
78 int from_tcap = 0; /* -c */
79 int from_tinfo = 0; /* -i */
80 int from_tbin = 0; /* -b */
81 char *directory = NULL; /* -D */
86 int lineno = 0; /* current line number */
88 /* print the first part of a warning message */
92 fprintf(stderr, "warning: ");
94 fprintf(stderr, "(%s)%d: warning: ",
95 _term_buf.name_long, lineno);
98 /* output a string indenting at the beginning of a line, and wraping
99 * at the right margin.
115 if (termcap && noOT && *s == 'O')
117 if (termcap && noGNU && *s == 'G')
119 if (termcap && noUW && *s == 'U')
124 if (l + pos > LINELEN && pos != 0) {
141 /* maximum # of parameters that can be pushed onto the stack */
142 #define MAX_PUSHED 16
145 int stack[MAX_PUSHED]; /* the stack */
146 int stackptr; /* the next empty place on the stack */
147 int onstack; /* the top of stack */
148 int seenm; /* seen a %m */
149 int seenn; /* seen a %n */
150 int seenr; /* seen a %r */
151 int param; /* current parameter */
152 char *dp; /* pointer to the end of the converted string */
154 /* push onstack on to the stack */
157 if (stackptr > MAX_PUSHED) {
159 fprintf(stderr, "string to complex to convert\n");
161 stack[stackptr++] = onstack;
164 /* pop the top of the stack into onstack */
170 fprintf(stderr, "I'm confused\n");
174 onstack = stack[--stackptr];
178 /* convert a character to a terminfo push */
200 if (sp[1] == '0' && sp[2] == '0') {
204 c = '\200'; /* '\0' ???? */
219 if (isgraph(c) && c != ',' && c != '\'' && c != '\\' && c != ':') {
220 *dp++ = '%'; *dp++ = '\''; *dp++ = c; *dp++ = '\'';
222 *dp++ = '%'; *dp++ = '{';
224 *dp++ = c / 100 + '0';
226 *dp++ = (c / 10) % 10 + '0';
227 *dp++ = c % 10 + '0';
233 /* push n copies of param on the terminfo stack if not already there */
244 if (onstack == parm) {
247 fprintf(stderr, "string may not be optimal");
248 *dp++ = '%'; *dp++ = 'P'; *dp++ = 'a';
250 *dp++ = '%'; *dp++ = 'g'; *dp++ = 'a';
260 while(n--) { /* %p0 */
261 *dp++ = '%'; *dp++ = 'p'; *dp++ = '0' + parm;
264 if (seenn && parm < 3) { /* %{96}%^ */
265 *dp++ = '%'; *dp++ = '{'; *dp++ = '9'; *dp++ = '6'; *dp++ = '}';
266 *dp++ = '%'; *dp++ = '^';
269 if (seenm && parm < 3) { /* %{127}%^ */
270 *dp++ = '%'; *dp++ = '{'; *dp++ = '1'; *dp++ = '2'; *dp++ = '7';
271 *dp++ = '}'; *dp++ = '%'; *dp++ = '^';
275 /* convert a string to terminfo format */
280 static char line[MAX_LINE];
295 || ((cap[0] == 'i' || cap[0] == 'r') && cap[1] == 's'
296 && (cap[2] == '1' || cap[2] == '2' || cap[2] == '3')))
297 /* if (k.* || [ir]s[123]) */
300 if (_strflags[i] != 'G')
306 if (s[0] == '\\' && s[1] != '\0')
308 else if (s[0] == '%' && s[1] != '\0') {
313 "string '%s' already in terminfo format\n", strcodes[i]);
323 if (!nocode && !termcap) {
326 "string '%s' not in terminfo format, converting...\n", cap);
339 case '%': *dp++ = '%'; break;
343 fprintf(stderr, "seen %%r twice\n");
349 fprintf(stderr, "seen %%m twice\n");
355 fprintf(stderr, "seen %%n twice\n");
358 case 'i': *dp++ = '%'; *dp++ = 'i'; break;
363 *dp++ = '%'; *dp++ = '{'; *dp++ = '6';
364 *dp++ = '}'; *dp++ = '%'; *dp++ = '*';
365 *dp++ = '%'; *dp++ = '+';
371 *dp++ = '%'; *dp++ = '{'; *dp++ = '2';
372 *dp++ = '}'; *dp++ = '%'; *dp++ = '*';
373 *dp++ = '%'; *dp++ = '-';
377 /* %?%{x}%>%t%{y}%+%; */
378 *dp++ = '%'; *dp++ = '?';
380 *dp++ = '%'; *dp++ = '>';
381 *dp++ = '%'; *dp++ = 't';
383 *dp++ = '%'; *dp++ = '+';
384 *dp++ = '%'; *dp++ = ';';
387 if ((*s == '=' || *s == '+' || *s == '-'
388 || *s == '*' || *s == '/')
389 && (s[1] == 'p' || s[1] == 'c')
396 getparm(param + s[2] - '@', 1);
397 if (param != onstack) {
406 *dp++ = '%'; *dp++ = '+';
409 *dp++ = '%'; *dp++ = '-';
412 *dp++ = '%'; *dp++ = '*';
415 *dp++ = '%'; *dp++ = '/';
434 *dp++ = '%'; *dp++ = '+';
439 *dp++ = '%'; *dp++ = '+';
440 *dp++ = '%'; *dp++ = 'c';
446 *dp++ = '%'; *dp++ = '-';
451 *dp++ = '%'; *dp++ = '-';
452 *dp++ = '%'; *dp++ = 'c';
457 *dp++ = '%'; *dp++ = 'c';
462 *dp++ = '%'; *dp++ = '0';
463 *dp++ = '2'; *dp++ = 'd';
468 *dp++ = '%'; *dp++ = '0';
469 *dp++ = '3'; *dp++ = 'd';
474 *dp++ = '%'; *dp++ = 'd';
487 fprintf(stderr, "'%s' unknown %% code %c",
489 if (*s >= 0 && *s < 32)
490 fprintf(stderr, "^%c\n", *s + '@');
491 else if (*s < 0 || *s >= 127)
492 fprintf(stderr, "\\%03o\n", *s & 0377);
494 fprintf(stderr, "%c\n", *s);
499 if (!compile) {*dp++ = *s++; *dp++ = *s++; break;}
502 if (!compile) {*dp++ = '\\'; *dp++ = 'n'; s++; break;}
505 if (!compile) {*dp++ = '\\'; *dp++ = 't'; s++; break;}
508 if (!compile) {*dp++ = '\\'; *dp++ = 'r'; s++; break;}
511 if (!compile) {*dp++ = '\\'; *dp++ = '0'; s++; break;}
514 if (!compile) {*dp++ = '\\'; *dp++ = 'f'; s++; break;}
517 if (!compile) {*dp++ = '\\'; *dp++ = 'b'; s++; break;}
520 if (!compile) {*dp++ = '\\'; *dp++ = 's'; s++; break;}
523 if (!compile) {*dp++ = '\\'; *dp++ = '^'; s++; break;}
526 if (!compile) {*dp++ = '\\'; *dp++ = ':'; s++; break;}
529 if (!compile) {*dp++ = '\\'; *dp++ = ','; s++; break;}
533 if (!compile) {*dp++ = '\\'; *dp++ = '\''; s++; break;}
539 else if (*s > 0 && *s < 32) {
543 } else if (*s <= 0 || *s >= 127) {
545 *dp++ = ((*s & 0300) >> 6) + '0';
546 *dp++ = ((*s & 0070) >> 3) + '0';
547 *dp++ = (*s & 0007) + '0';
558 #define LSB(n) ((unsigned) (n) & 0377)
559 #define MSB(n) (((unsigned) (n) >> 8) & 0377)
565 static char bin[MAX_BUF + 1];
572 int sz_name, n_bools, n_nums, n_offs, sz_strs;
573 extern int _boolorder[], _numorder[], _strorder[];
575 strncpy(bin + 12, name, 127);
576 bin[12 + 128] = '\0';
577 sz_name = strlen(name) + 1;
581 s = bin + 12 + sz_name;
582 for(i = 0; _boolorder[i] != -1; i++) {
583 switch(_term_buf.bools[i]) {
584 case -1: *s++ = 0; break;
585 case 0: *s++ = 0377; break;
586 default: *s++ = 1; break;
590 if ((sz_name + n_bools) & 1)
593 s = bin + 12 + sz_name + n_bools;
594 for(i = 0; _numorder[i] != -1; i++) {
595 n = _term_buf.nums[_numorder[i]];
597 case -2: *s++ = 0377; *s++ = 0377; break;
598 case -1: *s++ = 0376; *s++ = 0377; break;
606 s = bin + 12 + sz_name + n_bools + n_nums * 2;
607 for(i = 0; _strorder[i] != -1; i++) {
608 if (_term_buf.strs[_strorder[i]] == (char *) 0) {
609 *s++ = 0376; *s++ = 0377;
611 *s++ = 0377; *s++ = 0377;
616 s = bin + 12 + sz_name + n_bools + n_nums * 2;
617 strtbl = d = s + n_offs * 2;
618 for(i = 0; _strorder[i] != -1; i++) {
619 t = _term_buf.strs[_strorder[i]];
620 if (t == (char *) -1 || t == (char *) 0)
626 t = convstr(t, _strorder[i]);
629 if (d >= bin + MAX_BUF - 1) {
632 "compiled entry to big\n");
642 sz_strs = d - strtbl;
646 bin[2] = LSB(sz_name);
647 bin[3] = MSB(sz_name);
648 bin[4] = LSB(n_bools);
649 bin[5] = MSB(n_bools);
650 bin[6] = LSB(n_nums);
651 bin[7] = MSB(n_nums);
652 bin[8] = LSB(n_offs);
653 bin[9] = MSB(n_offs);
654 bin[10] = LSB(sz_strs);
655 bin[11] = MSB(sz_strs);
657 if (write(fd, bin, d - bin) == -1)
658 quit(errno, "can't write binary file");
668 if (directory != NULL)
672 while(p->type != -1 && p->file != NULL) {
673 if (stat(p->file, &st) == 0) {
674 if ((st.st_mode & 0170000) == 0040000) {
681 quit(-1, "can't find a terminfo directory");
684 /* convert a terminal name to a binary filename */
688 static char line[MAX_LINE+1];
690 sprintf(line, "%s/%c/%s", directory, *name, name);
697 static char line[MAX_LINE+1];
699 sprintf(line, "%s/%c", directory, *name);
707 if (*name == '/' || !isgraph(*name))
714 /* output a terminfo binary */
718 register char *s, *d, *last;
719 char tmp[MAX_LINE+1];
720 char line[MAX_LINE+1];
727 while(*s != '\0' && d < line + MAX_LINE) {
731 while(d > line && d[-1] == '|') {
737 s = strtok(line, "|");
740 while(s != NULL && last == NULL) {
743 } else if (badname(s)) {
746 fprintf(stderr, "bad terminal name '%s', ignored.\n",
749 if (access(bindir(s), 2) == -1) {
752 "can't access directory '%s'",
754 if (mkdir(bindir(s), 0777) == -1)
755 quit(errno, "can't make directory '%s'",
758 fd = open(binfile(s), O_WRONLY | O_CREAT | O_EXCL,
762 quit(errno, "can't open file '%s'",
764 if (unlink(binfile(s)) == -1)
765 quit(errno, "can't unlink file '%s'",
767 fd = open(binfile(s),
768 O_WRONLY | O_CREAT | O_EXCL, 0666);
770 quit(errno, "can't create file '%s'",
777 s = strtok(NULL, "|");
783 fprintf(stderr, "no terminal name, entry ignored.\n");
787 while(s != NULL && s + strlen(s) != d) {
788 if (*s == '\0' || strcmp(s, last) == 0) {
790 } else if (badname(s)) {
793 fprintf(stderr, "bad terminal name '%s', ignored.\n",
796 if (access(bindir(s), 2) == -1) {
799 "can't access directory '%s'",
801 if (mkdir(bindir(s), 0777) == -1)
802 quit(errno, "can't make directory '%s'",
805 if (access(binfile(s), 0) == -1) {
807 quit(errno, "can't access file '%s'",
809 } else if (unlink(binfile(s)) == -1) {
810 quit(errno, "can't unlink file '%s'",
813 strcpy(tmp, binfile(last));
814 if (link(tmp, binfile(s)) == -1) {
815 quit(errno, "can't link '%s' to '%s'",
819 s = strtok(NULL, "|");
824 /* output an entry in terminfo source format */
831 printf("%s,\n", name);
833 for(i = 0; i < NUM_OF_BOOLS; i++)
834 if (_term_buf.bools[i] == 0) {
835 sprintf(line, "%s@", boolnames[i]);
837 } else if (_term_buf.bools[i] != -1)
838 putstr(boolnames[i]);
840 for(i = 0; i < NUM_OF_NUMS; i++)
841 if (_term_buf.nums[i] == -1) {
842 sprintf(line, "%s@", numnames[i]);
844 } else if (_term_buf.nums[i] != -2) {
845 sprintf(line, "%s#%d", numnames[i], _term_buf.nums[i]);
849 for(i = 0; i < NUM_OF_STRS; i++)
850 if (_term_buf.strs[i] == NULL) {
851 sprintf(line, "%s@", strnames[i]);
853 } else if (_term_buf.strs[i] != (char *) -1) {
854 sprintf(line, "%s=%s", strnames[i],
855 convstr(_term_buf.strs[i], i));
861 /* convert a terminfo entry to binary format */
868 for(i = 0; i < NUM_OF_BOOLS; i++)
869 _term_buf.bools[i] = -1;
870 for(i = 0; i < NUM_OF_NUMS; i++)
871 _term_buf.nums[i] = -2;
872 for(i = 0; i < NUM_OF_STRS; i++)
873 _term_buf.strs[i] = (char *) -1;
875 _term_buf.name_all = NULL;
877 r = _gettinfo(buf, &_term_buf, path);
880 quit(-1, "problem reading entry");
883 fprintf(stderr, "problem reading entry\n");
888 outputbin(_term_buf.name_all);
890 outputinfo(_term_buf.name_all);
894 /* convert a terminfo binary to terminfo source */
901 for(i = 0; i < NUM_OF_BOOLS; i++)
902 _term_buf.bools[i] = -1;
903 for(i = 0; i < NUM_OF_NUMS; i++)
904 _term_buf.nums[i] = -2;
905 for(i = 0; i < NUM_OF_STRS; i++)
906 _term_buf.strs[i] = (char *) -1;
908 _term_buf.name_all = NULL;
910 r = _gettbin(buf, &_term_buf);
913 quit(-1, "problem reading entry");
916 fprintf(stderr, "problem reading entry\n");
920 outputinfo(_term_buf.name_all);
925 /* convert a termcap entry to terminfo format */
933 for(i = 0; i < NUM_OF_BOOLS; i++)
934 _term_buf.bools[i] = -1;
935 for(i = 0; i < NUM_OF_NUMS; i++)
936 _term_buf.nums[i] = -2;
937 for(i = 0; i < NUM_OF_STRS; i++)
938 _term_buf.strs[i] = (char *) -1;
940 _term_buf.name_all = NULL;
946 r = _gettcap(buf, &_term_buf, path);
949 quit(-1, "problem reading entry");
952 fprintf(stderr, "problem reading entry\n");
956 if (dodefault && !continued)
961 name = _term_buf.name_all;
963 printf("...%s\n", name);
965 if (name[0] != '\0' && name[1] != '\0' && name[2] == '|')
966 name += 3; /* skip the 2 letter code */
980 f = fopen(file, "r");
983 quit(errno, "can't open '%s'", file);
985 r = fread(buf, sizeof(char), MAX_BUF, f);
986 if (r < 12 || buf[0] != 032 || buf[1] != 01)
987 quit(-1, "file '%s' corrupted", file);
992 /* convert a termcap file to terminfo format */
1001 f = fopen(file, "r");
1004 quit(errno, "can't open '%s'", file);
1015 } while(c != '\n' && c != EOF);
1020 while(c != '\n' && c != EOF);
1025 while(isspace(c) && c != '\n')
1027 if (c == '\n' && buf == d) {
1043 } else if (c == '\n') {
1051 while(d > buf && *d != ':')
1053 if (d[1] == 't' && d[2] == 'c' && d[3] == '=') {
1062 "entry doesn't end with :\n");
1064 _term_buf.strbuf = _endstr();
1065 _del_strs(&_term_buf);
1067 printf("\tuse=%s,\n", d + 4);
1084 register int c, i = 0;
1086 while((c = getc(f)) == '#') {
1090 while((c = getc(f)) != '\n') {
1097 while((c = getc(f)) != '\n')
1114 while(isspace(*(buf-1))) {
1126 static char line[MAX_LINE+1];
1131 f = fopen(file, "r");
1134 quit(errno, "can't open '%s'", file);
1138 l = getln(f, line, MAX_LINE);
1140 if (line[l-1] == ':') {
1141 strncpy(buf, line, MAX_BUF);
1143 } else if (line[l-1] == '\\') {
1148 strncpy(buf + MAX_BUF - n, line, n);
1150 l = getln(f, line, MAX_LINE);
1151 } while(l != -1 && line[l-1] == '\\');
1152 if (n > 0 && l != -1)
1153 strncpy(buf + MAX_BUF - n, line, n);
1155 } else if (line[l-1] == ',') {
1159 strncpy(buf + MAX_BUF - n, line, n);
1161 l = getln(f, line, MAX_LINE);
1162 } while(l != -1 && isspace(line[0]));
1164 printf("buf = '%s'\n", buf);
1168 } else if (line[0] != '\0') {
1170 fprintf(stderr, "malformed line\n");
1172 printf("%s\n", line);
1175 l = getln(f, line, MAX_LINE);
1180 /* dummy routine for quit */
1188 /* print out usage, called by quit */
1193 fprintf(stderr, "%s\n%s\n%s\n%s\n",
1194 "usage: tconv [-b] [-c [-OUGd]] [-i] [-B [-D dir]] [-I] [-k] [-V]",
1195 " [-t term] [file]",
1197 " captoinfo [-t term] [-OUGdk] [file]");
1211 prg_name = strrchr(argv[0], '/');
1212 if (prg_name == NULL)
1221 if (strcmp(prg_name, "tic") == 0)
1224 while ((c = getopt(argc, argv, "bciBIOGUdkVD:t:")) != -1) {
1236 if (directory != NULL)
1237 quit(-1, "more than one directory specified");
1242 quit(-1, "more than one terminal specified");
1245 case 'd': dodefault = 0; break;
1246 case 'k': keepcomments = 1; break;
1247 case 'b': from_tbin = 1; break;
1248 case 'c': from_tcap = 1; break;
1249 case 'i': from_tinfo = 1; break;
1250 case 'B': compile = 1; break;
1251 case 'I': compile = 0; break;
1252 case 'V': pversion = 1; break;
1255 quit(-1, "bad or missing command line argument");
1260 quit(0, "%s\n%s", _mytinfo_version, SCCSid);
1263 if (optind == argc - 1)
1264 file = argv[optind];
1265 else if (optind != argc)
1266 quit(-1, "wrong number of arguments");
1268 if (from_tbin + from_tcap + from_tinfo > 1)
1269 quit(-1, "more than one input file type specified");
1271 if (!from_tcap && !from_tinfo && !from_tbin && file != NULL) {
1272 if (strcmp(prg_name, "cap2info") == 0
1273 || strcmp(prg_name, "captoinfo") == 0)
1275 else if (strcmp(prg_name, "tic") == 0)
1278 quit(-1, "no input file type specified");
1281 if (from_tbin && compile)
1282 quit(-1, "can't convert from binary to binary");
1286 cleanup = do_cleanup;
1291 path = _buildpath(file, 0, NULL, -1);
1293 path = _buildpath(file, 0,
1302 quit(-1, "can't build path");
1304 cleanup = do_cleanup;
1305 if (from_tcap && !compile)
1311 } else if (from_tcap && !compile)
1312 path = _buildpath("$TERMCAP", 1,
1317 else if (from_tinfo || from_tbin)
1318 path = _buildpath("$TERMINFO", 2,
1328 path = _buildpath("$TERMCAP", 1,
1358 term = getenv("TERM");
1360 quit(-1, "no terminal type given");
1363 cleanup = do_cleanup;
1365 r = _findterm(term, path, buf);
1375 quit(-1, "entry is already compiled");
1379 quit(-1, "can't find a terminal entry for '%s'", term);