2014-10-10 Robert Dewar <dewar@adacore.com>
[official-gcc.git] / gcc / ada / gnatname.adb
blob82f32747948b71ca36d2ef93a2f3bcf6dcd6451b
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- G N A T N A M E --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2001-2014, 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. 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 COPYING3. If not, go to --
19 -- http://www.gnu.org/licenses for a complete copy of the license. --
20 -- --
21 -- GNAT was originally developed by the GNAT team at New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc. --
23 -- --
24 ------------------------------------------------------------------------------
26 with Ada.Command_Line; use Ada.Command_Line;
27 with Ada.Text_IO; use Ada.Text_IO;
29 with GNAT.Command_Line; use GNAT.Command_Line;
30 with GNAT.Dynamic_Tables;
31 with GNAT.OS_Lib; use GNAT.OS_Lib;
33 with Opt;
34 with Osint; use Osint;
35 with Output; use Output;
36 with Prj; use Prj;
37 with Prj.Makr;
38 with Switch; use Switch;
39 with Table;
41 with System.Regexp; use System.Regexp;
43 procedure Gnatname is
45 Subdirs_Switch : constant String := "--subdirs=";
47 Usage_Output : Boolean := False;
48 -- Set to True when usage is output, to avoid multiple output
50 Usage_Needed : Boolean := False;
51 -- Set to True by -h switch
53 Version_Output : Boolean := False;
54 -- Set to True when version is output, to avoid multiple output
56 Very_Verbose : Boolean := False;
57 -- Set to True with -v -v
59 Create_Project : Boolean := False;
60 -- Set to True with a -P switch
62 File_Path : String_Access := new String'("gnat.adc");
63 -- Path name of the file specified by -c or -P switch
65 File_Set : Boolean := False;
66 -- Set to True by -c or -P switch.
67 -- Used to detect multiple -c/-P switches.
69 package Patterns is new GNAT.Dynamic_Tables
70 (Table_Component_Type => String_Access,
71 Table_Index_Type => Natural,
72 Table_Low_Bound => 0,
73 Table_Initial => 10,
74 Table_Increment => 100);
75 -- Table to accumulate the patterns
77 type Argument_Data is record
78 Directories : Patterns.Instance;
79 Name_Patterns : Patterns.Instance;
80 Excluded_Patterns : Patterns.Instance;
81 Foreign_Patterns : Patterns.Instance;
82 end record;
84 package Arguments is new Table.Table
85 (Table_Component_Type => Argument_Data,
86 Table_Index_Type => Natural,
87 Table_Low_Bound => 0,
88 Table_Initial => 10,
89 Table_Increment => 100,
90 Table_Name => "Gnatname.Arguments");
91 -- Table to accumulate directories and patterns
93 package Preprocessor_Switches is new Table.Table
94 (Table_Component_Type => String_Access,
95 Table_Index_Type => Natural,
96 Table_Low_Bound => 0,
97 Table_Initial => 10,
98 Table_Increment => 100,
99 Table_Name => "Gnatname.Preprocessor_Switches");
100 -- Table to store the preprocessor switches to be used in the call
101 -- to the compiler.
103 procedure Output_Version;
104 -- Print name and version
106 procedure Usage;
107 -- Print usage
109 procedure Scan_Args;
110 -- Scan the command line arguments
112 procedure Add_Source_Directory (S : String);
113 -- Add S in the Source_Directories table
115 procedure Get_Directories (From_File : String);
116 -- Read a source directory text file
118 --------------------------
119 -- Add_Source_Directory --
120 --------------------------
122 procedure Add_Source_Directory (S : String) is
123 begin
124 Patterns.Append
125 (Arguments.Table (Arguments.Last).Directories, new String'(S));
126 end Add_Source_Directory;
128 ---------------------
129 -- Get_Directories --
130 ---------------------
132 procedure Get_Directories (From_File : String) is
133 File : Ada.Text_IO.File_Type;
134 Line : String (1 .. 2_000);
135 Last : Natural;
137 begin
138 Open (File, In_File, From_File);
140 while not End_Of_File (File) loop
141 Get_Line (File, Line, Last);
143 if Last /= 0 then
144 Add_Source_Directory (Line (1 .. Last));
145 end if;
146 end loop;
148 Close (File);
150 exception
151 when Name_Error =>
152 Fail ("cannot open source directory file """ & From_File & '"');
153 end Get_Directories;
155 --------------------
156 -- Output_Version --
157 --------------------
159 procedure Output_Version is
160 begin
161 if not Version_Output then
162 Version_Output := True;
163 Output.Write_Eol;
164 Display_Version ("GNATNAME", "2001");
165 end if;
166 end Output_Version;
168 ---------------
169 -- Scan_Args --
170 ---------------
172 procedure Scan_Args is
174 procedure Check_Version_And_Help is new Check_Version_And_Help_G (Usage);
176 Project_File_Name_Expected : Boolean;
178 Pragmas_File_Expected : Boolean;
180 Directory_Expected : Boolean;
182 Dir_File_Name_Expected : Boolean;
184 Foreign_Pattern_Expected : Boolean;
186 Excluded_Pattern_Expected : Boolean;
188 procedure Check_Regular_Expression (S : String);
189 -- Compile string S into a Regexp, fail if any error
191 -----------------------------
192 -- Check_Regular_Expression--
193 -----------------------------
195 procedure Check_Regular_Expression (S : String) is
196 Dummy : Regexp;
197 pragma Warnings (Off, Dummy);
198 begin
199 Dummy := Compile (S, Glob => True);
200 exception
201 when Error_In_Regexp =>
202 Fail ("invalid regular expression """ & S & """");
203 end Check_Regular_Expression;
205 -- Start of processing for Scan_Args
207 begin
208 -- First check for --version or --help
210 Check_Version_And_Help ("GNATNAME", "2001");
212 -- Now scan the other switches
214 Project_File_Name_Expected := False;
215 Pragmas_File_Expected := False;
216 Directory_Expected := False;
217 Dir_File_Name_Expected := False;
218 Foreign_Pattern_Expected := False;
219 Excluded_Pattern_Expected := False;
221 for Next_Arg in 1 .. Argument_Count loop
222 declare
223 Next_Argv : constant String := Argument (Next_Arg);
224 Arg : String (1 .. Next_Argv'Length) := Next_Argv;
226 begin
227 if Arg'Length > 0 then
229 -- -P xxx
231 if Project_File_Name_Expected then
232 if Arg (1) = '-' then
233 Fail ("project file name missing");
235 else
236 File_Set := True;
237 File_Path := new String'(Arg);
238 Project_File_Name_Expected := False;
239 end if;
241 -- -c file
243 elsif Pragmas_File_Expected then
244 File_Set := True;
245 File_Path := new String'(Arg);
246 Create_Project := False;
247 Pragmas_File_Expected := False;
249 -- -d xxx
251 elsif Directory_Expected then
252 Add_Source_Directory (Arg);
253 Directory_Expected := False;
255 -- -D xxx
257 elsif Dir_File_Name_Expected then
258 Get_Directories (Arg);
259 Dir_File_Name_Expected := False;
261 -- -f xxx
263 elsif Foreign_Pattern_Expected then
264 Patterns.Append
265 (Arguments.Table (Arguments.Last).Foreign_Patterns,
266 new String'(Arg));
267 Check_Regular_Expression (Arg);
268 Foreign_Pattern_Expected := False;
270 -- -x xxx
272 elsif Excluded_Pattern_Expected then
273 Patterns.Append
274 (Arguments.Table (Arguments.Last).Excluded_Patterns,
275 new String'(Arg));
276 Check_Regular_Expression (Arg);
277 Excluded_Pattern_Expected := False;
279 -- There must be at least one Ada pattern or one foreign
280 -- pattern for the previous section.
282 -- --and
284 elsif Arg = "--and" then
286 if Patterns.Last
287 (Arguments.Table (Arguments.Last).Name_Patterns) = 0
288 and then
289 Patterns.Last
290 (Arguments.Table (Arguments.Last).Foreign_Patterns) = 0
291 then
292 Try_Help;
293 return;
294 end if;
296 -- If no directory were specified for the previous section,
297 -- then the directory is the project directory.
299 if Patterns.Last
300 (Arguments.Table (Arguments.Last).Directories) = 0
301 then
302 Patterns.Append
303 (Arguments.Table (Arguments.Last).Directories,
304 new String'("."));
305 end if;
307 -- Add and initialize another component to Arguments table
309 declare
310 New_Arguments : Argument_Data;
311 pragma Warnings (Off, New_Arguments);
312 -- Declaring this defaulted initialized object ensures
313 -- that the new allocated component of table Arguments
314 -- is correctly initialized.
316 -- This is VERY ugly, Table should never be used with
317 -- data requiring default initialization. We should
318 -- find a way to avoid violating this rule ???
320 begin
321 Arguments.Append (New_Arguments);
322 end;
324 Patterns.Init
325 (Arguments.Table (Arguments.Last).Directories);
326 Patterns.Set_Last
327 (Arguments.Table (Arguments.Last).Directories, 0);
328 Patterns.Init
329 (Arguments.Table (Arguments.Last).Name_Patterns);
330 Patterns.Set_Last
331 (Arguments.Table (Arguments.Last).Name_Patterns, 0);
332 Patterns.Init
333 (Arguments.Table (Arguments.Last).Excluded_Patterns);
334 Patterns.Set_Last
335 (Arguments.Table (Arguments.Last).Excluded_Patterns, 0);
336 Patterns.Init
337 (Arguments.Table (Arguments.Last).Foreign_Patterns);
338 Patterns.Set_Last
339 (Arguments.Table (Arguments.Last).Foreign_Patterns, 0);
341 -- Subdirectory switch
343 elsif Arg'Length > Subdirs_Switch'Length
344 and then Arg (1 .. Subdirs_Switch'Length) = Subdirs_Switch
345 then
346 Subdirs :=
347 new String'(Arg (Subdirs_Switch'Length + 1 .. Arg'Last));
349 -- --no-backup
351 elsif Arg = "--no-backup" then
352 Opt.No_Backup := True;
354 -- -c
356 elsif Arg'Length >= 2 and then Arg (1 .. 2) = "-c" then
357 if File_Set then
358 Fail ("only one -P or -c switch may be specified");
359 end if;
361 if Arg'Length = 2 then
362 Pragmas_File_Expected := True;
364 if Next_Arg = Argument_Count then
365 Fail ("configuration pragmas file name missing");
366 end if;
368 else
369 File_Set := True;
370 File_Path := new String'(Arg (3 .. Arg'Last));
371 Create_Project := False;
372 end if;
374 -- -d
376 elsif Arg'Length >= 2 and then Arg (1 .. 2) = "-d" then
377 if Arg'Length = 2 then
378 Directory_Expected := True;
380 if Next_Arg = Argument_Count then
381 Fail ("directory name missing");
382 end if;
384 else
385 Add_Source_Directory (Arg (3 .. Arg'Last));
386 end if;
388 -- -D
390 elsif Arg'Length >= 2 and then Arg (1 .. 2) = "-D" then
391 if Arg'Length = 2 then
392 Dir_File_Name_Expected := True;
394 if Next_Arg = Argument_Count then
395 Fail ("directory list file name missing");
396 end if;
398 else
399 Get_Directories (Arg (3 .. Arg'Last));
400 end if;
402 -- -eL
404 elsif Arg = "-eL" then
405 Opt.Follow_Links_For_Files := True;
406 Opt.Follow_Links_For_Dirs := True;
408 -- -f
410 elsif Arg'Length >= 2 and then Arg (1 .. 2) = "-f" then
411 if Arg'Length = 2 then
412 Foreign_Pattern_Expected := True;
414 if Next_Arg = Argument_Count then
415 Fail ("foreign pattern missing");
416 end if;
418 else
419 Patterns.Append
420 (Arguments.Table (Arguments.Last).Foreign_Patterns,
421 new String'(Arg (3 .. Arg'Last)));
422 Check_Regular_Expression (Arg (3 .. Arg'Last));
423 end if;
425 -- -gnatep or -gnateD
427 elsif Arg'Length > 7 and then
428 (Arg (1 .. 7) = "-gnatep" or else Arg (1 .. 7) = "-gnateD")
429 then
430 Preprocessor_Switches.Append (new String'(Arg));
432 -- -h
434 elsif Arg = "-h" then
435 Usage_Needed := True;
437 -- -p
439 elsif Arg'Length >= 2 and then Arg (1 .. 2) = "-P" then
440 if File_Set then
441 Fail ("only one -c or -P switch may be specified");
442 end if;
444 if Arg'Length = 2 then
445 if Next_Arg = Argument_Count then
446 Fail ("project file name missing");
448 else
449 Project_File_Name_Expected := True;
450 end if;
452 else
453 File_Set := True;
454 File_Path := new String'(Arg (3 .. Arg'Last));
455 end if;
457 Create_Project := True;
459 -- -v
461 elsif Arg = "-v" then
462 if Opt.Verbose_Mode then
463 Very_Verbose := True;
464 else
465 Opt.Verbose_Mode := True;
466 end if;
468 -- -x
470 elsif Arg'Length >= 2 and then Arg (1 .. 2) = "-x" then
471 if Arg'Length = 2 then
472 Excluded_Pattern_Expected := True;
474 if Next_Arg = Argument_Count then
475 Fail ("excluded pattern missing");
476 end if;
478 else
479 Patterns.Append
480 (Arguments.Table (Arguments.Last).Excluded_Patterns,
481 new String'(Arg (3 .. Arg'Last)));
482 Check_Regular_Expression (Arg (3 .. Arg'Last));
483 end if;
485 -- Junk switch starting with minus
487 elsif Arg (1) = '-' then
488 Fail ("wrong switch: " & Arg);
490 -- Not a recognized switch, assume file name
492 else
493 Canonical_Case_File_Name (Arg);
494 Patterns.Append
495 (Arguments.Table (Arguments.Last).Name_Patterns,
496 new String'(Arg));
497 Check_Regular_Expression (Arg);
498 end if;
499 end if;
500 end;
501 end loop;
502 end Scan_Args;
504 -----------
505 -- Usage --
506 -----------
508 procedure Usage is
509 begin
510 if not Usage_Output then
511 Usage_Needed := False;
512 Usage_Output := True;
513 Write_Str ("Usage: ");
514 Osint.Write_Program_Name;
515 Write_Line (" [switches] naming-pattern [naming-patterns]");
516 Write_Line (" {--and [switches] naming-pattern [naming-patterns]}");
517 Write_Eol;
518 Write_Line ("switches:");
520 Display_Usage_Version_And_Help;
522 Write_Line (" --subdirs=dir real obj/lib/exec dirs are subdirs");
523 Write_Line (" --no-backup do not create backup of project file");
524 Write_Eol;
526 Write_Line (" --and use different patterns");
527 Write_Eol;
529 Write_Line (" -cfile create configuration pragmas file");
530 Write_Line (" -ddir use dir as one of the source " &
531 "directories");
532 Write_Line (" -Dfile get source directories from file");
533 Write_Line (" -eL follow symbolic links when processing " &
534 "project files");
535 Write_Line (" -fpat foreign pattern");
536 Write_Line (" -gnateDsym=v preprocess with symbol definition");
537 Write_Line (" -gnatep=data preprocess files with data file");
538 Write_Line (" -h output this help message");
539 Write_Line (" -Pproj update or create project file proj");
540 Write_Line (" -v verbose output");
541 Write_Line (" -v -v very verbose output");
542 Write_Line (" -xpat exclude pattern pat");
543 end if;
544 end Usage;
546 -- Start of processing for Gnatname
548 begin
549 -- Add the directory where gnatname is invoked in front of the
550 -- path, if gnatname is invoked with directory information.
552 declare
553 Command : constant String := Command_Name;
555 begin
556 for Index in reverse Command'Range loop
557 if Command (Index) = Directory_Separator then
558 declare
559 Absolute_Dir : constant String :=
560 Normalize_Pathname
561 (Command (Command'First .. Index));
563 PATH : constant String :=
564 Absolute_Dir &
565 Path_Separator &
566 Getenv ("PATH").all;
568 begin
569 Setenv ("PATH", PATH);
570 end;
572 exit;
573 end if;
574 end loop;
575 end;
577 -- Initialize tables
579 Arguments.Set_Last (0);
580 declare
581 New_Arguments : Argument_Data;
582 pragma Warnings (Off, New_Arguments);
583 -- Declaring this defaulted initialized object ensures that the new
584 -- allocated component of table Arguments is correctly initialized.
585 begin
586 Arguments.Append (New_Arguments);
587 end;
589 Patterns.Init (Arguments.Table (1).Directories);
590 Patterns.Set_Last (Arguments.Table (1).Directories, 0);
591 Patterns.Init (Arguments.Table (1).Name_Patterns);
592 Patterns.Set_Last (Arguments.Table (1).Name_Patterns, 0);
593 Patterns.Init (Arguments.Table (1).Excluded_Patterns);
594 Patterns.Set_Last (Arguments.Table (1).Excluded_Patterns, 0);
595 Patterns.Init (Arguments.Table (1).Foreign_Patterns);
596 Patterns.Set_Last (Arguments.Table (1).Foreign_Patterns, 0);
598 Preprocessor_Switches.Set_Last (0);
600 -- Get the arguments
602 Scan_Args;
604 if Opt.Verbose_Mode then
605 Output_Version;
606 end if;
608 if Usage_Needed then
609 Usage;
610 end if;
612 -- If no Ada or foreign pattern was specified, print the usage and return
614 if Patterns.Last (Arguments.Table (Arguments.Last).Name_Patterns) = 0
615 and then
616 Patterns.Last (Arguments.Table (Arguments.Last).Foreign_Patterns) = 0
617 then
618 if Argument_Count = 0 then
619 Usage;
620 elsif not Usage_Output then
621 Try_Help;
622 end if;
624 return;
625 end if;
627 -- If no source directory was specified, use the current directory as the
628 -- unique directory. Note that if a file was specified with directory
629 -- information, the current directory is the directory of the specified
630 -- file.
632 if Patterns.Last
633 (Arguments.Table (Arguments.Last).Directories) = 0
634 then
635 Patterns.Append
636 (Arguments.Table (Arguments.Last).Directories, new String'("."));
637 end if;
639 -- Initialize
641 declare
642 Prep_Switches : Argument_List
643 (1 .. Integer (Preprocessor_Switches.Last));
645 begin
646 for Index in Prep_Switches'Range loop
647 Prep_Switches (Index) := Preprocessor_Switches.Table (Index);
648 end loop;
650 Prj.Makr.Initialize
651 (File_Path => File_Path.all,
652 Project_File => Create_Project,
653 Preproc_Switches => Prep_Switches,
654 Very_Verbose => Very_Verbose,
655 Flags => Gnatmake_Flags);
656 end;
658 -- Process each section successively
660 for J in 1 .. Arguments.Last loop
661 declare
662 Directories : Argument_List
663 (1 .. Integer
664 (Patterns.Last (Arguments.Table (J).Directories)));
665 Name_Patterns : Prj.Makr.Regexp_List
666 (1 .. Integer
667 (Patterns.Last (Arguments.Table (J).Name_Patterns)));
668 Excl_Patterns : Prj.Makr.Regexp_List
669 (1 .. Integer
670 (Patterns.Last (Arguments.Table (J).Excluded_Patterns)));
671 Frgn_Patterns : Prj.Makr.Regexp_List
672 (1 .. Integer
673 (Patterns.Last (Arguments.Table (J).Foreign_Patterns)));
675 begin
676 -- Build the Directories and Patterns arguments
678 for Index in Directories'Range loop
679 Directories (Index) :=
680 Arguments.Table (J).Directories.Table (Index);
681 end loop;
683 for Index in Name_Patterns'Range loop
684 Name_Patterns (Index) :=
685 Compile
686 (Arguments.Table (J).Name_Patterns.Table (Index).all,
687 Glob => True);
688 end loop;
690 for Index in Excl_Patterns'Range loop
691 Excl_Patterns (Index) :=
692 Compile
693 (Arguments.Table (J).Excluded_Patterns.Table (Index).all,
694 Glob => True);
695 end loop;
697 for Index in Frgn_Patterns'Range loop
698 Frgn_Patterns (Index) :=
699 Compile
700 (Arguments.Table (J).Foreign_Patterns.Table (Index).all,
701 Glob => True);
702 end loop;
704 -- Call Prj.Makr.Process where the real work is done
706 Prj.Makr.Process
707 (Directories => Directories,
708 Name_Patterns => Name_Patterns,
709 Excluded_Patterns => Excl_Patterns,
710 Foreign_Patterns => Frgn_Patterns);
711 end;
712 end loop;
714 -- Finalize
716 Prj.Makr.Finalize;
718 if Opt.Verbose_Mode then
719 Write_Eol;
720 end if;
721 end Gnatname;