Minor style fix.
[style_checker.git] / src / style_checker.adb
blobaa542b6e272e3789db1c1bb3b8453bf628453120
1 ------------------------------------------------------------------------------
2 -- Style Checker --
3 -- --
4 -- Copyright (C) 2006-2007, Pascal Obry --
5 -- --
6 -- This library is free software; you can redistribute it and/or modify --
7 -- it under the terms of the GNU General Public License as published by --
8 -- the Free Software Foundation; either version 2 of the License, or (at --
9 -- your option) any later version. --
10 -- --
11 -- This library is distributed in the hope that it will be useful, but --
12 -- WITHOUT ANY WARRANTY; without even the implied warranty of --
13 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU --
14 -- General Public License for more details. --
15 -- --
16 -- You should have received a copy of the GNU General Public License --
17 -- along with this library; if not, write to the Free Software Foundation, --
18 -- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. --
19 -- --
20 ------------------------------------------------------------------------------
23 -- Usage:
25 -- style_checker [options] [-lang name] [options]
27 -- The first options are set for all available languages.
28 -- Options that are set after a -lang name are only set for this specific
29 -- language (language names are not case sensitive).
31 -- To display the usage information:
32 -- $ style_checker
34 -- To check Ada files only (syntax, line length, trailing spaces):
35 -- $ style_checker -BCELS -lang Ada -slt file.ad*
37 -- To list available languages:
38 -- $ style_checker -lang
41 with Ada.Calendar;
42 with Ada.Command_Line;
43 with Ada.Containers.Indefinite_Hashed_Sets;
44 with Ada.Directories;
45 with Ada.IO_Exceptions;
46 with Ada.Strings.Fixed;
47 with Ada.Strings.Hash;
48 with Ada.Strings.Unbounded;
49 with Ada.Text_IO;
51 with GNAT.Command_Line;
52 with GNAT.Regpat;
54 with Version;
55 with Checks;
56 with File_Reader;
57 with Languages;
58 with Supported_Languages;
60 procedure Style_Checker is
62 use Ada;
63 use Ada.Strings;
64 use Ada.Strings.Unbounded;
65 use GNAT;
67 use type Directories.File_Kind;
68 use type Checks.Line_Ending_Style;
69 use type Checks.Mode;
71 package Ext_Set is new Containers.Indefinite_Hashed_Sets
72 (String, Hash, "=", "=");
74 Y : constant String :=
75 Calendar.Year_Number'Image (Calendar.Year (Calendar.Clock));
76 Current_Year : constant String := Y (Y'First + 1 .. Y'Last);
78 Absolute_Pathname : Boolean := False;
79 Style_Error : Boolean := False;
80 Ignore_Set : Ext_Set.Set;
81 Max_Error : Natural := Natural'Last;
82 Error_Count : Natural := 0;
83 Real_Filename : Unbounded_String;
85 type File_Checker is record
86 File : File_Reader.File_Type;
87 Lang : Languages.Lang_Access;
88 Count_Blank : Natural := 0;
89 Copyright_Found : Boolean := False;
90 Copyright_Year : Boolean := False;
91 Header_Size : Natural := 0;
92 In_Header : Boolean := True;
93 Consecutive_Comment : Natural := 0;
94 Last_Comment_Dot_EOL : Boolean := False;
95 end record;
97 procedure Check (Filename : in String);
98 -- Check this file
100 procedure Check_Line
101 (Checker : in out File_Checker;
102 Line : in String;
103 Line_Ending : in Checks.Line_Ending_Style);
104 -- Pass all checks that are line related
106 subtype Line_Offset is Integer range -1 .. 0;
108 procedure Report_Error
109 (File : in File_Reader.File_Type;
110 Message : in String;
111 Offset : in Line_Offset := 0);
112 -- Report an error to standard error
114 procedure Report_Error
115 (Filename : in String;
116 Message : in String;
117 At_Line : in Natural := 1);
118 -- Report an error to standard error
120 procedure Usage;
121 -- Display the usage information
123 procedure List_Languages;
124 -- Display supported languages
126 function Unquote (Str : in String) return String;
127 -- Removes leading/trailing spaces and quote if present
129 -----------
130 -- Check --
131 -----------
133 procedure Check (Filename : in String) is
134 Checker : File_Checker;
135 Line : String (1 .. 2_048);
136 K : Natural;
137 Nb_Line : Natural := 0;
138 Ending : Checks.Line_Ending_Style;
139 begin
140 Checker.Lang := new Languages.Lang'Class'(Languages.Get (Filename));
142 -- Run line oriented tests
144 File_Reader.Open (Checker.File, Filename);
146 while not File_Reader.End_Of_File (Checker.File) loop
147 File_Reader.Get_Line (Checker.File, Line, K, Ending);
148 Check_Line (Checker, Line (1 .. K), Ending);
149 end loop;
151 Nb_Line := File_Reader.Line (Checker.File);
153 File_Reader.Close (Checker.File);
155 -- Run file oriented tests
157 if Checker.Lang.Get_Syntax_Check then
158 if not Languages.Run_Syntax_Check (Checker.Lang.all, Filename) then
159 Style_Error := True;
160 end if;
161 end if;
163 if Checker.Lang.Get_Header_Size > Checker.Header_Size then
164 if Checker.Header_Size = 0 then
165 Report_Error
166 (Filename, "missing file header (must start on first line)");
167 else
168 Report_Error
169 (Filename, "file header should have at least"
170 & Positive'Image (Checker.Lang.Get_Header_Size)
171 & " lines");
172 end if;
173 end if;
175 if Checker.Lang.Get_Copyright_Present
176 and then not Checker.Copyright_Found
177 then
178 Report_Error (Filename, "missing copyright notice");
179 end if;
181 if Checker.Copyright_Found
182 and then Checker.Lang.Get_Copyright_Year
183 and then not Checker.Copyright_Year
184 then
185 Report_Error
186 (Filename, "missing year " & Current_Year & " in copyright");
187 end if;
189 if Checker.Lang.Get_Duplicate_Blank_Line = Checks.Rejected
190 and then Checker.Count_Blank >= 1
191 then
192 Report_Error
193 (Filename => Filename,
194 Message => "blank line not allowed at end of file",
195 At_Line => Nb_Line);
196 end if;
198 exception
199 when IO_Exceptions.Name_Error =>
200 Report_Error (Filename, "can't open file");
201 end Check;
203 ----------------
204 -- Check_Line --
205 ----------------
207 procedure Check_Line
208 (Checker : in out File_Checker;
209 Line : in String;
210 Line_Ending : in Checks.Line_Ending_Style)
212 procedure Check_Ending;
214 procedure Check_Length_Max;
216 procedure Check_Duplicate_Blank;
218 procedure Check_Trailing_Spaces;
220 procedure Check_Header;
222 procedure Check_Copyright;
224 procedure Check_Space_Comment;
226 procedure Check_Comment_Dot_EOL;
228 ---------------------------
229 -- Check_Comment_Dot_EOL --
230 ---------------------------
232 procedure Check_Comment_Dot_EOL is
233 Pos : Natural;
234 begin
235 if not Checker.Lang.Get_Comment_Dot_EOL
236 and then Checker.Lang.Comment /= ""
237 then
238 if Fixed.Index (Line, String'(Checker.Lang.Comment)) /= 0 then
239 -- This is a comment
240 Checker.Consecutive_Comment := Checker.Consecutive_Comment + 1;
242 Pos := Fixed.Index_Non_Blank (Line, Going => Backward);
244 if Line (Pos) = '.'
245 and then Pos > Line'First + 1
246 and then Line (Pos - 2 .. Pos - 1) /= ".."
247 then
248 Checker.Last_Comment_Dot_EOL := True;
249 else
250 Checker.Last_Comment_Dot_EOL := False;
251 end if;
253 else
254 -- No more in a comment line
256 if Checker.Consecutive_Comment = 1
257 and then Checker.Last_Comment_Dot_EOL
258 then
259 Report_Error
260 (Checker.File,
261 "single line comment should not terminate with dot",
262 Offset => -1);
263 end if;
265 Checker.Consecutive_Comment := 0;
266 Checker.Last_Comment_Dot_EOL := False;
267 end if;
268 end if;
269 end Check_Comment_Dot_EOL;
271 ---------------------
272 -- Check_Copyright --
273 ---------------------
275 procedure Check_Copyright is
276 use Text_IO;
277 Co_Start : Natural := 0;
278 Cp_Start : Natural := Fixed.Index (Line, " Copyright");
279 begin
280 if Checker.Lang.Comment /= "" then
281 Co_Start := Fixed.Index (Line, String'(Checker.Lang.Comment));
282 end if;
284 if Cp_Start /= 0
285 and then Cp_Start + 10 <= Line'Length
286 and then Line (Cp_Start + 10) /= ' '
287 then
288 -- We are not at the end of the line and no space after Copyright
289 Cp_Start := 0;
290 end if;
292 if (Checker.Lang.Get_Copyright_Present
293 or else Checker.Lang.Get_Copyright_Year)
294 and then Cp_Start /= 0
295 and then Co_Start /= 0
296 and then Cp_Start > Co_Start
297 then
298 Checker.Copyright_Found := True;
300 if Checker.Lang.Get_Copyright_Year then
301 if Fixed.Index (Line, Current_Year) /= 0 then
302 Checker.Copyright_Year := True;
303 end if;
304 end if;
305 end if;
307 -- Check that the copyright year follow the given regexp
309 if Cp_Start /= 0
310 and then Checker.Lang.Get_Copyright_Pattern /= ""
311 then
312 declare
313 Pattern : constant Regpat.Pattern_Matcher :=
314 Regpat.Compile (Checker.Lang.Get_Copyright_Pattern);
315 begin
316 if not Regpat.Match (Pattern, Line) then
317 Report_Error
318 (Checker.File,
319 "copyright line not matching expected pattern");
320 end if;
321 end;
322 end if;
323 end Check_Copyright;
325 ---------------------------
326 -- Check_Duplicate_Blank --
327 ---------------------------
329 procedure Check_Duplicate_Blank is
330 begin
331 if Checker.Lang.Get_Duplicate_Blank_Line = Checks.Rejected
332 and then (Line'Length = 0
333 or else Fixed.Count (Line, " " & ASCII.HT) = Line'Length)
334 then
335 Checker.Count_Blank := Checker.Count_Blank + 1;
337 if Checker.Count_Blank > 1 then
338 Report_Error (Checker.File, "duplicate blank line");
339 end if;
341 else
342 Checker.Count_Blank := 0;
343 end if;
344 end Check_Duplicate_Blank;
346 ------------------
347 -- Check_Ending --
348 ------------------
350 procedure Check_Ending is
351 begin
352 if Checker.Lang.Get_Line_Ending /= Checks.Any then
353 if Line_Ending = Checks.No then
354 Report_Error
355 (Checker.File,
356 "missing line terminator");
357 elsif Checker.Lang.Get_Line_Ending /= Line_Ending then
358 Report_Error
359 (Checker.File,
360 "wrong " & Checks.Line_Ending_Style'Image (Line_Ending) &
361 " line ending");
362 end if;
363 end if;
364 end Check_Ending;
366 ------------------
367 -- Check_Header --
368 ------------------
370 procedure Check_Header is
371 C : constant String := Checker.Lang.Comment;
372 begin
373 if Checker.In_Header
374 and then Line'Length >= C'Length
375 and then Line (Line'First .. Line'First + C'Length - 1) = C
376 then
377 Checker.Header_Size := Checker.Header_Size + 1;
378 else
379 Checker.In_Header := False;
380 end if;
381 end Check_Header;
383 ----------------------
384 -- Check_Length_Max --
385 ----------------------
387 procedure Check_Length_Max is
388 begin
389 if Line'Length > Checker.Lang.Get_Line_Length_Max then
390 Report_Error (Checker.File, "line too long");
391 end if;
392 end Check_Length_Max;
394 -------------------------
395 -- Check_Space_Comment --
396 -------------------------
398 procedure Check_Space_Comment is
399 N : constant Natural := Checker.Lang.Get_Space_Comment;
400 NI : constant String := Natural'Image (N);
401 C : constant String := Checker.Lang.Comment;
402 I : constant Natural := Fixed.Index_Non_Blank (Line);
403 begin
404 if N /= 0
405 and then I /= 0
406 and then I + C'Length - 1 <= Line'Last
407 and then Line (I .. I + C'Length - 1) = C
408 and then Line (Line'Last - C'Length + 1 .. Line'Last) /= C
409 and then (Line (I .. I + 1) /= "#!"
410 or else File_Reader.Line (Checker.File) > 1)
411 -- Do no check script headers
412 then
413 for K in I + C'Length .. I + C'Length + N - 1 loop
414 if Line (K) /= ' ' then
415 Report_Error
416 (Checker.File,
417 NI (NI'First + 1 .. NI'Last) & " spaces after " & C);
418 exit;
419 end if;
420 end loop;
421 end if;
422 end Check_Space_Comment;
424 ---------------------------
425 -- Check_Trailing_Spaces --
426 ---------------------------
428 procedure Check_Trailing_Spaces is
429 begin
430 if Checker.Lang.Get_Trailing_Spaces = Checks.Rejected
431 and then Line'Length > 0
432 and then (Line (Line'Last) = ' '
433 or else Line (Line'Last) = ASCII.HT)
434 then
435 Report_Error (Checker.File, "no trailing spaces allowed");
436 end if;
437 end Check_Trailing_Spaces;
439 begin
440 Check_Ending;
441 Check_Length_Max;
442 Check_Duplicate_Blank;
443 Check_Trailing_Spaces;
444 Check_Header;
445 Check_Copyright;
446 Check_Space_Comment;
447 Check_Comment_Dot_EOL;
448 end Check_Line;
450 --------------------
451 -- List_Languages --
452 --------------------
454 procedure List_Languages is
455 procedure P (Str : in String) renames Text_IO.Put_Line;
456 begin
457 Text_IO.New_Line;
458 P ("Style Checker " & Version.Simple);
459 Text_IO.New_Line;
460 Languages.List;
461 Text_IO.New_Line;
462 end List_Languages;
464 ------------------
465 -- Report_Error --
466 ------------------
468 procedure Report_Error
469 (File : in File_Reader.File_Type;
470 Message : in String;
471 Offset : in Line_Offset := 0)
473 Line : constant String :=
474 Natural'Image (File_Reader.Line (File) + Offset);
475 begin
476 Error_Count := Error_Count + 1;
477 if Error_Count <= Max_Error then
478 if Real_Filename = Null_Unbounded_String then
479 Text_IO.Put_Line
480 (Text_IO.Standard_Error,
481 File_Reader.Name (File, Absolute_Pathname) & ':'
482 & Line (Line'First + 1 .. Line'Last) & ": " & Message);
483 else
484 Text_IO.Put_Line
485 (Text_IO.Standard_Error,
486 To_String (Real_Filename) & ':'
487 & Line (Line'First + 1 .. Line'Last) & ": " & Message);
488 end if;
489 end if;
490 end Report_Error;
492 procedure Report_Error
493 (Filename : in String;
494 Message : in String;
495 At_Line : in Natural := 1)
497 Line : constant String := Natural'Image (At_Line);
498 begin
499 Error_Count := Error_Count + 1;
500 if Error_Count <= Max_Error then
501 if Real_Filename = Null_Unbounded_String then
502 Text_IO.Put_Line
503 (Text_IO.Standard_Error, Filename & ':'
504 & Line (Line'First + 1 .. Line'Last) & ": " & Message);
505 else
506 Text_IO.Put_Line
507 (Text_IO.Standard_Error,
508 To_String (Real_Filename) & ':'
509 & Line (Line'First + 1 .. Line'Last) & ": " & Message);
510 end if;
511 end if;
512 end Report_Error;
514 -------------
515 -- Unquote --
516 -------------
518 function Unquote (Str : in String) return String is
519 S : String := Fixed.Trim (Str, Strings.Both);
520 begin
521 if (S (S'First) = ''' and then S (S'Last) = ''')
522 or else (S (S'First) = '"' and then S (S'Last) = '"')
523 then
524 return S (S'First + 1 .. S'Last - 1);
525 else
526 return S;
527 end if;
528 end Unquote;
530 -----------
531 -- Usage --
532 -----------
534 procedure Usage is
535 procedure P (Str : in String) renames Text_IO.Put_Line;
536 begin
537 Text_IO.New_Line;
538 P ("Style Checker " & Version.Simple);
539 Text_IO.New_Line;
540 P ("style_checker [-lang name] [options] file1 file2...");
541 P (" -lang : list all built-in supported languages");
542 P (" -lang NAME : following options are for this specific language");
543 P (" -abs : output absolute path name");
544 P (" -ign EXT : ignore files having EXT has extension");
545 P (" -b : no duplicate blank lines (default)");
546 P (" -B : disable duplicate blank lines check");
547 P (" -c : check for space after comment tag (default)");
548 P (" -C : disable space in comment check");
549 P (" -cp : check copyright presence");
550 P (" -cP : disable check for copyright presence (default)");
551 P (" -cy : check for copyright year");
552 P (" -cY : disbale check for copyright year (default)");
553 P (" -cf : if present a copyright line should match the"
554 & " given pattern");
555 P (" -cF : disable copyright pattern check");
556 P (" -d : check single comment line dot ending");
557 P (" -D : disable check for single comment line dot ending");
558 P (" -e DOS|UNIX : line ending style (UNIX default)");
559 P (" -E : disable line ending check");
560 P (" -h N : start with an header of N line (default N 20)");
561 P (" -H : disable header check");
562 P (" -l N : line length <= N (default 79)");
563 P (" -L : disable line length check");
564 P (" -m N : output only the first N errors");
565 P (" -n NAME : filename to report in error message");
566 P (" -s : syntax check (default)");
567 P (" -sp PARAM : additional parameter for the style checker");
568 P (" -S : disable syntax check");
569 P (" -t : check for trailing spaces (default)");
570 P (" -T : disable trailing spaces check");
571 P (" -v : display version");
572 Text_IO.New_Line;
573 end Usage;
575 Lang : Languages.Lang_Access;
577 begin
578 if Ada.Command_Line.Argument_Count = 0 then
579 raise Checks.Syntax_Error;
581 elsif Ada.Command_Line.Argument_Count = 1
582 and then Ada.Command_Line.Argument (1) = "-lang"
583 then
584 List_Languages;
586 else
587 loop
588 case GNAT.Command_Line.Getopt
589 ("abs lang: ign: e: E l? h? H "
590 & "L b B s S t T v c? C cp cy cP cY cf: cF d D sp: m: n:")
592 when ASCII.NUL =>
593 exit;
595 when 'a' =>
596 if GNAT.Command_Line.Full_Switch = "abs" then
597 Absolute_Pathname := True;
598 else
599 raise Checks.Syntax_Error;
600 end if;
602 when 'd' =>
603 Languages.Set_Comment_Dot_EOL (Lang, False);
605 when 'D' =>
606 Languages.Set_Comment_Dot_EOL (Lang, True);
608 when 'e' =>
609 Languages.Set_Line_Ending
610 (Lang, Checks.Line_Ending_Style'Value
611 (GNAT.Command_Line.Parameter));
613 when 'E' =>
614 Languages.Set_Line_Ending (Lang, Checks.Any);
616 when 'i' =>
617 declare
618 Full : constant String := GNAT.Command_Line.Full_Switch;
619 begin
620 if Full = "ign" then
621 Ignore_Set.Include (GNAT.Command_Line.Parameter);
622 else
623 raise Checks.Syntax_Error;
624 end if;
625 end;
627 when 'l' =>
628 declare
629 Full : constant String := GNAT.Command_Line.Full_Switch;
630 begin
631 if Full = "lang" then
632 Lang := Languages.Get_From_Name
633 (GNAT.Command_Line.Parameter);
635 elsif Full = "l" then
636 declare
637 P : constant String := GNAT.Command_Line.Parameter;
638 begin
639 if P = "" then
640 Languages.Set_Line_Length_Max (Lang, 79);
641 else
642 Languages.Set_Line_Length_Max
643 (Lang, Positive'Value (P));
644 end if;
645 exception
646 when Constraint_Error | IO_Exceptions.Name_Error =>
647 raise Checks.Syntax_Error;
648 end;
649 end if;
650 end;
652 when 'L' =>
653 Languages.Set_Line_Length_Max (Lang, Positive'Last);
655 when 'h' =>
656 declare
657 P : constant String := GNAT.Command_Line.Parameter;
658 begin
659 if P = "" then
660 Languages.Set_Header_Size (Lang, 20);
661 else
662 Languages.Set_Header_Size (Lang, Positive'Value (P));
663 end if;
664 exception
665 when Constraint_Error | IO_Exceptions.Name_Error =>
666 raise Checks.Syntax_Error;
667 end;
669 when 'H' =>
670 Languages.Set_Header_Size (Lang, 0);
672 when 'b' =>
673 Languages.Set_Duplicate_Blank_Line (Lang, Checks.Rejected);
675 when 'B' =>
676 Languages.Set_Duplicate_Blank_Line (Lang, Checks.Accepted);
678 when 't' =>
679 Languages.Set_Trailing_Spaces (Lang, Checks.Rejected);
681 when 'T' =>
682 Languages.Set_Trailing_Spaces (Lang, Checks.Accepted);
684 when 's' =>
685 declare
686 Full : constant String := GNAT.Command_Line.Full_Switch;
687 begin
688 if Full = "sp" then
689 Languages.Add_Style_Checker_Parameter
690 (Lang, GNAT.Command_Line.Parameter);
692 else
693 Languages.Set_Syntax_Check (Lang, True);
694 end if;
695 end;
697 when 'S' =>
698 Languages.Set_Syntax_Check (Lang, False);
700 when 'c' =>
701 declare
702 Full : constant String := GNAT.Command_Line.Full_Switch;
703 begin
704 if Full = "c" then
705 declare
706 P : constant String := GNAT.Command_Line.Parameter;
707 begin
708 if P = "" then
709 Languages.Set_Space_Comment (Lang, 2);
710 else
711 Languages.Set_Space_Comment
712 (Lang, Positive'Value (P));
713 end if;
714 end;
716 elsif Full = "cp" then
717 Languages.Set_Copyright_Present (Lang, True);
719 elsif Full = "cP" then
720 Languages.Set_Copyright_Present (Lang, False);
722 elsif Full = "cy" then
723 Languages.Set_Copyright_Year (Lang, True);
725 elsif Full = "cY" then
726 Languages.Set_Copyright_Year (Lang, False);
728 elsif Full = "cf" then
729 Languages.Set_Copyright_Pattern
730 (Lang, Unquote (GNAT.Command_Line.Parameter));
732 elsif Full = "cF" then
733 Languages.Set_Copyright_Pattern (Lang, "");
734 end if;
735 end;
737 when 'C' =>
738 Languages.Set_Space_Comment (Lang, 0);
740 when 'm' =>
741 Max_Error := Natural'Value (GNAT.Command_Line.Parameter);
743 when 'n' =>
744 Real_Filename :=
745 To_Unbounded_String (GNAT.Command_Line.Parameter);
747 when 'v' =>
748 Text_IO.Put_Line ("Style Checker " & Version.Complete);
749 exit;
751 when others =>
752 raise Checks.Syntax_Error;
753 end case;
754 end loop;
756 -- Register some known extension to ignore
758 Ignore_Set.Include ("gif");
759 Ignore_Set.Include ("png");
760 Ignore_Set.Include ("jpg");
761 Ignore_Set.Include ("pdf");
762 Ignore_Set.Include ("ps");
763 Ignore_Set.Include ("exe");
764 Ignore_Set.Include ("dll");
765 Ignore_Set.Include ("so");
766 Ignore_Set.Include ("o");
767 Ignore_Set.Include ("obj");
769 loop
770 declare
771 Filename : constant String :=
772 GNAT.Command_Line.Get_Argument (Do_Expansion => True);
773 begin
774 exit when Filename'Length = 0;
776 if Directories.Exists (Filename) then
777 if Directories.Kind (Filename) /= Directories.Directory then
778 declare
779 Ext : constant String := Directories.Extension (Filename);
780 begin
781 if (Ext /= "" and then not Ignore_Set.Contains (Ext))
782 or else
783 (Ext = "" and then not Ignore_Set.Contains
784 (Directories.Simple_Name (Filename)))
785 then
786 -- Do not check directory
787 Check (Filename);
788 end if;
789 end;
790 end if;
792 else
793 Report_Error (Filename, "file not found");
794 end if;
795 end;
796 end loop;
798 end if;
800 if Style_Error or else Error_Count > 0 then
801 Ada.Command_Line.Set_Exit_Status (Ada.Command_Line.Failure);
802 else
803 Ada.Command_Line.Set_Exit_Status (Ada.Command_Line.Success);
804 end if;
806 exception
807 when Checks.Syntax_Error | GNAT.Command_Line.Invalid_Switch =>
808 Usage;
809 Ada.Command_Line.Set_Exit_Status (Ada.Command_Line.Failure);
810 end Style_Checker;