/[dtapublic]/projs/emts/trunk/build/emts_standalone/emts_ifsfscan/win/emts_ifsfscan.cpp
ViewVC logotype

Contents of /projs/emts/trunk/build/emts_standalone/emts_ifsfscan/win/emts_ifsfscan.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 322 - (show annotations) (download)
Thu Jan 9 01:54:41 2020 UTC (4 years, 5 months ago) by dashley
File size: 17992 byte(s)
Rearrange source code.
Remove tab characters from source file.
1 //$Header$
2 //{22c05466-2a15-4726-88b9-880b1c044ded}
3 //-------------------------------------------------------------------------------------------------
4 //Copyright (c) 2020, David T. Ashley
5 //
6 //This file is part of "emts_ifsfscan", a program for identifying gross formatting anomalies in
7 //source files.
8 //
9 //This source code and any program in which it is compiled/used is licensed under the MIT License,
10 //reproduced below.
11 //
12 //Permission is hereby granted, free of charge, to any person obtaining a copy of
13 //this software and associated documentation files(the "Software"), to deal in the
14 //Software without restriction, including without limitation the rights to use,
15 //copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the
16 //Software, and to permit persons to whom the Software is furnished to do so,
17 //subject to the following conditions :
18 //
19 //The above copyright notice and this permission notice shall be included in all
20 //copies or substantial portions of the Software.
21 //
22 //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
25 //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 //SOFTWARE.
29 //-------------------------------------------------------------------------------------------------
30 #include "emts.h"
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #if (K_EMTS_PF == K_EMTS_PF_WINAPI)
36 #include <tchar.h>
37 #endif
38 #include <time.h>
39 #if (K_EMTS_PF == K_EMTS_PF_WINAPI)
40 #include <windows.h>
41 #endif
42
43 #define FCMIOF_HORIZONTAL_BAR_SEP_CHAR ('-')
44 #define FCMIOF_LINE_LEN (78)
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 "emts_ifsfscan, (c) 2020 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 "emts_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 // 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
130 //--------------------------------------------------------------------------------
131 #if (K_EMTS_PF == K_EMTS_PF_WINAPI)
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 #endif
142
143 #if (K_EMTS_PF == K_EMTS_PF_WINAPI)
144 int STRING_is_longer_than_maxpath(const char* s)
145 {
146 if (_MAX_PATH <= 5)
147 return(1);
148 else if (strlen(s) > (_MAX_PATH - 5))
149 return(1);
150 else
151 return(0);
152 }
153 #endif
154
155 int STRING_contains_terminating_backslash(const char* s)
156 {
157 size_t i;
158
159 i = strlen(s);
160
161 if (i == 0)
162 {
163 return(0);
164 }
165 else
166 {
167 do
168 {
169 i--;
170 if (s[i] == '\\')
171 return(1);
172 else if ((s[i] != ' ') && (s[i] != '\t'))
173 return(0);
174 } while (i != 0);
175 return(0);
176 }
177 }
178
179 const char* STRING_vcinfo(size_t which)
180 {
181 static const char* const vcinfo[] =
182 {
183 "$HeadURL$",
184 "$Date$",
185 "$Revision$",
186 "$Author$",
187 "Project GUID: {a644e117-ed10-4355-aab8-691077a3f3c7}",
188 "emts_ifsfscan.cpp GUID: {22c05466-2a15-4726-88b9-880b1c044ded}",
189 };
190
191 if (which < (sizeof(vcinfo) / sizeof(vcinfo[0])))
192 return(vcinfo[which]);
193 else
194 return(NULL);
195 }
196
197 //--------------------------------------------------------------------------------
198 // F O R M A T T E D O U T P U T F U N C T I O N S
199 //--------------------------------------------------------------------------------
200 int FCMIOF_get_line_len(void)
201 {
202 return(FCMIOF_LINE_LEN);
203 }
204
205 void FCMIOF_stream_repchar(FILE* s, char c, unsigned n)
206 {
207 USERASSERT_assert(s != NULL, __FILE__, __LINE__);
208
209 while (n--)
210 fprintf(s, "%c", c);
211 }
212
213 void FCMIOF_repchar(char c, unsigned n)
214 {
215 while (n--)
216 printf("%c", c);
217 }
218
219 void FCMIOF_hline(void)
220 {
221 FCMIOF_repchar(FCMIOF_HORIZONTAL_BAR_SEP_CHAR, FCMIOF_LINE_LEN);
222 printf("\n");
223 }
224
225 void FCMIOF_stream_hline(FILE* s)
226 {
227 USERASSERT_assert(s != NULL, __FILE__, __LINE__);
228
229 FCMIOF_stream_repchar(s, FCMIOF_HORIZONTAL_BAR_SEP_CHAR, FCMIOF_LINE_LEN);
230 fprintf(s, "\n");
231 }
232
233 int is_legal_non_eol_character(char c)
234 {
235 if ((c >= 32) && (c <= 126))
236 return(1);
237 else
238 return(0);
239 }
240
241 int is_illegal_non_eol_character(char c)
242 {
243 if (((c < 32) || (c > 126)) && (c != 13) && (c != 10))
244 return(1);
245 else
246 return(0);
247 }
248
249 int is_tab(char c)
250 {
251 if (c == 9)
252 return(1);
253 else
254 return(0);
255 }
256
257 int is_cr(char c)
258 {
259 if (c == 13)
260 return(1);
261 else
262 return(0);
263 }
264
265 int is_lf(char c)
266 {
267 if (c == 10)
268 return(1);
269 else
270 return(0);
271 }
272
273 void emit_human_friendly_llu(unsigned long long arg)
274 {
275 size_t i, len;
276 char buffer[100];
277
278 #if (K_EMTS_PF == K_EMTS_PF_WINAPI)
279 sprintf_s(buffer, sizeof(buffer) / sizeof(buffer[0]), "%llu", arg);
280 #else
281 sprintf(buffer, "%llu", arg);
282 #endif
283
284 len = strlen(buffer);
285
286 for (i = 0; i < len; i++)
287 {
288 printf("%c", buffer[i]);
289 if (((len - i - 1) != 0) && (((len - i - 1) % 3) == 0))
290 printf(",");
291 }
292 }
293
294 void emit_file_pos_3tuple(unsigned long long line, unsigned long long col, unsigned long long offset)
295 {
296 printf(" Line: ");
297 emit_human_friendly_llu(line);
298 printf(", Col: ");
299 emit_human_friendly_llu(col);
300 printf(", Offset: ");
301 emit_human_friendly_llu(offset);
302 printf("\n");
303 }
304
305 void process_opened_handle(FILE* f)
306 {
307 unsigned long long char_no;
308 unsigned long long line_no;
309 unsigned long long col_no;
310 enum { PST_LINE, PST_CR_FOUND, PST_LF_FOUND } state = PST_LINE;
311 int exit_flag = 0;
312 char in_c, prev_c;
313 unsigned char in_uc;
314 int in_i;
315
316 in_i = fgetc(f);
317
318 if (in_i == EOF)
319 {
320 //Zero-length file or error. Because this tool isn't critical, no need to figure out which, exactly.
321 printf(" Zero-length file.\n");
322 return;
323 }
324
325 prev_c = ' ';
326 char_no = 0;
327 line_no = 1;
328 col_no = 1;
329 in_c = in_i & 0xff;
330 in_uc = in_i & 0xff;
331
332 do
333 {
334 //Illegal characters always get flagged.
335 if (is_illegal_non_eol_character(in_c))
336 {
337 emit_file_pos_3tuple(line_no, col_no, char_no);
338 printf(" Illegal character: 0x%02x.\n", ((unsigned)in_uc));
339 }
340
341 //printf("Character: %02x State: %u\n", in_c, (unsigned)state);
342
343 //Run through the state machine, which would look for bad EOL sequences.
344 switch (state)
345 {
346 case PST_LINE:
347 //Processing non-EOL characters.
348 if (is_lf(in_c))
349 {
350 if ((char_no != 0) && (prev_c == ' '))
351 {
352 emit_file_pos_3tuple(line_no, col_no, char_no);
353 printf(" Line contains trailing whitespace.\n");
354 }
355
356 //Line feeds not allowed without preceding carriage return.
357 emit_file_pos_3tuple(line_no, col_no, char_no);
358 printf(" Out of sequence line feed character (0x0a).\n");
359 line_no++;
360 col_no = 1;
361 state = PST_LF_FOUND;
362 }
363 else if (is_cr(in_c))
364 {
365 if ((char_no != 0) && (prev_c == ' '))
366 {
367 emit_file_pos_3tuple(line_no, col_no, char_no);
368 printf(" Line contains trailing whitespace.\n");
369 }
370
371 //Legal
372 state = PST_CR_FOUND;
373 }
374 else
375 {
376 //Ordinary character.
377 col_no++;
378 }
379 break;
380 case PST_CR_FOUND:
381 if (is_lf(in_c))
382 {
383 //Legal
384 line_no++;
385 col_no = 1;
386 state = PST_LF_FOUND;
387 }
388 else if (is_cr(in_c))
389 {
390 //Back-to-back carriage returns not allowed.
391 emit_file_pos_3tuple(line_no, col_no, char_no);
392 printf(" Out of sequence carriage return character (0x0D).\n");
393 col_no++;
394 }
395 else
396 {
397 //Ordinary character. Illegal, because LF must follow CR.
398 emit_file_pos_3tuple(line_no, col_no, char_no);
399 printf(" Carriage return followed by 0x%02x rather than LF.\n", (unsigned)in_uc);
400 col_no++;
401 }
402 break;
403 case PST_LF_FOUND:
404 if (is_lf(in_c))
405 {
406 //Illegal. Back-to-back line feeds not allowed.
407 emit_file_pos_3tuple(line_no, col_no, char_no);
408 printf(" Out of sequence line feed character (0x0A).\n");
409 line_no++;
410 col_no = 1;
411 }
412 else if (is_cr(in_c))
413 {
414 //Legal. Blank lines are fine.
415 col_no++;
416 state = PST_CR_FOUND;
417 }
418 else
419 {
420 //Ordinary character. Legal.
421 col_no++;
422 state = PST_LINE;
423 }
424 break;
425 default:
426 USERASSERT_assert(0, __FILE__, __LINE__);
427 break;
428 }
429
430 in_i = fgetc(f);
431 prev_c = in_c;
432 in_c = in_i & 0xff;
433 in_uc = in_i & 0xff;
434 char_no++;
435 if (in_i == EOF)
436 {
437 if (state != PST_LF_FOUND)
438 {
439 emit_file_pos_3tuple(line_no, col_no, char_no - 1);
440 printf(" Final line of file does not have CR/LF sequence.\n");
441 }
442 if ((state == PST_LINE) && (prev_c == ' '))
443 {
444 emit_file_pos_3tuple(line_no, col_no, char_no - 1);
445 printf(" Final line contains trailing whitespace.\n");
446 }
447
448 exit_flag = 1;
449 }
450 } while (!exit_flag);
451 }
452
453 void process_file_by_name(const char* s)
454 {
455 FILE* f;
456
457 printf(" %s\n", s);
458
459 f = fopen(s, "rb");
460
461 if (!f)
462 {
463 printf(" fopen() failed.\n");
464 }
465 else
466 {
467 process_opened_handle(f);
468
469 if (fclose(f))
470 {
471 printf(" fclose() failed.\n");
472 }
473 }
474 }
475
476 void process_filename_or_wildcard(const char* fname_or_wildcard)
477 {
478 #if (K_EMTS_PF == K_EMTS_PF_WINAPI)
479 HANDLE hFind;
480 WIN32_FIND_DATA FindFileData;
481
482 //Incoming pointer is worthy of an assertion. The OS should not every deliver
483 //a NULL pointer or empty string to us.
484 USERASSERT_assert(fname_or_wildcard != NULL, __FILE__, __LINE__);
485 USERASSERT_assert(strlen(fname_or_wildcard) > 0, __FILE__, __LINE__);
486
487 printf("%s\n", fname_or_wildcard);
488
489 if (STRING_is_longer_than_maxpath(fname_or_wildcard))
490 {
491 printf(" Specified filename or wildcard too long--cannot process.\n");
492 }
493 else if (STRING_contains_terminating_backslash(fname_or_wildcard))
494 {
495 printf(" Specified filename or wildcard contains terminating \"\\\"--cannot process.\n");
496 }
497 else if (STRING_contains_wildcard(fname_or_wildcard))
498 {
499 hFind = FindFirstFile((TCHAR*)fname_or_wildcard, &FindFileData);
500
501 if (hFind == INVALID_HANDLE_VALUE)
502 {
503 printf(" Wildcard does not match existing files or is invalid.\n");
504 }
505 else
506 {
507 char path_drive[_MAX_PATH + 5];
508 char path_dir[_MAX_PATH + 5];
509 char path_fname[_MAX_PATH + 5];
510 char path_ext[_MAX_PATH + 5];
511 char path_full[_MAX_PATH + 5];
512
513 if (!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
514 {
515 _splitpath(fname_or_wildcard, path_drive, path_dir, path_fname, path_ext);
516
517 strcpy(path_full, path_drive);
518 strcat(path_full, path_dir);
519 strcat(path_full, FindFileData.cFileName);
520
521 process_file_by_name(path_full);
522 }
523
524 while (FindNextFile(hFind, &FindFileData) != 0)
525 {
526 if (!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
527 {
528 _splitpath(fname_or_wildcard, path_drive, path_dir, path_fname, path_ext);
529
530 strcpy(path_full, path_drive);
531 strcat(path_full, path_dir);
532 strcat(path_full, FindFileData.cFileName);
533
534 process_file_by_name(path_full);
535 }
536 }
537 }
538
539 if (hFind != INVALID_HANDLE_VALUE)
540 {
541 FindClose(hFind);
542 }
543 }
544 else
545 {
546 process_file_by_name(fname_or_wildcard);
547 }
548 #else
549 //Incoming pointer is worthy of an assertion. The OS should not every deliver
550 //a NULL pointer or empty string to us.
551 USERASSERT_assert(fname_or_wildcard != NULL, __FILE__, __LINE__);
552 USERASSERT_assert(strlen(fname_or_wildcard) > 0, __FILE__, __LINE__);
553
554 printf("%s\n", fname_or_wildcard);
555
556 process_file_by_name(fname_or_wildcard);
557 #endif
558 }
559
560 void emit_no_par_documentation(void)
561 {
562 size_t i;
563
564 FCMIOF_stream_hline(stdout);
565 for (i = 0; i < (sizeof(prog_desc_text) / sizeof(prog_desc_text[0])); i++)
566 printf("%s\n", prog_desc_text[i]);
567 FCMIOF_stream_hline(stdout);
568 for (i = 0; i < (sizeof(license_preamble) / sizeof(license_preamble[0])); i++)
569 printf("%s\n", license_preamble[i]);
570 FCMIOF_stream_hline(stdout);
571 for (i = 0; i < (sizeof(license_text) / sizeof(license_text[0])); i++)
572 printf("%s\n", license_text[i]);
573 FCMIOF_stream_hline(stdout);
574 printf("Program built on %s at %s.\n", __DATE__, __TIME__);
575 i = 0;
576 while (STRING_vcinfo(i))
577 {
578 printf("%s\n", STRING_vcinfo(i));
579 i++;
580 }
581 FCMIOF_stream_hline(stdout);
582 for (i = 0; i < (sizeof(prog_help_text) / sizeof(prog_help_text[0])); i++)
583 printf("%s\n", prog_help_text[i]);
584 FCMIOF_stream_hline(stdout);
585 }
586
587 void emit_execution_preamble(void)
588 {
589 FCMIOF_stream_hline(stdout);
590 printf("Use \"ets_ifsfscan\" with no parameters to obtain license and help information.\n");
591 FCMIOF_stream_hline(stdout);
592 }
593
594 int main(int argc, char **argv)
595 {
596 int i;
597
598 if (argc <= 1)
599 {
600 //This is most likely someone trying to figure out what the program is or does.
601 //Spit everything.
602 emit_no_par_documentation();
603 }
604 else
605 {
606 emit_execution_preamble();
607
608 //Every argument beyond the program name has to be either a file name or
609 //wildcard. Just process them in order.
610 for (i = 1; i < argc; i++)
611 process_filename_or_wildcard(argv[i]);
612
613 FCMIOF_stream_hline(stdout);
614 }
615
616 return 0;
617 }

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