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.
35 * @(#) mytinfo tconv.c 3.2 92/02/01 public domain, By Ross Ridge
36 * $FreeBSD: src/usr.bin/tconv/tconv.c,v 1.5.2.1 2001/03/04 09:07:50 kris Exp $
37 * $DragonFly: src/usr.bin/tconv/tconv.c,v 1.5 2004/01/22 04:22:53 rob Exp $
48 #include <sys/types.h>
51 #if defined(__DragonFly__)
55 #if !defined(__DragonFly__)
60 /* the right margin of the output */
63 struct term_path
*path
; /* returned from _buildpath */
66 char buf
[MAX_BUF
+1]; /* buffer for the termcap entry */
68 int noOT
= 1; /* -O */
69 int noGNU
= 1; /* -G */
70 int noUW
= 1; /* -W */
71 int dodefault
= 1; /* -d */
72 int keepcomments
= 0; /* -k */
73 int compile
= 0; /* -B */
74 int from_tcap
= 0; /* -c */
75 int from_tinfo
= 0; /* -i */
76 int from_tbin
= 0; /* -b */
77 char *directory
= NULL
; /* -D */
82 int lineno
= 0; /* current line number */
84 /* print the first part of a warning message */
88 fprintf(stderr
, "warning: ");
90 fprintf(stderr
, "(%s)%d: warning: ",
91 _term_buf
.name_long
, lineno
);
94 /* output a string indenting at the beginning of a line, and wraping
95 * at the right margin.
111 if (termcap
&& noOT
&& *s
== 'O')
113 if (termcap
&& noGNU
&& *s
== 'G')
115 if (termcap
&& noUW
&& *s
== 'U')
120 if (l
+ pos
> LINELEN
&& pos
!= 0) {
137 /* maximum # of parameters that can be pushed onto the stack */
138 #define MAX_PUSHED 16
141 int stack
[MAX_PUSHED
]; /* the stack */
142 int stackptr
; /* the next empty place on the stack */
143 int onstack
; /* the top of stack */
144 int seenm
; /* seen a %m */
145 int seenn
; /* seen a %n */
146 int seenr
; /* seen a %r */
147 int param
; /* current parameter */
148 char *dp
; /* pointer to the end of the converted string */
150 /* push onstack on to the stack */
154 if (stackptr
> MAX_PUSHED
) {
156 fprintf(stderr
, "string to complex to convert\n");
158 stack
[stackptr
++] = onstack
;
161 /* pop the top of the stack into onstack */
168 fprintf(stderr
, "I'm confused\n");
172 onstack
= stack
[--stackptr
];
176 /* convert a character to a terminfo push */
178 cvtchar(register char *sp
)
198 if (sp
[1] == '0' && sp
[2] == '0') {
202 c
= '\200'; /* '\0' ???? */
217 if (isgraph(c
) && c
!= ',' && c
!= '\'' && c
!= '\\' && c
!= ':') {
218 *dp
++ = '%'; *dp
++ = '\''; *dp
++ = c
; *dp
++ = '\'';
220 *dp
++ = '%'; *dp
++ = '{';
222 *dp
++ = c
/ 100 + '0';
224 *dp
++ = (c
/ 10) % 10 + '0';
225 *dp
++ = c
% 10 + '0';
231 /* push n copies of param on the terminfo stack if not already there */
233 getparm(int parm
, int n
)
241 if (onstack
== parm
) {
244 fprintf(stderr
, "string may not be optimal");
245 *dp
++ = '%'; *dp
++ = 'P'; *dp
++ = 'a';
247 *dp
++ = '%'; *dp
++ = 'g'; *dp
++ = 'a';
257 while(n
--) { /* %p0 */
258 *dp
++ = '%'; *dp
++ = 'p'; *dp
++ = '0' + parm
;
261 if (seenn
&& parm
< 3) { /* %{96}%^ */
262 *dp
++ = '%'; *dp
++ = '{'; *dp
++ = '9'; *dp
++ = '6'; *dp
++ = '}';
263 *dp
++ = '%'; *dp
++ = '^';
266 if (seenm
&& parm
< 3) { /* %{127}%^ */
267 *dp
++ = '%'; *dp
++ = '{'; *dp
++ = '1'; *dp
++ = '2'; *dp
++ = '7';
268 *dp
++ = '}'; *dp
++ = '%'; *dp
++ = '^';
272 /* convert a string to terminfo format */
274 convstr(register char *s
, int i
)
276 static char line
[MAX_LINE
];
291 || ((cap
[0] == 'i' || cap
[0] == 'r') && cap
[1] == 's'
292 && (cap
[2] == '1' || cap
[2] == '2' || cap
[2] == '3')))
293 /* if (k.* || [ir]s[123]) */
296 if (_strflags
[i
] != 'G')
302 if (s
[0] == '\\' && s
[1] != '\0')
304 else if (s
[0] == '%' && s
[1] != '\0') {
309 "string '%s' already in terminfo format\n", strcodes
[i
]);
319 if (!nocode
&& !termcap
) {
322 "string '%s' not in terminfo format, converting...\n", cap
);
335 case '%': *dp
++ = '%'; break;
339 fprintf(stderr
, "seen %%r twice\n");
345 fprintf(stderr
, "seen %%m twice\n");
351 fprintf(stderr
, "seen %%n twice\n");
354 case 'i': *dp
++ = '%'; *dp
++ = 'i'; break;
359 *dp
++ = '%'; *dp
++ = '{'; *dp
++ = '6';
360 *dp
++ = '}'; *dp
++ = '%'; *dp
++ = '*';
361 *dp
++ = '%'; *dp
++ = '+';
367 *dp
++ = '%'; *dp
++ = '{'; *dp
++ = '2';
368 *dp
++ = '}'; *dp
++ = '%'; *dp
++ = '*';
369 *dp
++ = '%'; *dp
++ = '-';
373 /* %?%{x}%>%t%{y}%+%; */
374 *dp
++ = '%'; *dp
++ = '?';
376 *dp
++ = '%'; *dp
++ = '>';
377 *dp
++ = '%'; *dp
++ = 't';
379 *dp
++ = '%'; *dp
++ = '+';
380 *dp
++ = '%'; *dp
++ = ';';
383 if ((*s
== '=' || *s
== '+' || *s
== '-'
384 || *s
== '*' || *s
== '/')
385 && (s
[1] == 'p' || s
[1] == 'c')
392 getparm(param
+ s
[2] - '@', 1);
393 if (param
!= onstack
) {
402 *dp
++ = '%'; *dp
++ = '+';
405 *dp
++ = '%'; *dp
++ = '-';
408 *dp
++ = '%'; *dp
++ = '*';
411 *dp
++ = '%'; *dp
++ = '/';
430 *dp
++ = '%'; *dp
++ = '+';
435 *dp
++ = '%'; *dp
++ = '+';
436 *dp
++ = '%'; *dp
++ = 'c';
442 *dp
++ = '%'; *dp
++ = '-';
447 *dp
++ = '%'; *dp
++ = '-';
448 *dp
++ = '%'; *dp
++ = 'c';
453 *dp
++ = '%'; *dp
++ = 'c';
458 *dp
++ = '%'; *dp
++ = '0';
459 *dp
++ = '2'; *dp
++ = 'd';
464 *dp
++ = '%'; *dp
++ = '0';
465 *dp
++ = '3'; *dp
++ = 'd';
470 *dp
++ = '%'; *dp
++ = 'd';
483 fprintf(stderr
, "'%s' unknown %% code %c",
485 if (*s
>= 0 && *s
< 32)
486 fprintf(stderr
, "^%c\n", *s
+ '@');
487 else if (*s
< 0 || *s
>= 127)
488 fprintf(stderr
, "\\%03o\n", *s
& 0377);
490 fprintf(stderr
, "%c\n", *s
);
495 if (!compile
) {*dp
++ = *s
++; *dp
++ = *s
++; break;}
498 if (!compile
) {*dp
++ = '\\'; *dp
++ = 'n'; s
++; break;}
501 if (!compile
) {*dp
++ = '\\'; *dp
++ = 't'; s
++; break;}
504 if (!compile
) {*dp
++ = '\\'; *dp
++ = 'r'; s
++; break;}
507 if (!compile
) {*dp
++ = '\\'; *dp
++ = '0'; s
++; break;}
510 if (!compile
) {*dp
++ = '\\'; *dp
++ = 'f'; s
++; break;}
513 if (!compile
) {*dp
++ = '\\'; *dp
++ = 'b'; s
++; break;}
516 if (!compile
) {*dp
++ = '\\'; *dp
++ = 's'; s
++; break;}
519 if (!compile
) {*dp
++ = '\\'; *dp
++ = '^'; s
++; break;}
522 if (!compile
) {*dp
++ = '\\'; *dp
++ = ':'; s
++; break;}
525 if (!compile
) {*dp
++ = '\\'; *dp
++ = ','; s
++; break;}
529 if (!compile
) {*dp
++ = '\\'; *dp
++ = '\''; s
++; break;}
535 else if (*s
> 0 && *s
< 32) {
539 } else if (*s
<= 0 || *s
>= 127) {
541 *dp
++ = ((*s
& 0300) >> 6) + '0';
542 *dp
++ = ((*s
& 0070) >> 3) + '0';
543 *dp
++ = (*s
& 0007) + '0';
554 #define LSB(n) ((unsigned) (n) & 0377)
555 #define MSB(n) (((unsigned) (n) >> 8) & 0377)
558 writebin(int fd
, char *name
)
560 static char bin
[MAX_BUF
+ 1];
567 int sz_name
, n_bools
, n_nums
, n_offs
, sz_strs
;
568 extern int _boolorder
[], _numorder
[], _strorder
[];
570 strncpy(bin
+ 12, name
, 127);
571 bin
[12 + 128] = '\0';
572 sz_name
= strlen(name
) + 1;
576 s
= bin
+ 12 + sz_name
;
577 for(i
= 0; _boolorder
[i
] != -1; i
++) {
578 switch(_term_buf
.bools
[i
]) {
579 case -1: *s
++ = 0; break;
580 case 0: *s
++ = 0377; break;
581 default: *s
++ = 1; break;
585 if ((sz_name
+ n_bools
) & 1)
588 s
= bin
+ 12 + sz_name
+ n_bools
;
589 for(i
= 0; _numorder
[i
] != -1; i
++) {
590 n
= _term_buf
.nums
[_numorder
[i
]];
592 case -2: *s
++ = 0377; *s
++ = 0377; break;
593 case -1: *s
++ = 0376; *s
++ = 0377; break;
601 s
= bin
+ 12 + sz_name
+ n_bools
+ n_nums
* 2;
602 for(i
= 0; _strorder
[i
] != -1; i
++) {
603 if (_term_buf
.strs
[_strorder
[i
]] == (char *) 0) {
604 *s
++ = 0376; *s
++ = 0377;
606 *s
++ = 0377; *s
++ = 0377;
611 s
= bin
+ 12 + sz_name
+ n_bools
+ n_nums
* 2;
612 strtbl
= d
= s
+ n_offs
* 2;
613 for(i
= 0; _strorder
[i
] != -1; i
++) {
614 t
= _term_buf
.strs
[_strorder
[i
]];
615 if (t
== (char *) -1 || t
== (char *) 0)
621 t
= convstr(t
, _strorder
[i
]);
624 if (d
>= bin
+ MAX_BUF
- 1) {
627 "compiled entry to big\n");
637 sz_strs
= d
- strtbl
;
641 bin
[2] = LSB(sz_name
);
642 bin
[3] = MSB(sz_name
);
643 bin
[4] = LSB(n_bools
);
644 bin
[5] = MSB(n_bools
);
645 bin
[6] = LSB(n_nums
);
646 bin
[7] = MSB(n_nums
);
647 bin
[8] = LSB(n_offs
);
648 bin
[9] = MSB(n_offs
);
649 bin
[10] = LSB(sz_strs
);
650 bin
[11] = MSB(sz_strs
);
652 if (write(fd
, bin
, d
- bin
) == -1)
653 quit(errno
, "can't write binary file");
664 if (directory
!= NULL
)
668 while(p
->type
!= -1 && p
->file
!= NULL
) {
669 if (stat(p
->file
, &st
) == 0) {
670 if ((st
.st_mode
& 0170000) == 0040000) {
677 quit(-1, "can't find a terminfo directory");
680 /* convert a terminal name to a binary filename */
684 static char line
[MAX_LINE
+1];
686 sprintf(line
, "%s/%c/%s", directory
, *name
, name
);
693 static char line
[MAX_LINE
+1];
695 sprintf(line
, "%s/%c", directory
, *name
);
703 if (*name
== '/' || !isgraph(*name
))
710 /* output a terminfo binary */
712 outputbin(char *name
)
714 register char *s
, *d
, *last
;
715 char tmp
[MAX_LINE
+1];
716 char line
[MAX_LINE
+1];
723 while(*s
!= '\0' && d
< line
+ MAX_LINE
) {
727 while(d
> line
&& d
[-1] == '|') {
733 s
= strtok(line
, "|");
736 while(s
!= NULL
&& last
== NULL
) {
739 } else if (badname(s
)) {
742 fprintf(stderr
, "bad terminal name '%s', ignored.\n",
745 if (access(bindir(s
), 2) == -1) {
748 "can't access directory '%s'",
750 if (mkdir(bindir(s
), 0777) == -1)
751 quit(errno
, "can't make directory '%s'",
754 fd
= open(binfile(s
), O_WRONLY
| O_CREAT
| O_EXCL
,
758 quit(errno
, "can't open file '%s'",
760 if (unlink(binfile(s
)) == -1)
761 quit(errno
, "can't unlink file '%s'",
763 fd
= open(binfile(s
),
764 O_WRONLY
| O_CREAT
| O_EXCL
, 0666);
766 quit(errno
, "can't create file '%s'",
773 s
= strtok(NULL
, "|");
779 fprintf(stderr
, "no terminal name, entry ignored.\n");
783 while(s
!= NULL
&& s
+ strlen(s
) != d
) {
784 if (*s
== '\0' || strcmp(s
, last
) == 0) {
786 } else if (badname(s
)) {
789 fprintf(stderr
, "bad terminal name '%s', ignored.\n",
792 if (access(bindir(s
), 2) == -1) {
795 "can't access directory '%s'",
797 if (mkdir(bindir(s
), 0777) == -1)
798 quit(errno
, "can't make directory '%s'",
801 if (access(binfile(s
), 0) == -1) {
803 quit(errno
, "can't access file '%s'",
805 } else if (unlink(binfile(s
)) == -1) {
806 quit(errno
, "can't unlink file '%s'",
809 strcpy(tmp
, binfile(last
));
810 if (link(tmp
, binfile(s
)) == -1) {
811 quit(errno
, "can't link '%s' to '%s'",
815 s
= strtok(NULL
, "|");
820 /* output an entry in terminfo source format */
822 outputinfo(char *name
)
827 printf("%s,\n", name
);
829 for(i
= 0; i
< NUM_OF_BOOLS
; i
++)
830 if (_term_buf
.bools
[i
] == 0) {
831 sprintf(line
, "%s@", boolnames
[i
]);
833 } else if (_term_buf
.bools
[i
] != -1)
834 putstr(boolnames
[i
]);
836 for(i
= 0; i
< NUM_OF_NUMS
; i
++)
837 if (_term_buf
.nums
[i
] == -1) {
838 sprintf(line
, "%s@", numnames
[i
]);
840 } else if (_term_buf
.nums
[i
] != -2) {
841 sprintf(line
, "%s#%d", numnames
[i
], _term_buf
.nums
[i
]);
845 for(i
= 0; i
< NUM_OF_STRS
; i
++)
846 if (_term_buf
.strs
[i
] == NULL
) {
847 sprintf(line
, "%s@", strnames
[i
]);
849 } else if (_term_buf
.strs
[i
] != (char *) -1) {
850 sprintf(line
, "%s=%s", strnames
[i
],
851 convstr(_term_buf
.strs
[i
], i
));
857 /* convert a terminfo entry to binary format */
865 for(i
= 0; i
< NUM_OF_BOOLS
; i
++)
866 _term_buf
.bools
[i
] = -1;
867 for(i
= 0; i
< NUM_OF_NUMS
; i
++)
868 _term_buf
.nums
[i
] = -2;
869 for(i
= 0; i
< NUM_OF_STRS
; i
++)
870 _term_buf
.strs
[i
] = (char *) -1;
872 _term_buf
.name_all
= NULL
;
874 r
= _gettinfo(buf
, &_term_buf
, path
);
877 quit(-1, "problem reading entry");
880 fprintf(stderr
, "problem reading entry\n");
885 outputbin(_term_buf
.name_all
);
887 outputinfo(_term_buf
.name_all
);
891 /* convert a terminfo binary to terminfo source */
899 for(i
= 0; i
< NUM_OF_BOOLS
; i
++)
900 _term_buf
.bools
[i
] = -1;
901 for(i
= 0; i
< NUM_OF_NUMS
; i
++)
902 _term_buf
.nums
[i
] = -2;
903 for(i
= 0; i
< NUM_OF_STRS
; i
++)
904 _term_buf
.strs
[i
] = (char *) -1;
906 _term_buf
.name_all
= NULL
;
908 r
= _gettbin(buf
, &_term_buf
);
911 quit(-1, "problem reading entry");
914 fprintf(stderr
, "problem reading entry\n");
918 outputinfo(_term_buf
.name_all
);
923 /* convert a termcap entry to terminfo format */
932 for(i
= 0; i
< NUM_OF_BOOLS
; i
++)
933 _term_buf
.bools
[i
] = -1;
934 for(i
= 0; i
< NUM_OF_NUMS
; i
++)
935 _term_buf
.nums
[i
] = -2;
936 for(i
= 0; i
< NUM_OF_STRS
; i
++)
937 _term_buf
.strs
[i
] = (char *) -1;
939 _term_buf
.name_all
= NULL
;
945 r
= _gettcap(buf
, &_term_buf
, path
);
948 quit(-1, "problem reading entry");
951 fprintf(stderr
, "problem reading entry\n");
955 if (dodefault
&& !continued
)
960 name
= _term_buf
.name_all
;
962 printf("...%s\n", name
);
964 if (name
[0] != '\0' && name
[1] != '\0' && name
[2] == '|')
965 name
+= 3; /* skip the 2 letter code */
974 convbinfile(char *file
)
979 f
= fopen(file
, "r");
982 quit(errno
, "can't open '%s'", file
);
984 r
= fread(buf
, sizeof(char), MAX_BUF
, f
);
985 if (r
< 12 || buf
[0] != 032 || buf
[1] != 01)
986 quit(-1, "file '%s' corrupted", file
);
991 /* convert a termcap file to terminfo format */
993 convtcfile(char *file
)
1000 f
= fopen(file
, "r");
1003 quit(errno
, "can't open '%s'", file
);
1014 } while(c
!= '\n' && c
!= EOF
);
1019 while(c
!= '\n' && c
!= EOF
);
1024 while(isspace(c
) && c
!= '\n')
1026 if (c
== '\n' && buf
== d
) {
1042 } else if (c
== '\n') {
1050 while(d
> buf
&& *d
!= ':')
1052 if (d
[1] == 't' && d
[2] == 'c' && d
[3] == '=') {
1061 "entry doesn't end with :\n");
1063 _term_buf
.strbuf
= _endstr();
1064 _del_strs(&_term_buf
);
1066 printf("\tuse=%s,\n", d
+ 4);
1079 getln(FILE *f
, register char *buf
, int len
)
1081 register int c
, i
= 0;
1083 while((c
= getc(f
)) == '#') {
1087 while((c
= getc(f
)) != '\n') {
1094 while((c
= getc(f
)) != '\n')
1111 while(isspace(*(buf
-1))) {
1121 convtifile(char *file
)
1123 static char line
[MAX_LINE
+1];
1128 f
= fopen(file
, "r");
1131 quit(errno
, "can't open '%s'", file
);
1135 l
= getln(f
, line
, MAX_LINE
);
1137 if (line
[l
-1] == ':') {
1138 strncpy(buf
, line
, MAX_BUF
);
1140 } else if (line
[l
-1] == '\\') {
1145 strncpy(buf
+ MAX_BUF
- n
, line
, n
);
1147 l
= getln(f
, line
, MAX_LINE
);
1148 } while(l
!= -1 && line
[l
-1] == '\\');
1149 if (n
> 0 && l
!= -1)
1150 strncpy(buf
+ MAX_BUF
- n
, line
, n
);
1152 } else if (line
[l
-1] == ',') {
1156 strncpy(buf
+ MAX_BUF
- n
, line
, n
);
1158 l
= getln(f
, line
, MAX_LINE
);
1159 } while(l
!= -1 && isspace(line
[0]));
1161 printf("buf = '%s'\n", buf
);
1165 } else if (line
[0] != '\0') {
1167 fprintf(stderr
, "malformed line\n");
1169 printf("%s\n", line
);
1172 l
= getln(f
, line
, MAX_LINE
);
1177 /* dummy routine for quit */
1185 /* print out usage, called by quit */
1190 fprintf(stderr
, "%s\n%s\n%s\n%s\n",
1191 "usage: tconv [-b] [-c [-OUGd]] [-i] [-B [-D dir]] [-I] [-k] [-V]",
1192 " [-t term] [file]",
1194 " captoinfo [-t term] [-OUGdk] [file]");
1199 main(int argc
, char **argv
)
1207 prg_name
= strrchr(argv
[0], '/');
1208 if (prg_name
== NULL
)
1217 if (strcmp(prg_name
, "tic") == 0)
1220 while ((c
= getopt(argc
, argv
, "bciBIOGUdkVD:t:")) != -1) {
1232 if (directory
!= NULL
)
1233 quit(-1, "more than one directory specified");
1238 quit(-1, "more than one terminal specified");
1241 case 'd': dodefault
= 0; break;
1242 case 'k': keepcomments
= 1; break;
1243 case 'b': from_tbin
= 1; break;
1244 case 'c': from_tcap
= 1; break;
1245 case 'i': from_tinfo
= 1; break;
1246 case 'B': compile
= 1; break;
1247 case 'I': compile
= 0; break;
1248 case 'V': pversion
= 1; break;
1251 quit(-1, "bad or missing command line argument");
1256 quit(0, "%s\n%s", _mytinfo_version
, SCCSid
);
1259 if (optind
== argc
- 1)
1260 file
= argv
[optind
];
1261 else if (optind
!= argc
)
1262 quit(-1, "wrong number of arguments");
1264 if (from_tbin
+ from_tcap
+ from_tinfo
> 1)
1265 quit(-1, "more than one input file type specified");
1267 if (!from_tcap
&& !from_tinfo
&& !from_tbin
&& file
!= NULL
) {
1268 if (strcmp(prg_name
, "cap2info") == 0
1269 || strcmp(prg_name
, "captoinfo") == 0)
1271 else if (strcmp(prg_name
, "tic") == 0)
1274 quit(-1, "no input file type specified");
1277 if (from_tbin
&& compile
)
1278 quit(-1, "can't convert from binary to binary");
1282 cleanup
= do_cleanup
;
1287 path
= _buildpath(file
, 0, NULL
, -1);
1289 path
= _buildpath(file
, 0,
1298 quit(-1, "can't build path");
1300 cleanup
= do_cleanup
;
1301 if (from_tcap
&& !compile
)
1307 } else if (from_tcap
&& !compile
)
1308 path
= _buildpath("$TERMCAP", 1,
1313 else if (from_tinfo
|| from_tbin
)
1314 path
= _buildpath("$TERMINFO", 2,
1324 path
= _buildpath("$TERMCAP", 1,
1354 term
= getenv("TERM");
1356 quit(-1, "no terminal type given");
1359 cleanup
= do_cleanup
;
1361 r
= _findterm(term
, path
, buf
);
1371 quit(-1, "entry is already compiled");
1375 quit(-1, "can't find a terminal entry for '%s'", term
);