/* CONV.c -- To convert high ascii characters in infile to strings in outfile as specified in tabfile */ /* Usage: CONV [-m] tabfile [ infile [ outfile [messfile] ] ] * * Where: tabfile conversion table file spec * infile input file spec * outfile output file spec -- default .conv * messfile message file spec -- default "messages" * * If "infile" does not appear on the command line, then the input * file spec will be "stdin", the output file spec will be "stdout" * and the message file spec will be "messages". The "-m" switch * suppresses the message file. */ #include "stdio.h" #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif #define FLNMSIZE 128 /* max file name length */ #define MAXCHAR 256 /* max value for type unsigned char */ #define MAXTAB 128 /* max length of line in tabfile */ #define NCODES 256 /* number of codes allowed in tabfile */ #define LOVIS 32 /* smallest visible code */ #define HICODE 128 /* beginning of extended codes */ #define HIVIS 160 /* smallest extended visible code */ #define LFC '\n' /* the newline character */ #define NLC '\0' /* the null character */ FILE *tabfile, *infile, *outfile, *messfile; /* file pointers */ extern void *malloc(); static char tabname[FLNMSIZE+1], inname[FLNMSIZE+1], outname[FLNMSIZE+1]; static char callname[FLNMSIZE+1], messname[FLNMSIZE+1]; short tabal[NCODES]; char *tabar[NCODES]; long lcount = 0; int messoff, filter; main(argc,argv) int argc; /* argument count */ char *argv[]; /* array of argument pointers*/ { int icv = 0, imake = 0, chx = 0; int iput, argn; short warnflag = 0; unsigned long offset = 0L; static char usg[]="Usage: %s [-m] tabfile [ infile [ outfile [messfile] ] ]\n"; char bchx, **argw; messoff = 0; filter = 0; infile = stdin; outfile = stdout; messfile = stderr; strncpy(callname, argv[0], FLNMSIZE); if (argc == 2 && ( (!strcmp(argv[1], "?"))||(!strcmp(argv[1], "h"))|| (!strcmp(argv[1], "-h")) ) ) { fprintf(stderr, usg, callname); exit(0); } if ( (argc < 2)||(argc > 6)|| ( (argc==2)&&(!strcmp(argv[1],"-m")) ) ) { /* impossible number of args */ fprintf(stderr, usg, callname); exit(20); } argn = argc - 1; argw = argv; if(!strcmp(argv[1], "-m")) { if(argc==6) { fprintf(stderr, "%s: No message file arg. with -m switch.\n", callname); exit(20); } messoff = 1; argw = &argv[1]; argn --; } strncpy(tabname,argw[1],FLNMSIZE); /* get the file names */ filter = 1; inname[0] = '\0'; outname[0] ='\0'; strcpy(messname, "messages."); strcat(messname, argv[0]); if(argn >= 2) { filter = 0; strncpy(inname,argw[2],FLNMSIZE); if(argn >= 3) { strncpy(outname, argw[3], FLNMSIZE); if(argn >= 4){ strncpy(messname, argw[4], FLNMSIZE); } } else { strncpy(outname, inname, FLNMSIZE-5); strcat(outname, ".conv"); } } tabfile = fopen(tabname,"r"); /* open conversion table */ if (tabfile == NULL) { /* if error */ fprintf(stderr, "%s: Can't open '%s'\n",callname, tabname); exit(20); } if(!filter) { infile = fopen(inname,"r"); /* open input file */ if (infile == NULL) { fprintf(stderr, "%s: Can't open '%s'\n",callname, inname); fclose(tabfile); exit(20); } outfile = fopen(outname, "w"); if (outfile == NULL) { fputs(" Cannot open output file.\n", stderr); fputs(" Enter full path name for output file. > ", stderr); if (gets(outname) == NULL) filefail(outname); if (strlen(outname) == 0) filefail(outname); outfile = fopen(outname, "w"); if (outfile == NULL) filefail(outname); } } if(!messoff) { messfile = fopen(messname, "w"); if (messfile == NULL) { fputs(" Cannot open message file.\n", stderr); fputs(" Enter full path name for message file. > ", stderr); if (gets(messname) == NULL) filefail(messname); if (strlen(messname) == 0) filefail(messname); messfile = fopen(messname, "w"); if (messfile == NULL) filefail(messname); } fprintf(messfile, " callname is %s\n", callname); fprintf(messfile, " tabname is %s\n", tabname); fprintf(messfile, " inname is %s\n", inname); fprintf(messfile, " outname is %s\n", outname); } /* Ready to work */ /* First, read table into memory */ imake = maketab(); /* returns 0 if table processing is OK */ if (imake == 0) { if(!messoff)tabprint(messfile); /* Table is ready; process infile character by character */ while ((chx = getc(infile)) != EOF) { offset ++; if(tabal[chx] > 0) /* put out subst. string */ { for(icv = 0; icv < tabal[chx]; icv++) { putc(((int)(tabar[chx][icv])), outfile); } } /* pass it through if tabal[chx] < 0 (no table entry) */ else if(tabal[chx] < 0) { putc(chx, outfile); if( (!messoff)&&(chx >=HICODE) ) { bchx = (char)' '; if(chx >= HIVIS) bchx = (char)chx; if(!warnflag) { fputs("\n\n HIGH CODES WITHOUT SUBSTITUTES\n\n", messfile); warnflag = 1; } fprintf(messfile, "No subst. for code %2X (%c) at offset %6lu (hex) %6lX\n", chx, bchx, offset, offset); } } /* pass nothing when tabal[chx] == 0; user wants void */ } /* next character */ } /* finished processing infile */ fclose(tabfile); if (!filter){fclose(infile); fclose(outfile);} if (!messoff)fclose(messfile); if (imake != 0) { fprintf(stderr, "%s: Code imake is %d\n", callname, imake); exit(11); } if(!messoff) fputs("\n", messfile); if(!messoff) fputs(" Check message file.\n", stderr); /* exit() -- small 'e' -- is supposed to free all malloc() memory */ exit(0); } /* MAKETAB -- to make conversion table. "tabfile" must be organized into lines terminated by newlines. The first character in each line is the character for which the remainder of the line is the substitution string. Each line in "tabfile" must have at least two characters including the terminating newline. The maximum length of a substitution string is the smaller of the largest positive integer representable by the type "short" or the value MAXTAB. The conversion table is a pair of tables of size NCODES, where NCODES is the number of codes that can be converted. "tabal" is a table of shorts, each containing the length of the NON NULL-terminated character string in "tabar". The "tabal" entry is -1 when there is no entry for that code in tabfile. When the "tabal" entry is -1, the corresponding code is simply passed through, i.e., it is its own substitution string. The "tabal" entry is 0 when tabfile specifies an empty substitution string for the code. When the "tabal" entry is 0, nothing is passed to the output stream when that the corresponding code appears in the input stream. The '#' character is the escape character when found in tabfile The recognized escape sequences are: ## the character '#' #0 the null character NLC #N or #n the newline character LFC A '#' preceding anything else is ignored. "tabfile" must not contain literal nulls or literal newlines (except in the latter case at the end of each line). */ int maketab() { int imt = 0, asc = 0, irow = 0, icol = 0, jcol = 0, chx = 0; int nstr = 0; char *chptr, strg[MAXTAB+1]; for (imt = 0; imt < NCODES; imt++) tabal[imt]= -1; irow = 0; while ( fgets(strg, MAXTAB, tabfile) != NULL ) /* read tabfile line */ { ++irow; /* row number in conversion table */ icol = strlen(strg); if (icol<2) { fprintf(stderr, "%s: No. of cols < 3 in table row %d\n", callname, irow); return(5); } nstr = (int)strg[0]; if(nstr < 0) { asc = MAXCHAR + nstr; } else asc = nstr; /* So asc should be the (unsigned) ascii code for this row */ /* -- unless it is '#': see below */ if (asc > NCODES-1) { fprintf(stderr, "%s: Code beyond range in row %d\n", callname, irow); return(7); } if (strg[icol] != '\0') { fprintf(stderr, "%s: String not null-terminated, row %d\n", callname, irow); fputs(" *** Internal error in program ***\n", stderr); return(8); } if (strg[icol-1] != '\n') { fprintf(stderr, "%s: Row %d does not end with newline\n", callname, irow); return(9); } /* first character and newline aren't in substitution string */ /* icol = number of characters in subst. string, including '#' */ /* jcol = number of characters in subst. string without '#' */ /* imt = strg index for first character of substitution string */ icol --; icol --; jcol = icol; imt = 1; /* Now asc is the (unsigned) ascii code for current table row */ /* unless it is a '#' -- in which case we look at strg[1] */ if(strg[0] == '#') { switch(strg[1]) { case '#': { asc = '#'; imt ++; jcol --; break; } case '0': { asc = NLC; imt ++; jcol --; break; } case 'N': case 'n': { asc = LFC; imt ++; jcol --; break; } default: { break; } } } if(jcol == 0) /* Empty substitution string for asc */ { tabal[asc] = 0; continue; } if(jcol > 0) { chptr = malloc((unsigned long)jcol); if ( chptr == NULL) { fprintf(stderr, "%s: Not enough memory for table, row %d\n", callname, irow); return(10); } tabar[asc] = chptr; while(imt <= icol) { if(strg[imt] == '#') { imt ++; jcol --; switch (strg[imt]) { case '#': { *chptr = '#'; break; } case '0': { *chptr = NLC; break; } case 'N': case 'n': { *chptr = LFC; break; } default: { *chptr = strg[imt]; break; } } /* end of switch */ } /* case: strg[imt] == '#' */ else { *chptr = strg[imt]; } chptr ++; imt ++; } /* loop while imt <= icol */ tabal[asc] = jcol; } /* end of case: jcol > 0 */ } /* to next row in tabfile */ return(0); } /* WAYOUT -- error routine */ wayout(kcode, xline) int kcode; char xline[]; { fprintf(stderr, "%s: Error %d on line %ld --\n%s\n", callname, kcode, lcount, xline); return(kcode); } /* TABPRINT -- to print out the rows in the table array "tabar" */ tabprint(ifile) FILE *ifile; { int itp = 0, jtp = 0, pflag = 0, blank1 = 0, blank2 = 0; int chx; char ctp = ' '; fprintf(ifile, "--Table array\n"); fputs("\n STANDARD ASCII\n\n", ifile); for (itp=0; itp 0) { ctp = (char)' '; if(itp >= LOVIS) ctp = (char)itp; fprintf(ifile, "%5d %c %2X: ", itp, ctp, itp); for (jtp = 0; jtp < tabal[itp]; jtp ++) { putc((int)(tabar[itp][jtp]), ifile); } putc('\n', ifile); } } fputs("\n HIGH CODES\n\n", ifile); blank1 = HICODE; blank2 = HICODE; for (itp=HICODE; itp= 0) { /* row itp is a table entry */ if( (tabal[itp] == 1)&&(tabar[itp][0] == ' ') ) { /* row itp is a solo blank */ blank2++; } else /* row itp is a table entry not a solo blank */ { if(blank2 > blank1) fprintf(ifile, "Blank singleton from row %5d to row %5d\n", blank1, blank2-1); blank1 = itp+1; blank2 = itp+1; ctp = (char)' '; if(itp >= HIVIS) ctp = (char)itp; fprintf(ifile, "%5d %c %2X: ", itp, ctp, itp); for (jtp = 0; jtp < tabal[itp]; jtp ++) { putc(((int)(tabar[itp][jtp])), ifile); } putc('\n', ifile); } } else /* no entry in table for itp */ { if(blank2 > blank1) fprintf(ifile, "Blank singleton from row %5d to row %5d\n", blank1, blank2-1); blank1 = itp+1; blank2 = itp+1; } } /* next table row */ if(blank2 > blank1) fprintf(ifile, "Blank singleton from row %5d to row %5d\n", blank1, blank2-1); fprintf(ifile, "\n"); } /* FILEFAIL -- exit routine when write mode file cannot be opened */ filefail(filename) char filename[]; { fprintf(stderr, "%s: Cannot open file %s for output\n", callname, filename); fclose(tabfile); if(!filter) { fclose(infile); if(!outfile)fclose(outfile); } exit(20); }