1 /* $Id$
2 Written 1999 by Tobias Ernst and released do the Public Domain.
3 This file is part of NLTOOLS, the nodelist processor of the Husky fidonet
4 software project.
5
6 Tool to check the CRC value in a Fidonet Nodelist
7 References: FTS-0005, FTS-5000
8 */
9
10 #include <stdio.h>
11 #include <errno.h>
12 #include <string.h>
13 #include <stdlib.h>
14 #include <ctype.h>
15
16 #include <huskylib/huskylib.h>
17
18 #include "crc16.h"
19 #include "version.h"
20
21 enum
22 { SCANCOLON, SCANDIGIT, CRCVAL, AFTERCRCVAL, FINISH };
23 enum
24 { ok = 0, unknown_option = 1, illegal_parameter = 2, nodelist_without_crc = 4, error_nodelist =
25 8, error_CRC = 16 } exit_codes;
26
27 #define PROGRAM "nlcrc"
28 char *versionStr = "";
29
analyze_first_line(FILE * f)30 unsigned short analyze_first_line( FILE * f )
31 {
32 char c = 0;
33 int state = SCANCOLON;
34 unsigned short crc = 0;
35
36 while( state != FINISH )
37 {
38 fread( &c, 1, 1, f );
39 if( c == '\n' )
40 {
41 if( state < CRCVAL )
42 {
43 fprintf( stderr, "Warning: File does not contain checksum.\n" );
44 exit( nodelist_without_crc );
45 }
46 else
47 {
48 state = FINISH;
49 }
50 }
51 else if( isdigit( c ) )
52 {
53 switch ( state )
54 {
55 case SCANDIGIT:
56 crc = c - '0';
57 state = CRCVAL;
58 break;
59 case CRCVAL:
60 crc = crc * 10U + ( c - '0' );
61 break;
62 default:;
63 }
64 }
65 else if( c == ':' )
66 {
67 switch ( state )
68 {
69 case SCANCOLON:
70 state = SCANDIGIT;
71 break;
72 default:;
73 }
74 }
75 else
76 {
77 switch ( state )
78 {
79 case CRCVAL:
80 state = AFTERCRCVAL;
81 break;
82 default:;
83 }
84 }
85 }
86 return crc;
87 }
88
89 #define BUFSZ 32768
90
analyze_rest(FILE * f)91 unsigned short analyze_rest( FILE * f )
92 {
93 static unsigned char buffer[BUFSZ + 1];
94 size_t l;
95 unsigned short crc;
96 unsigned char *p = NULL;
97
98 crc16_init( &crc );
99
100 errno = 0;
101 while( ( ( l = fread( buffer, 1, BUFSZ, f ) ) > 0 ) && p == NULL )
102 {
103 buffer[l] = '\0';
104 p = ( unsigned char * ) strchr( ( char * ) buffer, 0x1A );
105
106 if( p != NULL )
107 {
108 l = p - buffer;
109 }
110
111 crc16_process( &crc, buffer, l );
112 }
113
114 crc16_finalize( &crc );
115
116 return crc;
117 }
118
usage()119 void usage( )
120 {
121 printf( "\nUsage: " PROGRAM " <FILENAME>\n\n"
122 "\tIf nothing is printed ans exit code is zero, the CRC was OK. If the CRC is not\n"
123 "\tOK, an error message and a exit code 8 is given.\n" );
124 }
125
main(int argc,char ** argv)126 int main( int argc, char **argv )
127 {
128 FILE *f;
129 unsigned short should, is;
130 int flag_quiet;
131 char *nlname = NULL;
132
133 versionStr = GenVersionStr( PROGRAM, VER_MAJOR, VER_MINOR, VER_PATCH, VER_BRANCH, cvs_date );
134
135 {
136 int i;
137 for( i = 1; i < argc; i++ )
138 {
139 int j, plen;
140 if( argv[i][0] == '-' )
141 {
142 int plen = sstrlen( argv[i] );
143 for( j = 1; j < plen; j++ )
144 switch ( argv[i][j] )
145 {
146 case 'h':
147 usage( );
148 return ok;
149 case 'v':
150 printversion( );
151 return ok;
152 case 'q':
153 flag_quiet = 1;
154 break;
155 default:
156 printf( "Illegal option '%c'!\n\n", argv[i][j] );
157 usage( );
158 return unknown_option;
159 }
160 }
161 else if( !nlname )
162 nlname = argv[i];
163 else
164 {
165 printf( "Illegal call: supports only one nodelist file name!\n"
166 "Detected filename: \"%s\"\n" "Extra parameter is \"%s\"\nExit.", nlname, argv[i] );
167 return illegal_parameter;
168 }
169 }
170 if( !nlname )
171 printf( "Illegal call: nodelist filename is needed!\n" );
172 return illegal_parameter;
173 }
174
175 if( !flag_quiet )
176 printversion( );
177
178 if( ( f = fopen( nlname, "rb" ) ) == NULL )
179 {
180 fprintf( stderr, "Cannot open %s.\n", argv[1] );
181 return error_nodelist;
182 }
183
184 should = analyze_first_line( f );
185 is = analyze_rest( f );
186
187 fclose( f );
188
189 if( should != is )
190 {
191 fprintf( stderr, "Nodelist %s fails CRC check (%u != %u)\n",
192 argv[1], ( unsigned ) should, ( unsigned ) is );
193 return error_CRC;
194 }
195
196 return ok;
197 }
198