/*    chk -- C program check sum    */

/* 御使用のコンパイラにあわせて       */
/* 次の４つのうちから、ひとつを選んで */
/* 注釈の外に出して下さい。           */
/* #define DRACO */ /*  FM-7/AV系 Draco-C      */
/* #define MWC   */ /*  OS-9/6809 Microware-C  */
#define MSC         /*  MS-DOS    Micro-Soft C */
/* #define RR */    /*  Runser    Draco-C      */
 
#ifdef  RR
  /*    Runser    */
# include "rusio.c"
# include "string.c"
# include "chklib.c"
# define PRINTER stdprt
# define errno 0
#else
# ifdef DRACO
   /*    Draco C    */
#  include "0:fileio.c"
#  include "0:string.c"
#  define PRINTER stdprt
#  define errno 0
# else
   /*    MW-C & MS-C    */
#  include <stdio.h>
#  include <ctype.h>
#  ifdef MWC
    /*    MW-C    */
#   define PRINTER stderr
#  else
    /*    MS-C    */
#   define PRINTER stdprn
#   define errno 0
#  endif
# endif
#endif

#ifndef RR
# define ERR  (-1)
#endif
#define YES    1
#define NO     0
#define NULL   0

#define BUF_LEN 256

FILE *out ;

char buf [ BUF_LEN ];
int  list = NO, numb = NO,
     check = NO,
     file = NO ;

main( argc, argv )
    int  argc;
    char **argv;
{
    FILE *fp, *fopen();

    out = stdout ;

    if ( option( argc, argv ) < 1 ) {
        putc ( '\n', out );
        checksum( stdin, out );
    } else {
        while ( --argc ) {
            if ( **++argv != '-' ) {
                if ( ( fp = fopen( *argv , "r" ) ) != NULL ) {
                    if ( !check && !list && !numb )
                        fprintf( out, "\n    file <%s>\n\n", *argv );
                    checksum( fp, out );
                    fclose( fp );
                } else {
                    exit( errno );
                }
            }
        }
    }
    if ( file )
        fclose( out );
}

option( argc, argv )
    int  argc;
    char **argv;
{
    char c, *p, fname[256];
    int  count, print;

    count = 0;    print = NO;

    while ( --argc )
        if ( *(p=*++argv) == '-' )
            while ( c = *++p ) {
                switch( c ) {
                case 'f':
                case 'F':
                    file = YES;
                    if ( *++p != '=' ) {
                      prterr( "\n <-f> option format is illegal.\n" );
                      prterr( "   -f=<file name> (ex. -f=1:chk.c)\n\n" );
                      exit( 0 );
                    } else
                      strcpy( fname, ++p );
                    break;
                case 'p':
                case 'P':   print = YES;   break;
                case 'n':
                case 'N':   numb=YES; list=NO; check=NO;   break;
                case 'l':
                case 'L':   list=YES; numb=NO; check=NO;   break;
                case 'c':
                case 'C':   check=YES; list=NO; numb=NO;   break;
                case '?':   usage();
                default:
                    fprintf( stderr, "\nunknown option: -%c\n\n", c );
                    exit(0);
                }
                if ( c == 'f' || c == 'F' )
                    break;
            }
        else
            ++count;

    if ( file && print ) {
        prterr( "\n You must choose between -f and -p option.\n\n" );
        exit(0);
    } else
        if ( print )
            out = PRINTER;
        else
            if ( file && ( out = fopen( fname, "w" ) ) == NULL )
                exit( errno );

    return( count );
}

usage()
{
    prterr( "\n" );
    prterr( "usage:  chk [opt] [<file name>] [opt]\n" );
    prterr( "  opt: -f=filename   output for <filename>\n" );
#ifdef MWC
    prterr( "       -p   output for standard error path\n" );
#else
    prterr( "       -p   output for printer\n" );
#endif
    prterr( "       -l   printout text (without line number)\n" );
    prterr( "       -n   printout line number + text\n" );
    prterr( "       -c   printout line number + check sum + text\n" );
    prterr( "       -?   You know this one.\n" );
    prterr( "\n" );
    exit(0);
}

prterr( s )
    char *s;
{    fprintf( stderr, s );    }

eor( ch, pos )
    char ch;    int pos;
{    return( ch ^ pos );    }

low( i )
    int i;
{    return( i & 0x00FF );    }

