60
60
Uninitialized : constant Integer := 0;
62
Rule_Label : array (Rule_Types) of Ada.Strings.Wide_Unbounded.Unbounded_Wide_String;
63
Comments : array (Rule_Types) of Integer := (others => Uninitialized);
65
type Header_Kind is (Minimum, Model);
66
package Header_Flag_Utilities is new Framework.Language.Flag_Utilities (Header_Kind);
68
Reported : array (Rule_Types) of Boolean;
62
Ctl_Labels : array (Control_Kinds) of Ada.Strings.Wide_Unbounded.Unbounded_Wide_String;
63
Comments : array (Control_Kinds) of Integer := (others => Uninitialized);
65
type Subrules is (Minimum, Model);
66
package Subrules_Flag_Utilities is new Framework.Language.Flag_Utilities (Subrules);
68
Reported : array (Control_Kinds) of Boolean;
69
69
Model_File : Ada.Wide_Text_IO.File_Type;
70
Model_Rule : Rule_Types;
70
Model_Kind : Control_Kinds;
71
71
Model_Label : Ada.Strings.Wide_Unbounded.Unbounded_Wide_String;
72
72
Model_Reported : Boolean;
76
76
-- The same pattern can be used several times, hence it needs to be global
77
77
pragma Warnings (Off);
78
-- Gnat warns that Pattern and Last may be referenced before they have a value,
79
-- but this cannot happen because Repeat is initialized to False (in Enter_Unit)
78
-- Gnat warns that Pattern and Pat_Last may be referenced before they have a value,
79
-- but this cannot happen because Line_Repeat is initialized to No_Repeat (in Enter_Unit)
80
80
Pattern : Pattern_String;
81
81
Pat_Last : Natural;
82
82
pragma Warnings (Off);
89
procedure Add_Use (Label : in Wide_String; Rule_Type : in Rule_Types) is
84
Stop_Pattern : Pattern_String;
85
Stop_Pat_Last : Natural;
86
Stop_Has_Star : Boolean;
88
type Line_Match_States is (Repeat, Single);
89
Matcher_State : Line_Match_States;
95
procedure Add_Control (Ctl_Label : in Wide_String; Ctl_Kind : in Control_Kinds) is
90
96
use Ada.Characters.Handling, Ada.Exceptions, Ada.Strings.Wide_Unbounded, Ada.Wide_Text_IO;
91
use Framework.Language, String_Matching, Header_Flag_Utilities;
97
use Framework.Language, String_Matching, Subrules_Flag_Utilities;
93
Buff : Pattern_String;
99
Buff : Pattern_String;
97
103
if not Parameter_Exists then
98
104
Parameter_Error (Rule_Id, "kind of check required");
100
Kind := Get_Flag_Parameter (Allow_Any => False);
106
Subrule := Get_Flag_Parameter (Allow_Any => False);
104
if Comments (Rule_Type) /= Uninitialized then
110
if Comments (Ctl_Kind) /= Uninitialized then
105
111
Parameter_Error (Rule_Id, "rule already specified");
106
112
elsif not Parameter_Exists then
107
113
Parameter_Error (Rule_Id, "number of comment lines required");
109
Comments (Rule_Type) := Get_Integer_Parameter (Min => 1);
110
Rule_Label (Rule_Type) := To_Unbounded_Wide_String (Label);
115
Comments (Ctl_Kind) := Get_Integer_Parameter (Min => 1);
116
Ctl_Labels (Ctl_Kind) := To_Unbounded_Wide_String (Ctl_Label);
113
119
if Is_Open (Model_File) then
159
165
when Occur : Pattern_Error =>
160
Parameter_Error (Rule_Id, "incorrect pattern at "
161
& To_Wide_String (Name (Model_File)) & ':'
162
& Ada.Wide_Text_IO.Count'Wide_Image (Line (Model_File))
163
& ": " & Buff (1 .. Last)
164
& " (" & To_Wide_String (Exception_Message (Occur)) & ')');
166
Parameter_Error (Rule_Id, "incorrect pattern "
167
& " (" & To_Wide_String (Exception_Message (Occur)) & ") at "
168
& To_Wide_String (Name (Model_File)) & ':'
169
& Ada.Wide_Text_IO.Count'Wide_Image (Line (Model_File))
170
& ": " & Buff (1 .. Last));
165
171
when End_Error =>
169
Model_Rule := Rule_Type;
170
Model_Label := To_Unbounded_Wide_String (Label);
175
Model_Kind := Ctl_Kind;
176
Model_Label := To_Unbounded_Wide_String (Ctl_Label);
173
179
Rule_Used := True;
180
186
procedure Help is
181
use Utilities, Header_Flag_Utilities;
187
use Utilities, Subrules_Flag_Utilities;
183
189
User_Message ("Rule: " & Rule_Id);
184
190
Help_On_Flags ("Parameter (1):");
262
268
-- Here we have a non-comment line in the range where a check is required
263
Report (Rule_Id, To_Wide_String (Rule_Label (Rule_Type)), Rule_Type, Loc,
269
Report (Rule_Id, To_Wide_String (Ctl_Labels (Ctl_Kind)), Ctl_Kind, Loc,
264
270
"not enough header comment lines");
265
Reported (Rule_Type) := True;
266
if Rule_Type = Check and Comments (Search) >= 1 then
271
Reported (Ctl_Kind) := True;
272
if Ctl_Kind = Check and Comments (Search) >= 1 then
267
273
Reported (Search) := True;
269
275
end Check_Comments_Number;
271
277
procedure Check_Model is
273
278
use Ada.Wide_Text_IO;
280
function Line_Match (With_Pattern : Wide_String; Last : Natural) return Boolean is
282
-- True matching that considers that the empty line matches only the empty pattern
284
if Line'Length = 0 or Last = 0 then
285
return Last = Line'Length;
287
return Match (Line, With_Pattern (1 .. Last));
275
292
if not Is_Open (Model_File) or Model_Reported then
280
Get_Line (Model_File, Pattern, Pat_Last);
281
if Pattern (1 .. Pat_Last) = "*" then
283
Get_Line (Model_File, Pattern, Pat_Last);
287
if (Pat_Last = 0 and Line'Length /= 0)
288
or else not Match (Line, Pattern (1..Pat_Last))
291
-- maybe the end of the repeated pattern
293
-- give it another chance
296
Report (Rule_Id, To_Wide_String (Model_Label), Model_Rule, Loc,
297
"line does not match pattern");
298
Model_Reported := True;
303
Model_Reported := True;
296
case Matcher_State is
299
Get_Line (Model_File, Pattern, Pat_Last);
302
Model_Reported := True;
306
if Pattern (1 .. Pat_Last) = "*" then
307
-- Remember that a "*" line is always followed by a regular line
308
-- (checked in Add_Control)
309
Get_Line (Model_File, Pattern, Pat_Last);
312
Get_Line (Model_File, Stop_Pattern, Stop_Pat_Last);
313
Matcher_State := Repeat;
314
Stop_Has_Star := Stop_Pattern (1 .. Stop_Pat_Last) = "*" ;
315
if Stop_Has_Star then
316
Get_Line (Model_File, Stop_Pattern, Stop_Pat_Last);
320
-- Nothing after "*" pattern: no need to check further
321
Model_Reported := True;
325
-- Retry in Repeat state
328
elsif Line_Match (Pattern, Pat_Last) then
332
Report (Rule_Id, To_Wide_String (Model_Label), Model_Kind, Loc,
333
"line does not match pattern """ & Pattern (1 .. Pat_Last) & '"');
334
Model_Reported := True;
338
-- Check the stopping pattern first, to avoid "greedy" effects
339
if Line_Match (Stop_Pattern, Stop_Pat_Last) then
340
Pattern := Stop_Pattern;
341
Pat_Last := Stop_Pat_Last;
342
if Stop_Has_Star then
343
-- Stay in Repeat state
345
Get_Line (Model_File, Stop_Pattern, Stop_Pat_Last);
346
Stop_Has_Star := Stop_Pattern (1 .. Stop_Pat_Last) = "*" ;
347
if Stop_Has_Star then
348
Get_Line (Model_File, Stop_Pattern, Stop_Pat_Last);
352
-- Nothing after "*" pattern: no need to check further
353
Model_Reported := True;
356
Matcher_State := Single;
359
elsif Line_Match (Pattern, Pat_Last) then
363
Report (Rule_Id, To_Wide_String (Model_Label), Model_Kind, Loc,
364
"line does not match pattern """ & Stop_Pattern (1 .. Stop_Pat_Last) & '"');
365
Model_Reported := True;
307
if not Rule_Used or Reported = (Rule_Types => True) then
372
or (Reported = (Control_Kinds => True) and Model_Reported)
310
376
Rules_Manager.Enter (Rule_Id);
312
378
Line_Num := Get_First_Line (Loc);
314
for R in Rule_Types loop
380
for R in Control_Kinds loop
315
381
Check_Comments_Number (R);