Document -lang to display supported languages
[style_checker.git] / src / style_checker.adb
blobdf7d5992c3337f4db1bf9662c476996638b87c0a
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 begin
234 if not Checker.Lang.Get_Comment_Dot_EOL
235 and then Checker.Lang.Comment /= ""
236 then
237 if Fixed.Index (Line, String'(Checker.Lang.Comment)) /= 0 then
238 -- This is a comment
239 Checker.Consecutive_Comment := Checker.Consecutive_Comment + 1;
241 if Line
242 (Fixed.Index_Non_Blank (Line, Going => Backward)) = '.'
243 then
244 Checker.Last_Comment_Dot_EOL := True;
245 else
246 Checker.Last_Comment_Dot_EOL := False;
247 end if;
249 else
250 -- No more in a comment line
252 if Checker.Consecutive_Comment = 1
253 and then Checker.Last_Comment_Dot_EOL
254 then
255 Report_Error
256 (Checker.File,
257 "single line comment should not terminate with dot",
258 Offset => -1);
259 end if;
261 Checker.Consecutive_Comment := 0;
262 Checker.Last_Comment_Dot_EOL := False;
263 end if;
264 end if;
265 end Check_Comment_Dot_EOL;
267 ---------------------
268 -- Check_Copyright --
269 ---------------------
271 procedure Check_Copyright is
272 use Text_IO;
273 Co_Start : Natural := 0;
274 Cp_Start : Natural := Fixed.Index (Line, " Copyright");
275 begin
276 if Checker.Lang.Comment /= "" then
277 Co_Start := Fixed.Index (Line, String'(Checker.Lang.Comment));
278 end if;
280 if Cp_Start /= 0
281 and then Cp_Start + 10 <= Line'Length
282 and then Line (Cp_Start + 10) /= ' '
283 then
284 -- We are not at the end of the line and no space after Copyright
285 Cp_Start := 0;
286 end if;
288 if (Checker.Lang.Get_Copyright_Present
289 or else Checker.Lang.Get_Copyright_Year)
290 and then Cp_Start /= 0
291 and then Co_Start /= 0
292 and then Cp_Start > Co_Start
293 then
294 Checker.Copyright_Found := True;
296 if Checker.Lang.Get_Copyright_Year then
297 if Fixed.Index (Line, Current_Year) /= 0 then
298 Checker.Copyright_Year := True;
299 end if;
300 end if;
301 end if;
303 -- Check that the copyright year follow the given regexp
305 if Cp_Start /= 0
306 and then Checker.Lang.Get_Copyright_Pattern /= ""
307 then
308 declare
309 Pattern : constant Regpat.Pattern_Matcher :=
310 Regpat.Compile (Checker.Lang.Get_Copyright_Pattern);
311 begin
312 if not Regpat.Match (Pattern, Line) then
313 Report_Error
314 (Checker.File,
315 "copyright line not matching expected pattern");
316 end if;
317 end;
318 end if;
319 end Check_Copyright;
321 ---------------------------
322 -- Check_Duplicate_Blank --
323 ---------------------------
325 procedure Check_Duplicate_Blank is
326 begin
327 if Checker.Lang.Get_Duplicate_Blank_Line = Checks.Rejected
328 and then (Line'Length = 0
329 or else Fixed.Count (Line, " " & ASCII.HT) = Line'Length)
330 then
331 Checker.Count_Blank := Checker.Count_Blank + 1;
333 if Checker.Count_Blank > 1 then
334 Report_Error (Checker.File, "duplicate blank line");
335 end if;
337 else
338 Checker.Count_Blank := 0;
339 end if;
340 end Check_Duplicate_Blank;
342 ------------------
343 -- Check_Ending --
344 ------------------
346 procedure Check_Ending is
347 begin
348 if Checker.Lang.Get_Line_Ending /= Checks.Any then
349 if Line_Ending = Checks.No then
350 Report_Error
351 (Checker.File,
352 "missing line terminator");
353 elsif Checker.Lang.Get_Line_Ending /= Line_Ending then
354 Report_Error
355 (Checker.File,
356 "wrong " & Checks.Line_Ending_Style'Image (Line_Ending) &
357 " line ending");
358 end if;
359 end if;
360 end Check_Ending;
362 ------------------
363 -- Check_Header --
364 ------------------
366 procedure Check_Header is
367 C : constant String := Checker.Lang.Comment;
368 begin
369 if Checker.In_Header
370 and then Line'Length >= C'Length
371 and then Line (Line'First .. Line'First + C'Length - 1) = C
372 then
373 Checker.Header_Size := Checker.Header_Size + 1;
374 else
375 Checker.In_Header := False;
376 end if;
377 end Check_Header;
379 ----------------------
380 -- Check_Length_Max --
381 ----------------------
383 procedure Check_Length_Max is
384 begin
385 if Line'Length > Checker.Lang.Get_Line_Length_Max then
386 Report_Error (Checker.File, "line too long");
387 end if;
388 end Check_Length_Max;
390 -------------------------
391 -- Check_Space_Comment --
392 -------------------------
394 procedure Check_Space_Comment is
395 N : constant Natural := Checker.Lang.Get_Space_Comment;
396 NI : constant String := Natural'Image (N);
397 C : constant String := Checker.Lang.Comment;
398 I : constant Natural := Fixed.Index_Non_Blank (Line);
399 begin
400 if N /= 0
401 and then I /= 0
402 and then I + C'Length - 1 <= Line'Last
403 and then Line (I .. I + C'Length - 1) = C
404 and then Line (Line'Last - C'Length + 1 .. Line'Last) /= C
405 and then (Line (I .. I + 1) /= "#!"
406 or else File_Reader.Line (Checker.File) > 1)
407 -- Do no check script headers
408 then
409 for K in I + C'Length .. I + C'Length + N - 1 loop
410 if Line (K) /= ' ' then
411 Report_Error
412 (Checker.File,
413 NI (NI'First + 1 .. NI'Last) & " spaces after " & C);
414 exit;
415 end if;
416 end loop;
417 end if;
418 end Check_Space_Comment;
420 ---------------------------
421 -- Check_Trailing_Spaces --
422 ---------------------------
424 procedure Check_Trailing_Spaces is
425 begin
426 if Checker.Lang.Get_Trailing_Spaces = Checks.Rejected
427 and then Line'Length > 0
428 and then (Line (Line'Last) = ' '
429 or else Line (Line'Last) = ASCII.HT)
430 then
431 Report_Error (Checker.File, "no trailing spaces allowed");
432 end if;
433 end Check_Trailing_Spaces;
435 begin
436 Check_Ending;
437 Check_Length_Max;
438 Check_Duplicate_Blank;
439 Check_Trailing_Spaces;
440 Check_Header;
441 Check_Copyright;
442 Check_Space_Comment;
443 Check_Comment_Dot_EOL;
444 end Check_Line;
446 --------------------
447 -- List_Languages --
448 --------------------
450 procedure List_Languages is
451 procedure P (Str : in String) renames Text_IO.Put_Line;
452 begin
453 Text_IO.New_Line;
454 P ("Style Checker " & Version.Simple);
455 Text_IO.New_Line;
456 Languages.List;
457 Text_IO.New_Line;
458 end List_Languages;
460 ------------------
461 -- Report_Error --
462 ------------------
464 procedure Report_Error
465 (File : in File_Reader.File_Type;
466 Message : in String;
467 Offset : in Line_Offset := 0)
469 Line : constant String :=
470 Natural'Image (File_Reader.Line (File) + Offset);
471 begin
472 Error_Count := Error_Count + 1;
473 if Error_Count <= Max_Error then
474 if Real_Filename = Null_Unbounded_String then
475 Text_IO.Put_Line
476 (Text_IO.Standard_Error,
477 File_Reader.Name (File, Absolute_Pathname) & ':'
478 & Line (Line'First + 1 .. Line'Last) & ": " & Message);
479 else
480 Text_IO.Put_Line
481 (Text_IO.Standard_Error,
482 To_String (Real_Filename) & ':'
483 & Line (Line'First + 1 .. Line'Last) & ": " & Message);
484 end if;
485 end if;
486 end Report_Error;
488 procedure Report_Error
489 (Filename : in String;
490 Message : in String;
491 At_Line : in Natural := 1)
493 Line : constant String := Natural'Image (At_Line);
494 begin
495 Error_Count := Error_Count + 1;
496 if Error_Count <= Max_Error then
497 if Real_Filename = Null_Unbounded_String then
498 Text_IO.Put_Line
499 (Text_IO.Standard_Error, Filename & ':'
500 & Line (Line'First + 1 .. Line'Last) & ": " & Message);
501 else
502 Text_IO.Put_Line
503 (Text_IO.Standard_Error,
504 To_String (Real_Filename) & ':'
505 & Line (Line'First + 1 .. Line'Last) & ": " & Message);
506 end if;
507 end if;
508 end Report_Error;
510 -------------
511 -- Unquote --
512 -------------
514 function Unquote (Str : in String) return String is
515 S : String := Fixed.Trim (Str, Strings.Both);
516 begin
517 if (S (S'First) = ''' and then S (S'Last) = ''')
518 or else (S (S'First) = '"' and then S (S'Last) = '"')
519 then
520 return S (S'First + 1 .. S'Last - 1);
521 else
522 return S;
523 end if;
524 end Unquote;
526 -----------
527 -- Usage --
528 -----------
530 procedure Usage is
531 procedure P (Str : in String) renames Text_IO.Put_Line;
532 begin
533 Text_IO.New_Line;
534 P ("Style Checker " & Version.Simple);
535 Text_IO.New_Line;
536 P ("style_checker [-lang name] [options] file1 file2...");
537 P (" -lang : list all built-in supported languages");
538 P (" -lang NAME : following options are for this specific language");
539 P (" -abs : output absolute path name");
540 P (" -ign EXT : ignore files having EXT has extension");
541 P (" -b : no duplicate blank lines (default)");
542 P (" -B : disable duplicate blank lines check");
543 P (" -c : check for space after comment tag (default)");
544 P (" -C : disable space in comment check");
545 P (" -cp : check copyright presence");
546 P (" -cP : disable check for copyright presence (default)");
547 P (" -cy : check for copyright year");
548 P (" -cY : disbale check for copyright year (default)");
549 P (" -cf : if present a copyright line should match the"
550 & "given pattern");
551 P (" -cF : disable copyright pattern check");
552 P (" -d : check single comment line dot ending");
553 P (" -D : disable check for single comment line dot ending");
554 P (" -e DOS|UNIX : line ending style (UNIX default)");
555 P (" -E : disable line ending check");
556 P (" -h N : start with an header of N line (default N 20)");
557 P (" -H : disable header check");
558 P (" -l N : line length <= N (default 79)");
559 P (" -L : disable line length check");
560 P (" -m N : output only the first N errors");
561 P (" -n NAME : filename to report in error message");
562 P (" -s : syntax check (default)");
563 P (" -sp PARAM : additional parameter for the style checker");
564 P (" -S : disable syntax check");
565 P (" -t : check for trailing spaces (default)");
566 P (" -T : disable trailing spaces check");
567 P (" -v : display version");
568 Text_IO.New_Line;
569 end Usage;
571 Lang : Languages.Lang_Access;
573 begin
574 if Ada.Command_Line.Argument_Count = 0 then
575 raise Checks.Syntax_Error;
577 elsif Ada.Command_Line.Argument_Count = 1
578 and then Ada.Command_Line.Argument (1) = "-lang"
579 then
580 List_Languages;
582 else
583 loop
584 case GNAT.Command_Line.Getopt
585 ("abs lang: ign: e: E l? h? H "
586 & "L b B s S t T v c? C cp cy cP cY cf: cF d D sp: m: n:")
588 when ASCII.NUL =>
589 exit;
591 when 'a' =>
592 if GNAT.Command_Line.Full_Switch = "abs" then
593 Absolute_Pathname := True;
594 else
595 raise Checks.Syntax_Error;
596 end if;
598 when 'd' =>
599 Languages.Set_Comment_Dot_EOL (Lang, False);
601 when 'D' =>
602 Languages.Set_Comment_Dot_EOL (Lang, True);
604 when 'e' =>
605 Languages.Set_Line_Ending
606 (Lang, Checks.Line_Ending_Style'Value
607 (GNAT.Command_Line.Parameter));
609 when 'E' =>
610 Languages.Set_Line_Ending (Lang, Checks.Any);
612 when 'i' =>
613 declare
614 Full : constant String := GNAT.Command_Line.Full_Switch;
615 begin
616 if Full = "ign" then
617 Ignore_Set.Include (GNAT.Command_Line.Parameter);
618 else
619 raise Checks.Syntax_Error;
620 end if;
621 end;
623 when 'l' =>
624 declare
625 Full : constant String := GNAT.Command_Line.Full_Switch;
626 begin
627 if Full = "lang" then
628 Lang := Languages.Get_From_Name
629 (GNAT.Command_Line.Parameter);
631 elsif Full = "l" then
632 declare
633 P : constant String := GNAT.Command_Line.Parameter;
634 begin
635 if P = "" then
636 Languages.Set_Line_Length_Max (Lang, 79);
637 else
638 Languages.Set_Line_Length_Max
639 (Lang, Positive'Value (P));
640 end if;
641 exception
642 when Constraint_Error | IO_Exceptions.Name_Error =>
643 raise Checks.Syntax_Error;
644 end;
645 end if;
646 end;
648 when 'L' =>
649 Languages.Set_Line_Length_Max (Lang, Positive'Last);
651 when 'h' =>
652 declare
653 P : constant String := GNAT.Command_Line.Parameter;
654 begin
655 if P = "" then
656 Languages.Set_Header_Size (Lang, 20);
657 else
658 Languages.Set_Header_Size (Lang, Positive'Value (P));
659 end if;
660 exception
661 when Constraint_Error | IO_Exceptions.Name_Error =>
662 raise Checks.Syntax_Error;
663 end;
665 when 'H' =>
666 Languages.Set_Header_Size (Lang, 0);
668 when 'b' =>
669 Languages.Set_Duplicate_Blank_Line (Lang, Checks.Rejected);
671 when 'B' =>
672 Languages.Set_Duplicate_Blank_Line (Lang, Checks.Accepted);
674 when 't' =>
675 Languages.Set_Trailing_Spaces (Lang, Checks.Rejected);
677 when 'T' =>
678 Languages.Set_Trailing_Spaces (Lang, Checks.Accepted);
680 when 's' =>
681 declare
682 Full : constant String := GNAT.Command_Line.Full_Switch;
683 begin
684 if Full = "sp" then
685 Languages.Add_Style_Checker_Parameter
686 (Lang, GNAT.Command_Line.Parameter);
688 else
689 Languages.Set_Syntax_Check (Lang, True);
690 end if;
691 end;
693 when 'S' =>
694 Languages.Set_Syntax_Check (Lang, False);
696 when 'c' =>
697 declare
698 Full : constant String := GNAT.Command_Line.Full_Switch;
699 begin
700 if Full = "c" then
701 declare
702 P : constant String := GNAT.Command_Line.Parameter;
703 begin
704 if P = "" then
705 Languages.Set_Space_Comment (Lang, 2);
706 else
707 Languages.Set_Space_Comment
708 (Lang, Positive'Value (P));
709 end if;
710 end;
712 elsif Full = "cp" then
713 Languages.Set_Copyright_Present (Lang, True);
715 elsif Full = "cP" then
716 Languages.Set_Copyright_Present (Lang, False);
718 elsif Full = "cy" then
719 Languages.Set_Copyright_Year (Lang, True);
721 elsif Full = "cY" then
722 Languages.Set_Copyright_Year (Lang, False);
724 elsif Full = "cf" then
725 Languages.Set_Copyright_Pattern
726 (Lang, Unquote (GNAT.Command_Line.Parameter));
728 elsif Full = "cF" then
729 Languages.Set_Copyright_Pattern (Lang, "");
730 end if;
731 end;
733 when 'C' =>
734 Languages.Set_Space_Comment (Lang, 0);
736 when 'm' =>
737 Max_Error := Natural'Value (GNAT.Command_Line.Parameter);
739 when 'n' =>
740 Real_Filename :=
741 To_Unbounded_String (GNAT.Command_Line.Parameter);
743 when 'v' =>
744 Text_IO.Put_Line ("Style Checker " & Version.Complete);
745 exit;
747 when others =>
748 raise Checks.Syntax_Error;
749 end case;
750 end loop;
752 -- Register some known extension to ignore
754 Ignore_Set.Include ("gif");
755 Ignore_Set.Include ("png");
756 Ignore_Set.Include ("jpg");
757 Ignore_Set.Include ("pdf");
758 Ignore_Set.Include ("ps");
759 Ignore_Set.Include ("exe");
760 Ignore_Set.Include ("dll");
761 Ignore_Set.Include ("so");
762 Ignore_Set.Include ("o");
763 Ignore_Set.Include ("obj");
765 loop
766 declare
767 Filename : constant String :=
768 GNAT.Command_Line.Get_Argument (Do_Expansion => True);
769 begin
770 exit when Filename'Length = 0;
772 if Directories.Exists (Filename) then
773 if Directories.Kind (Filename) /= Directories.Directory then
774 declare
775 Ext : constant String := Directories.Extension (Filename);
776 begin
777 if (Ext /= "" and then not Ignore_Set.Contains (Ext))
778 or else
779 (Ext = "" and then not Ignore_Set.Contains
780 (Directories.Simple_Name (Filename)))
781 then
782 -- Do not check directory
783 Check (Filename);
784 end if;
785 end;
786 end if;
788 else
789 Report_Error (Filename, "file not found");
790 end if;
791 end;
792 end loop;
794 end if;
796 if Style_Error or else Error_Count > 0 then
797 Ada.Command_Line.Set_Exit_Status (Ada.Command_Line.Failure);
798 else
799 Ada.Command_Line.Set_Exit_Status (Ada.Command_Line.Success);
800 end if;
802 exception
803 when Checks.Syntax_Error | GNAT.Command_Line.Invalid_Switch =>
804 Usage;
805 Ada.Command_Line.Set_Exit_Status (Ada.Command_Line.Failure);
806 end Style_Checker;