2003-12-26 Guilhem Lavaux <guilhem@kaffe.org>
[official-gcc.git] / gcc / ada / prj-util.adb
blobe11200026f8e3ec1f6fbd909be026e985e7535c4
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- P R J . U T I L --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2001-2003 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 2, 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. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING. If not, write --
19 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
20 -- MA 02111-1307, USA. --
21 -- --
22 -- GNAT was originally developed by the GNAT team at New York University. --
23 -- Extensive contributions were provided by Ada Core Technologies Inc. --
24 -- --
25 ------------------------------------------------------------------------------
27 with Ada.Unchecked_Deallocation;
29 with GNAT.Case_Util; use GNAT.Case_Util;
31 with Namet; use Namet;
32 with Osint; use Osint;
33 with Output; use Output;
34 with Prj.Com;
35 with Snames; use Snames;
37 package body Prj.Util is
39 procedure Free is new Ada.Unchecked_Deallocation
40 (Text_File_Data, Text_File);
42 -----------
43 -- Close --
44 -----------
46 procedure Close (File : in out Text_File) is
47 begin
48 if File = null then
49 Prj.Com.Fail ("Close attempted on an invalid Text_File");
50 end if;
52 -- Close file, no need to test status, since this is a file that we
53 -- read, and the file was read successfully before we closed it.
55 Close (File.FD);
56 Free (File);
57 end Close;
59 -----------------
60 -- End_Of_File --
61 -----------------
63 function End_Of_File (File : Text_File) return Boolean is
64 begin
65 if File = null then
66 Prj.Com.Fail ("End_Of_File attempted on an invalid Text_File");
67 end if;
69 return File.End_Of_File_Reached;
70 end End_Of_File;
72 -------------------
73 -- Executable_Of --
74 -------------------
76 function Executable_Of
77 (Project : Project_Id; Main : Name_Id) return Name_Id
79 pragma Assert (Project /= No_Project);
81 The_Packages : constant Package_Id :=
82 Projects.Table (Project).Decl.Packages;
84 Builder_Package : constant Prj.Package_Id :=
85 Prj.Util.Value_Of
86 (Name => Name_Builder,
87 In_Packages => The_Packages);
89 Executable : Variable_Value :=
90 Prj.Util.Value_Of
91 (Name => Main,
92 Attribute_Or_Array_Name => Name_Executable,
93 In_Package => Builder_Package);
95 Executable_Suffix : Variable_Value :=
96 Prj.Util.Value_Of
97 (Name => Main,
98 Attribute_Or_Array_Name =>
99 Name_Executable_Suffix,
100 In_Package => Builder_Package);
102 Body_Append : constant String := Get_Name_String
103 (Projects.Table
104 (Project).
105 Naming.Current_Body_Suffix);
107 Spec_Append : constant String := Get_Name_String
108 (Projects.Table
109 (Project).
110 Naming.Current_Spec_Suffix);
112 begin
113 if Builder_Package /= No_Package then
114 if Executable = Nil_Variable_Value then
115 Get_Name_String (Main);
117 -- Try as index the name minus the implementation suffix or minus
118 -- the specification suffix.
120 declare
121 Name : String (1 .. Name_Len) := Name_Buffer (1 .. Name_Len);
122 Last : Positive := Name_Len;
124 Naming : constant Naming_Data :=
125 Projects.Table (Project).Naming;
127 Spec_Suffix : constant String :=
128 Get_Name_String (Naming.Current_Spec_Suffix);
129 Body_Suffix : constant String :=
130 Get_Name_String (Naming.Current_Body_Suffix);
132 Truncated : Boolean := False;
134 begin
135 if Last > Body_Suffix'Length
136 and then Name (Last - Body_Suffix'Length + 1 .. Last) =
137 Body_Suffix
138 then
139 Truncated := True;
140 Last := Last - Body_Suffix'Length;
141 end if;
143 if not Truncated
144 and then Last > Spec_Suffix'Length
145 and then Name (Last - Spec_Suffix'Length + 1 .. Last) =
146 Spec_Suffix
147 then
148 Truncated := True;
149 Last := Last - Spec_Suffix'Length;
150 end if;
152 if Truncated then
153 Name_Len := Last;
154 Name_Buffer (1 .. Name_Len) := Name (1 .. Last);
155 Executable :=
156 Prj.Util.Value_Of
157 (Name => Name_Find,
158 Attribute_Or_Array_Name => Name_Executable,
159 In_Package => Builder_Package);
160 end if;
161 end;
162 end if;
164 -- If we have found an Executable attribute, return its value,
165 -- possibly suffixed by the executable suffix.
167 if Executable /= Nil_Variable_Value
168 and then Executable.Value /= Empty_Name
169 then
170 declare
171 Exec_Suffix : String_Access := Get_Executable_Suffix;
172 Result : Name_Id := Executable.Value;
174 begin
175 if Exec_Suffix'Length /= 0 then
176 Get_Name_String (Executable.Value);
177 Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
179 -- If the Executable does not end with the executable
180 -- suffix, add it.
182 if Name_Len <= Exec_Suffix'Length
183 or else
184 Name_Buffer
185 (Name_Len - Exec_Suffix'Length + 1 .. Name_Len) /=
186 Exec_Suffix.all
187 then
188 -- Get the original Executable to keep the correct
189 -- case for systems where file names are case
190 -- insensitive (Windows).
192 Get_Name_String (Executable.Value);
193 Name_Buffer
194 (Name_Len + 1 .. Name_Len + Exec_Suffix'Length) :=
195 Exec_Suffix.all;
196 Name_Len := Name_Len + Exec_Suffix'Length;
197 Result := Name_Find;
198 end if;
200 Free (Exec_Suffix);
201 end if;
203 return Result;
204 end;
205 end if;
206 end if;
208 Get_Name_String (Main);
210 -- If there is a body suffix or a spec suffix, remove this suffix,
211 -- otherwise remove any suffix ('.' followed by other characters), if
212 -- there is one.
214 if Name_Len > Body_Append'Length
215 and then Name_Buffer (Name_Len - Body_Append'Length + 1 .. Name_Len) =
216 Body_Append
217 then
218 -- Found the body termination, remove it
220 Name_Len := Name_Len - Body_Append'Length;
222 elsif Name_Len > Spec_Append'Length
223 and then Name_Buffer (Name_Len - Spec_Append'Length + 1 .. Name_Len) =
224 Spec_Append
225 then
226 -- Found the spec termination, remove it
228 Name_Len := Name_Len - Spec_Append'Length;
230 else
231 -- Remove any suffix, if there is one
233 Get_Name_String (Strip_Suffix (Main));
234 end if;
236 if Executable_Suffix /= Nil_Variable_Value
237 and then not Executable_Suffix.Default
238 then
239 -- If attribute Executable_Suffix is specified, add this suffix
241 declare
242 Suffix : constant String :=
243 Get_Name_String (Executable_Suffix.Value);
244 begin
245 Name_Buffer (Name_Len + 1 .. Name_Len + Suffix'Length) := Suffix;
246 Name_Len := Name_Len + Suffix'Length;
247 return Name_Find;
248 end;
250 else
251 -- Otherwise, add the standard suffix for the platform, if any
253 return Executable_Name (Name_Find);
254 end if;
255 end Executable_Of;
257 --------------
258 -- Get_Line --
259 --------------
261 procedure Get_Line
262 (File : Text_File;
263 Line : out String;
264 Last : out Natural)
266 C : Character;
268 procedure Advance;
270 -------------
271 -- Advance --
272 -------------
274 procedure Advance is
275 begin
276 if File.Cursor = File.Buffer_Len then
277 File.Buffer_Len :=
278 Read
279 (FD => File.FD,
280 A => File.Buffer'Address,
281 N => File.Buffer'Length);
283 if File.Buffer_Len = 0 then
284 File.End_Of_File_Reached := True;
285 return;
286 else
287 File.Cursor := 1;
288 end if;
290 else
291 File.Cursor := File.Cursor + 1;
292 end if;
293 end Advance;
295 -- Start of processing for Get_Line
297 begin
298 if File = null then
299 Prj.Com.Fail ("Get_Line attempted on an invalid Text_File");
300 end if;
302 Last := Line'First - 1;
304 if not File.End_Of_File_Reached then
305 loop
306 C := File.Buffer (File.Cursor);
307 exit when C = ASCII.CR or else C = ASCII.LF;
308 Last := Last + 1;
309 Line (Last) := C;
310 Advance;
312 if File.End_Of_File_Reached then
313 return;
314 end if;
316 exit when Last = Line'Last;
317 end loop;
319 if C = ASCII.CR or else C = ASCII.LF then
320 Advance;
322 if File.End_Of_File_Reached then
323 return;
324 end if;
325 end if;
327 if C = ASCII.CR
328 and then File.Buffer (File.Cursor) = ASCII.LF
329 then
330 Advance;
331 end if;
332 end if;
333 end Get_Line;
335 --------------
336 -- Is_Valid --
337 --------------
339 function Is_Valid (File : Text_File) return Boolean is
340 begin
341 return File /= null;
342 end Is_Valid;
344 ----------
345 -- Open --
346 ----------
348 procedure Open (File : out Text_File; Name : in String) is
349 FD : File_Descriptor;
350 File_Name : String (1 .. Name'Length + 1);
352 begin
353 File_Name (1 .. Name'Length) := Name;
354 File_Name (File_Name'Last) := ASCII.NUL;
355 FD := Open_Read (Name => File_Name'Address,
356 Fmode => GNAT.OS_Lib.Text);
357 if FD = Invalid_FD then
358 File := null;
359 else
360 File := new Text_File_Data;
361 File.FD := FD;
362 File.Buffer_Len :=
363 Read (FD => FD,
364 A => File.Buffer'Address,
365 N => File.Buffer'Length);
367 if File.Buffer_Len = 0 then
368 File.End_Of_File_Reached := True;
369 else
370 File.Cursor := 1;
371 end if;
372 end if;
373 end Open;
375 --------------
376 -- Value_Of --
377 --------------
379 function Value_Of
380 (Variable : Variable_Value;
381 Default : String)
382 return String
384 begin
385 if Variable.Kind /= Single
386 or else Variable.Default
387 or else Variable.Value = No_Name
388 then
389 return Default;
390 else
391 return Get_Name_String (Variable.Value);
392 end if;
393 end Value_Of;
395 function Value_Of
396 (Index : Name_Id;
397 In_Array : Array_Element_Id)
398 return Name_Id
400 Current : Array_Element_Id := In_Array;
401 Element : Array_Element;
402 Real_Index : Name_Id := Index;
404 begin
405 if Current = No_Array_Element then
406 return No_Name;
407 end if;
409 Element := Array_Elements.Table (Current);
411 if not Element.Index_Case_Sensitive then
412 Get_Name_String (Index);
413 To_Lower (Name_Buffer (1 .. Name_Len));
414 Real_Index := Name_Find;
415 end if;
417 while Current /= No_Array_Element loop
418 Element := Array_Elements.Table (Current);
420 if Real_Index = Element.Index then
421 exit when Element.Value.Kind /= Single;
422 exit when Element.Value.Value = Empty_String;
423 return Element.Value.Value;
424 else
425 Current := Element.Next;
426 end if;
427 end loop;
429 return No_Name;
430 end Value_Of;
432 function Value_Of
433 (Index : Name_Id;
434 In_Array : Array_Element_Id)
435 return Variable_Value
437 Current : Array_Element_Id := In_Array;
438 Element : Array_Element;
439 Real_Index : Name_Id := Index;
441 begin
442 if Current = No_Array_Element then
443 return Nil_Variable_Value;
444 end if;
446 Element := Array_Elements.Table (Current);
448 if not Element.Index_Case_Sensitive then
449 Get_Name_String (Index);
450 To_Lower (Name_Buffer (1 .. Name_Len));
451 Real_Index := Name_Find;
452 end if;
454 while Current /= No_Array_Element loop
455 Element := Array_Elements.Table (Current);
457 if Real_Index = Element.Index then
458 return Element.Value;
459 else
460 Current := Element.Next;
461 end if;
462 end loop;
464 return Nil_Variable_Value;
465 end Value_Of;
467 function Value_Of
468 (Name : Name_Id;
469 Attribute_Or_Array_Name : Name_Id;
470 In_Package : Package_Id)
471 return Variable_Value
473 The_Array : Array_Element_Id;
474 The_Attribute : Variable_Value := Nil_Variable_Value;
476 begin
477 if In_Package /= No_Package then
479 -- First, look if there is an array element that fits
481 The_Array :=
482 Value_Of
483 (Name => Attribute_Or_Array_Name,
484 In_Arrays => Packages.Table (In_Package).Decl.Arrays);
485 The_Attribute :=
486 Value_Of
487 (Index => Name,
488 In_Array => The_Array);
490 -- If there is no array element, look for a variable
492 if The_Attribute = Nil_Variable_Value then
493 The_Attribute :=
494 Value_Of
495 (Variable_Name => Attribute_Or_Array_Name,
496 In_Variables => Packages.Table (In_Package).Decl.Attributes);
497 end if;
498 end if;
500 return The_Attribute;
501 end Value_Of;
503 function Value_Of
504 (Index : Name_Id;
505 In_Array : Name_Id;
506 In_Arrays : Array_Id)
507 return Name_Id
509 Current : Array_Id := In_Arrays;
510 The_Array : Array_Data;
512 begin
513 while Current /= No_Array loop
514 The_Array := Arrays.Table (Current);
515 if The_Array.Name = In_Array then
516 return Value_Of (Index, In_Array => The_Array.Value);
517 else
518 Current := The_Array.Next;
519 end if;
520 end loop;
522 return No_Name;
523 end Value_Of;
525 function Value_Of
526 (Name : Name_Id;
527 In_Arrays : Array_Id)
528 return Array_Element_Id
530 Current : Array_Id := In_Arrays;
531 The_Array : Array_Data;
533 begin
534 while Current /= No_Array loop
535 The_Array := Arrays.Table (Current);
537 if The_Array.Name = Name then
538 return The_Array.Value;
539 else
540 Current := The_Array.Next;
541 end if;
542 end loop;
544 return No_Array_Element;
545 end Value_Of;
547 function Value_Of
548 (Name : Name_Id;
549 In_Packages : Package_Id)
550 return Package_Id
552 Current : Package_Id := In_Packages;
553 The_Package : Package_Element;
555 begin
556 while Current /= No_Package loop
557 The_Package := Packages.Table (Current);
558 exit when The_Package.Name /= No_Name
559 and then The_Package.Name = Name;
560 Current := The_Package.Next;
561 end loop;
563 return Current;
564 end Value_Of;
566 function Value_Of
567 (Variable_Name : Name_Id;
568 In_Variables : Variable_Id)
569 return Variable_Value
571 Current : Variable_Id := In_Variables;
572 The_Variable : Variable;
574 begin
575 while Current /= No_Variable loop
576 The_Variable := Variable_Elements.Table (Current);
578 if Variable_Name = The_Variable.Name then
579 return The_Variable.Value;
580 else
581 Current := The_Variable.Next;
582 end if;
583 end loop;
585 return Nil_Variable_Value;
586 end Value_Of;
588 ---------------
589 -- Write_Str --
590 ---------------
592 procedure Write_Str
593 (S : String;
594 Max_Length : Positive;
595 Separator : Character)
597 First : Positive := S'First;
598 Last : Natural := S'Last;
600 begin
601 -- Nothing to do for empty strings
603 if S'Length > 0 then
605 -- Start on a new line if current line is already longer than
606 -- Max_Length.
608 if Positive (Column) >= Max_Length then
609 Write_Eol;
610 end if;
612 -- If length of remainder is longer than Max_Length, we need to
613 -- cut the remainder in several lines.
615 while Positive (Column) + S'Last - First > Max_Length loop
617 -- Try the maximum length possible
619 Last := First + Max_Length - Positive (Column);
621 -- Look for last Separator in the line
623 while Last >= First and then S (Last) /= Separator loop
624 Last := Last - 1;
625 end loop;
627 -- If we do not find a separator, we output the maximum length
628 -- possible.
630 if Last < First then
631 Last := First + Max_Length - Positive (Column);
632 end if;
634 Write_Line (S (First .. Last));
636 -- Set the beginning of the new remainder
638 First := Last + 1;
639 end loop;
641 -- What is left goes to the buffer, without EOL
643 Write_Str (S (First .. S'Last));
644 end if;
645 end Write_Str;
646 end Prj.Util;