Add support for checking tabulations.
[style_checker.git] / src / style_checker.adb
blob42a355a758d705acac6ac69dda3cb854d02c6eea
1 ------------------------------------------------------------------------------
2 -- Style Checker --
3 -- --
4 -- Copyright (C) 2006-2010, 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 Multiline_Comment : Boolean := False;
94 Consecutive_Comment : Natural := 0;
95 Last_Comment_Dot_EOL : Boolean := False;
96 end record;
98 procedure Check (Filename : in String);
99 -- Check this file
101 procedure Check_Line
102 (Checker : in out File_Checker;
103 Line : in String;
104 Line_Ending : in Checks.Line_Ending_Style);
105 -- Pass all checks that are line related
107 subtype Line_Offset is Integer range -1 .. 0;
109 procedure Report_Error
110 (File : in File_Reader.File_Type;
111 Message : in String;
112 Offset : in Line_Offset := 0);
113 -- Report an error to standard error
115 procedure Report_Error
116 (Filename : in String;
117 Message : in String;
118 At_Line : in Natural := 1);
119 -- Report an error to standard error
121 procedure Usage;
122 -- Display the usage information
124 procedure List_Languages;
125 -- Display supported languages
127 function Unquote (Str : in String) return String;
128 -- Removes leading/trailing spaces and quote if present
130 -----------
131 -- Check --
132 -----------
134 procedure Check (Filename : in String) is
135 Checker : File_Checker;
136 Line : String (1 .. 2_048);
137 K : Natural;
138 Nb_Line : Natural := 0;
139 Ending : Checks.Line_Ending_Style;
140 begin
141 Checker.Lang := new Languages.Lang'Class'(Languages.Get (Filename));
143 -- Run line oriented tests
145 File_Reader.Open (Checker.File, Filename);
147 while not File_Reader.End_Of_File (Checker.File) loop
148 File_Reader.Get_Line (Checker.File, Line, K, Ending);
149 Check_Line (Checker, Line (1 .. K), Ending);
150 end loop;
152 Nb_Line := File_Reader.Line (Checker.File);
154 File_Reader.Close (Checker.File);
156 -- Run file oriented tests
158 if Checker.Lang.Get_Syntax_Check then
159 if not Languages.Run_Syntax_Check (Checker.Lang.all, Filename) then
160 Style_Error := True;
161 end if;
162 end if;
164 if Checker.Lang.Get_Header_Size > Checker.Header_Size then
165 if Checker.Header_Size = 0 then
166 Report_Error
167 (Filename, "missing file header (must start on first line)");
168 else
169 Report_Error
170 (Filename, "file header should have at least"
171 & Positive'Image (Checker.Lang.Get_Header_Size)
172 & " lines, found" & Integer'Image (Checker.Header_Size));
173 end if;
174 end if;
176 if Checker.Lang.Get_Copyright_Present
177 and then not Checker.Copyright_Found
178 then
179 Report_Error (Filename, "missing copyright notice");
180 end if;
182 if Checker.Copyright_Found
183 and then Checker.Lang.Get_Copyright_Year
184 and then not Checker.Copyright_Year
185 then
186 Report_Error
187 (Filename, "missing year " & Current_Year & " in copyright");
188 end if;
190 if Checker.Lang.Get_Duplicate_Blank_Line = Checks.Rejected
191 and then Checker.Count_Blank >= 1
192 then
193 Report_Error
194 (Filename => Filename,
195 Message => "blank line not allowed at end of file",
196 At_Line => Nb_Line);
197 end if;
199 exception
200 when IO_Exceptions.Name_Error =>
201 Report_Error (Filename, "can't open file");
202 end Check;
204 ----------------
205 -- Check_Line --
206 ----------------
208 procedure Check_Line
209 (Checker : in out File_Checker;
210 Line : in String;
211 Line_Ending : in Checks.Line_Ending_Style)
213 procedure Check_Ending;
215 procedure Check_Length_Max;
217 procedure Check_Duplicate_Blank;
219 procedure Check_Trailing_Spaces;
221 procedure Check_Header;
223 procedure Check_Copyright;
225 procedure Check_Space_Comment;
227 procedure Check_Comment_Dot_EOL;
229 procedure Check_Tab;
231 ---------------------------
232 -- Check_Comment_Dot_EOL --
233 ---------------------------
235 procedure Check_Comment_Dot_EOL is
236 Pos : Natural;
237 begin
238 if not Checker.Lang.Get_Comment_Dot_EOL
239 and then Checker.Lang.Comment /= ""
240 then
241 if Fixed.Index (Line, String'(Checker.Lang.Comment)) /= 0 then
242 -- This is a comment
243 Checker.Consecutive_Comment := Checker.Consecutive_Comment + 1;
245 Pos := Fixed.Index_Non_Blank (Line, Going => Backward);
247 if Line (Pos) = '.'
248 and then Pos > Line'First + 1
249 and then Line (Pos - 2 .. Pos - 1) /= ".."
250 then
251 Checker.Last_Comment_Dot_EOL := True;
252 else
253 Checker.Last_Comment_Dot_EOL := False;
254 end if;
256 else
257 -- No more in a comment line
259 if Checker.Consecutive_Comment = 1
260 and then Checker.Last_Comment_Dot_EOL
261 then
262 Report_Error
263 (Checker.File,
264 "single line comment should not terminate with dot",
265 Offset => -1);
266 end if;
268 Checker.Consecutive_Comment := 0;
269 Checker.Last_Comment_Dot_EOL := False;
270 end if;
271 end if;
272 end Check_Comment_Dot_EOL;
274 ---------------------
275 -- Check_Copyright --
276 ---------------------
278 procedure Check_Copyright is
279 use Text_IO;
280 Co_Start : Natural := 0;
281 Cp_Start : Natural := Fixed.Index (Line, " Copyright");
282 begin
283 if Checker.Lang.Comment /= "" then
284 Co_Start := Fixed.Index (Line, String'(Checker.Lang.Comment));
285 end if;
287 if Cp_Start /= 0
288 and then Cp_Start + 10 <= Line'Length
289 and then Line (Cp_Start + 10) /= ' '
290 then
291 -- We are not at the end of the line and no space after Copyright
292 Cp_Start := 0;
293 end if;
295 if (Checker.Lang.Get_Copyright_Present
296 or else Checker.Lang.Get_Copyright_Year)
297 and then Cp_Start /= 0
298 and then Co_Start /= 0
299 and then Cp_Start > Co_Start
300 then
301 Checker.Copyright_Found := True;
303 if Checker.Lang.Get_Copyright_Year then
304 if Fixed.Index (Line, Current_Year) /= 0 then
305 Checker.Copyright_Year := True;
306 end if;
307 end if;
308 end if;
310 -- Check that the copyright year follow the given regexp
312 if Cp_Start /= 0
313 and then Checker.Lang.Get_Copyright_Pattern /= ""
314 then
315 declare
316 Pattern : constant Regpat.Pattern_Matcher :=
317 Regpat.Compile (Checker.Lang.Get_Copyright_Pattern);
318 begin
319 if not Regpat.Match (Pattern, Line) then
320 Report_Error
321 (Checker.File,
322 "copyright line not matching expected pattern");
323 end if;
324 end;
325 end if;
326 end Check_Copyright;
328 ---------------------------
329 -- Check_Duplicate_Blank --
330 ---------------------------
332 procedure Check_Duplicate_Blank is
333 begin
334 if Checker.Lang.Get_Duplicate_Blank_Line = Checks.Rejected
335 and then (Line'Length = 0
336 or else Fixed.Count (Line, " " & ASCII.HT) = Line'Length)
337 then
338 Checker.Count_Blank := Checker.Count_Blank + 1;
340 if Checker.Count_Blank > 1 then
341 Report_Error (Checker.File, "duplicate blank line");
342 end if;
344 else
345 Checker.Count_Blank := 0;
346 end if;
347 end Check_Duplicate_Blank;
349 ------------------
350 -- Check_Ending --
351 ------------------
353 procedure Check_Ending is
354 begin
355 if Checker.Lang.Get_Line_Ending /= Checks.Any then
356 if Line_Ending = Checks.No then
357 Report_Error
358 (Checker.File,
359 "missing line terminator");
360 elsif Checker.Lang.Get_Line_Ending /= Line_Ending then
361 Report_Error
362 (Checker.File,
363 "wrong " & Checks.Line_Ending_Style'Image (Line_Ending) &
364 " line ending");
365 end if;
366 end if;
367 end Check_Ending;
369 ------------------
370 -- Check_Header --
371 ------------------
373 procedure Check_Header is
374 C : constant String := Checker.Lang.Comment;
375 CS : constant String := Checker.Lang.Start_Multiline_Comment;
376 CE : constant String := Checker.Lang.End_Multiline_Comment;
377 Is_C : constant Boolean :=
378 C /= ""
379 and then Line'Length >= C'Length
380 and then Line
381 (Line'First .. Line'First + C'Length - 1) = C;
382 Is_CS : constant Boolean :=
383 CS /= ""
384 and then File_Reader.Line (Checker.File) = 1
385 and then Line'Length >= CS'Length
386 and then Line
387 (Line'First .. Line'First + CS'Length - 1) = CS;
388 Is_CE : constant Boolean :=
389 CE /= ""
390 and then Line'Length >= CE'Length
391 and then Line
392 (Line'Last - CE'Length + 1 .. Line'Last) = CE;
393 begin
394 -- Check that we are starting with a multi-line comment
396 if File_Reader.Line (Checker.File) = 1 then
397 if Is_C or else Is_CS then
398 Checker.Header_Size := Checker.Header_Size + 1;
400 if Is_CS then
401 Checker.Multiline_Comment := True;
402 end if;
404 else
405 Checker.In_Header := False;
406 end if;
408 else
409 if Checker.In_Header
410 and then
411 (Is_C or else (Checker.Multiline_Comment and then not Is_CE))
412 then
413 Checker.Header_Size := Checker.Header_Size + 1;
414 else
415 if Is_CE then
416 Checker.Header_Size := Checker.Header_Size + 1;
417 end if;
418 Checker.In_Header := False;
419 end if;
420 end if;
421 end Check_Header;
423 ----------------------
424 -- Check_Length_Max --
425 ----------------------
427 procedure Check_Length_Max is
428 begin
429 if Line'Length > Checker.Lang.Get_Line_Length_Max then
430 Report_Error (Checker.File, "line too long");
431 end if;
432 end Check_Length_Max;
434 -------------------------
435 -- Check_Space_Comment --
436 -------------------------
438 procedure Check_Space_Comment is
439 N : constant Natural := Checker.Lang.Get_Space_Comment;
440 NI : constant String := Natural'Image (N);
441 C : constant String := Checker.Lang.Comment;
442 I : constant Natural := Fixed.Index_Non_Blank (Line);
443 begin
444 if N /= 0
445 and then I /= 0
446 and then I + C'Length - 1 <= Line'Last
447 and then Line (I .. I + C'Length - 1) = C
448 and then Line (Line'Last - C'Length + 1 .. Line'Last) /= C
449 and then (Line (I .. I + 1) /= "#!"
450 or else File_Reader.Line (Checker.File) > 1)
451 -- Do no check script headers
452 then
453 for K in I + C'Length .. I + C'Length + N - 1 loop
454 if Line (K) /= ' ' then
455 Report_Error
456 (Checker.File,
457 NI (NI'First + 1 .. NI'Last) & " spaces after " & C);
458 exit;
459 end if;
460 end loop;
461 end if;
462 end Check_Space_Comment;
464 ---------------
465 -- Check_Tab --
466 ---------------
468 procedure Check_Tab is
469 begin
470 if Checker.Lang.Get_Tabulation = Checks.Rejected
471 and then Strings.Fixed.Index (Line, String'(1 => ASCII.HT)) /= 0
472 then
473 Report_Error (Checker.File, "no tabulations allowed");
474 end if;
475 end Check_Tab;
477 ---------------------------
478 -- Check_Trailing_Spaces --
479 ---------------------------
481 procedure Check_Trailing_Spaces is
482 begin
483 if Checker.Lang.Get_Trailing_Spaces = Checks.Rejected
484 and then Line'Length > 0
485 and then (Line (Line'Last) = ' '
486 or else Line (Line'Last) = ASCII.HT)
487 then
488 Report_Error (Checker.File, "no trailing spaces allowed");
489 end if;
490 end Check_Trailing_Spaces;
492 begin
493 Check_Ending;
494 Check_Length_Max;
495 Check_Duplicate_Blank;
496 Check_Trailing_Spaces;
497 Check_Header;
498 Check_Copyright;
499 Check_Space_Comment;
500 Check_Comment_Dot_EOL;
501 Check_Tab;
502 end Check_Line;
504 --------------------
505 -- List_Languages --
506 --------------------
508 procedure List_Languages is
509 procedure P (Str : in String) renames Text_IO.Put_Line;
510 begin
511 Text_IO.New_Line;
512 P ("Style Checker " & Version.Simple);
513 Text_IO.New_Line;
514 Languages.List;
515 Text_IO.New_Line;
516 end List_Languages;
518 ------------------
519 -- Report_Error --
520 ------------------
522 procedure Report_Error
523 (File : in File_Reader.File_Type;
524 Message : in String;
525 Offset : in Line_Offset := 0)
527 Line : constant String :=
528 Natural'Image (File_Reader.Line (File) + Offset);
529 begin
530 Error_Count := Error_Count + 1;
531 if Error_Count <= Max_Error then
532 if Real_Filename = Null_Unbounded_String then
533 Text_IO.Put_Line
534 (Text_IO.Standard_Error,
535 File_Reader.Name (File, Absolute_Pathname) & ':'
536 & Line (Line'First + 1 .. Line'Last) & ": " & Message);
537 else
538 Text_IO.Put_Line
539 (Text_IO.Standard_Error,
540 To_String (Real_Filename) & ':'
541 & Line (Line'First + 1 .. Line'Last) & ": " & Message);
542 end if;
543 end if;
544 end Report_Error;
546 procedure Report_Error
547 (Filename : in String;
548 Message : in String;
549 At_Line : in Natural := 1)
551 Line : constant String := Natural'Image (At_Line);
552 begin
553 Error_Count := Error_Count + 1;
554 if Error_Count <= Max_Error then
555 if Real_Filename = Null_Unbounded_String then
556 Text_IO.Put_Line
557 (Text_IO.Standard_Error, Filename & ':'
558 & Line (Line'First + 1 .. Line'Last) & ": " & Message);
559 else
560 Text_IO.Put_Line
561 (Text_IO.Standard_Error,
562 To_String (Real_Filename) & ':'
563 & Line (Line'First + 1 .. Line'Last) & ": " & Message);
564 end if;
565 end if;
566 end Report_Error;
568 -------------
569 -- Unquote --
570 -------------
572 function Unquote (Str : in String) return String is
573 S : constant String := Fixed.Trim (Str, Strings.Both);
574 begin
575 if (S (S'First) = ''' and then S (S'Last) = ''')
576 or else (S (S'First) = '"' and then S (S'Last) = '"')
577 then
578 return S (S'First + 1 .. S'Last - 1);
579 else
580 return S;
581 end if;
582 end Unquote;
584 -----------
585 -- Usage --
586 -----------
588 procedure Usage is
589 procedure P (Str : in String) renames Text_IO.Put_Line;
590 begin
591 Text_IO.New_Line;
592 P ("Style Checker " & Version.Simple);
593 Text_IO.New_Line;
594 P ("style_checker [-lang name] [options] file1 file2...");
595 P (" -lang : list all built-in supported languages");
596 P (" -lang NAME : following options are for this specific language");
597 P (" -a : check for tabulations (default)");
598 P (" -A : disable tabulations check");
599 P (" -abs : output absolute path name");
600 P (" -ign EXT : ignore files having EXT has extension");
601 P (" -b : no duplicate blank lines (default)");
602 P (" -B : disable duplicate blank lines check");
603 P (" -c : check for space after comment tag (default)");
604 P (" -C : disable space in comment check");
605 P (" -cp : check copyright presence");
606 P (" -cP : disable check for copyright presence (default)");
607 P (" -cy : check for copyright year");
608 P (" -cY : disable check for copyright year (default)");
609 P (" -cf : if present a copyright line should match the"
610 & " given pattern");
611 P (" -cF : disable copyright pattern check");
612 P (" -d : check single comment line dot ending");
613 P (" -D : disable check for single comment line dot"
614 & " ending (default)");
615 P (" -e DOS|UNIX : line ending style (UNIX default)");
616 P (" -E : disable line ending check");
617 P (" -h N : start with an header of N line (default N 20)");
618 P (" -H : disable header check");
619 P (" -l N : line length <= N (default 79)");
620 P (" -L : disable line length check");
621 P (" -m N : output only the first N errors");
622 P (" -n NAME : filename to report in error message");
623 P (" -s : syntax check (default)");
624 P (" -sp PARAM : additional parameter for the style checker");
625 P (" -S : disable syntax check");
626 P (" -t : check for trailing spaces (default)");
627 P (" -T : disable trailing spaces check");
628 P (" -v : display version");
629 Text_IO.New_Line;
630 end Usage;
632 Lang : Languages.Lang_Access;
634 begin
635 if Ada.Command_Line.Argument_Count = 0 then
636 raise Checks.Syntax_Error;
638 elsif Ada.Command_Line.Argument_Count = 1
639 and then Ada.Command_Line.Argument (1) = "-lang"
640 then
641 List_Languages;
643 elsif Ada.Command_Line.Argument_Count = 1
644 and then Ada.Command_Line.Argument (1) = "-h"
645 then
646 Usage;
647 Ada.Command_Line.Set_Exit_Status (Ada.Command_Line.Failure);
649 else
650 loop
651 case GNAT.Command_Line.Getopt
652 ("a A abs lang: ign: e: E l? h? H "
653 & "L b B s S t T v c? C cp cy cP cY cf: cF d D sp: m: n:")
655 when ASCII.NUL =>
656 exit;
658 when 'a' =>
659 if GNAT.Command_Line.Full_Switch = "abs" then
660 Absolute_Pathname := True;
662 elsif GNAT.Command_Line.Full_Switch = "a" then
663 Languages.Set_Tabulation (Lang, Checks.Rejected);
665 else
666 raise Checks.Syntax_Error;
667 end if;
669 when 'A' =>
670 Languages.Set_Tabulation (Lang, Checks.Accepted);
672 when 'd' =>
673 Languages.Set_Comment_Dot_EOL (Lang, False);
675 when 'D' =>
676 Languages.Set_Comment_Dot_EOL (Lang, True);
678 when 'e' =>
679 Languages.Set_Line_Ending
680 (Lang, Checks.Line_Ending_Style'Value
681 (GNAT.Command_Line.Parameter));
683 when 'E' =>
684 Languages.Set_Line_Ending (Lang, Checks.Any);
686 when 'i' =>
687 declare
688 Full : constant String := GNAT.Command_Line.Full_Switch;
689 begin
690 if Full = "ign" then
691 Ignore_Set.Include (GNAT.Command_Line.Parameter);
692 else
693 raise Checks.Syntax_Error;
694 end if;
695 end;
697 when 'l' =>
698 declare
699 Full : constant String := GNAT.Command_Line.Full_Switch;
700 begin
701 if Full = "lang" then
702 Lang := Languages.Get_From_Name
703 (GNAT.Command_Line.Parameter);
705 elsif Full = "l" then
706 declare
707 P : constant String := GNAT.Command_Line.Parameter;
708 begin
709 if P = "" then
710 Languages.Set_Line_Length_Max (Lang, 79);
711 else
712 Languages.Set_Line_Length_Max
713 (Lang, Positive'Value (P));
714 end if;
715 exception
716 when Constraint_Error | IO_Exceptions.Name_Error =>
717 raise Checks.Syntax_Error;
718 end;
719 end if;
720 end;
722 when 'L' =>
723 Languages.Set_Line_Length_Max (Lang, Positive'Last);
725 when 'h' =>
726 declare
727 P : constant String := GNAT.Command_Line.Parameter;
728 begin
729 if P = "" then
730 Languages.Set_Header_Size (Lang, 20);
731 else
732 Languages.Set_Header_Size (Lang, Positive'Value (P));
733 end if;
734 exception
735 when Constraint_Error | IO_Exceptions.Name_Error =>
736 raise Checks.Syntax_Error;
737 end;
739 when 'H' =>
740 Languages.Set_Header_Size (Lang, 0);
742 when 'b' =>
743 Languages.Set_Duplicate_Blank_Line (Lang, Checks.Rejected);
745 when 'B' =>
746 Languages.Set_Duplicate_Blank_Line (Lang, Checks.Accepted);
748 when 't' =>
749 Languages.Set_Trailing_Spaces (Lang, Checks.Rejected);
751 when 'T' =>
752 Languages.Set_Trailing_Spaces (Lang, Checks.Accepted);
754 when 's' =>
755 declare
756 Full : constant String := GNAT.Command_Line.Full_Switch;
757 begin
758 if Full = "sp" then
759 Languages.Add_Style_Checker_Parameter
760 (Lang, GNAT.Command_Line.Parameter);
762 else
763 Languages.Set_Syntax_Check (Lang, True);
764 end if;
765 end;
767 when 'S' =>
768 Languages.Set_Syntax_Check (Lang, False);
770 when 'c' =>
771 declare
772 Full : constant String := GNAT.Command_Line.Full_Switch;
773 begin
774 if Full = "c" then
775 declare
776 P : constant String := GNAT.Command_Line.Parameter;
777 begin
778 if P = "" then
779 Languages.Set_Space_Comment (Lang, 2);
780 else
781 Languages.Set_Space_Comment
782 (Lang, Positive'Value (P));
783 end if;
784 end;
786 elsif Full = "cp" then
787 Languages.Set_Copyright_Present (Lang, True);
789 elsif Full = "cP" then
790 Languages.Set_Copyright_Present (Lang, False);
792 elsif Full = "cy" then
793 Languages.Set_Copyright_Year (Lang, True);
795 elsif Full = "cY" then
796 Languages.Set_Copyright_Year (Lang, False);
798 elsif Full = "cf" then
799 Languages.Set_Copyright_Pattern
800 (Lang, Unquote (GNAT.Command_Line.Parameter));
802 elsif Full = "cF" then
803 Languages.Set_Copyright_Pattern (Lang, "");
804 end if;
805 end;
807 when 'C' =>
808 Languages.Set_Space_Comment (Lang, 0);
810 when 'm' =>
811 Max_Error := Natural'Value (GNAT.Command_Line.Parameter);
813 when 'n' =>
814 Real_Filename :=
815 To_Unbounded_String (GNAT.Command_Line.Parameter);
817 when 'v' =>
818 Text_IO.Put_Line ("Style Checker " & Version.Complete);
819 exit;
821 when others =>
822 raise Checks.Syntax_Error;
823 end case;
824 end loop;
826 -- Register some known extension to ignore
828 Ignore_Set.Include ("gif");
829 Ignore_Set.Include ("png");
830 Ignore_Set.Include ("jpg");
831 Ignore_Set.Include ("pdf");
832 Ignore_Set.Include ("ps");
833 Ignore_Set.Include ("exe");
834 Ignore_Set.Include ("dll");
835 Ignore_Set.Include ("so");
836 Ignore_Set.Include ("o");
837 Ignore_Set.Include ("obj");
838 Ignore_Set.Include ("tar");
839 Ignore_Set.Include ("gz");
840 Ignore_Set.Include ("bz2");
841 Ignore_Set.Include ("7z");
843 loop
844 declare
845 Filename : constant String :=
846 GNAT.Command_Line.Get_Argument (Do_Expansion => True);
847 begin
848 exit when Filename'Length = 0;
850 if Directories.Exists (Filename) then
851 if Directories.Kind (Filename) /= Directories.Directory then
852 declare
853 Ext : constant String := Directories.Extension (Filename);
854 begin
855 if (Ext /= "" and then not Ignore_Set.Contains (Ext))
856 or else
857 (Ext = "" and then not Ignore_Set.Contains
858 (Directories.Simple_Name (Filename)))
859 then
860 -- Do not check directory
861 Check (Filename);
862 end if;
863 end;
864 end if;
866 else
867 Report_Error (Filename, "file not found");
868 end if;
869 end;
870 end loop;
872 end if;
874 if Style_Error or else Error_Count > 0 then
875 Ada.Command_Line.Set_Exit_Status (Ada.Command_Line.Failure);
876 else
877 Ada.Command_Line.Set_Exit_Status (Ada.Command_Line.Success);
878 end if;
880 exception
881 when Checks.Syntax_Error | GNAT.Command_Line.Invalid_Switch =>
882 Usage;
883 Ada.Command_Line.Set_Exit_Status (Ada.Command_Line.Failure);
884 end Style_Checker;