/*************************************************************
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.
Revised: April 27/1991
Send suggestion or bug report to  <rzhu@watmath.waterloo.edu> 
**************************************************************/

#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()
{
	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 ( isprint(c) || isspace(c) ) {
				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()
{
	int	c;

	if ( cntrl_count || out_range_count ) {
		rewind(in_file);
		if ( (fix_file = fopen(fix_name, "wb")) == 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, "rb")) == NULL)
			usage();
		if ((out_file=fopen(out_name,"wb")) == 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.)  */
