home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume26 / mytinfo / part03 / tconv.c next >
C/C++ Source or Header  |  1992-12-26  |  26KB  |  1,375 lines

  1. /*
  2.  * tconv.c
  3.  *
  4.  * Ross Ridge 
  5.  * Public Domain
  6.  * 92/02/01 07:30:23
  7.  *
  8.  * tconv [-b] [-c [-OUGd]] [-i] [-B [-D dir]] [-I] [-k] [-V] [-t term] [file]
  9.  *
  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
  16.  *
  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
  22.  *
  23.  * -k        keep comments
  24.  * -D dir    directory to put terminfo binaries in
  25.  *
  26.  * -t term    name of terminal to translate
  27.  * file        filename of termcap/terminfo database to use 
  28.  *
  29.  * If a file is specifed and no terminal is given the entire file we be
  30.  * translated.
  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.
  34.  *
  35.  */
  36.  
  37. #define NOTLIB
  38. #include "defs.h"
  39. #define SINGLE
  40. #include "term.h"
  41.  
  42. #include <ctype.h>
  43. #include <fcntl.h>
  44. #ifdef USE_STDDEF
  45. #include <sys/types.h>
  46. #endif
  47. #include <sys/stat.h>
  48.  
  49. #include "strtok.c"
  50. #include "mkdir.c"
  51.  
  52. #ifndef lint
  53. static const char SCCSid[] = "@(#) mytinfo tconv.c 3.2 92/02/01 public domain, By Ross Ridge";
  54. #endif
  55.  
  56. extern int errno;
  57.  
  58. /* the right margin of the output */
  59. #define LINELEN 76
  60.  
  61. struct term_path *path;    /* returned from _buildpath */
  62.  
  63. TERMINAL _term_buf;
  64. char buf[MAX_BUF+1];    /* buffer for the termcap entry */
  65.  
  66. int noOT = 1;        /* -O */
  67. int noGNU = 1;        /* -G */
  68. int noUW = 1;        /* -W */
  69. int dodefault = 1;    /* -d */
  70. int keepcomments = 0;    /* -k */
  71. int compile = 0;    /* -B */
  72. int from_tcap = 0;    /* -c */
  73. int from_tinfo = 0;    /* -i */
  74. int from_tbin = 0;    /* -b */
  75. char *directory = NULL; /* -D */
  76.  
  77. int continued = 0;
  78. int termcap = 1;
  79.  
  80. int lineno = 0;        /* current line number */
  81.  
  82. /* print the first part of a warning message */
  83. void
  84. warn() {
  85.     if (lineno == 0)
  86.         fprintf(stderr, "warning: ");
  87.     else
  88.         fprintf(stderr, "(%s)%d: warning: ",
  89.             _term_buf.name_long, lineno);
  90. }
  91.  
  92. /* output a string indenting at the beginning of a line, and wraping
  93.  * at the right margin. 
  94.  */
  95. void
  96. putstr(s)
  97. char *s; {
  98.     static pos = 0;
  99.     int l;
  100.  
  101.     if (s == NULL) {
  102.         if (pos != 0) {
  103.             pos = 0;
  104.             putchar('\n');
  105.         }
  106.         return;
  107.     }
  108.     
  109.     if (termcap && noOT && *s == 'O')
  110.         return;
  111.     if (termcap && noGNU && *s == 'G')
  112.         return;
  113.     if (termcap && noUW && *s == 'U')
  114.         return;
  115.  
  116.     l = strlen(s) + 2;
  117.  
  118.     if (l + pos > LINELEN && pos != 0) {
  119.         putchar('\n');
  120.         pos = 0;
  121.     }
  122.  
  123.     if (pos == 0) {
  124.         putchar('\t');
  125.         pos = 8;
  126.     } else
  127.         putchar(' ');
  128.  
  129.     printf("%s,", s);
  130.  
  131.     pos += l;
  132. }
  133.  
  134. #ifndef MAX_PUSHED
  135. /* maximum # of parameters that can be pushed onto the stack */
  136. #define MAX_PUSHED 16
  137. #endif
  138.  
  139. int stack[MAX_PUSHED];    /* the stack */
  140. int stackptr;        /* the next empty place on the stack */
  141. int onstack;        /* the top of stack */
  142. int seenm;        /* seen a %m */
  143. int seenn;        /* seen a %n */
  144. int seenr;        /* seen a %r */
  145. int param;        /* current parameter */
  146. char *dp;        /* pointer to the end of the converted string */
  147.  
  148. /* push onstack on to the stack */
  149. void
  150. push() {
  151.     if (stackptr > MAX_PUSHED) {
  152.         warn();
  153.         fprintf(stderr, "string to complex to covert\n");
  154.     } else
  155.         stack[stackptr++] = onstack;
  156. }
  157.  
  158. /* pop the top of the stack into onstack */
  159. void
  160. pop() {
  161.     if (stackptr == 0) 
  162.         if (onstack == 0) {
  163.             warn();
  164.             fprintf(stderr, "I'm confused\n");
  165.         } else
  166.             onstack = 0;
  167.     else
  168.         onstack = stack[--stackptr];
  169.     param++;
  170. }
  171.  
  172. /* convert a character to a terminfo push */
  173. static int
  174. cvtchar(sp)
  175. register char *sp; {
  176.     char c;
  177.     int l;
  178.  
  179.     switch(*sp) {
  180.     case '\\':
  181.         switch(*++sp) {
  182.         case '\'':
  183.         case '$':
  184.         case '\\':
  185.         case '%':
  186.             c = *sp;
  187.             l = 2;
  188.             break;
  189.         case '\0':
  190.             c = '\\';
  191.             l = 1;
  192.             break;
  193.         case '0':
  194.             if (sp[1] == '0' && sp[2] == '0') {
  195.                 c = '\0';
  196.                 l = 4;
  197.             } else {
  198.                 c = '\200'; /* '\0' ???? */
  199.                 l = 2;
  200.             }
  201.             break;
  202.         default:
  203.             c = *sp;
  204.             l = 2;
  205.             break;
  206.         }
  207.         break;
  208.     default:
  209.         c = *sp;
  210.         l = 1;
  211.     }
  212.     c &= 0177;
  213.     if (isgraph(c) && c != ',' && c != '\'' && c != '\\' && c != ':') {
  214.         *dp++ = '%'; *dp++ = '\''; *dp++ = c; *dp++ = '\'';
  215.     } else {
  216.         *dp++ = '%'; *dp++ = '{';
  217.         if (c > 99)
  218.             *dp++ = c / 100 + '0';
  219.         if (c > 9)
  220.             *dp++ = (c / 10) % 10 + '0';
  221.         *dp++ = c % 10 + '0';
  222.         *dp++ = '}';
  223.     }
  224.     return l;
  225. }
  226.  
  227. /* push n copies of param on the terminfo stack if not already there */
  228. void
  229. getparm(parm, n)
  230. int parm;
  231. int n; {
  232.     if (seenr)  {
  233.         if (parm == 1)
  234.             parm = 2;
  235.         else if (parm == 2)
  236.             parm = 1;
  237.     }
  238.     if (onstack == parm) {
  239.         if (n > 1) {
  240.             warn();
  241.             fprintf(stderr, "string may not be optimal");
  242.             *dp++ = '%'; *dp++ = 'P'; *dp++ = 'a';
  243.             while(n--) {
  244.                 *dp++ = '%'; *dp++ = 'g'; *dp++ = 'a';
  245.             }
  246.         }
  247.         return;
  248.     }
  249.     if (onstack != 0)
  250.         push();
  251.  
  252.     onstack = parm;
  253.     
  254.     while(n--) {        /* %p0 */
  255.         *dp++ = '%'; *dp++ = 'p'; *dp++ = '0' + parm;
  256.     }
  257.  
  258.     if (seenn && parm < 3) { /* %{96}%^ */
  259.         *dp++ = '%'; *dp++ = '{'; *dp++ = '9'; *dp++ = '6'; *dp++ = '}';
  260.         *dp++ = '%'; *dp++ = '^';
  261.     }
  262.     
  263.     if (seenm && parm < 3) { /* %{127}%^ */
  264.         *dp++ = '%'; *dp++ = '{'; *dp++ = '1'; *dp++ = '2'; *dp++ = '7';
  265.         *dp++ = '}'; *dp++ = '%'; *dp++ = '^';
  266.     }
  267. }
  268.  
  269. /* convert a string to terminfo format */
  270. char *
  271. convstr(s, i)
  272. register char *s;
  273. int i; {
  274.     static char line[MAX_LINE];
  275.     register char *cap;
  276.     int nocode = 0;
  277.  
  278.     stackptr = 0;
  279.     onstack = 0;
  280.     seenm = 0;
  281.     seenn = 0;
  282.     seenr = 0;
  283.     param = 1;
  284.  
  285.     dp = line;
  286.     cap = strnames[i];
  287. #if 0
  288.     if (cap[0] == 'k'
  289.         || ((cap[0] == 'i' || cap[0] == 'r') && cap[1] == 's'
  290.         && (cap[2] == '1' || cap[2] == '2' || cap[2] == '3')))
  291.     /* if (k.* || [ir]s[123]) */
  292.         nocode = 1;
  293. #else
  294.     if (_strflags[i] != 'G')
  295.         nocode = 1;
  296. #endif
  297.     if (!nocode) {
  298.         char *d = s;
  299.         while(*s != '\0') {
  300.             if (s[0] == '\\' && s[1] != '\0')
  301.                 s++;
  302.             else if (s[0] == '%' && s[1] != '\0') {
  303.                 if (s[1] == 'p') {
  304.                     if (termcap) {
  305.                         warn();
  306.                         fprintf(stderr,
  307. "string '%s' already in terminfo format\n", strcodes[i]);
  308.                         nocode = 1;
  309.                         break;
  310.                     } else
  311.                         nocode = 1;
  312.                 }
  313.                 s++;
  314.             }
  315.             s++;
  316.         }
  317.         if (!nocode && !termcap) {
  318.             warn();
  319.             fprintf(stderr,
  320. "string '%s' not in terminfo format, converting...\n", cap);
  321.         }
  322.         s = d;
  323.     }
  324.     while(*s != '\0') {
  325.         switch(*s) {
  326.         case '%':
  327.             s++;
  328.             if (nocode) {
  329.                 *dp++ = '%';
  330.                 break;
  331.             }
  332.             switch(*s++) {
  333.             case '%': *dp++ = '%'; break;
  334.             case 'r':
  335.                 if (seenr++ == 1) {
  336.                     warn();
  337.                     fprintf(stderr, "seen %%r twice\n");
  338.                 }
  339.                 break;
  340.             case 'm':
  341.                 if (seenm++ == 1) {
  342.                     warn();
  343.                     fprintf(stderr, "seen %%m twice\n");
  344.                 }
  345.                 break;
  346.             case 'n':
  347.                 if (seenn++ == 1) {
  348.                     warn();
  349.                     fprintf(stderr, "seen %%n twice\n");
  350.                 }
  351.                 break;
  352.             case 'i': *dp++ = '%'; *dp++ = 'i'; break;
  353.             case '6': 
  354.             case 'B':
  355.                 getparm(param, 2);
  356.                 /* %{6}%*%+ */
  357.                 *dp++ = '%'; *dp++ = '{'; *dp++ = '6';
  358.                 *dp++ = '}'; *dp++ = '%'; *dp++ = '*';
  359.                 *dp++ = '%'; *dp++ = '+';
  360.                 break;
  361.             case '8':
  362.             case 'D':
  363.                 getparm(param, 2);
  364.                 /* %{2}%*%- */
  365.                 *dp++ = '%'; *dp++ = '{'; *dp++ = '2';
  366.                 *dp++ = '}'; *dp++ = '%'; *dp++ = '*';
  367.                 *dp++ = '%'; *dp++ = '-';
  368.                 break;
  369.             case '>':
  370.                 getparm(param, 2);
  371.                 /* %?%{x}%>%t%{y}%+%; */
  372.                 *dp++ = '%'; *dp++ = '?'; 
  373.                 s += cvtchar(s);
  374.                 *dp++ = '%'; *dp++ = '>';
  375.                 *dp++ = '%'; *dp++ = 't';
  376.                 s += cvtchar(s);
  377.                 *dp++ = '%'; *dp++ = '+';
  378.                 *dp++ = '%'; *dp++ = ';';
  379.                 break;
  380.             case 'a':
  381.                 if ((*s == '=' || *s == '+' || *s == '-'
  382.                      || *s == '*' || *s == '/')
  383.                     && (s[1] == 'p' || s[1] == 'c')
  384.                         && s[2] != '\0') {
  385.                     int l;
  386.                     l = 2;
  387.                     if (*s != '=')
  388.                         getparm(param, 1);
  389.                     if (s[1] == 'p') {
  390.                         getparm(param + s[2] - '@', 1);
  391.                         if (param != onstack) {
  392.                             pop();
  393.                             param--;
  394.                         }
  395.                         l++;
  396.                     } else
  397.                         l += cvtchar(s + 2);
  398.                     switch(*s) {
  399.                     case '+':
  400.                         *dp++ = '%'; *dp++ = '+';
  401.                         break;
  402.                     case '-':
  403.                         *dp++ = '%'; *dp++ = '-';
  404.                         break;
  405.                     case '*':
  406.                         *dp++ = '%'; *dp++ = '*';
  407.                         break;
  408.                     case '/':
  409.                         *dp++ = '%'; *dp++ = '/';
  410.                         break;
  411.                     case '=':
  412.                         if (seenr)
  413.                             if (param == 1)
  414.                                 onstack = 2;
  415.                             else if (param == 2)
  416.                                 onstack = 1;
  417.                             else
  418.                                 onstack = param;
  419.                         else
  420.                             onstack = param;
  421.                         break;
  422.                     }
  423.                     s += l;
  424.                     break;
  425.                 }
  426.                 getparm(param, 1);
  427.                 s += cvtchar(s);
  428.                 *dp++ = '%'; *dp++ = '+';
  429.                 break;
  430.             case '+':
  431.                 getparm(param, 1);
  432.                 s += cvtchar(s);
  433.                 *dp++ = '%'; *dp++ = '+';
  434.                 *dp++ = '%'; *dp++ = 'c';
  435.                 pop();
  436.                 break;
  437.             case 's':
  438.                 s += cvtchar(s);
  439.                 getparm(param, 1);
  440.                 *dp++ = '%'; *dp++ = '-';
  441.                 break;
  442.             case '-':
  443.                 s += cvtchar(s);
  444.                 getparm(param, 1);
  445.                 *dp++ = '%'; *dp++ = '-';
  446.                 *dp++ = '%'; *dp++ = 'c';
  447.                 pop();
  448.                 break;
  449.             case '.':
  450.                 getparm(param, 1);
  451.                 *dp++ = '%'; *dp++ = 'c';
  452.                 pop();
  453.                 break;
  454.             case '2':
  455.                 getparm(param, 1);
  456.                 *dp++ = '%'; *dp++ = '0';
  457.                 *dp++ = '2'; *dp++ = 'd';
  458.                 pop();
  459.                 break;
  460.             case '3':
  461.                 getparm(param, 1);
  462.                 *dp++ = '%'; *dp++ = '0';
  463.                 *dp++ = '3'; *dp++ = 'd';
  464.                 pop();
  465.                 break;
  466.             case 'd':
  467.                 getparm(param, 1);
  468.                 *dp++ = '%'; *dp++ = 'd';
  469.                 pop();
  470.                 break;
  471.             case 'f':
  472.                 param++;
  473.                 break;
  474.             case 'b':
  475.                 param--;
  476.                 break;
  477.             default:
  478.                 warn();
  479.                 *dp++ = '%';
  480.                 s--;
  481.                 fprintf(stderr, "'%s' unknown %% code %%c",
  482.                     strcodes[i], *s);
  483.                 if (*s >= 0 && *s < 32)
  484.                     fprintf(stderr, "^%c\n", *s + '@');
  485.                 else if (*s < 0 || *s >= 127)
  486.                     fprintf(stderr, "\\%03o\n", *s & 0377);
  487.                 else
  488.                     fprintf(stderr, "%c\n", *s);
  489.                 break;
  490.             }
  491.             break;
  492.         case '\\':
  493.             if (!compile) {*dp++ = *s++; *dp++ = *s++; break;}
  494.             /* FALLTHROUGH */
  495.         case '\n':
  496.             if (!compile) {*dp++ = '\\'; *dp++ = 'n'; s++; break;}
  497.             /* FALLTHROUGH */
  498.         case '\t':
  499.             if (!compile) {*dp++ = '\\'; *dp++ = 't'; s++; break;}
  500.             /* FALLTHROUGH */
  501.         case '\r':
  502.             if (!compile) {*dp++ = '\\'; *dp++ = 'r'; s++; break;}
  503.             /* FALLTHROUGH */
  504.         case '\200':
  505.             if (!compile) {*dp++ = '\\'; *dp++ = '0'; s++; break;}
  506.             /* FALLTHROUGH */
  507.         case '\f':
  508.             if (!compile) {*dp++ = '\\'; *dp++ = 'f'; s++; break;}
  509.             /* FALLTHROUGH */
  510.         case '\b':
  511.             if (!compile) {*dp++ = '\\'; *dp++ = 'b'; s++; break;}
  512.             /* FALLTHROUGH */
  513.         case ' ':
  514.             if (!compile) {*dp++ = '\\'; *dp++ = 's'; s++; break;}
  515.             /* FALLTHROUGH */
  516.         case '^':
  517.             if (!compile) {*dp++ = '\\'; *dp++ = '^'; s++; break;}
  518.             /* FALLTHROUGH */
  519.         case ':':
  520.             if (!compile) {*dp++ = '\\'; *dp++ = ':'; s++; break;}
  521.             /* FALLTHROUGH */
  522.         case ',':
  523.             if (!compile) {*dp++ = '\\'; *dp++ = ','; s++; break;}
  524.             /* FALLTHROUGH */
  525. #if 0
  526.         case '\'':
  527.             if (!compile) {*dp++ = '\\'; *dp++ = '\''; s++; break;}
  528.             /* FALLTHROUGH */
  529. #endif
  530.         default:
  531.             if (compile) 
  532.                 *dp++ = *s++;
  533.             else if (*s > 0 && *s < 32) {
  534.                 *dp++ = '^';
  535.                 *dp++ = *s + '@';
  536.                 s++;
  537.             } else if (*s <= 0 || *s >= 127) {
  538.                 *dp++ = '\\';
  539.                 *dp++ = ((*s & 0300) >> 6) + '0';
  540.                 *dp++ = ((*s & 0070) >> 3) + '0';
  541.                 *dp++ = (*s & 0007) + '0';
  542.                 s++;
  543.             } else
  544.                 *dp++ = *s++;
  545.             break;
  546.         }
  547.     }
  548.     *dp = '\0';
  549.     return line;
  550. }
  551.  
  552. #define LSB(n) ((unsigned) (n) & 0377)
  553. #define MSB(n) (((unsigned) (n) >> 8) & 0377)
  554.  
  555. void
  556. writebin(fd, name)
  557. int fd;
  558. char *name; {
  559.     static char bin[MAX_BUF + 1];
  560.     register char *s;
  561.     register char *d;
  562.     register int i;
  563.     register char *t;
  564.     register int n;
  565.     char *strtbl;
  566.     int sz_name, n_bools, n_nums, n_offs, sz_strs;
  567.     extern int _boolorder[], _numorder[], _strorder[];
  568.  
  569.     strncpy(bin + 12, name, 127);
  570.     bin[12 + 128] = '\0';
  571.     sz_name = strlen(name) + 1;
  572.     if (sz_name > 128)
  573.         sz_name = 128;
  574.  
  575.     s = bin + 12 + sz_name;
  576.     for(i = 0; _boolorder[i] != -1; i++) {
  577.         switch(_term_buf.bools[i]) {
  578.         case -1: *s++ = 0; break;
  579.         case  0: *s++ = 0377; break;
  580.         default: *s++ = 1; break;
  581.         }
  582.     }
  583.     n_bools = i;
  584.     if ((sz_name + n_bools) & 1)
  585.         n_bools++;
  586.  
  587.     s = bin + 12 + sz_name + n_bools;
  588.     for(i = 0; _numorder[i] != -1; i++) {
  589.         n = _term_buf.nums[_numorder[i]];
  590.         switch(n) {
  591.         case -2: *s++ = 0377; *s++ = 0377; break;
  592.         case -1: *s++ = 0376; *s++ = 0377; break;
  593.         default:
  594.             *s++ = LSB(n);
  595.             *s++ = MSB(n);
  596.         }
  597.     }
  598.     n_nums = i;
  599.  
  600.     s = bin + 12 + sz_name + n_bools + n_nums * 2;
  601.     for(i = 0; _strorder[i] != -1; i++) {
  602.         if (_term_buf.strs[_strorder[i]] == (char *) 0) {
  603.             *s++ = 0376; *s++ = 0377;
  604.         } else {
  605.             *s++ = 0377; *s++ = 0377;
  606.         }
  607.     }
  608.     n_offs = i;
  609.  
  610.     s = bin + 12 + sz_name + n_bools + n_nums * 2;
  611.     strtbl = d = s + n_offs * 2;
  612.     for(i = 0; _strorder[i] != -1; i++) {
  613.         t = _term_buf.strs[_strorder[i]];
  614.         if (t == (char *) -1 || t == (char *)  0)
  615.             s += 2;
  616.         else {
  617.             n = d - strtbl;
  618.             *s++ = LSB(n);
  619.             *s++ = MSB(n);
  620.             t = convstr(t, _strorder[i]);
  621.             while(*t != '\0') {
  622.                 *d++ = *t++;
  623.                 if (d >= bin + MAX_BUF - 1) {
  624.                     warn();
  625.                     fprintf(stderr,
  626.                     "compiled entry to big\n");
  627.                     *d++ = '\0';
  628.                     goto toobig;
  629.                 }
  630.             }
  631.             *d++ = '\0';
  632.         }
  633.     }
  634.  
  635. toobig:
  636.     sz_strs = d - strtbl;
  637.  
  638.     bin[0] = 032;
  639.     bin[1] = 01;
  640.     bin[2] = LSB(sz_name);
  641.     bin[3] = MSB(sz_name);
  642.     bin[4] = LSB(n_bools);
  643.     bin[5] = MSB(n_bools);
  644.     bin[6] = LSB(n_nums);
  645.     bin[7] = MSB(n_nums);
  646.     bin[8] = LSB(n_offs);
  647.     bin[9] = MSB(n_offs);
  648.     bin[10] = LSB(sz_strs);
  649.     bin[11] = MSB(sz_strs);
  650.  
  651.     if (write(fd, bin, d - bin) == -1) 
  652.         quit(errno, "can't write binary file");
  653.  
  654.     return;
  655. }
  656.  
  657. void
  658. find_directory() {
  659.     struct term_path *p;
  660.     struct stat st;
  661.  
  662.     if (directory != NULL)
  663.         return;
  664.  
  665.     p = path;
  666.     while(p->type != -1 && p->file != NULL) {
  667.         if (stat(p->file, &st) == 0) {
  668.             if ((st.st_mode & 0170000) == 0040000) {
  669.                 directory = p->file;
  670.                 return;
  671.             }
  672.         }
  673.         p++;
  674.     }
  675.     quit(-1, "can't find a terminfo directory");
  676. }
  677.  
  678. /* convert a terminal name to a binary filename */
  679. char *
  680. binfile(name)
  681. char *name; {
  682.     static char line[MAX_LINE+1];
  683.  
  684.     sprintf(line, "%s/%c/%s", directory, *name, name);
  685.     return line;
  686. }
  687.  
  688. char *
  689. bindir(name)
  690. char *name; {
  691.     static char line[MAX_LINE+1];
  692.  
  693.     sprintf(line, "%s/%c", directory, *name);
  694.     return line;
  695. }
  696.  
  697. int
  698. badname(name)
  699. char *name; {
  700.     while(*name) {
  701.         if (*name == '/' || !isgraph(*name))
  702.             return 1;
  703.         name++;
  704.     }
  705.     return 0;
  706. }
  707.  
  708. /* output a terminfo binary */
  709. void
  710. outputbin(name)
  711. char *name; {
  712.     register char *s, *d, *last;
  713.     char tmp[MAX_LINE+1];
  714.     char line[MAX_LINE+1];
  715.     int fd;
  716.  
  717.     find_directory();
  718.  
  719.     s = name;
  720.     d = line;
  721.     while(*s != '\0' && d < line + MAX_LINE) {
  722.         *d++ = *s++;
  723.     }
  724.  
  725.     while(d > line && d[-1] == '|') {
  726.         d--;
  727.     }
  728.  
  729.     *d = '\0';
  730.  
  731.     s = strtok(line, "|");
  732.     last = NULL;
  733.  
  734.     while(s != NULL && last == NULL) {
  735.         if (*s == '\0') {
  736.             ;
  737.         } else if (badname(s)) {
  738.             if (lineno)
  739.                 warn();
  740.             fprintf(stderr, "bad terminal name '%s', ingored.\n",
  741.                 s);
  742.         } else {
  743.             if (access(bindir(s), 2) == -1) {
  744.                 if (errno != ENOENT) 
  745.                     quit(errno,
  746.                          "can't access directory '%s'",
  747.                          bindir(s));
  748.                 if (mkdir(bindir(s), 0777) == -1) 
  749.                     quit(errno, "can't make directory '%s'",
  750.                          bindir(s));
  751.             }
  752.             fd = open(binfile(s), O_WRONLY | O_CREAT | O_EXCL,
  753.                   0666);
  754.             if (fd == -1) {
  755.                 if (errno != EEXIST)
  756.                     quit(errno, "can't open file '%s'",
  757.                          binfile(s));
  758.                 if (unlink(binfile(s)) == -1) 
  759.                     quit(errno, "can't unlink file '%s'",
  760.                          binfile(s));
  761.                 fd = open(binfile(s),
  762.                       O_WRONLY | O_CREAT | O_EXCL, 0666);
  763.                 if (fd == -1)
  764.                     quit(errno, "can't create file '%s'",
  765.                          binfile(s));
  766.             }
  767.             writebin(fd, name);
  768.             close(fd);
  769.             last = s;
  770.         }
  771.         s = strtok(NULL, "|");
  772.     }
  773.  
  774.     if (last == NULL) {
  775.         if (lineno)
  776.             warn();
  777.         fprintf(stderr, "no terminal name, entry ignored.\n");
  778.         return;
  779.     }
  780.  
  781.     while(s != NULL && s + strlen(s) != d) {
  782.         if (*s == '\0' || strcmp(s, last) == 0) {
  783.             ;
  784.         } else if (badname(s)) {
  785.             if (lineno)
  786.                 warn();
  787.             fprintf(stderr, "bad terminal name '%s', ingored.\n",
  788.                 s);
  789.         } else {
  790.             if (access(bindir(s), 2) == -1) {
  791.                 if (errno != ENOENT) 
  792.                     quit(errno,
  793.                          "can't access directory '%s'",
  794.                          bindir(s));
  795.                 if (mkdir(bindir(s), 0777) == -1) 
  796.                     quit(errno, "can't make directory '%s'",
  797.                          bindir(s));
  798.             }
  799.             if (access(binfile(s), 0) == -1) {
  800.                 if (errno != ENOENT)
  801.                     quit(errno, "can't access file '%s'",
  802.                          binfile(s));
  803.             } else if (unlink(binfile(s)) == -1) {
  804.                     quit(errno, "can't unlink file '%s'",
  805.                          binfile(s));
  806.             }
  807.             strcpy(tmp, binfile(last));
  808.             if (link(tmp, binfile(s)) == -1) {
  809.                 quit(errno, "can't link '%s' to '%s'",
  810.                      last, binfile(s));
  811.             }
  812.         }
  813.         s = strtok(NULL, "|");
  814.     }
  815.     return;
  816. }
  817.  
  818. /* output an entry in terminfo source format */
  819. void
  820. outputinfo(name)
  821. char *name; {
  822.     int i;
  823.     char line[MAX_LINE];
  824.  
  825.     printf("%s,\n", name);
  826.  
  827.     for(i = 0; i < NUM_OF_BOOLS; i++)
  828.         if (_term_buf.bools[i] == 0) {
  829.             sprintf(line, "%s@", boolnames[i]);
  830.             putstr(line);
  831.         } else if (_term_buf.bools[i] != -1)
  832.             putstr(boolnames[i]);
  833.  
  834.     for(i = 0; i < NUM_OF_NUMS; i++)
  835.         if (_term_buf.nums[i] == -1) {
  836.             sprintf(line, "%s@", numnames[i]);
  837.             putstr(line);
  838.         } else if (_term_buf.nums[i] != -2) {
  839.             sprintf(line, "%s#%d", numnames[i], _term_buf.nums[i]);
  840.             putstr(line);
  841.         }
  842.  
  843.     for(i = 0; i < NUM_OF_STRS; i++)
  844.         if (_term_buf.strs[i] == NULL) {
  845.             sprintf(line, "%s@", strnames[i]);
  846.             putstr(line);
  847.         } else if (_term_buf.strs[i] != (char *) -1) {
  848.             sprintf(line, "%s=%s", strnames[i],
  849.                 convstr(_term_buf.strs[i], i));
  850.             putstr(line);
  851.         }
  852.     putstr(NULL);
  853. }
  854.  
  855. /* convert a terminfo entry to binary format */
  856. void
  857. convtinfo() {
  858.     int i, r;
  859.  
  860.     termcap = 0;
  861.  
  862.     for(i = 0; i < NUM_OF_BOOLS; i++)
  863.         _term_buf.bools[i] = -1;
  864.     for(i = 0; i < NUM_OF_NUMS; i++)
  865.         _term_buf.nums[i] = -2;
  866.     for(i = 0; i < NUM_OF_STRS; i++)
  867.         _term_buf.strs[i] = (char *) -1;
  868.  
  869.     _term_buf.name_all = NULL;
  870.  
  871.     r = _gettinfo(buf, &_term_buf, path);
  872.     if (r != 0) {
  873.         if (lineno == 0)
  874.             quit(-1, "problem reading entry");
  875.         else {
  876.             warn();
  877.             fprintf(stderr, "problem reading entry\n");
  878.         }
  879.     }
  880.  
  881.     if (compile)
  882.         outputbin(_term_buf.name_all);
  883.     else
  884.         outputinfo(_term_buf.name_all);
  885.     return;
  886. }
  887.  
  888. /* convert a terminfo binary to terminfo source */
  889. void
  890. convtbin() {
  891.     int i, r;
  892.  
  893.     termcap = 0;
  894.  
  895.     for(i = 0; i < NUM_OF_BOOLS; i++)
  896.         _term_buf.bools[i] = -1;
  897.     for(i = 0; i < NUM_OF_NUMS; i++)
  898.         _term_buf.nums[i] = -2;
  899.     for(i = 0; i < NUM_OF_STRS; i++)
  900.         _term_buf.strs[i] = (char *) -1;
  901.  
  902.     _term_buf.name_all = NULL;
  903.  
  904.     r = _gettbin(buf, &_term_buf);
  905.     if (r != 0) {
  906.         if (lineno == 0)
  907.             quit(-1, "problem reading entry");
  908.         else {
  909.             warn();
  910.             fprintf(stderr, "problem reading entry\n");
  911.         }
  912.     }
  913.  
  914.     outputinfo(_term_buf.name_all);
  915.  
  916.     return;
  917. }
  918.  
  919. /* convert a termcap entry to terminfo format */
  920. void
  921. convtcap() {
  922.     int i, r;
  923.     char *name;
  924.  
  925.     termcap = 1;
  926.  
  927.     for(i = 0; i < NUM_OF_BOOLS; i++)
  928.         _term_buf.bools[i] = -1;
  929.     for(i = 0; i < NUM_OF_NUMS; i++)
  930.         _term_buf.nums[i] = -2;
  931.     for(i = 0; i < NUM_OF_STRS; i++)
  932.         _term_buf.strs[i] = (char *) -1;
  933.  
  934.     _term_buf.name_all = NULL;
  935.  
  936.  
  937. #if DEBUG
  938.     printf("%s\n", buf);
  939. #endif
  940.     r = _gettcap(buf, &_term_buf, path);
  941.     if (r != 0) {
  942.         if (lineno == 0)
  943.             quit(-1, "problem reading entry");
  944.         else {
  945.             warn();
  946.             fprintf(stderr, "problem reading entry\n");
  947.         }
  948.     }
  949.  
  950.     if (dodefault && !continued)
  951.         _tcapdefault();
  952.  
  953.     _tcapconv();
  954.  
  955.     name = _term_buf.name_all;
  956. #if DEBUG
  957.     printf("...%s\n", name);
  958. #endif
  959.     if (name[0] != '\0' && name[1] != '\0' && name[2] == '|')
  960.         name += 3;    /* skip the 2 letter code */
  961.  
  962.     if (compile) 
  963.         outputbin(name);
  964.     else
  965.         outputinfo(name);
  966. }
  967.  
  968. void
  969. convbinfile(file)
  970. char *file; {
  971.     register FILE *f;
  972.     int r;
  973.  
  974.     f = fopen(file, "r");
  975.  
  976.     if (f == NULL)
  977.         quit(errno, "can't open '%s'", file);
  978.  
  979.     r = fread(buf, sizeof(char), MAX_BUF, f);
  980.     if (r < 12 || buf[0] != 032 || buf[1] != 01)
  981.         quit(-1, "file '%s' corrupted", file);
  982.  
  983.     convtbin();
  984. }
  985.  
  986. /* convert a termcap file to terminfo format */
  987. void
  988. convtcfile(file)
  989. char *file; {
  990.     int nocolon;
  991.     register int c;
  992.     register char *d;
  993.     register FILE *f;
  994.  
  995.     f = fopen(file, "r");
  996.  
  997.     if (f == NULL)
  998.         quit(errno, "can't open '%s'", file);
  999.  
  1000.     d = buf;
  1001.     c = getc(f);
  1002.     while(c != EOF) {
  1003.         lineno++;
  1004.         if (c == '#') {
  1005.             if (keepcomments) {
  1006.                 do {
  1007.                     putchar(c);
  1008.                     c = getc(f);
  1009.                 } while(c != '\n' && c != EOF);
  1010.                 putchar('\n');
  1011.             } else
  1012.                 do
  1013.                     c = getc(f);
  1014.                 while(c != '\n' && c != EOF);
  1015.             if (c != EOF)
  1016.                 c = getc(f);
  1017.             continue;
  1018.         }
  1019.         while(isspace(c) && c != '\n')
  1020.             c = getc(f);
  1021.         if (c == '\n' && buf == d) {
  1022.             c = getc(f);
  1023.             continue;
  1024.         }
  1025.  
  1026.         while(c != EOF) {
  1027.             if (c == '\\') {
  1028.                 c = getc(f);
  1029.                 if (c == EOF) 
  1030.                     break;
  1031.                 if (c == '\n') {
  1032.                     c = getc(f);
  1033.                     break;
  1034.                 }
  1035.                 *d++ = '\\';
  1036.                 *d++ = c;
  1037.             } else if (c == '\n') {
  1038.                 *d = '\0';
  1039.                 if (*--d == ':') {
  1040.                     nocolon = 0;
  1041.                     *d-- = '\0';
  1042.                 } else {
  1043.                     nocolon = 1;
  1044.                 }
  1045.                 while(d > buf && *d != ':')
  1046.                     d--;
  1047.                 if (d[1] == 't' && d[2] == 'c' && d[3] == '=') {
  1048.                     continued = 1;
  1049.                     d[1] = '\0';
  1050.                 } else
  1051.                     continued = 0;
  1052.                 convtcap();
  1053.                 if (nocolon) {
  1054.                     warn();
  1055.                     fprintf(stderr,
  1056.                         "entry doesn't end with :\n");
  1057.                 }
  1058.                 _term_buf.strbuf = _endstr();
  1059.                 _del_strs(&_term_buf);
  1060.                 if (continued) {
  1061.                     printf("\tuse=%s,\n", d + 4);
  1062.                 }
  1063.                 d = buf;
  1064.                 c = getc(f);
  1065.                 break;
  1066.             } else
  1067.                 *d++ = c;
  1068.             c = getc(f);
  1069.         }
  1070.     }
  1071. }
  1072.  
  1073. static int
  1074. getln(f, buf, len)
  1075. FILE *f;
  1076. register char *buf;
  1077. int len; {
  1078.     register int c, i = 0;
  1079.  
  1080.     while((c = getc(f)) == '#') {
  1081.         lineno++;
  1082.         if (keepcomments) {
  1083.             putchar('#');
  1084.             while((c = getc(f)) != '\n') {
  1085.                 if (c == EOF)
  1086.                     return -1;
  1087.                 putchar(c);
  1088.             }
  1089.             putchar('\n');
  1090.         } else {
  1091.             while((c = getc(f)) != '\n')
  1092.                 if (c == EOF)
  1093.                     return -1;
  1094.         }
  1095.     }
  1096.  
  1097.     lineno++;
  1098.     while(c != '\n') {
  1099.         if (c == EOF)
  1100.             return -1;
  1101.         if (i < len) {
  1102.             i++;
  1103.             *buf++ = c;
  1104.         }
  1105.         c = getc(f);
  1106.     }
  1107.  
  1108.     while(isspace(*(buf-1))) {
  1109.         buf--;
  1110.         i--;
  1111.     }
  1112.  
  1113.     *buf = '\0';
  1114.     return i;
  1115. }
  1116.  
  1117. void
  1118. convtifile(file)
  1119. char *file; {
  1120.     static char line[MAX_LINE+1];
  1121.     int l;
  1122.     int n;
  1123.     register FILE *f;
  1124.  
  1125.     f = fopen(file, "r");
  1126.  
  1127.     if (f == NULL)
  1128.         quit(errno, "can't open '%s'", file);
  1129.  
  1130.     lineno = 0;
  1131.  
  1132.     l = getln(f, line, MAX_LINE);
  1133.     while(l != -1) {
  1134.         if (line[l-1] == ':') {
  1135.             strncpy(buf, line, MAX_BUF);
  1136.             convtcap();
  1137.         } else if (line[l-1] == '\\') {
  1138.             n = MAX_BUF;
  1139.             do {
  1140.                 line[--l] = '\0';
  1141.                 if (n > 0)
  1142.                     strncpy(buf + MAX_BUF - n, line, n);
  1143.                 n -= l;
  1144.                 l = getln(f, line, MAX_LINE);
  1145.             } while(l != -1 && line[l-1] == '\\');
  1146.             if (n > 0 && l != -1)
  1147.                 strncpy(buf + MAX_BUF - n, line, n);
  1148.             convtcap();
  1149.         } else if (line[l-1] == ',') {
  1150.             n = MAX_BUF;
  1151.             do {
  1152.                 if (n > 0)
  1153.                     strncpy(buf + MAX_BUF - n, line, n);
  1154.                 n -= l;
  1155.                 l = getln(f, line, MAX_LINE);
  1156.             } while(l != -1 && isspace(line[0]));
  1157. #if 0
  1158.             printf("buf = '%s'\n", buf);
  1159. #endif
  1160.             convtinfo();
  1161.             continue;
  1162.         } else if (line[0] != '\0') {
  1163.             warn();
  1164.             fprintf(stderr, "malformed line\n");
  1165.             if (keepcomments) {
  1166.                 printf("%s\n", line);
  1167.             }
  1168.         }
  1169.         l = getln(f, line, MAX_LINE);
  1170.     }
  1171.     return;
  1172. }
  1173.  
  1174. /* dummy routine for quit */
  1175. /* ARGSUSED */
  1176. void
  1177. do_cleanup(e)
  1178. int e; {
  1179.     return;
  1180. }
  1181.  
  1182. /* print out usage, called by quit */
  1183. /* ARGSUSED */
  1184. void
  1185. usage(e)
  1186. int e; {
  1187.     fprintf(stderr,
  1188. "usage: %s [-b] [-c [-OUGd]] [-i] [-B [-D dir]] [-I] [-k] [-V]\n\t[-t term] [file]\n",
  1189.         prg_name);
  1190.     return;
  1191. }
  1192.  
  1193. int
  1194. main(argc, argv)
  1195. int argc;
  1196. char **argv; {
  1197.     extern char *optarg;
  1198.     extern int optind;
  1199.     extern int opterr;
  1200.     char *term = NULL;
  1201.     char *file = NULL;
  1202.     int r;
  1203.     char c;
  1204.     int pversion = 0;
  1205.  
  1206.     prg_name = strrchr(argv[0], '/');
  1207.     if (prg_name == NULL)
  1208.         prg_name = argv[0];
  1209.     else
  1210.         prg_name++;
  1211.  
  1212.     cleanup = usage;
  1213.  
  1214.     opterr = 0;
  1215.  
  1216.     if (strcmp(prg_name, "tic") == 0)
  1217.         compile = 1;
  1218.  
  1219.     while ((c = getopt(argc, argv, "bciBIOGUdkVD:t:")) != -1) {
  1220.         switch(c) {
  1221.         case 'O':
  1222.             noOT = 0;
  1223.             break;
  1224.         case 'G':
  1225.             noGNU = 0;
  1226.             break;
  1227.         case 'U':
  1228.             noUW = 0;
  1229.             break;
  1230.         case 'D':
  1231.             if (directory != NULL)
  1232.                 quit(-1, "more than one directory specified");
  1233.             directory = optarg;
  1234.             break;
  1235.         case 't':
  1236.             if (term != NULL)
  1237.                 quit(-1, "more than one terminal specified");
  1238.             term = optarg;
  1239.             break;
  1240.         case 'd': dodefault = 0; break;
  1241.         case 'k': keepcomments = 1; break;
  1242.         case 'b': from_tbin = 1; break;
  1243.         case 'c': from_tcap = 1; break;
  1244.         case 'i': from_tinfo = 1; break;
  1245.         case 'B': compile = 1; break;
  1246.         case 'I': compile = 0; break;
  1247.         case 'V': pversion = 1; break;
  1248.         case '?': 
  1249.         default:
  1250.             quit(-1, "bad or missing command line argument");
  1251.         }
  1252.     }
  1253.  
  1254.     if (pversion) {
  1255.         quit(0, "%s\n%s", _mytinfo_version, SCCSid);
  1256.     }
  1257.  
  1258.     if (optind == argc - 1)
  1259.         file = argv[optind];
  1260.     else if (optind != argc)
  1261.         quit(-1, "wrong number of arguments");
  1262.  
  1263.     if (from_tbin + from_tcap + from_tinfo > 1) 
  1264.         quit(-1, "more than one input file type specified");
  1265.  
  1266.     if (!from_tcap && !from_tinfo && !from_tbin && file != NULL) {
  1267.         if (strcmp(prg_name, "cap2info") == 0
  1268.             || strcmp(prg_name, "captoinfo") == 0)
  1269.             from_tcap = 1;
  1270.         else if (strcmp(prg_name, "tic") == 0)
  1271.             from_tinfo = 1;
  1272.         else 
  1273.             quit(-1, "no input file type specified");
  1274.     }
  1275.  
  1276.     if (from_tbin && compile) 
  1277.         quit(-1, "can't convert from binary to binary");
  1278.  
  1279.     if (file != NULL) {
  1280.         if (from_tbin) {
  1281.             cleanup = do_cleanup;
  1282.             convbinfile(file);
  1283.             exit(0);
  1284.         }
  1285.         if (!compile)
  1286.             path = _buildpath(file, 0, NULL, -1);
  1287.         else {
  1288.             path = _buildpath(file, 0,
  1289.                       "$TERMINFO", 2,
  1290.                       "$MYTERMINFO", 2,
  1291. #ifdef TERMINFODIR
  1292.                       TERMINFODIR, 0,
  1293. #endif
  1294.                       NULL, -1);
  1295.         }
  1296.         if (path == NULL)
  1297.             quit(-1, "can't build path");
  1298.         if (term == NULL) {
  1299.             cleanup = do_cleanup;
  1300.             if (from_tcap && !compile)
  1301.                 convtcfile(file);
  1302.             else 
  1303.                 convtifile(file);
  1304.             exit(0);
  1305.         }
  1306.     } else if (from_tcap && !compile)
  1307.         path = _buildpath("$TERMCAP", 1,
  1308. #ifdef TERMCAPFILE
  1309.                   TERMCAPFILE, 0,
  1310. #endif
  1311.                   NULL, -1);
  1312.     else if (from_tinfo || from_tbin)
  1313.         path = _buildpath("$TERMINFO", 2,
  1314.                   "$MYTERMINFO", 2,
  1315. #ifdef TERMINFODIR
  1316.                   TERMINFODIR, 0,
  1317. #endif
  1318. #ifdef TERMINFOSRC
  1319.                   TERMINFOSRC, 0,
  1320. #endif
  1321.                   NULL, -1);
  1322.     else if (from_tcap)
  1323.         path = _buildpath("$TERMCAP", 1,
  1324. #ifdef TERMCAPFILE
  1325.                   TERMCAPFILE, 0,
  1326. #endif
  1327.                   "$TERMINFO", 2,
  1328.                   "$MYTERMINFO", 2,
  1329. #ifdef TERMINFODIR
  1330.                   TERMINFODIR, 0,
  1331. #endif
  1332.                   NULL, -1);
  1333.     else 
  1334.         path = _buildpath("$TERMINFO", 2,
  1335.                   "$MYTERMINFO", 2,
  1336.                   "$TERMCAP", 1,
  1337. #ifdef TERMINFODIR
  1338.                   TERMINFODIR, 0,
  1339. #endif
  1340. #ifdef TERMINFOSRC
  1341.                   TERMINFOSRC, 0,
  1342. #endif
  1343. #ifdef TERMCAPFILE
  1344.                   TERMCAPFILE, 0,
  1345. #endif
  1346.                   NULL, -1);
  1347.     if (term == NULL) {
  1348.         term = getenv("TERM");
  1349.         if (term == NULL)
  1350.             quit(-1, "no terminal type given");
  1351.     }
  1352.  
  1353.     cleanup = do_cleanup;
  1354.  
  1355.     r = _findterm(term, path, buf);
  1356.     switch(r) {
  1357.     case 1:
  1358.         convtcap();
  1359.         break;
  1360.     case 2:
  1361.         convtinfo();
  1362.         break;
  1363.     case 3:
  1364.         if (compile)
  1365.             quit(-1, "entry is already compiled");
  1366.         convtbin();
  1367.         break;
  1368.     default:
  1369.         quit(-1, "can't find a terminal entry for '%s'", term);
  1370.     }
  1371.  
  1372.     exit(0);
  1373.     return 0;
  1374. }
  1375.