Subject: Bug-Detecting Program for GuoBiao Files

From: Rupert Zhu <[email-masked]>
Date: Fri, 26 Apr 91 12:13:42 EDT

Bug-Detecting Program
                         =====================

       The bug-detecting program  gbdetect.c  is 100% accurate for GuoBiao
standard.  It can detect all kinds of ill characters in a GuoBiao file which
may hang a printer or an editor.  The following is a brief description.

(1) If no bug is reported by  gbdetect  program, then the file is absolutely
    safe for editing and printing.
(2) If some bugs are detected, the lines containing the bugs are put into the
    file  "file_name.err".
(3) If at least one of the bugs being found is fixable, a corrected version
    of input file will be created and put in file  "file_name.fix".  (Most
    common bugs are caused by out-of-range characters, and they are fixable.)
(4) There are some rare kinds of bugs which cannot be fixed by this program
    yet.
(5) Even if all the bugs are fixable, the technically corrected version
    may still not be literally correct.  Manual work may be needed on the
    file  "file_name.fix".

Prepared by: Rupert Zhu
For CND Chinese Magazine
April 25, 1991
------------------------------ CUT HERE -------------------------------

/*************************************************************
Program:  gbdetect.c
detect ill code in a GuoBiao file
Output lines with ill code in file  "filename.err"
Output corrected version in file "filename.fix", if fixable bug is detected.
Note: A Chinese character in GuoBiao coding consists of two bytes.
     Range of byte 1:  0xA1--0xA7, 0xB0--0xF7    (BYX and CCDOS)
     Range of byte 2:  0xA1--0xFE
     (Unused range of byte 1:  0xA8--0xAF, 0xF8--0xFE)
For usage, type  "gbdetect"  on command line (after compilation).
Author: Rupert Zhu.  April 25/1991.
Send suggestion or bug report to  <[email-masked]>
**************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define  TRUE       1
#define  FALSE      0

char	*pgname;      /* name of this program  */
int	s_flag = FALSE;   /* command line flag for using stdin and stdout */
int	name_flag = FALSE;  /* indicate whether a file_name is provided */
int	cntrl_count = 0;       /*  no. of control char not '\n' or '\r' */
int	out_range_count = 0;   /*  no. of char between 0x80 and 0xA0 */
int	shift_count = 0;      /*  no. of char in range but at wrong position */
int	uneven_count = 0;     /*  no. of lines with odd number of high byte  */
int	bug_count = 0;         /*  total no. of bug characters  */
char	in_name[81];     /* input file name (with extension) */
char	out_name[81];    /* output file name (with extension .err) */
char	fix_name[81];    /* file for corrected text (with extension .fix) */
char	name[81];        /* file name (without extension */
FILE	*in_file;        /* file to be tested  */
FILE	*out_file;       /* file to hold error text */
FILE	*fix_file;       /* file to hold corrected version, if any */

void usage()
{
fprintf(stderr, "\t|----------------------------------------------------|\n");
fprintf(stderr, "\t| Usage:  gbdetect file_name                         |\n");
fprintf(stderr, "\t|     Lines containing bug is put in  file_name.err  |\n");
fprintf(stderr, "\t|     If any bug is detected, a corrected version    |\n");
fprintf(stderr, "\t|     is created and put in  file_name.fix           |\n");
fprintf(stderr, "\t| Example:  gbdetect  CM9104A.GB                     |\n");
fprintf(stderr, "\t|     Error text in file       CM9104A.err           |\n");
fprintf(stderr, "\t|     Corrected text in file   CM9104A.fix           |\n");
fprintf(stderr, "\t|----------------------------------------------------|\n");
exit(1);
}

/* this does the real detecting work */
void detect(void)
{
	unsigned char	c, buf[10240];
	int	i, even = TRUE, bug = FALSE;

	while ( fgets(buf, 10000, in_file) != NULL ) {
		bug = FALSE;
		i = 0;
		while ( ( c = buf[i] ) != '\0' )  {
			i ++;
			if ( iscntrl(c) && !isspace(c) ) {
				bug = TRUE;      /* ASCII control char */
				cntrl_count ++;
			}
			if ( ( c >= 0x80 && c <= 0xA0 ) || c >= 0xFF ) {
				bug = TRUE;      /* out of GuoBiao range */
				out_range_count ++;
			}
			if ( c >= 0 && c <= 0x7F ) {
				if (!even) {
					bug = TRUE;  /* un-even block */
					uneven_count ++;
				}
				even = TRUE;      /* reset at ASCII char */
			}
			if ( c >= 0xA1 && c <= 0xFE )
				even = !even;     /* paired off */
			if ( !even &&         /* c is first byte in a pair */
			    ((c>=0xA8 && c<=0xAF) || (c>= 0xF8 && c<=0xFE))) {
				bug = TRUE;     /* first byte out of range */
				shift_count ++;  /* misplaced second byte? */
			}
		}
		if (bug) {
			fputs(buf, out_file);
			fputc('\n', out_file);
		}
	}
	bug_count = cntrl_count + out_range_count + shift_count +uneven_count;
}

