forrest@CSA4.LBL.GOV (07/14/88)
$Part2:
$ File_is="TC2TT.C"
$ Check_Sum_is=16860395
$ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY
X/*
X
X TC2TT Version 0.1 - Converts Unix (*tm) termcap files into VMS (*tm)
X TERMTABLE.TXT files. See accompanying README.TC2TT for more
X information.
X
X This program may not be sold. Otherwise it is in the public
X domain.
X
X Compile and link this program like any other Vax C program.
X It requires no special linking parameters.
X
X Jon Forrest
X Lawrence Berkeley Lab
X FORREST@LBL.GOV
X ucbvax!lbl-csam!ux1!forrest
X
X*/
X
X#include <stdio.h>
X#include <string.h>
X#include <ctype.h>
X#include "table.h"
X
X#ifdef VMS
X#define TERMCAP "termcap."
X#define ERRLOG "errlog."
X#else
X#define TERMCAP "termcap"
X#define ERRLOG "errlog"
X#endif
X
X#define LINE_LEN 256
X#define TERMNAME_LEN 64 /* max len of terminal name */
X#define LONGNAME 2 /* long terminal name */
X#define EOL ((char *)1)
X#define NO_TC 0
X#define TC 1
X#define FOUND 1
X
X/*
X** The following two lines are global only because of a bug in the
X** VMS Debugger in VMS 4.7 which doesn't allow local character arrays to be
X** examined.
X*/
X
Xchar input_line1[LINE_LEN];
Xchar input_line2[LINE_LEN];
Xchar term_name[TERMNAME_LEN]; /* official name of current terminal */
XFILE *ifp, *ofp, *efp;
XFILE *tcfp = NULL;
Xint do_end = 0; /* don't output END 1st time */
X
Xmain()
X{
X
X if ((ifp = fopen(TERMCAP,"r")) == NULL)
X {
X perror(TERMCAP);
X exit(1);
X }
X if ((ofp = fopen("termtable.txt","w")) == NULL)
X {
X perror("termtable.txt");
X exit(1);
X }
X if ((efp = fopen(ERRLOG,"w")) == NULL)
X {
X perror(ERRLOG);
X exit(1);
X }
X
X while (do_entry(ifp, input_line1, NO_TC) != EOF);
X if (do_end)
X fprintf(ofp,"END\n");
X fclose(ifp);
X fclose(ofp);
X fclose(efp);
X if (tcfp != NULL)
X fclose(tcfp);
X}
X
X/*
X** Process an entry for a terminal in termcap. This might be because
X** we're processing a new entry or because we're looking for a terminal
X** specified in a tc capability. The actual purpose is shown in the
X** third argument.
X*/
X
Xdo_entry(ifp, input_line, purpose)
X FILE *ifp;
X char *input_line;
X int purpose;
X{
X register char *beg_cap;
X register struct table_item *t_ptr;
X char curr_term_name[TERMNAME_LEN];
X char *get_next_cap();
X struct table_item *binary();
X
X for (;;)
X {
X if (fgets(input_line, LINE_LEN, ifp) == NULL)
X return(EOF);
X
X /* ignore comment lines */
X if (*input_line == '#')
X continue;
X
X beg_cap = input_line;
X
X /*
X ** If we're not finding a terminal as a result of a
X ** tc command and we're at the first line in an entry
X */
X
X if ((purpose != TC) && (!isspace(*beg_cap)))
X {
X char *curr_ptr, *term_ptr;
X int did_dash, did_plus;
X
X if (do_end)
X fprintf(ofp,"END\n");
X
X /* get the terminal name */
X get_term_name(beg_cap,curr_term_name,LONGNAME);
X curr_ptr = curr_term_name;
X term_ptr = term_name;
X did_dash = did_plus = 0;
X while (*curr_ptr)
X switch (*curr_ptr)
X {
X case '-':
X curr_ptr++;
X *term_ptr++ = '_';
X if (did_dash == 0)
X {
X fprintf(efp,"%s : Changed dash(s) to '_'\n",curr_term_name);
X did_dash = 1;
X }
X break;
X case '+':
X curr_ptr++;
X *term_ptr++ = 'p';
X *term_ptr++ = 'l';
X *term_ptr++ = 'u';
X *term_ptr++ = 's';
X if (did_plus == 0)
X {
X fprintf(efp,"%s : Changed + to plus\n",curr_term_name);
X did_plus = 1;
X }
X break;
X default:
X *term_ptr++ = *curr_ptr++;
X break;
X }
X *term_ptr = '\0';
X
X fprintf(ofp,"NAME = \"%s\"\n",term_name);
X do_end = 1;
X }
X
X /* get next cap on the line, if any left */
X while ((beg_cap = get_next_cap(beg_cap)) != EOL)
X {
X /*
X ** If the cap is a "tc" then we have to
X ** recursively call do_entry to put together
X ** all the information for the original term
X */
X
X if (strncmp(beg_cap,"tc",2) == 0)
X {
X if (find_term(beg_cap) == FOUND)
X do_entry(tcfp, input_line2, TC);
X else
X fprintf(efp,"%s : No entry found for tc\n",term_name);
X }
X else
X {
X /* look up the cap in the list */
X t_ptr = binary(beg_cap);
X if (t_ptr != ((struct table_item *)0))
X do_cap(beg_cap, t_ptr);
X }
X }
X if (purpose == TC)
X return((int)EOL);
X }
X}
X
X/*
X** Reads the first line in a terminal entry and fills in term_name
X** with the terminal name found. since there can be many different
X** terminal names, the one to use is in which_name. For example,
X** if which_name is 2 this means to use the second terminal name found.
X** If successful, returns which_name, otherwise returns NULL.
X*/
X
Xget_term_name(c_ptr,term_name,which_name)
X register char *c_ptr;
X char term_name[];
X int which_name;
X{
X register int i;
X
X for (i = 1; i < which_name; i++)
X {
X c_ptr = strchr(c_ptr,'|');
X if (c_ptr == NULL)
X return (NULL);
X c_ptr++;
X }
X
X /* now c_ptr points to the which_name'th terminal name */
X for (i = 0;(i < TERMNAME_LEN) && (*c_ptr != '|') && (*c_ptr != ':');)
X term_name[i++] = *c_ptr++;
X if (i == TERMNAME_LEN)
X {
X term_name[i - 1] = '\0';
X fprintf(efp,"Term name starting with \"%s\" too long\n",
X term_name);
X exit(0);
X }
X term_name[i] = '\0';
X return(which_name);
X}
X
Xchar *
Xget_next_cap(beg_cap)
X register char *beg_cap;
X{
X beg_cap = strchr(beg_cap,':');
X
X if (beg_cap == NULL)
X return(EOL);
X else
X {
X beg_cap++;
X if ((*beg_cap == '\\') || (*beg_cap == '\n'))
X return(EOL);
X else
X return(beg_cap);
X }
X}
X
Xdo_cap(beg_cap, t_ptr)
X char *beg_cap;
X struct table_item *t_ptr;
X{
X int arg_num = 1;
X int inc_amount = 1;
X int reverse = 0;
X char *cap_begin;
X
X if (*t_ptr->vms_name == '\0')
X {
X fprintf(efp,"%s : No SMG translation for %s\n",term_name,t_ptr->unix_name);
X return;
X }
X cap_begin = beg_cap;
X
X /* move past the capability name */
X beg_cap++;
X beg_cap++;
X if (*beg_cap == '@')
X return;
X
X switch(t_ptr->type)
X {
X case BOOL:
X fprintf(ofp,"BOOLEAN %s = 1\n",t_ptr->vms_name);
X break;
X case STR:
X if (*beg_cap != '=')
X {
V fprintf(efp,"%s : missing equal char in capability %.2s\n",term_name,cap_beg
Xin);
X break;
X }
X beg_cap++;
X
X fprintf(ofp,"STRING %s = \"",t_ptr->vms_name);
X
X /* skip padding values and asteric */
X while (isdigit(*beg_cap) || (*beg_cap == '*') || (*beg_cap == '.'))
X beg_cap++;
X
X /* go through all characters in string */
X while (*beg_cap != ':')
X {
X switch (*beg_cap)
X {
X case '\n':
X
V fprintf(efp,"%s : missing ending colon in capability %.2s\n",term_name,cap_
Xbegin);
X return;
X case '\\':
X beg_cap++;
X switch (*beg_cap)
X {
X case 'E': /* escape */
X fputc('$',ofp);
X break;
X case 'n': /* newline */
X fprintf(ofp,"^j");
X break;
X case 'r': /* carriage return */
X fprintf(ofp,"^m");
X break;
X case 't': /* horizontal tab */
X fprintf(ofp,"^i");
X break;
X case 'b': /* backspace */
X fprintf(ofp,"^h");
X break;
X case 'f': /* form feed */
X fprintf(ofp,"^l");
X break;
X case '^': /* caret */
X fprintf(ofp,"_^");
X break;
X case '\\': /* backslash */
X fputc('\\',ofp);
X break;
X case '0':
X if (strncmp(beg_cap,"072",3) == 0)
X {
X fputc(':',ofp);
X beg_cap++;
X beg_cap++;
X }
X else
X {
X /* better be just 3 digits */
X fputc(*beg_cap++,ofp);
X fputc(*beg_cap++,ofp);
X fputc(*beg_cap,ofp);
X }
X break;
X };
X beg_cap++;
X break;
X case '^': /* control */
X fputc(*beg_cap++,ofp);
X fputc(*beg_cap++,ofp);
X break;
X case '%':
X /* missing %> */
X beg_cap++;
X switch (*beg_cap)
X {
X case 'n':
X case 'B':
X case 'D':
X case '>':
V fprintf(efp,"%s : cursor addressing mode %%%c not supported\n",term_name,*
Xbeg_cap);
X break;
X case '%':
X fputc('%',ofp);
X break;
X case '+':
X case 'c':
X case '.':
X fprintf(ofp,"(%%%d",arg_num);
X if (*beg_cap++ == '+')
X {
X fprintf(ofp,"+%d)",*beg_cap - 1);
X beg_cap++;
X }
X else
X fputc(')',ofp);
X if (reverse)
X arg_num--;
X else
X arg_num++;
X break;
X case 'i':
X beg_cap++;
X inc_amount = 0;
X break;
X case 'r':
X reverse = 1;
X arg_num = 2;
X beg_cap++;
X break;
X /* convert to ASCII */
X case 'd':
X case '2':
X case '3':
X if (inc_amount)
X {
X fprintf(ofp,"(%%%d-%d)",arg_num,inc_amount);
X if (reverse)
X arg_num--;
X else
X arg_num++;
X }
X else
X {
X /* the 2 or 3 isn't valid
X if (*beg_cap == 'd')
X fprintf(ofp,"!UL");
X else
X fprintf(ofp,"!%cUL",*beg_cap);
X */
X if (*beg_cap != 'd')
X fprintf(efp,"%s : %cdchanged to !UL\n",term_name,*beg_cap);
X fprintf(ofp,"!UL");
X }
X beg_cap++;
X break;
X }
X break;
X
X /* characters that must be escaped */
X case '&':
X case '\'':
X case '@':
X case '"':
X case '$':
X case '!':
X case '(':
X case '_':
X case '+':
X case '-':
X case '*':
X case '/':
X fputc('_',ofp);
X fputc(*beg_cap++,ofp);
X break;
X
X default:
X fputc(*beg_cap++,ofp);
X break;
X }
X }
X fprintf(ofp,"\"\n");
X break;
X case NUM:
X fprintf(ofp,"NUMERIC %s = ",t_ptr->vms_name);
X while (*beg_cap++ != '#');
X while(isdigit(*beg_cap))
X fputc(*beg_cap++,ofp);
X fputc('\n',ofp);
X break;
X };
X return;
X}
X
Xstruct table_item *
Xbinary (cap)
X char *cap;
X{
X int cond;
X register struct table_item *low = &table[0];
V register struct table_item *high = &table[(sizeof table / sizeof (struct table
X_item)) - 1];
X register struct table_item *mid;
X
X while (low <= high)
X {
X mid = low + (high - low) / 2;
X if ((cond = strncmp(cap, mid->unix_name, 2)) < 0)
X high = mid - 1;
X else
X if (cond > 0)
X low = mid + 1;
X else
X return(mid);
X }
X return(NULL);
X}
X
X/*
X** given the address of a tc entry, find the full entry for
X** the terminal given in the tc entry. When this routine returns
X** tcfp will be positioned to the first line of the entry.
X*/
X
Xfind_term(char_ptr)
X register char *char_ptr;
X{
X char *temp_ptr;
X long start_pos;
X int term_num;
X char t_name[TERMNAME_LEN];
X
X /* move over to the terminal name */
X char_ptr++;
X char_ptr++;
X char_ptr++;
X
X /* look for the end of the tc cap terminal name and terminate with null */
X temp_ptr = char_ptr;
X while((*temp_ptr != ':') && (*temp_ptr != '\n'))
X temp_ptr++;
X *temp_ptr = '\0';
X
X /* char_ptr now points to the terminal name to find */
X if (tcfp == NULL)
X tcfp = fopen(TERMCAP,"r");
X else
X rewind(tcfp);
X
X for(;;)
X {
X if (fgets(input_line2, LINE_LEN, tcfp) == NULL)
X return(NULL);
X
X /* point to the beginning of the line */
X temp_ptr = input_line2;
X
X if ((*temp_ptr == '#') || (isspace(*temp_ptr)))
X continue;
X
X start_pos = ftell(tcfp);
X
X term_num = 1;
X while (get_term_name(temp_ptr, t_name, term_num))
X {
X if (strcmp(char_ptr, t_name) == 0)
X {
X fseek(tcfp, start_pos, 0);
X move_over(tcfp);
X return(FOUND);
X }
X else
X {
X term_num++;
X continue;
X }
X }
X continue;
X }
X}
X
Xmove_over(tcfp)
X FILE *tcfp;
X{
X int in_char;
X
X /* read over all terminal names */
X for (;;)
X {
X in_char = fgetc(tcfp);
X if ((in_char != ':') && (in_char != '\\'))
X continue;
X
X /* Now we're either at ':' or the '\'.
X ** If at ':' then the next char is either '\',
X ** meaning more lines are coming, or another cap.
X ** It had better not be '\n' because this means that
X ** a line consisting of only a terminal name was given.
X ** If at '\' the line is missing the ':' and the next char
X ** is '\n' followed by at least one continuation line.
X */
X
X if (in_char == ':')
X {
X in_char = fgetc(tcfp);
X if (in_char == '\\')
X while(isspace(in_char = fgetc(tcfp)));
X }
X else
X {
X while(isspace(fgetc(tcfp)));
X }
X
X /* in either case, restore the character just read */
X ungetc(in_char,tcfp);
X break;
X }
X}
$ GoSub Convert_File
$ Goto Part3