checksum( fp )
    FILE *fp;
{
    char c, next_c, last_c, qc, chsum,
         token[256], left[20];

    int  i, j, cpos, tpos, lmod,
         lsum, xsum, ysum[10],
         line, in_rem, in_asm, in_quote;
 
    line = 100;    in_rem = in_asm = in_quote = NO;


    if ( list || numb ) {
        while ( lread( fp ) != ERR ) {
            if ( numb )
                fprintf( out, "%3d0 '", ++line );
            fprintf( out, "%s\n", buf );
        }
    } else {
        do {
            for ( i = 0 ; i < 10 ; i++ )
                ysum[i] = 0;    xsum = 0;
 
            for ( i = 0 ; i < 100 ; i ++ ) {
                if ( ( cpos = lread( fp ) ) == ERR )
                    break;

                ++ line;    tpos = chsum = 0;
                in_quote = NO;
 
                if ( !check ) {
                    if ( i == 0 ) {
                        fprintf( out,
                            "  line  10 20 30 40 50 60 70 80 90 00  Sum\n" );
                        fprintf( out,
                            " -----  -- -- -- -- -- -- -- -- -- --   --\n" );
                    }
 
                    if ( (lmod = i % 10) == 0 ) {
                        fprintf( out, "%5d0  ", line );
                        get_l( cpos, left );
                    }
                }
 
                /*    in-line assembler exit ?    */
                if ( ! in_rem && buf[cpos] == '#' ) {
                    get_token( cpos, token );
                    if ( strcmp( token, "#endasm" ) == 0 )
                        in_asm = NO;
                } else
                    *token = '\0';
 
                if ( in_asm ) {
                    /*    in-line assembler source    */
 
                    if ( buf[cpos] != '*' ) {
                        last_c = 0;
                        while ( ( c = buf[cpos++] ) ) {
 
                            if ( !in_quote && isspace(last_c) && c == ';' )
                                break;
 
                            if ( c == '"' || c == '/' ) {
                                if ( in_quote ) {
                                    if ( qc == c )
                                        in_quote = NO;
                                } else {
                                    if ( isspace(last_c) ) {
                                        in_quote = YES;
                                        qc = c;
                                    }
                                }
                            }
 
                            if ( in_quote || ! isspace( c ) ) {
                                chsum += eor( c, ++tpos );
                            }
                            last_c = c;
                        }
                    }
                } else {
                    /*    in-line assembler in ?    */
                    if ( strcmp( token, "#asm" ) == 0 )
                        in_asm = YES;
 
                    /*    C program    */
 
                    while ( ( c = buf[cpos] ) ) {
                        next_c = buf[++cpos];
 
                        if ( in_rem ) {
                            if ( c == '*' && next_c == '/' ) {
                                in_rem = NO;    ++cpos;
                            }
                        } else {
                            if ( c == '/' && next_c == '*' ) {
                                in_rem = YES;   ++cpos;
                            } else {
                                if ( in_quote ) {
                                    if ( c == '\\' ) {
                                        chsum += eor( c, ++tpos );
                                        c = buf[cpos++];
                                    } else if ( qc == c ) {
                                        in_quote = NO;
                                    }
                                } else {
                                    if ( c == '"' || c == '\'' ) {
                                        in_quote = YES;
                                        qc = c;
                                    }
                                }
 
                                if ( in_quote || ! isspace( c ) ) {
                                    chsum += eor( c, ++tpos );
                                }
                            }
                        }
                    }
                }
 
                lsum = low( chsum );
                if ( check ) {
                    fprintf( out, "%3d0 '0", line );
                    fprintf( out, (tpos) ? "%02x":"--", lsum );
                    fprintf( out, " '%s\n", buf );
                } else {
                    fprintf( out, (tpos) ? "%02x ":"-- ", lsum );
 
                    xsum += lsum;
                    ysum[lmod] += lsum;
 
                    if ( lmod == 9 ) {
                        fprintf( out, ": %02x  <%s>\n", low( xsum ), left );
                        xsum = 0;
                    }
                }
            }

            if ( !check ) {
                if ( lmod < 9 ) {
                    for ( j = lmod + 1 ; j < 10 ; j ++ )
                        fprintf( out, "   " );
                    fprintf( out, ": %02x  <%s>\n", low( xsum ), left );
                }
 
                if ( i > 0 ) {
                    fprintf( out,
                        " -----  ----------------------------------\n" );
                    fprintf( out,"        " );
 
                    xsum = 0;
                    for ( j = 0 ; j < 10 ; j ++ ) {
                        fprintf( out, "%02x ", low( ysum[j] ) );
                        xsum += ysum[j];
                    }
                    fprintf( out, "/ %02x\n\n", low( xsum ) );
                }
            }
        } while ( cpos >= 0 );
    }
}

lread( fp )
    FILE *fp;
{
    char *s;
    int  pos;

    if ( fgets( buf, BUF_LEN, fp ) == NULL )
        return( ERR );

    /*    trimming last spaces    */
    if ( (pos = strlen( buf )) > 0 ) {
        while ( --pos >= 0 && isspace(buf[pos]) )
            buf[pos] = '\0';
    }

    /*    split line number    */
    while ( 1 ) {
        pos = 0;    s = buf;
 
        while ( *s && isspace( *s ) ) { s++;  pos++; }

        if ( isdigit( *s ) ) {
            while ( *s && *s++ != '\'' ) ;
            strcpy( buf, s );
        } else
            break;
    }
 
    return( pos );
}

get_l( pos, s )
    int pos;
    char *s;
{
    int i;    i = 0;

    while ( (*s++ = buf[ pos++ ]) && (i++)<16 ) ;

    *s = '\0';
}

get_token( pos, token )
    int  pos;
    char *token;
{
    while ( buf[pos] && isspace( buf[pos] ) )
        ++pos;
    while ( buf[pos] && !isspace( buf[pos] ) )
        *token++ = buf[pos++];
    *token = '\0';

    return ( pos );
}
