Remove some compile time warnings about duplicate definitions.
[official-gcc.git] / gcc / ada / g-awk.adb
blob654e11c494cbfaf40082456ce1a691ee3e6005d1
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- G N A T . A W K --
6 -- --
7 -- B o d y --
8 -- --
9 -- $Revision: 1.1 $
10 -- --
11 -- Copyright (C) 2000-2001 Ada Core Technologies, Inc. --
12 -- --
13 -- GNAT is free software; you can redistribute it and/or modify it under --
14 -- terms of the GNU General Public License as published by the Free Soft- --
15 -- ware Foundation; either version 2, or (at your option) any later ver- --
16 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
17 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
18 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
19 -- for more details. You should have received a copy of the GNU General --
20 -- Public License distributed with GNAT; see file COPYING. If not, write --
21 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
22 -- MA 02111-1307, USA. --
23 -- --
24 -- As a special exception, if other files instantiate generics from this --
25 -- unit, or you link this unit with other files to produce an executable, --
26 -- this unit does not by itself cause the resulting executable to be --
27 -- covered by the GNU General Public License. This exception does not --
28 -- however invalidate any other reasons why the executable file might be --
29 -- covered by the GNU Public License. --
30 -- --
31 -- GNAT is maintained by Ada Core Technologies Inc (http://www.gnat.com). --
32 -- --
33 ------------------------------------------------------------------------------
35 pragma Style_Checks (All_Checks);
36 -- Turn off alpha ordering check for subprograms, since we cannot
37 -- Put Finalize and Initialize in alpha order (see comments).
39 with Ada.Exceptions;
40 with Ada.Text_IO;
41 with Ada.Strings.Unbounded;
42 with Ada.Strings.Fixed;
43 with Ada.Strings.Maps;
44 with Ada.Unchecked_Deallocation;
46 with GNAT.Directory_Operations;
47 with GNAT.Dynamic_Tables;
48 with GNAT.OS_Lib;
50 package body GNAT.AWK is
52 use Ada;
53 use Ada.Strings.Unbounded;
55 ----------------
56 -- Split mode --
57 ----------------
59 package Split is
61 type Mode is abstract tagged null record;
62 -- This is the main type which is declared abstract. This type must be
63 -- derived for each split style.
65 type Mode_Access is access Mode'Class;
67 procedure Current_Line (S : Mode; Session : Session_Type)
68 is abstract;
69 -- Split Session's current line using split mode.
71 ------------------------
72 -- Split on separator --
73 ------------------------
75 type Separator (Size : Positive) is new Mode with record
76 Separators : String (1 .. Size);
77 end record;
79 procedure Current_Line
80 (S : Separator;
81 Session : Session_Type);
83 ---------------------
84 -- Split on column --
85 ---------------------
87 type Column (Size : Positive) is new Mode with record
88 Columns : Widths_Set (1 .. Size);
89 end record;
91 procedure Current_Line (S : Column; Session : Session_Type);
93 end Split;
95 procedure Free is new Unchecked_Deallocation
96 (Split.Mode'Class, Split.Mode_Access);
98 ----------------
99 -- File_Table --
100 ----------------
102 type AWK_File is access String;
104 package File_Table is
105 new Dynamic_Tables (AWK_File, Natural, 1, 5, 50);
106 -- List of filename associated with a Session.
108 procedure Free is new Unchecked_Deallocation (String, AWK_File);
110 -----------------
111 -- Field_Table --
112 -----------------
114 type Field_Slice is record
115 First : Positive;
116 Last : Natural;
117 end record;
118 -- This is a field slice (First .. Last) in session's current line.
120 package Field_Table is
121 new Dynamic_Tables (Field_Slice, Natural, 1, 10, 100);
122 -- List of fields for the current line.
124 --------------
125 -- Patterns --
126 --------------
128 -- Define all patterns style : exact string, regular expression, boolean
129 -- function.
131 package Patterns is
133 type Pattern is abstract tagged null record;
134 -- This is the main type which is declared abstract. This type must be
135 -- derived for each patterns style.
137 type Pattern_Access is access Pattern'Class;
139 function Match
140 (P : Pattern;
141 Session : Session_Type)
142 return Boolean
143 is abstract;
144 -- Returns True if P match for the current session and False otherwise.
146 procedure Release (P : in out Pattern);
147 -- Release memory used by the pattern structure.
149 --------------------------
150 -- Exact string pattern --
151 --------------------------
153 type String_Pattern is new Pattern with record
154 Str : Unbounded_String;
155 Rank : Count;
156 end record;
158 function Match
159 (P : String_Pattern;
160 Session : Session_Type)
161 return Boolean;
163 --------------------------------
164 -- Regular expression pattern --
165 --------------------------------
167 type Pattern_Matcher_Access is access Regpat.Pattern_Matcher;
169 type Regexp_Pattern is new Pattern with record
170 Regx : Pattern_Matcher_Access;
171 Rank : Count;
172 end record;
174 function Match
175 (P : Regexp_Pattern;
176 Session : Session_Type)
177 return Boolean;
179 procedure Release (P : in out Regexp_Pattern);
181 ------------------------------
182 -- Boolean function pattern --
183 ------------------------------
185 type Callback_Pattern is new Pattern with record
186 Pattern : Pattern_Callback;
187 end record;
189 function Match
190 (P : Callback_Pattern;
191 Session : Session_Type)
192 return Boolean;
194 end Patterns;
196 procedure Free is new Unchecked_Deallocation
197 (Patterns.Pattern'Class, Patterns.Pattern_Access);
199 -------------
200 -- Actions --
201 -------------
203 -- Define all action style : simple call, call with matches
205 package Actions is
207 type Action is abstract tagged null record;
208 -- This is the main type which is declared abstract. This type must be
209 -- derived for each action style.
211 type Action_Access is access Action'Class;
213 procedure Call
214 (A : Action;
215 Session : Session_Type)
216 is abstract;
217 -- Call action A as required.
219 -------------------
220 -- Simple action --
221 -------------------
223 type Simple_Action is new Action with record
224 Proc : Action_Callback;
225 end record;
227 procedure Call
228 (A : Simple_Action;
229 Session : Session_Type);
231 -------------------------
232 -- Action with matches --
233 -------------------------
235 type Match_Action is new Action with record
236 Proc : Match_Action_Callback;
237 end record;
239 procedure Call
240 (A : Match_Action;
241 Session : Session_Type);
243 end Actions;
245 procedure Free is new Unchecked_Deallocation
246 (Actions.Action'Class, Actions.Action_Access);
248 --------------------------
249 -- Pattern/Action table --
250 --------------------------
252 type Pattern_Action is record
253 Pattern : Patterns.Pattern_Access; -- If Pattern is True
254 Action : Actions.Action_Access; -- Action will be called
255 end record;
257 package Pattern_Action_Table is
258 new Dynamic_Tables (Pattern_Action, Natural, 1, 5, 50);
260 ------------------
261 -- Session Data --
262 ------------------
264 type Session_Data is record
265 Current_File : Text_IO.File_Type;
266 Current_Line : Unbounded_String;
267 Separators : Split.Mode_Access;
268 Files : File_Table.Instance;
269 File_Index : Natural := 0;
270 Fields : Field_Table.Instance;
271 Filters : Pattern_Action_Table.Instance;
272 NR : Natural := 0;
273 FNR : Natural := 0;
274 Matches : Regpat.Match_Array (0 .. 100);
275 -- latest matches for the regexp pattern
276 end record;
278 procedure Free is
279 new Unchecked_Deallocation (Session_Data, Session_Data_Access);
281 ----------------
282 -- Initialize --
283 ----------------
285 procedure Initialize (Session : in out Session_Type) is
286 begin
287 Session.Data := new Session_Data;
289 -- Initialize separators
291 Session.Data.Separators :=
292 new Split.Separator'(Default_Separators'Length, Default_Separators);
294 -- Initialize all tables
296 File_Table.Init (Session.Data.Files);
297 Field_Table.Init (Session.Data.Fields);
298 Pattern_Action_Table.Init (Session.Data.Filters);
299 end Initialize;
301 -----------------------
302 -- Session Variables --
303 -----------------------
305 -- These must come after the body of Initialize, since they make
306 -- implicit calls to Initialize at elaboration time.
308 Def_Session : Session_Type;
309 Cur_Session : Session_Type;
311 --------------
312 -- Finalize --
313 --------------
315 -- Note: Finalize must come after Initialize and the definition
316 -- of the Def_Session and Cur_Session variables, since it references
317 -- the latter.
319 procedure Finalize (Session : in out Session_Type) is
320 begin
321 -- We release the session data only if it is not the default session.
323 if Session.Data /= Def_Session.Data then
324 Free (Session.Data);
326 -- Since we have closed the current session, set it to point
327 -- now to the default session.
329 Cur_Session.Data := Def_Session.Data;
330 end if;
331 end Finalize;
333 ----------------------
334 -- Private Services --
335 ----------------------
337 function Always_True return Boolean;
338 -- A function that always returns True.
340 function Apply_Filters
341 (Session : Session_Type := Current_Session)
342 return Boolean;
343 -- Apply any filters for which the Pattern is True for Session. It returns
344 -- True if a least one filters has been applied (i.e. associated action
345 -- callback has been called).
347 procedure Open_Next_File
348 (Session : Session_Type := Current_Session);
349 pragma Inline (Open_Next_File);
350 -- Open next file for Session closing current file if needed. It raises
351 -- End_Error if there is no more file in the table.
353 procedure Raise_With_Info
354 (E : Exceptions.Exception_Id;
355 Message : String;
356 Session : Session_Type);
357 pragma No_Return (Raise_With_Info);
358 -- Raises exception E with the message prepended with the current line
359 -- number and the filename if possible.
361 procedure Read_Line (Session : Session_Type);
362 -- Read a line for the Session and set Current_Line.
364 procedure Split_Line (Session : Session_Type);
365 -- Split session's Current_Line according to the session separators and
366 -- set the Fields table. This procedure can be called at any time.
368 ----------------------
369 -- Private Packages --
370 ----------------------
372 -------------
373 -- Actions --
374 -------------
376 package body Actions is
378 ----------
379 -- Call --
380 ----------
382 procedure Call
383 (A : Simple_Action;
384 Session : Session_Type)
386 begin
387 A.Proc.all;
388 end Call;
390 ----------
391 -- Call --
392 ----------
394 procedure Call
395 (A : Match_Action;
396 Session : Session_Type)
398 begin
399 A.Proc (Session.Data.Matches);
400 end Call;
402 end Actions;
404 --------------
405 -- Patterns --
406 --------------
408 package body Patterns is
410 -----------
411 -- Match --
412 -----------
414 function Match
415 (P : String_Pattern;
416 Session : Session_Type)
417 return Boolean
419 begin
420 return P.Str = Field (P.Rank, Session);
421 end Match;
423 -----------
424 -- Match --
425 -----------
427 function Match
428 (P : Regexp_Pattern;
429 Session : Session_Type)
430 return Boolean
432 use type Regpat.Match_Location;
434 begin
435 Regpat.Match
436 (P.Regx.all, Field (P.Rank, Session), Session.Data.Matches);
437 return Session.Data.Matches (0) /= Regpat.No_Match;
438 end Match;
440 -----------
441 -- Match --
442 -----------
444 function Match
445 (P : Callback_Pattern;
446 Session : Session_Type)
447 return Boolean
449 begin
450 return P.Pattern.all;
451 end Match;
453 -------------
454 -- Release --
455 -------------
457 procedure Release (P : in out Pattern) is
458 begin
459 null;
460 end Release;
462 -------------
463 -- Release --
464 -------------
466 procedure Release (P : in out Regexp_Pattern) is
467 procedure Free is new Unchecked_Deallocation
468 (Regpat.Pattern_Matcher, Pattern_Matcher_Access);
470 begin
471 Free (P.Regx);
472 end Release;
474 end Patterns;
476 -----------
477 -- Split --
478 -----------
480 package body Split is
482 use Ada.Strings;
484 ------------------
485 -- Current_Line --
486 ------------------
488 procedure Current_Line (S : Separator; Session : Session_Type) is
489 Line : constant String := To_String (Session.Data.Current_Line);
490 Fields : Field_Table.Instance renames Session.Data.Fields;
492 Start : Positive;
493 Stop : Natural;
495 Seps : Maps.Character_Set := Maps.To_Set (S.Separators);
497 begin
498 -- First field start here
500 Start := Line'First;
502 -- Record the first field start position which is the first character
503 -- in the line.
505 Field_Table.Increment_Last (Fields);
506 Fields.Table (Field_Table.Last (Fields)).First := Start;
508 loop
509 -- Look for next separator
511 Stop := Fixed.Index
512 (Source => Line (Start .. Line'Last),
513 Set => Seps);
515 exit when Stop = 0;
517 Fields.Table (Field_Table.Last (Fields)).Last := Stop - 1;
519 -- if separators are set to the default (space and tab) we skip
520 -- all spaces and tabs following current field.
522 if S.Separators = Default_Separators then
523 Start := Fixed.Index
524 (Line (Stop + 1 .. Line'Last),
525 Maps.To_Set (Default_Separators),
526 Outside,
527 Strings.Forward);
528 else
529 Start := Stop + 1;
530 end if;
532 -- Record in the field table the start of this new field
534 Field_Table.Increment_Last (Fields);
535 Fields.Table (Field_Table.Last (Fields)).First := Start;
537 end loop;
539 Fields.Table (Field_Table.Last (Fields)).Last := Line'Last;
540 end Current_Line;
542 ------------------
543 -- Current_Line --
544 ------------------
546 procedure Current_Line (S : Column; Session : Session_Type) is
547 Line : constant String := To_String (Session.Data.Current_Line);
548 Fields : Field_Table.Instance renames Session.Data.Fields;
549 Start : Positive := Line'First;
551 begin
552 -- Record the first field start position which is the first character
553 -- in the line.
555 for C in 1 .. S.Columns'Length loop
557 Field_Table.Increment_Last (Fields);
559 Fields.Table (Field_Table.Last (Fields)).First := Start;
561 Start := Start + S.Columns (C);
563 Fields.Table (Field_Table.Last (Fields)).Last := Start - 1;
565 end loop;
567 -- If there is some remaining character on the line, add them in a
568 -- new field.
570 if Start - 1 < Line'Length then
572 Field_Table.Increment_Last (Fields);
574 Fields.Table (Field_Table.Last (Fields)).First := Start;
576 Fields.Table (Field_Table.Last (Fields)).Last := Line'Last;
577 end if;
578 end Current_Line;
580 end Split;
582 --------------
583 -- Add_File --
584 --------------
586 procedure Add_File
587 (Filename : String;
588 Session : Session_Type := Current_Session)
590 Files : File_Table.Instance renames Session.Data.Files;
592 begin
593 if OS_Lib.Is_Regular_File (Filename) then
594 File_Table.Increment_Last (Files);
595 Files.Table (File_Table.Last (Files)) := new String'(Filename);
596 else
597 Raise_With_Info
598 (File_Error'Identity,
599 "File " & Filename & " not found.",
600 Session);
601 end if;
602 end Add_File;
604 ---------------
605 -- Add_Files --
606 ---------------
608 procedure Add_Files
609 (Directory : String;
610 Filenames : String;
611 Number_Of_Files_Added : out Natural;
612 Session : Session_Type := Current_Session)
614 use Directory_Operations;
616 Dir : Dir_Type;
617 Filename : String (1 .. 200);
618 Last : Natural;
620 begin
621 Number_Of_Files_Added := 0;
623 Open (Dir, Directory);
625 loop
626 Read (Dir, Filename, Last);
627 exit when Last = 0;
629 Add_File (Filename (1 .. Last), Session);
630 Number_Of_Files_Added := Number_Of_Files_Added + 1;
631 end loop;
633 Close (Dir);
635 exception
636 when others =>
637 Raise_With_Info
638 (File_Error'Identity,
639 "Error scaning directory " & Directory
640 & " for files " & Filenames & '.',
641 Session);
642 end Add_Files;
644 -----------------
645 -- Always_True --
646 -----------------
648 function Always_True return Boolean is
649 begin
650 return True;
651 end Always_True;
653 -------------------
654 -- Apply_Filters --
655 -------------------
657 function Apply_Filters
658 (Session : Session_Type := Current_Session)
659 return Boolean
661 Filters : Pattern_Action_Table.Instance renames Session.Data.Filters;
662 Results : Boolean := False;
664 begin
665 -- Iterate through the filters table, if pattern match call action.
667 for F in 1 .. Pattern_Action_Table.Last (Filters) loop
668 if Patterns.Match (Filters.Table (F).Pattern.all, Session) then
669 Results := True;
670 Actions.Call (Filters.Table (F).Action.all, Session);
671 end if;
672 end loop;
674 return Results;
675 end Apply_Filters;
677 -----------
678 -- Close --
679 -----------
681 procedure Close (Session : Session_Type) is
682 Filters : Pattern_Action_Table.Instance renames Session.Data.Filters;
683 Files : File_Table.Instance renames Session.Data.Files;
685 begin
686 -- Close current file if needed
688 if Text_IO.Is_Open (Session.Data.Current_File) then
689 Text_IO.Close (Session.Data.Current_File);
690 end if;
692 -- Release separators
694 Free (Session.Data.Separators);
696 -- Release Filters table
698 for F in 1 .. Pattern_Action_Table.Last (Filters) loop
699 Patterns.Release (Filters.Table (F).Pattern.all);
700 Free (Filters.Table (F).Pattern);
701 Free (Filters.Table (F).Action);
702 end loop;
704 for F in 1 .. File_Table.Last (Files) loop
705 Free (Files.Table (F));
706 end loop;
708 File_Table.Set_Last (Session.Data.Files, 0);
709 Field_Table.Set_Last (Session.Data.Fields, 0);
710 Pattern_Action_Table.Set_Last (Session.Data.Filters, 0);
712 Session.Data.NR := 0;
713 Session.Data.FNR := 0;
714 Session.Data.File_Index := 0;
715 Session.Data.Current_Line := Null_Unbounded_String;
716 end Close;
718 ---------------------
719 -- Current_Session --
720 ---------------------
722 function Current_Session return Session_Type is
723 begin
724 return Cur_Session;
725 end Current_Session;
727 ---------------------
728 -- Default_Session --
729 ---------------------
731 function Default_Session return Session_Type is
732 begin
733 return Def_Session;
734 end Default_Session;
736 --------------------
737 -- Discrete_Field --
738 --------------------
740 function Discrete_Field
741 (Rank : Count;
742 Session : Session_Type := Current_Session)
743 return Discrete
745 begin
746 return Discrete'Value (Field (Rank, Session));
747 end Discrete_Field;
749 -----------------
750 -- End_Of_Data --
751 -----------------
753 function End_Of_Data
754 (Session : Session_Type := Current_Session)
755 return Boolean
757 begin
758 return Session.Data.File_Index = File_Table.Last (Session.Data.Files)
759 and then End_Of_File (Session);
760 end End_Of_Data;
762 -----------------
763 -- End_Of_File --
764 -----------------
766 function End_Of_File
767 (Session : Session_Type := Current_Session)
768 return Boolean
770 begin
771 return Text_IO.End_Of_File (Session.Data.Current_File);
772 end End_Of_File;
774 -----------
775 -- Field --
776 -----------
778 function Field
779 (Rank : Count;
780 Session : Session_Type := Current_Session)
781 return String
783 Fields : Field_Table.Instance renames Session.Data.Fields;
785 begin
786 if Rank > Number_Of_Fields (Session) then
787 Raise_With_Info
788 (Field_Error'Identity,
789 "Field number" & Count'Image (Rank) & " does not exist.",
790 Session);
792 elsif Rank = 0 then
794 -- Returns the whole line, this is what $0 does under Session_Type.
796 return To_String (Session.Data.Current_Line);
798 else
799 return Slice (Session.Data.Current_Line,
800 Fields.Table (Positive (Rank)).First,
801 Fields.Table (Positive (Rank)).Last);
802 end if;
803 end Field;
805 function Field
806 (Rank : Count;
807 Session : Session_Type := Current_Session)
808 return Integer
810 begin
811 return Integer'Value (Field (Rank, Session));
813 exception
814 when Constraint_Error =>
815 Raise_With_Info
816 (Field_Error'Identity,
817 "Field number" & Count'Image (Rank)
818 & " cannot be converted to an integer.",
819 Session);
820 end Field;
822 function Field
823 (Rank : Count;
824 Session : Session_Type := Current_Session)
825 return Float
827 begin
828 return Float'Value (Field (Rank, Session));
830 exception
831 when Constraint_Error =>
832 Raise_With_Info
833 (Field_Error'Identity,
834 "Field number" & Count'Image (Rank)
835 & " cannot be converted to a float.",
836 Session);
837 end Field;
839 ----------
840 -- File --
841 ----------
843 function File
844 (Session : Session_Type := Current_Session)
845 return String
847 Files : File_Table.Instance renames Session.Data.Files;
849 begin
850 if Session.Data.File_Index = 0 then
851 return "??";
852 else
853 return Files.Table (Session.Data.File_Index).all;
854 end if;
855 end File;
857 --------------------
858 -- For_Every_Line --
859 --------------------
861 procedure For_Every_Line
862 (Separators : String := Use_Current;
863 Filename : String := Use_Current;
864 Callbacks : Callback_Mode := None;
865 Session : Session_Type := Current_Session)
867 Filter_Active : Boolean;
868 Quit : Boolean;
870 begin
871 Open (Separators, Filename, Session);
873 while not End_Of_Data (Session) loop
874 Read_Line (Session);
875 Split_Line (Session);
877 if Callbacks in Only .. Pass_Through then
878 Filter_Active := Apply_Filters (Session);
879 end if;
881 if Callbacks /= Only then
882 Quit := False;
883 Action (Quit);
884 exit when Quit;
885 end if;
886 end loop;
888 Close (Session);
889 end For_Every_Line;
891 --------------
892 -- Get_Line --
893 --------------
895 procedure Get_Line
896 (Callbacks : Callback_Mode := None;
897 Session : Session_Type := Current_Session)
899 Filter_Active : Boolean;
901 begin
902 if not Text_IO.Is_Open (Session.Data.Current_File) then
903 raise File_Error;
904 end if;
906 loop
907 Read_Line (Session);
908 Split_Line (Session);
910 if Callbacks in Only .. Pass_Through then
911 Filter_Active := Apply_Filters (Session);
912 end if;
914 exit when Callbacks = None
915 or else Callbacks = Pass_Through
916 or else (Callbacks = Only and then not Filter_Active);
918 end loop;
919 end Get_Line;
921 ----------------------
922 -- Number_Of_Fields --
923 ----------------------
925 function Number_Of_Fields
926 (Session : Session_Type := Current_Session)
927 return Count
929 begin
930 return Count (Field_Table.Last (Session.Data.Fields));
931 end Number_Of_Fields;
933 --------------------------
934 -- Number_Of_File_Lines --
935 --------------------------
937 function Number_Of_File_Lines
938 (Session : Session_Type := Current_Session)
939 return Count
941 begin
942 return Count (Session.Data.FNR);
943 end Number_Of_File_Lines;
945 ---------------------
946 -- Number_Of_Files --
947 ---------------------
949 function Number_Of_Files
950 (Session : Session_Type := Current_Session)
951 return Natural
953 Files : File_Table.Instance renames Session.Data.Files;
955 begin
956 return File_Table.Last (Files);
957 end Number_Of_Files;
959 ---------------------
960 -- Number_Of_Lines --
961 ---------------------
963 function Number_Of_Lines
964 (Session : Session_Type := Current_Session)
965 return Count
967 begin
968 return Count (Session.Data.NR);
969 end Number_Of_Lines;
971 ----------
972 -- Open --
973 ----------
975 procedure Open
976 (Separators : String := Use_Current;
977 Filename : String := Use_Current;
978 Session : Session_Type := Current_Session)
980 begin
981 if Text_IO.Is_Open (Session.Data.Current_File) then
982 raise Session_Error;
983 end if;
985 if Filename /= Use_Current then
986 File_Table.Init (Session.Data.Files);
987 Add_File (Filename, Session);
988 end if;
990 if Separators /= Use_Current then
991 Set_Field_Separators (Separators, Session);
992 end if;
994 Open_Next_File (Session);
996 exception
997 when End_Error =>
998 raise File_Error;
999 end Open;
1001 --------------------
1002 -- Open_Next_File --
1003 --------------------
1005 procedure Open_Next_File
1006 (Session : Session_Type := Current_Session)
1008 Files : File_Table.Instance renames Session.Data.Files;
1010 begin
1011 if Text_IO.Is_Open (Session.Data.Current_File) then
1012 Text_IO.Close (Session.Data.Current_File);
1013 end if;
1015 Session.Data.File_Index := Session.Data.File_Index + 1;
1017 -- If there are no mores file in the table, raise End_Error
1019 if Session.Data.File_Index > File_Table.Last (Files) then
1020 raise End_Error;
1021 end if;
1023 Text_IO.Open
1024 (File => Session.Data.Current_File,
1025 Name => Files.Table (Session.Data.File_Index).all,
1026 Mode => Text_IO.In_File);
1027 end Open_Next_File;
1029 -----------
1030 -- Parse --
1031 -----------
1033 procedure Parse
1034 (Separators : String := Use_Current;
1035 Filename : String := Use_Current;
1036 Session : Session_Type := Current_Session)
1038 Filter_Active : Boolean;
1039 begin
1040 Open (Separators, Filename, Session);
1042 while not End_Of_Data (Session) loop
1043 Get_Line (None, Session);
1044 Filter_Active := Apply_Filters (Session);
1045 end loop;
1047 Close (Session);
1048 end Parse;
1050 ---------------------
1051 -- Raise_With_Info --
1052 ---------------------
1054 procedure Raise_With_Info
1055 (E : Exceptions.Exception_Id;
1056 Message : String;
1057 Session : Session_Type)
1059 function Filename return String;
1060 -- Returns current filename and "??" if the informations is not
1061 -- available.
1063 function Line return String;
1064 -- Returns current line number without the leading space
1066 --------------
1067 -- Filename --
1068 --------------
1070 function Filename return String is
1071 File : constant String := AWK.File (Session);
1073 begin
1074 if File = "" then
1075 return "??";
1076 else
1077 return File;
1078 end if;
1079 end Filename;
1081 ----------
1082 -- Line --
1083 ----------
1085 function Line return String is
1086 L : constant String := Natural'Image (Session.Data.FNR);
1088 begin
1089 return L (2 .. L'Last);
1090 end Line;
1092 -- Start of processing for Raise_With_Info
1094 begin
1095 Exceptions.Raise_Exception
1097 '[' & Filename & ':' & Line & "] " & Message);
1098 raise Constraint_Error; -- to please GNAT as this is a No_Return proc
1099 end Raise_With_Info;
1101 ---------------
1102 -- Read_Line --
1103 ---------------
1105 procedure Read_Line (Session : Session_Type) is
1107 function Read_Line return String;
1108 -- Read a line in the current file. This implementation is recursive
1109 -- and does not have a limitation on the line length.
1111 NR : Natural renames Session.Data.NR;
1112 FNR : Natural renames Session.Data.FNR;
1114 function Read_Line return String is
1115 Buffer : String (1 .. 1_024);
1116 Last : Natural;
1118 begin
1119 Text_IO.Get_Line (Session.Data.Current_File, Buffer, Last);
1121 if Last = Buffer'Last then
1122 return Buffer & Read_Line;
1123 else
1124 return Buffer (1 .. Last);
1125 end if;
1126 end Read_Line;
1128 -- Start of processing for Read_Line
1130 begin
1131 if End_Of_File (Session) then
1132 Open_Next_File (Session);
1133 FNR := 0;
1134 end if;
1136 Session.Data.Current_Line := To_Unbounded_String (Read_Line);
1138 NR := NR + 1;
1139 FNR := FNR + 1;
1140 end Read_Line;
1142 --------------
1143 -- Register --
1144 --------------
1146 procedure Register
1147 (Field : Count;
1148 Pattern : String;
1149 Action : Action_Callback;
1150 Session : Session_Type := Current_Session)
1152 Filters : Pattern_Action_Table.Instance renames Session.Data.Filters;
1153 U_Pattern : constant Unbounded_String := To_Unbounded_String (Pattern);
1155 begin
1156 Pattern_Action_Table.Increment_Last (Filters);
1158 Filters.Table (Pattern_Action_Table.Last (Filters)) :=
1159 (Pattern => new Patterns.String_Pattern'(U_Pattern, Field),
1160 Action => new Actions.Simple_Action'(Proc => Action));
1161 end Register;
1163 procedure Register
1164 (Field : Count;
1165 Pattern : GNAT.Regpat.Pattern_Matcher;
1166 Action : Action_Callback;
1167 Session : Session_Type := Current_Session)
1169 Filters : Pattern_Action_Table.Instance renames Session.Data.Filters;
1171 A_Pattern : Patterns.Pattern_Matcher_Access :=
1172 new Regpat.Pattern_Matcher'(Pattern);
1173 begin
1174 Pattern_Action_Table.Increment_Last (Filters);
1176 Filters.Table (Pattern_Action_Table.Last (Filters)) :=
1177 (Pattern => new Patterns.Regexp_Pattern'(A_Pattern, Field),
1178 Action => new Actions.Simple_Action'(Proc => Action));
1179 end Register;
1181 procedure Register
1182 (Field : Count;
1183 Pattern : GNAT.Regpat.Pattern_Matcher;
1184 Action : Match_Action_Callback;
1185 Session : Session_Type := Current_Session)
1187 Filters : Pattern_Action_Table.Instance renames Session.Data.Filters;
1189 A_Pattern : Patterns.Pattern_Matcher_Access :=
1190 new Regpat.Pattern_Matcher'(Pattern);
1191 begin
1192 Pattern_Action_Table.Increment_Last (Filters);
1194 Filters.Table (Pattern_Action_Table.Last (Filters)) :=
1195 (Pattern => new Patterns.Regexp_Pattern'(A_Pattern, Field),
1196 Action => new Actions.Match_Action'(Proc => Action));
1197 end Register;
1199 procedure Register
1200 (Pattern : Pattern_Callback;
1201 Action : Action_Callback;
1202 Session : Session_Type := Current_Session)
1204 Filters : Pattern_Action_Table.Instance renames Session.Data.Filters;
1206 begin
1207 Pattern_Action_Table.Increment_Last (Filters);
1209 Filters.Table (Pattern_Action_Table.Last (Filters)) :=
1210 (Pattern => new Patterns.Callback_Pattern'(Pattern => Pattern),
1211 Action => new Actions.Simple_Action'(Proc => Action));
1212 end Register;
1214 procedure Register
1215 (Action : Action_Callback;
1216 Session : Session_Type := Current_Session)
1218 begin
1219 Register (Always_True'Access, Action, Session);
1220 end Register;
1222 -----------------
1223 -- Set_Current --
1224 -----------------
1226 procedure Set_Current (Session : Session_Type) is
1227 begin
1228 Cur_Session.Data := Session.Data;
1229 end Set_Current;
1231 --------------------------
1232 -- Set_Field_Separators --
1233 --------------------------
1235 procedure Set_Field_Separators
1236 (Separators : String := Default_Separators;
1237 Session : Session_Type := Current_Session)
1239 begin
1240 Free (Session.Data.Separators);
1242 Session.Data.Separators :=
1243 new Split.Separator'(Separators'Length, Separators);
1245 -- If there is a current line read, split it according to the new
1246 -- separators.
1248 if Session.Data.Current_Line /= Null_Unbounded_String then
1249 Split_Line (Session);
1250 end if;
1251 end Set_Field_Separators;
1253 ----------------------
1254 -- Set_Field_Widths --
1255 ----------------------
1257 procedure Set_Field_Widths
1258 (Field_Widths : Widths_Set;
1259 Session : Session_Type := Current_Session) is
1261 begin
1262 Free (Session.Data.Separators);
1264 Session.Data.Separators :=
1265 new Split.Column'(Field_Widths'Length, Field_Widths);
1267 -- If there is a current line read, split it according to
1268 -- the new separators.
1270 if Session.Data.Current_Line /= Null_Unbounded_String then
1271 Split_Line (Session);
1272 end if;
1273 end Set_Field_Widths;
1275 ----------------
1276 -- Split_Line --
1277 ----------------
1279 procedure Split_Line (Session : Session_Type) is
1280 Fields : Field_Table.Instance renames Session.Data.Fields;
1282 begin
1283 Field_Table.Init (Fields);
1285 Split.Current_Line (Session.Data.Separators.all, Session);
1286 end Split_Line;
1288 begin
1289 -- We have declared two sessions but both should share the same data.
1290 -- The current session must point to the default session as its initial
1291 -- value. So first we release the session data then we set current
1292 -- session data to point to default session data.
1294 Free (Cur_Session.Data);
1295 Cur_Session.Data := Def_Session.Data;
1296 end GNAT.AWK;