void fix(void)
{
	int	c;

	if ( cntrl_count || out_range_count ) {
		rewind(in_file);
		if ( (fix_file = fopen(fix_name, "w+b")) == NULL ) {
			fprintf(stderr, "File open failed\n");
			exit(1);
		}
		while ( ( c = fgetc(in_file) ) != EOF ) {
			if (isprint(c) || isspace(c) || (c>=0xA1 && c<=0xFE))
				fputc(c, fix_file);
		}
		fprintf(stderr, "\t|------------------------------------|\n");
		fprintf(stderr, "\t| A corrected version is created     |\n");
		fprintf(stderr, "\t| in file:       %-16.15s    |\n", fix_name);
		fprintf(stderr, "\t|------------------------------------|\n");
	}
	if ( shift_count || uneven_count ) {
		fprintf(stderr, "\t|-------------------------------------|\n");
		fprintf(stderr, "\t| Warning: Cannot completely fix the  |\n");
		fprintf(stderr, "\t|   file, whether or not a corrected  |\n");
		fprintf(stderr, "\t|   version is created                |\n");
		fprintf(stderr, "\t|-------------------------------------|\n");
	}
}

/* if -s flag, use stdin and stdout; otherwise, use the name provided */
void open_file()
{
	if ( s_flag ) {
		in_file = stdin;
		out_file = stdout;
	}
	else if ( !strcmp(in_name, out_name) || !strcmp(in_name, fix_name)) {
		fprintf(stderr, "\t|-------------------------------------|\n");
		fprintf(stderr, "\t| Warning: Input file should not have |\n");
		fprintf(stderr, "\t|          extension  .err  or  .fix  |\n");
		fprintf(stderr, "\t| Job aborted !                       |\n");
		fprintf(stderr, "\t|-------------------------------------|\n");
		exit(1);
	}
	else if (name_flag) {
		if ((in_file=fopen(in_name, "r+b")) == NULL)
			usage();
		if ((out_file=fopen(out_name,"w+b")) == NULL) {
			fprintf(stderr, "Cannot open out_file");
			exit(1);
		}
	}
}

/* report to user what is done */
void message()
{
	if (name_flag && !s_flag) {
		fprintf(stderr, "\t|------------------------------------|\n");
		fprintf(stderr, "\t| Input_file  =  %-16.15s    |\n", in_name);
		fprintf(stderr, "\t| Output_file =  %-16.15s    |\n", out_name);
		fprintf(stderr, "\t| Undue control characters =  %4d   |\n",
		cntrl_count);
		fprintf(stderr, "\t| Out of range characters  =  %4d   |\n",
		out_range_count);
		fprintf(stderr, "\t| Misplaced first byte     =  %4d   |\n",
		shift_count);
		fprintf(stderr, "\t| Un-even blocks           =  %4d   |\n",
		uneven_count);
		fprintf(stderr, "\t| Total Bug Characters     =  %4d   |\n",
		bug_count);
		fprintf(stderr, "\t| Job Well Done !                    |\n");
		fprintf(stderr, "\t|------------------------------------|\n");
	}
}

main(argc, argv)
int argc; char *argv[];
{
	int	i;
	char	*cp;

	if (argc <= 1 || argc >= 4)
		usage();
	pgname = argv[0];
	in_file = NULL;
	out_file = NULL;
	for (i=1; i<argc; i++) {
		cp = argv[i];
		if (*cp == '-') {  /* a flag */
			if (*++cp == 's') {   /* stdin, stdout  */
				s_flag++;
			}
		}
		else {         /* a file name argument */
			if ( name_flag == TRUE )
				usage();
			name_flag = TRUE;
			strcpy(in_name, cp);
			sscanf(in_name, "%[^.]", name);
			strcpy(out_name, "");   /* initialization */
			strcat(out_name, name);
			strcat(out_name, ".err");   /* use extension .err */
			strcpy(fix_name, "");   /* initialization */
			strcat(fix_name, name);
			strcat(fix_name, ".fix");   /* use extension .fix */
		}
	}
	if ( !name_flag && !s_flag )
		usage();
	else {
		open_file();
		detect();
		message();
		fix();
	}
}

/* This is written in standard C, instead of ANSI C, for maximum
   portability.  (Some old C compilers do not know ANSI C yet.)  */