OSDN Git Service

* gcc-interface/decl.c (gnat_to_gnu_entity) <E_Class_Wide_Type>: Fix
[pf3gnuchains/gcc-fork.git] / gcc / ada / a-clrefi.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT RUN-TIME COMPONENTS                         --
4 --                                                                          --
5 --       A D A . C O M M A N D _ L I N E . R E S P O N S E _ F I L E        --
6 --                                                                          --
7 --                                 B o d y                                  --
8 --                                                                          --
9 --          Copyright (C) 2007-2009, Free Software Foundation, Inc.         --
10 --                                                                          --
11 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
12 -- terms of the  GNU General Public License as published  by the Free Soft- --
13 -- ware  Foundation;  either version 3,  or (at your option) any later ver- --
14 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE.                                     --
17 --                                                                          --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception,   --
20 -- version 3.1, as published by the Free Software Foundation.               --
21 --                                                                          --
22 -- You should have received a copy of the GNU General Public License and    --
23 -- a copy of the GCC Runtime Library Exception along with this program;     --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
25 -- <http://www.gnu.org/licenses/>.                                          --
26 --                                                                          --
27 -- GNAT was originally developed  by the GNAT team at  New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
29 --                                                                          --
30 ------------------------------------------------------------------------------
31
32 pragma Compiler_Unit;
33
34 with Ada.Unchecked_Deallocation;
35
36 with System.OS_Lib; use System.OS_Lib;
37
38 package body Ada.Command_Line.Response_File is
39
40    type File_Rec;
41    type File_Ptr is access File_Rec;
42    type File_Rec is record
43       Name : String_Access;
44       Next : File_Ptr;
45       Prev : File_Ptr;
46    end record;
47    --  To build a stack of response file names
48
49    procedure Free is new Ada.Unchecked_Deallocation (File_Rec, File_Ptr);
50
51    type Argument_List_Access is access Argument_List;
52    procedure Free is new Ada.Unchecked_Deallocation
53      (Argument_List, Argument_List_Access);
54    --  Free only the allocated Argument_List, not allocated String components
55
56    --------------------
57    -- Arguments_From --
58    --------------------
59
60    function Arguments_From
61      (Response_File_Name        : String;
62       Recursive                 : Boolean := False;
63       Ignore_Non_Existing_Files : Boolean := False)
64       return Argument_List
65    is
66       First_File : File_Ptr := null;
67       Last_File  : File_Ptr := null;
68       --  The stack of response files
69
70       Arguments  : Argument_List_Access := new Argument_List (1 .. 4);
71       Last_Arg   : Natural := 0;
72
73       procedure Add_Argument (Arg : String);
74       --  Add argument Arg to argument list Arguments, increasing Arguments
75       --  if necessary.
76
77       procedure Recurse (File_Name : String);
78       --  Get the arguments from the file and call itself recursively if one of
79       --  the argument starts with character '@'.
80
81       ------------------
82       -- Add_Argument --
83       ------------------
84
85       procedure Add_Argument (Arg : String) is
86       begin
87          if Last_Arg = Arguments'Last then
88             declare
89                New_Arguments : constant Argument_List_Access :=
90                                  new Argument_List (1 .. Arguments'Last * 2);
91             begin
92                New_Arguments (Arguments'Range) := Arguments.all;
93                Arguments.all := (others => null);
94                Free (Arguments);
95                Arguments := New_Arguments;
96             end;
97          end if;
98
99          Last_Arg := Last_Arg + 1;
100          Arguments (Last_Arg) := new String'(Arg);
101       end Add_Argument;
102
103       -------------
104       -- Recurse --
105       -------------
106
107       procedure Recurse (File_Name : String) is
108          FD : File_Descriptor;
109
110          Buffer_Size : constant := 1500;
111          Buffer : String (1 .. Buffer_Size);
112
113          Buffer_Length : Natural;
114
115          Buffer_Cursor : Natural;
116
117          End_Of_File_Reached : Boolean;
118
119          Line : String (1 .. Max_Line_Length + 1);
120          Last : Natural;
121
122          First_Char : Positive;
123          --  Index of the first character of an argument in Line
124
125          Last_Char : Natural;
126          --  Index of the last character of an argument in Line
127
128          In_String : Boolean;
129          --  True when inside a quoted string
130
131          Arg : Positive;
132
133          function End_Of_File return Boolean;
134          --  True when the end of the response file has been reached
135
136          procedure Get_Buffer;
137          --  Read one buffer from the response file
138
139          procedure Get_Line;
140          --  Get one line from the response file
141
142          -----------------
143          -- End_Of_File --
144          -----------------
145
146          function End_Of_File return Boolean is
147          begin
148             return End_Of_File_Reached and then Buffer_Cursor > Buffer_Length;
149          end End_Of_File;
150
151          ----------------
152          -- Get_Buffer --
153          ----------------
154
155          procedure Get_Buffer is
156          begin
157             Buffer_Length := Read (FD, Buffer (1)'Address, Buffer'Length);
158             End_Of_File_Reached := Buffer_Length < Buffer'Length;
159             Buffer_Cursor := 1;
160          end Get_Buffer;
161
162          --------------
163          -- Get_Line --
164          --------------
165
166          procedure Get_Line is
167             Ch : Character;
168
169          begin
170             Last := 0;
171
172             if End_Of_File then
173                return;
174             end if;
175
176             loop
177                Ch := Buffer (Buffer_Cursor);
178
179                exit when Ch = ASCII.CR or else
180                          Ch = ASCII.LF or else
181                          Ch = ASCII.FF;
182
183                Last := Last + 1;
184                Line (Last) := Ch;
185
186                if Last = Line'Last then
187                   return;
188                end if;
189
190                Buffer_Cursor := Buffer_Cursor + 1;
191
192                if Buffer_Cursor > Buffer_Length then
193                   Get_Buffer;
194
195                   if End_Of_File then
196                      return;
197                   end if;
198                end if;
199             end loop;
200
201             loop
202                Ch := Buffer (Buffer_Cursor);
203
204                exit when Ch /= ASCII.HT and then
205                          Ch /= ASCII.LF and then
206                          Ch /= ASCII.FF;
207
208                Buffer_Cursor := Buffer_Cursor + 1;
209
210                if Buffer_Cursor > Buffer_Length then
211                   Get_Buffer;
212
213                   if End_Of_File then
214                      return;
215                   end if;
216                end if;
217             end loop;
218          end Get_Line;
219
220       --  Start or Recurse
221
222       begin
223          Last_Arg := 0;
224
225          --  Open the response file. If not found, fail or report a warning,
226          --  depending on the value of Ignore_Non_Existing_Files.
227
228          FD := Open_Read (File_Name, Text);
229
230          if FD = Invalid_FD then
231             if Ignore_Non_Existing_Files then
232                return;
233             else
234                raise File_Does_Not_Exist;
235             end if;
236          end if;
237
238          --  Put the response file name on the stack
239
240          if First_File = null then
241             First_File :=
242               new File_Rec'
243                 (Name => new String'(File_Name),
244                  Next => null,
245                  Prev => null);
246             Last_File  := First_File;
247
248          else
249             declare
250                Current : File_Ptr := First_File;
251
252             begin
253                loop
254                   if Current.Name.all = File_Name then
255                      raise Circularity_Detected;
256                   end if;
257
258                   Current := Current.Next;
259                   exit when Current = null;
260                end loop;
261
262                Last_File.Next :=
263                  new File_Rec'
264                    (Name => new String'(File_Name),
265                     Next => null,
266                     Prev => Last_File);
267                Last_File := Last_File.Next;
268             end;
269          end if;
270
271          End_Of_File_Reached := False;
272          Get_Buffer;
273
274          --  Read the response file line by line
275
276          Line_Loop :
277          while not End_Of_File loop
278             Get_Line;
279
280             if Last = Line'Last then
281                raise Line_Too_Long;
282             end if;
283
284             First_Char := 1;
285
286             --  Get each argument on the line
287
288             Arg_Loop :
289             loop
290                --  First, skip any white space
291
292                while First_Char <= Last loop
293                   exit when Line (First_Char) /= ' ' and then
294                             Line (First_Char) /= ASCII.HT;
295                   First_Char := First_Char + 1;
296                end loop;
297
298                exit Arg_Loop when First_Char > Last;
299
300                Last_Char := First_Char;
301                In_String := False;
302
303                --  Get the character one by one
304
305                Character_Loop :
306                while Last_Char <= Last loop
307
308                   --  Inside a string, check only for '"'
309
310                   if In_String then
311                      if Line (Last_Char) = '"' then
312
313                         --  Remove the '"'
314
315                         Line (Last_Char .. Last - 1) :=
316                           Line (Last_Char + 1 .. Last);
317                         Last := Last - 1;
318
319                         --  End of string is end of argument
320
321                         if Last_Char > Last or else
322                           Line (Last_Char) = ' ' or else
323                           Line (Last_Char) = ASCII.HT
324                         then
325                            In_String := False;
326
327                            Last_Char := Last_Char - 1;
328                            exit Character_Loop;
329
330                         else
331                            --  If there are two consecutive '"', the quoted
332                            --  string is not closed
333
334                            In_String := Line (Last_Char) = '"';
335
336                            if In_String then
337                               Last_Char := Last_Char + 1;
338                            end if;
339                         end if;
340
341                      else
342                         Last_Char := Last_Char + 1;
343                      end if;
344
345                   elsif Last_Char = Last then
346
347                      --  An opening '"' at the end of the line is an error
348
349                      if Line (Last) = '"' then
350                         raise No_Closing_Quote;
351
352                      else
353                         --  The argument ends with the line
354
355                         exit Character_Loop;
356                      end if;
357
358                   elsif Line (Last_Char) = '"' then
359
360                      --  Entering a quoted string: remove the '"'
361
362                      In_String := True;
363                      Line (Last_Char .. Last - 1) :=
364                        Line (Last_Char + 1 .. Last);
365                      Last := Last - 1;
366
367                   else
368                      --  Outside quoted strings, white space ends the argument
369
370                      exit Character_Loop
371                           when Line (Last_Char + 1) = ' ' or else
372                                Line (Last_Char + 1) = ASCII.HT;
373
374                      Last_Char := Last_Char + 1;
375                   end if;
376                end loop Character_Loop;
377
378                --  It is an error to not close a quoted string before the end
379                --  of the line.
380
381                if In_String then
382                   raise No_Closing_Quote;
383                end if;
384
385                --  Add the argument to the list
386
387                declare
388                   Arg : String (1 .. Last_Char - First_Char + 1);
389                begin
390                   Arg := Line (First_Char .. Last_Char);
391                   Add_Argument (Arg);
392                end;
393
394                --  Next argument, if line is not finished
395
396                First_Char := Last_Char + 1;
397             end loop Arg_Loop;
398          end loop Line_Loop;
399
400          Close (FD);
401
402          --  If Recursive is True, check for any argument starting with '@'
403
404          if Recursive then
405             Arg := 1;
406             while Arg <= Last_Arg loop
407
408                if Arguments (Arg)'Length > 0 and then
409                   Arguments (Arg) (1) = '@'
410                then
411                   --  Ignore argument "@" with no file name
412
413                   if Arguments (Arg)'Length = 1 then
414                      Arguments (Arg .. Last_Arg - 1) :=
415                        Arguments (Arg + 1 .. Last_Arg);
416                      Last_Arg := Last_Arg - 1;
417
418                   else
419                      --  Save the current arguments and get those in the new
420                      --  response file.
421
422                      declare
423                         Inc_File_Name     : constant String :=
424                                               Arguments (Arg)
425                                               (2 .. Arguments (Arg)'Last);
426                         Current_Arguments : constant Argument_List :=
427                                               Arguments (1 .. Last_Arg);
428                      begin
429                         Recurse (Inc_File_Name);
430
431                         --  Insert the new arguments where the new response
432                         --  file was imported.
433
434                         declare
435                            New_Arguments : constant Argument_List :=
436                                              Arguments (1 .. Last_Arg);
437                            New_Last_Arg  : constant Positive :=
438                                              Current_Arguments'Length +
439                                              New_Arguments'Length - 1;
440
441                         begin
442                            --  Grow Arguments if it is not large enough
443
444                            if Arguments'Last < New_Last_Arg then
445                               Last_Arg := Arguments'Last;
446                               Free (Arguments);
447
448                               while Last_Arg < New_Last_Arg loop
449                                  Last_Arg := Last_Arg * 2;
450                               end loop;
451
452                               Arguments := new Argument_List (1 .. Last_Arg);
453                            end if;
454
455                            Last_Arg := New_Last_Arg;
456
457                            Arguments (1 .. Last_Arg) :=
458                              Current_Arguments (1 .. Arg - 1) &
459                            New_Arguments &
460                            Current_Arguments
461                              (Arg + 1 .. Current_Arguments'Last);
462
463                            Arg := Arg + New_Arguments'Length;
464                         end;
465                      end;
466                   end if;
467
468                else
469                   Arg := Arg + 1;
470                end if;
471             end loop;
472          end if;
473
474          --  Remove the response file name from the stack
475
476          if First_File = Last_File then
477             System.Strings.Free (First_File.Name);
478             Free (First_File);
479             First_File := null;
480             Last_File := null;
481
482          else
483             System.Strings.Free (Last_File.Name);
484             Last_File := Last_File.Prev;
485             Free (Last_File.Next);
486          end if;
487
488       exception
489          when others =>
490             Close (FD);
491
492             raise;
493       end Recurse;
494
495    --  Start of Arguments_From
496
497    begin
498       --  The job is done by procedure Recurse
499
500       Recurse (Response_File_Name);
501
502       --  Free Arguments before returning the result
503
504       declare
505          Result : constant Argument_List := Arguments (1 .. Last_Arg);
506       begin
507          Free (Arguments);
508          return Result;
509       end;
510
511    exception
512       when others =>
513
514          --  When an exception occurs, deallocate everything
515
516          Free (Arguments);
517
518          while First_File /= null loop
519             Last_File := First_File.Next;
520             System.Strings.Free (First_File.Name);
521             Free (First_File);
522             First_File := Last_File;
523          end loop;
524
525          raise;
526    end Arguments_From;
527
528 end Ada.Command_Line.Response_File;