/[dtapublic]/projs/emts/trunk/src/ets_toolcol/emts_ifsfscan/c_main.c
ViewVC logotype

Annotation of /projs/emts/trunk/src/ets_toolcol/emts_ifsfscan/c_main.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 293 - (hide annotations) (download)
Wed Jan 1 05:23:25 2020 UTC (4 years, 6 months ago) by dashley
File MIME type: text/plain
File size: 17520 byte(s)
Update from "ets" to "emts".
Propagate changed GUIDs.
1 dashley 224
2     //#define _CRT_SECURE_NO_WARNINGS
3 dashley 150 //$Header$
4 dashley 293 //{7e1f1cd6-0150-45d7-9864-e784dbdf0fd8}
5 dashley 150 //-------------------------------------------------------------------------------------------------
6 dashley 293 //Copyright (c) 2020, David T. Ashley
7 dashley 193 //
8 dashley 293 //This file is part of "emts_ifsfscan", a program for identifying gross formatting anomalies in
9 dashley 212 //source files (Windows/ASCII text files only).
10 dashley 193 //
11     //This source code and any program in which it is compiled/used is licensed under the MIT License,
12 dashley 150 //reproduced below.
13 dashley 193 //
14 dashley 150 //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 dashley 293 //subject to the following conditions:
20 dashley 150 //
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 dashley 193 //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 dashley 150 //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 dashley 151 #include <stdlib.h>
34 dashley 193 #include <string.h>
35 dashley 197 #include <tchar.h>
36 dashley 193 #include <time.h>
37 dashley 197 #include <windows.h>
38 dashley 150
39 dashley 193 #define FCMIOF_HORIZONTAL_BAR_SEP_CHAR ('-')
40     #define FCMIOF_LINE_LEN (78)
41    
42 dashley 224 #ifdef _CRT_SECURE_NO_WARNINGS
43     //#error not set
44     #endif
45    
46 dashley 193 //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 dashley 151 {
50 dashley 293 "ets_ifsfscan, (c) 2020 David T. Ashley (dashley@gmail.com)",
51 dashley 193 "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 dashley 202 "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 dashley 151 };
76    
77 dashley 193 const char * const prog_desc_text[] =
78 dashley 151 {
79 dashley 293 "emts_ifsfscan (mnemonic: Ill-Formed Source File SCAN) is a program for",
80 dashley 212 "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 dashley 151 };
84    
85 dashley 193 const char * const prog_help_text[] =
86 dashley 151 {
87 dashley 212 "Usage: ets_ifsfscan [filename_or_wildcard [filename_or_wildcard [...]]]",
88 dashley 202 "",
89     "Notes:",
90 dashley 193 " (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 dashley 202 " (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 dashley 193 " (5) : This program accepts only the ASCII character set (it will not",
98     " process UTF-8 or any other encodings).",
99 dashley 151 };
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 dashley 193 void CCMFATAL_fatal(const char *desc, const char *file, size_t line)
105 dashley 151 {
106 dashley 193 printf("\n");
107 dashley 202 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 dashley 151 }
112    
113     //--------------------------------------------------------------------------------
114     // A S S E R T I O N F U N C T I O N S
115     //--------------------------------------------------------------------------------
116 dashley 193 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 dashley 151
128    
129 dashley 193 //--------------------------------------------------------------------------------
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 dashley 151
142 dashley 193 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 dashley 151
152 dashley 193 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 dashley 197 "$HeadURL$",
181 dashley 195 "$Date$",
182 dashley 193 "$Revision$",
183 dashley 197 "$Author$",
184 dashley 293 "Project GUID: {a644e117-ed10-4355-aab8-691077a3f3c7}",
185     "c_main.c GUID: {7e1f1cd6-0150-45d7-9864-e784dbdf0fd8}",
186     "emts_ifsfscan.cpp GUID: {22c05466-2a15-4726-88b9-880b1c044ded}",
187 dashley 193 };
188    
189 dashley 197 if (which < (sizeof(vcinfo) / sizeof(vcinfo[0])))
190     return(vcinfo[which]);
191     else
192     return(NULL);
193 dashley 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 dashley 151 int FCMIOF_get_line_len(void)
199     {
200 dashley 202 return(FCMIOF_LINE_LEN);
201 dashley 151 }
202    
203     void FCMIOF_stream_repchar(FILE *s, char c, unsigned n)
204     {
205 dashley 193 USERASSERT_assert(s != NULL, __FILE__, __LINE__);
206 dashley 151
207 dashley 202 while (n--)
208     fprintf(s, "%c", c);
209 dashley 151 }
210    
211     void FCMIOF_repchar(char c, unsigned n)
212     {
213 dashley 202 while (n--)
214     printf("%c", c);
215 dashley 151 }
216    
217     void FCMIOF_hline(void)
218     {
219 dashley 202 FCMIOF_repchar(FCMIOF_HORIZONTAL_BAR_SEP_CHAR, FCMIOF_LINE_LEN);
220     printf("\n");
221 dashley 151 }
222    
223     void FCMIOF_stream_hline(FILE *s)
224     {
225 dashley 193 USERASSERT_assert(s != NULL, __FILE__, __LINE__);
226 dashley 151
227 dashley 202 FCMIOF_stream_repchar(s, FCMIOF_HORIZONTAL_BAR_SEP_CHAR, FCMIOF_LINE_LEN);
228     fprintf(s, "\n");
229 dashley 151 }
230    
231 dashley 197 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 dashley 199 size_t i, len;
274     char buffer[100];
275    
276 dashley 210 sprintf_s(buffer, sizeof(buffer)/sizeof(buffer[0]), "%llu", arg);
277 dashley 199 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 dashley 197 }
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 dashley 202
309 dashley 197 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 dashley 199 in_c = in_i & 0xff;
323     in_uc = in_i & 0xff;
324 dashley 197
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 dashley 199 //printf("Character: %02x State: %u\n", in_c, (unsigned)state);
335    
336 dashley 197 //Run through the state machine, which would look for bad EOL sequences.
337     switch (state)
338     {
339     case PST_LINE:
340 dashley 199 //Processing non-EOL characters.
341 dashley 197 if (is_lf(in_c))
342     {
343 dashley 199 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 dashley 197 //Line feeds not allowed without preceding carriage return.
350     emit_file_pos_3tuple(line_no, col_no, char_no);
351 dashley 199 printf(" Out of sequence line feed character (0x0a).\n");
352 dashley 197 line_no++;
353     col_no = 1;
354     state = PST_LF_FOUND;
355     }
356     else if (is_cr(in_c))
357     {
358 dashley 199 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 dashley 197 //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 dashley 199 printf(" Out of sequence carriage return character (0x0D).\n");
386 dashley 197 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 dashley 199 state = PST_CR_FOUND;
410 dashley 197 }
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 dashley 199 prev_c = in_c;
425     in_c = in_i & 0xff;
426     in_uc = in_i & 0xff;
427 dashley 197 char_no++;
428     if (in_i == EOF)
429 dashley 199 {
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 dashley 197 exit_flag = 1;
442 dashley 199 }
443 dashley 197 } 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 dashley 193 void process_filename_or_wildcard(const char *fname_or_wildcard)
470     {
471 dashley 197 HANDLE hFind;
472     WIN32_FIND_DATA FindFileData;
473    
474 dashley 193 //Incoming pointer is worthy of an assertion. The OS should not every deliver
475     //a NULL pointer or empty string to us.
476 dashley 197 USERASSERT_assert(fname_or_wildcard != NULL, __FILE__, __LINE__);
477 dashley 193 USERASSERT_assert(strlen(fname_or_wildcard) > 0, __FILE__, __LINE__);
478 dashley 151
479 dashley 197 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 dashley 193 }
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 dashley 197 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 dashley 193 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 dashley 214 printf("Use \"ets_ifsfscan\" with no parameters to obtain license and help information.\n");
573 dashley 193 FCMIOF_stream_hline(stdout);
574     }
575    
576 dashley 150 int c_main(int argc, char **argv)
577     {
578 dashley 193 int i;
579    
580 dashley 150 if (argc <= 1)
581     {
582 dashley 193 //This is most likely someone trying to figure out what the program is or does.
583     //Spit everything.
584     emit_no_par_documentation();
585 dashley 150 }
586 dashley 193 else
587     {
588     emit_execution_preamble();
589 dashley 150
590 dashley 193 //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 dashley 150 return 0;
599 dashley 202 }

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