/[dtapublic]/projs/ets/trunk/src/ets_tool/ifsfscan/c_main.c
ViewVC logotype

Contents of /projs/ets/trunk/src/ets_tool/ifsfscan/c_main.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 224 - (show annotations) (download)
Sun Jul 22 22:45:17 2018 UTC (6 years, 3 months ago) by dashley
File MIME type: text/plain
File size: 17516 byte(s)
Reorganize.  Copy ets_ifsfscan to new location.
1
2 //#define _CRT_SECURE_NO_WARNINGS
3 //$Header$
4 //{43a387a9-4905-4f4c-8e90-506628d6cc11}
5 //-------------------------------------------------------------------------------------------------
6 //Copyright (c) 2018, David T. Ashley
7 //
8 //This file is part of "ets_ifsfscan", a program for identifying gross formatting anomalies in
9 //source files (Windows/ASCII text files only).
10 //
11 //This source code and any program in which it is compiled/used is licensed under the MIT License,
12 //reproduced below.
13 //
14 //Permission is hereby granted, free of charge, to any person obtaining a copy of
15 //this software and associated documentation files(the "Software"), to deal in the
16 //Software without restriction, including without limitation the rights to use,
17 //copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the
18 //Software, and to permit persons to whom the Software is furnished to do so,
19 //subject to the following conditions :
20 //
21 //The above copyright notice and this permission notice shall be included in all
22 //copies or substantial portions of the Software.
23 //
24 //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29 //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 //SOFTWARE.
31 //-------------------------------------------------------------------------------------------------
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <tchar.h>
36 #include <time.h>
37 #include <windows.h>
38
39 #define FCMIOF_HORIZONTAL_BAR_SEP_CHAR ('-')
40 #define FCMIOF_LINE_LEN (78)
41
42 #ifdef _CRT_SECURE_NO_WARNINGS
43 //#error not set
44 #endif
45
46 //The last column allowed for a characters below is Column 82 (or it will be
47 //less than aesthetic).
48 const char * const license_preamble[] =
49 {
50 "ets_ifsfscan, (c) 2018 David T. Ashley (dashley@gmail.com)",
51 "This program's source files, executable files, and all other related files",
52 "(such as Visual Studio project files) are licensed under \"The MIT License\",",
53 "reproduced below."
54 };
55
56 const char * const license_text[] =
57 {
58 "Permission is hereby granted, free of charge, to any person obtaining a copy",
59 "of this software and associated documentation files(the \"Software\"), to deal",
60 "in the Software without restriction, including without limitation the rights",
61 "to use, copy, modify, merge, publish, distribute, sublicense, and / or sell",
62 "copies of the Software, and to permit persons to whom the Software is",
63 "furnished to do so, subject to the following conditions:",
64 "",
65 "The above copyright notice and this permission notice shall be included in",
66 "all copies or substantial portions of the Software.",
67 "",
68 "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR",
69 "IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,",
70 "FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE",
71 "AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER",
72 "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,",
73 "OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE",
74 "SOFTWARE."
75 };
76
77 const char * const prog_desc_text[] =
78 {
79 "ets_ifsfscan (mnemonic: Ill-Formed Source File SCAN) is a program for",
80 "detecting gross formatting errors in source files (Windows/ASCII text",
81 "files only). The errors detected are non-ASCII characters, tab characters,",
82 "abnormal end-of-line characters, and trailing whitespace on lines."
83 };
84
85 const char * const prog_help_text[] =
86 {
87 "Usage: ets_ifsfscan [filename_or_wildcard [filename_or_wildcard [...]]]",
88 "",
89 "Notes:",
90 " (1) : Wildcards (\"*\", \"?\") are processed by Windows, so Windows is",
91 " the arbiter of which wildcards are accepted and how they expand.",
92 " (2) : This program never writes to a file, so it cannot destroy data",
93 " (except, possibly, by stdout output redirected to a file).",
94 " (3) : This program accepts no options (like \"-help\" or \"-verbose\").",
95 " (4) : This program accepts only Windows line endings (13-10).",
96 " This program is incompatible with *nix and *nix files.",
97 " (5) : This program accepts only the ASCII character set (it will not",
98 " process UTF-8 or any other encodings).",
99 };
100
101 //--------------------------------------------------------------------------------
102 // T E R M I N A T I O N F U N C T I O N S
103 //--------------------------------------------------------------------------------
104 void CCMFATAL_fatal(const char *desc, const char *file, size_t line)
105 {
106 printf("\n");
107 printf("Fatal error. Must terminate execution.\n");
108 printf("File: %s, Line: %zu.\n", file, line);
109 printf("Error description: %s\n", desc);
110 exit(4); //Error code 4 for error termination.
111 }
112
113 //--------------------------------------------------------------------------------
114 // A S S E R T I O N F U N C T I O N S
115 //--------------------------------------------------------------------------------
116 void USERASSERT_assert(int assertion, const char *file, size_t line)
117 {
118 if (! assertion)
119 {
120 printf("\n");
121 printf("Assertion failed. It is necessary to use the source code to diagnose\n");
122 printf("and resolve this error.\n");
123 printf("File: %s, Line: %zu.\n", file, line);
124 exit(4); //Error code 4 for error termination.
125 }
126 }
127
128
129 //--------------------------------------------------------------------------------
130 // S T R I N G A N D C H A R A C T E R A R R A Y F U N C T I O N S
131 //--------------------------------------------------------------------------------
132 int STRING_contains_wildcard(const char *s)
133 {
134 if (strchr(s, '?') != NULL)
135 return(1);
136 else if (strchr(s, '*') != NULL)
137 return(1);
138 else
139 return(0);
140 }
141
142 int STRING_is_longer_than_maxpath(const char *s)
143 {
144 if (_MAX_PATH <= 5)
145 return(1);
146 else if (strlen(s) > (_MAX_PATH - 5))
147 return(1);
148 else
149 return(0);
150 }
151
152 int STRING_contains_terminating_backslash(const char *s)
153 {
154 size_t i;
155
156 i = strlen(s);
157
158 if (i == 0)
159 {
160 return(0);
161 }
162 else
163 {
164 do
165 {
166 i--;
167 if (s[i] == '\\')
168 return(1);
169 else if ((s[i] != ' ') && (s[i] != '\t'))
170 return(0);
171 } while (i != 0);
172 return(0);
173 }
174 }
175
176 const char *STRING_vcinfo(size_t which)
177 {
178 static const char * const vcinfo[] =
179 {
180 "$HeadURL$",
181 "$Date$",
182 "$Revision$",
183 "$Author$",
184 "Project GUID: {f2e6f1b7-8fc5-4582-9cd7-c153febd11f7}",
185 "c_main.c GUID: {43a387a9-4905-4f4c-8e90-506628d6cc11}",
186 "ets_ifsfscan.cpp GUID: {1ea3115f-1f6d-4f0b-979b-ad92423db59a}",
187 };
188
189 if (which < (sizeof(vcinfo) / sizeof(vcinfo[0])))
190 return(vcinfo[which]);
191 else
192 return(NULL);
193 }
194
195 //--------------------------------------------------------------------------------
196 // F O R M A T T E D O U T P U T F U N C T I O N S
197 //--------------------------------------------------------------------------------
198 int FCMIOF_get_line_len(void)
199 {
200 return(FCMIOF_LINE_LEN);
201 }
202
203 void FCMIOF_stream_repchar(FILE *s, char c, unsigned n)
204 {
205 USERASSERT_assert(s != NULL, __FILE__, __LINE__);
206
207 while (n--)
208 fprintf(s, "%c", c);
209 }
210
211 void FCMIOF_repchar(char c, unsigned n)
212 {
213 while (n--)
214 printf("%c", c);
215 }
216
217 void FCMIOF_hline(void)
218 {
219 FCMIOF_repchar(FCMIOF_HORIZONTAL_BAR_SEP_CHAR, FCMIOF_LINE_LEN);
220 printf("\n");
221 }
222
223 void FCMIOF_stream_hline(FILE *s)
224 {
225 USERASSERT_assert(s != NULL, __FILE__, __LINE__);
226
227 FCMIOF_stream_repchar(s, FCMIOF_HORIZONTAL_BAR_SEP_CHAR, FCMIOF_LINE_LEN);
228 fprintf(s, "\n");
229 }
230
231 int is_legal_non_eol_character(char c)
232 {
233 if ((c >= 32) && (c <= 126))
234 return(1);
235 else
236 return(0);
237 }
238
239 int is_illegal_non_eol_character(char c)
240 {
241 if (((c < 32) || (c > 126)) && (c != 13) && (c != 10))
242 return(1);
243 else
244 return(0);
245 }
246
247 int is_tab(char c)
248 {
249 if (c == 9)
250 return(1);
251 else
252 return(0);
253 }
254
255 int is_cr(char c)
256 {
257 if (c == 13)
258 return(1);
259 else
260 return(0);
261 }
262
263 int is_lf(char c)
264 {
265 if (c == 10)
266 return(1);
267 else
268 return(0);
269 }
270
271 void emit_human_friendly_llu(unsigned long long arg)
272 {
273 size_t i, len;
274 char buffer[100];
275
276 sprintf_s(buffer, sizeof(buffer)/sizeof(buffer[0]), "%llu", arg);
277 len = strlen(buffer);
278
279 for (i = 0; i < len; i++)
280 {
281 printf("%c", buffer[i]);
282 if (((len-i-1) != 0) && (((len - i - 1) % 3) == 0))
283 printf(",");
284 }
285 }
286
287 void emit_file_pos_3tuple(unsigned long long line, unsigned long long col, unsigned long long offset)
288 {
289 printf(" Line: ");
290 emit_human_friendly_llu(line);
291 printf(", Col: ");
292 emit_human_friendly_llu(col);
293 printf(", Offset: ");
294 emit_human_friendly_llu(offset);
295 printf("\n");
296 }
297
298 void process_opened_handle(FILE *f)
299 {
300 unsigned long long char_no;
301 unsigned long long line_no;
302 unsigned long long col_no;
303 enum {PST_LINE, PST_CR_FOUND, PST_LF_FOUND} state = PST_LINE;
304 int exit_flag = 0;
305 char in_c, prev_c;
306 unsigned char in_uc;
307 int in_i;
308
309 in_i = fgetc(f);
310
311 if (in_i == EOF)
312 {
313 //Zero-length file or error. Because this tool isn't critical, no need to figure out which, exactly.
314 printf(" Zero-length file.\n");
315 return;
316 }
317
318 prev_c = ' ';
319 char_no = 0;
320 line_no = 1;
321 col_no = 1;
322 in_c = in_i & 0xff;
323 in_uc = in_i & 0xff;
324
325 do
326 {
327 //Illegal characters always get flagged.
328 if (is_illegal_non_eol_character(in_c))
329 {
330 emit_file_pos_3tuple(line_no, col_no, char_no);
331 printf(" Illegal character: 0x%02x.\n", ((unsigned)in_uc));
332 }
333
334 //printf("Character: %02x State: %u\n", in_c, (unsigned)state);
335
336 //Run through the state machine, which would look for bad EOL sequences.
337 switch (state)
338 {
339 case PST_LINE:
340 //Processing non-EOL characters.
341 if (is_lf(in_c))
342 {
343 if ((char_no != 0) && (prev_c == ' '))
344 {
345 emit_file_pos_3tuple(line_no, col_no, char_no);
346 printf(" Line contains trailing whitespace.\n");
347 }
348
349 //Line feeds not allowed without preceding carriage return.
350 emit_file_pos_3tuple(line_no, col_no, char_no);
351 printf(" Out of sequence line feed character (0x0a).\n");
352 line_no++;
353 col_no = 1;
354 state = PST_LF_FOUND;
355 }
356 else if (is_cr(in_c))
357 {
358 if ((char_no != 0) && (prev_c == ' '))
359 {
360 emit_file_pos_3tuple(line_no, col_no, char_no);
361 printf(" Line contains trailing whitespace.\n");
362 }
363
364 //Legal
365 state = PST_CR_FOUND;
366 }
367 else
368 {
369 //Ordinary character.
370 col_no++;
371 }
372 break;
373 case PST_CR_FOUND:
374 if (is_lf(in_c))
375 {
376 //Legal
377 line_no++;
378 col_no = 1;
379 state = PST_LF_FOUND;
380 }
381 else if (is_cr(in_c))
382 {
383 //Back-to-back carriage returns not allowed.
384 emit_file_pos_3tuple(line_no, col_no, char_no);
385 printf(" Out of sequence carriage return character (0x0D).\n");
386 col_no++;
387 }
388 else
389 {
390 //Ordinary character. Illegal, because LF must follow CR.
391 emit_file_pos_3tuple(line_no, col_no, char_no);
392 printf(" Carriage return followed by 0x%02x rather than LF.\n", (unsigned)in_uc);
393 col_no++;
394 }
395 break;
396 case PST_LF_FOUND:
397 if (is_lf(in_c))
398 {
399 //Illegal. Back-to-back line feeds not allowed.
400 emit_file_pos_3tuple(line_no, col_no, char_no);
401 printf(" Out of sequence line feed character (0x0A).\n");
402 line_no++;
403 col_no = 1;
404 }
405 else if (is_cr(in_c))
406 {
407 //Legal. Blank lines are fine.
408 col_no++;
409 state = PST_CR_FOUND;
410 }
411 else
412 {
413 //Ordinary character. Legal.
414 col_no++;
415 state = PST_LINE;
416 }
417 break;
418 default:
419 USERASSERT_assert(0, __FILE__, __LINE__);
420 break;
421 }
422
423 in_i = fgetc(f);
424 prev_c = in_c;
425 in_c = in_i & 0xff;
426 in_uc = in_i & 0xff;
427 char_no++;
428 if (in_i == EOF)
429 {
430 if (state != PST_LF_FOUND)
431 {
432 emit_file_pos_3tuple(line_no, col_no, char_no-1);
433 printf(" Final line of file does not have CR/LF sequence.\n");
434 }
435 if ((state == PST_LINE) && (prev_c == ' '))
436 {
437 emit_file_pos_3tuple(line_no, col_no, char_no - 1);
438 printf(" Final line contains trailing whitespace.\n");
439 }
440
441 exit_flag = 1;
442 }
443 } while (!exit_flag);
444 }
445
446 void process_file_by_name(const char *s)
447 {
448 FILE *f;
449
450 printf(" %s\n", s);
451
452 f = fopen(s, "rb");
453
454 if (!f)
455 {
456 printf(" fopen() failed.\n");
457 }
458 else
459 {
460 process_opened_handle(f);
461
462 if (fclose(f))
463 {
464 printf(" fclose() failed.\n");
465 }
466 }
467 }
468
469 void process_filename_or_wildcard(const char *fname_or_wildcard)
470 {
471 HANDLE hFind;
472 WIN32_FIND_DATA FindFileData;
473
474 //Incoming pointer is worthy of an assertion. The OS should not every deliver
475 //a NULL pointer or empty string to us.
476 USERASSERT_assert(fname_or_wildcard != NULL, __FILE__, __LINE__);
477 USERASSERT_assert(strlen(fname_or_wildcard) > 0, __FILE__, __LINE__);
478
479 printf("%s\n", fname_or_wildcard);
480
481 if (STRING_is_longer_than_maxpath(fname_or_wildcard))
482 {
483 printf(" Specified filename or wildcard too long--cannot process.\n");
484 }
485 else if (STRING_contains_terminating_backslash(fname_or_wildcard))
486 {
487 printf(" Specified filename or wildcard contains terminating \"\\\"--cannot process.\n");
488 }
489 else if (STRING_contains_wildcard(fname_or_wildcard))
490 {
491 hFind = FindFirstFile((TCHAR *)fname_or_wildcard, &FindFileData);
492
493 if (hFind == INVALID_HANDLE_VALUE)
494 {
495 printf(" Wildcard does not match existing files or is invalid.\n");
496 }
497 else
498 {
499 char path_drive[_MAX_PATH + 5];
500 char path_dir[_MAX_PATH + 5];
501 char path_fname[_MAX_PATH + 5];
502 char path_ext[_MAX_PATH + 5];
503 char path_full[_MAX_PATH + 5];
504
505 if (!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
506 {
507 _splitpath(fname_or_wildcard, path_drive, path_dir, path_fname, path_ext);
508
509 strcpy(path_full, path_drive);
510 strcat(path_full, path_dir);
511 strcat(path_full, FindFileData.cFileName);
512
513 process_file_by_name(path_full);
514 }
515
516 while (FindNextFile(hFind, &FindFileData) != 0)
517 {
518 if (!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
519 {
520 _splitpath(fname_or_wildcard, path_drive, path_dir, path_fname, path_ext);
521
522 strcpy(path_full, path_drive);
523 strcat(path_full, path_dir);
524 strcat(path_full, FindFileData.cFileName);
525
526 process_file_by_name(path_full);
527 }
528 }
529 }
530
531 if (hFind != INVALID_HANDLE_VALUE)
532 {
533 FindClose(hFind);
534 }
535 }
536 else
537 {
538 process_file_by_name(fname_or_wildcard);
539 }
540 }
541
542 void emit_no_par_documentation(void)
543 {
544 size_t i;
545
546 FCMIOF_stream_hline(stdout);
547 for (i = 0; i < (sizeof(prog_desc_text) / sizeof(prog_desc_text[0])); i++)
548 printf("%s\n", prog_desc_text[i]);
549 FCMIOF_stream_hline(stdout);
550 for (i = 0; i < (sizeof(license_preamble) / sizeof(license_preamble[0])); i++)
551 printf("%s\n", license_preamble[i]);
552 FCMIOF_stream_hline(stdout);
553 for (i = 0; i < (sizeof(license_text) / sizeof(license_text[0])); i++)
554 printf("%s\n", license_text[i]);
555 FCMIOF_stream_hline(stdout);
556 printf("Program built on %s at %s.\n", __DATE__, __TIME__);
557 i = 0;
558 while (STRING_vcinfo(i))
559 {
560 printf("%s\n", STRING_vcinfo(i));
561 i++;
562 }
563 FCMIOF_stream_hline(stdout);
564 for (i = 0; i < (sizeof(prog_help_text) / sizeof(prog_help_text[0])); i++)
565 printf("%s\n", prog_help_text[i]);
566 FCMIOF_stream_hline(stdout);
567 }
568
569 void emit_execution_preamble(void)
570 {
571 FCMIOF_stream_hline(stdout);
572 printf("Use \"ets_ifsfscan\" with no parameters to obtain license and help information.\n");
573 FCMIOF_stream_hline(stdout);
574 }
575
576 int c_main(int argc, char **argv)
577 {
578 int i;
579
580 if (argc <= 1)
581 {
582 //This is most likely someone trying to figure out what the program is or does.
583 //Spit everything.
584 emit_no_par_documentation();
585 }
586 else
587 {
588 emit_execution_preamble();
589
590 //Every argument beyond the program name has to be either a file name or
591 //wildcard. Just process them in order.
592 for (i = 1; i < argc; i++)
593 process_filename_or_wildcard(argv[i]);
594
595 FCMIOF_stream_hline(stdout);
596 }
597
598 return 0;
599 }

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision URL Header

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25