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