[multiple changes]
[gcc.git] / gcc / ada / gnatname.adb
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 ------------------------------------------------------------------------------
25
26 with Ada.Command_Line; use Ada.Command_Line;
27 with Ada.Text_IO; use Ada.Text_IO;
28
29 with GNAT.Command_Line; use GNAT.Command_Line;
30 with GNAT.Dynamic_Tables;
31 with GNAT.OS_Lib; use GNAT.OS_Lib;
32
33 with Hostparm;
34 with Opt;
35 with Osint; use Osint;
36 with Output; use Output;
37 with Prj; use Prj;
38 with Prj.Makr;
39 with Switch; use Switch;
40 with Table;
41
42 with System.Regexp; use System.Regexp;
43
44 procedure Gnatname is
45
46 Subdirs_Switch : constant String := "--subdirs=";
47
48 Usage_Output : Boolean := False;
49 -- Set to True when usage is output, to avoid multiple output
50
51 Usage_Needed : Boolean := False;
52 -- Set to True by -h switch
53
54 Version_Output : Boolean := False;
55 -- Set to True when version is output, to avoid multiple output
56
57 Very_Verbose : Boolean := False;
58 -- Set to True with -v -v
59
60 Create_Project : Boolean := False;
61 -- Set to True with a -P switch
62
63 File_Path : String_Access := new String'("gnat.adc");
64 -- Path name of the file specified by -c or -P switch
65
66 File_Set : Boolean := False;
67 -- Set to True by -c or -P switch.
68 -- Used to detect multiple -c/-P switches.
69
70 package Patterns is new GNAT.Dynamic_Tables
71 (Table_Component_Type => String_Access,
72 Table_Index_Type => Natural,
73 Table_Low_Bound => 0,
74 Table_Initial => 10,
75 Table_Increment => 100);
76 -- Table to accumulate the patterns
77
78 type Argument_Data is record
79 Directories : Patterns.Instance;
80 Name_Patterns : Patterns.Instance;
81 Excluded_Patterns : Patterns.Instance;
82 Foreign_Patterns : Patterns.Instance;
83 end record;
84
85 package Arguments is new Table.Table
86 (Table_Component_Type => Argument_Data,
87 Table_Index_Type => Natural,
88 Table_Low_Bound => 0,
89 Table_Initial => 10,
90 Table_Increment => 100,
91 Table_Name => "Gnatname.Arguments");
92 -- Table to accumulate directories and patterns
93
94 package Preprocessor_Switches is new Table.Table
95 (Table_Component_Type => String_Access,
96 Table_Index_Type => Natural,
97 Table_Low_Bound => 0,
98 Table_Initial => 10,
99 Table_Increment => 100,
100 Table_Name => "Gnatname.Preprocessor_Switches");
101 -- Table to store the preprocessor switches to be used in the call
102 -- to the compiler.
103
104 procedure Output_Version;
105 -- Print name and version
106
107 procedure Usage;
108 -- Print usage
109
110 procedure Scan_Args;
111 -- Scan the command line arguments
112
113 procedure Add_Source_Directory (S : String);
114 -- Add S in the Source_Directories table
115
116 procedure Get_Directories (From_File : String);
117 -- Read a source directory text file
118
119 --------------------------
120 -- Add_Source_Directory --
121 --------------------------
122
123 procedure Add_Source_Directory (S : String) is
124 begin
125 Patterns.Append
126 (Arguments.Table (Arguments.Last).Directories, new String'(S));
127 end Add_Source_Directory;
128
129 ---------------------
130 -- Get_Directories --
131 ---------------------
132
133 procedure Get_Directories (From_File : String) is
134 File : Ada.Text_IO.File_Type;
135 Line : String (1 .. 2_000);
136 Last : Natural;
137
138 begin
139 Open (File, In_File, From_File);
140
141 while not End_Of_File (File) loop
142 Get_Line (File, Line, Last);
143
144 if Last /= 0 then
145 Add_Source_Directory (Line (1 .. Last));
146 end if;
147 end loop;
148
149 Close (File);
150
151 exception
152 when Name_Error =>
153 Fail ("cannot open source directory file """ & From_File & '"');
154 end Get_Directories;
155
156 --------------------
157 -- Output_Version --
158 --------------------
159
160 procedure Output_Version is
161 begin
162 if not Version_Output then
163 Version_Output := True;
164 Output.Write_Eol;
165 Display_Version ("GNATNAME", "2001");
166 end if;
167 end Output_Version;
168
169 ---------------
170 -- Scan_Args --
171 ---------------
172
173 procedure Scan_Args is
174
175 procedure Check_Version_And_Help is new Check_Version_And_Help_G (Usage);
176
177 Project_File_Name_Expected : Boolean;
178
179 Pragmas_File_Expected : Boolean;
180
181 Directory_Expected : Boolean;
182
183 Dir_File_Name_Expected : Boolean;
184
185 Foreign_Pattern_Expected : Boolean;
186
187 Excluded_Pattern_Expected : Boolean;
188
189 procedure Check_Regular_Expression (S : String);
190 -- Compile string S into a Regexp, fail if any error
191
192 -----------------------------
193 -- Check_Regular_Expression--
194 -----------------------------
195
196 procedure Check_Regular_Expression (S : String) is
197 Dummy : Regexp;
198 pragma Warnings (Off, Dummy);
199 begin
200 Dummy := Compile (S, Glob => True);
201 exception
202 when Error_In_Regexp =>
203 Fail ("invalid regular expression """ & S & """");
204 end Check_Regular_Expression;
205
206 -- Start of processing for Scan_Args
207
208 begin
209 -- First check for --version or --help
210
211 Check_Version_And_Help ("GNATNAME", "2001");
212
213 -- Now scan the other switches
214
215 Project_File_Name_Expected := False;
216 Pragmas_File_Expected := False;
217 Directory_Expected := False;
218 Dir_File_Name_Expected := False;
219 Foreign_Pattern_Expected := False;
220 Excluded_Pattern_Expected := False;
221
222 for Next_Arg in 1 .. Argument_Count loop
223 declare
224 Next_Argv : constant String := Argument (Next_Arg);
225 Arg : String (1 .. Next_Argv'Length) := Next_Argv;
226
227 begin
228 if Arg'Length > 0 then
229
230 -- -P xxx
231
232 if Project_File_Name_Expected then
233 if Arg (1) = '-' then
234 Fail ("project file name missing");
235
236 else
237 File_Set := True;
238 File_Path := new String'(Arg);
239 Project_File_Name_Expected := False;
240 end if;
241
242 -- -c file
243
244 elsif Pragmas_File_Expected then
245 File_Set := True;
246 File_Path := new String'(Arg);
247 Create_Project := False;
248 Pragmas_File_Expected := False;
249
250 -- -d xxx
251
252 elsif Directory_Expected then
253 Add_Source_Directory (Arg);
254 Directory_Expected := False;
255
256 -- -D xxx
257
258 elsif Dir_File_Name_Expected then
259 Get_Directories (Arg);
260 Dir_File_Name_Expected := False;
261
262 -- -f xxx
263
264 elsif Foreign_Pattern_Expected then
265 Patterns.Append
266 (Arguments.Table (Arguments.Last).Foreign_Patterns,
267 new String'(Arg));
268 Check_Regular_Expression (Arg);
269 Foreign_Pattern_Expected := False;
270
271 -- -x xxx
272
273 elsif Excluded_Pattern_Expected then
274 Patterns.Append
275 (Arguments.Table (Arguments.Last).Excluded_Patterns,
276 new String'(Arg));
277 Check_Regular_Expression (Arg);
278 Excluded_Pattern_Expected := False;
279
280 -- There must be at least one Ada pattern or one foreign
281 -- pattern for the previous section.
282
283 -- --and
284
285 elsif Arg = "--and" then
286
287 if Patterns.Last
288 (Arguments.Table (Arguments.Last).Name_Patterns) = 0
289 and then
290 Patterns.Last
291 (Arguments.Table (Arguments.Last).Foreign_Patterns) = 0
292 then
293 Try_Help;
294 return;
295 end if;
296
297 -- If no directory were specified for the previous section,
298 -- then the directory is the project directory.
299
300 if Patterns.Last
301 (Arguments.Table (Arguments.Last).Directories) = 0
302 then
303 Patterns.Append
304 (Arguments.Table (Arguments.Last).Directories,
305 new String'("."));
306 end if;
307
308 -- Add and initialize another component to Arguments table
309
310 declare
311 New_Arguments : Argument_Data;
312 pragma Warnings (Off, New_Arguments);
313 -- Declaring this defaulted initialized object ensures
314 -- that the new allocated component of table Arguments
315 -- is correctly initialized.
316
317 -- This is VERY ugly, Table should never be used with
318 -- data requiring default initialization. We should
319 -- find a way to avoid violating this rule ???
320
321 begin
322 Arguments.Append (New_Arguments);
323 end;
324
325 Patterns.Init
326 (Arguments.Table (Arguments.Last).Directories);
327 Patterns.Set_Last
328 (Arguments.Table (Arguments.Last).Directories, 0);
329 Patterns.Init
330 (Arguments.Table (Arguments.Last).Name_Patterns);
331 Patterns.Set_Last
332 (Arguments.Table (Arguments.Last).Name_Patterns, 0);
333 Patterns.Init
334 (Arguments.Table (Arguments.Last).Excluded_Patterns);
335 Patterns.Set_Last
336 (Arguments.Table (Arguments.Last).Excluded_Patterns, 0);
337 Patterns.Init
338 (Arguments.Table (Arguments.Last).Foreign_Patterns);
339 Patterns.Set_Last
340 (Arguments.Table (Arguments.Last).Foreign_Patterns, 0);
341
342 -- Subdirectory switch
343
344 elsif Arg'Length > Subdirs_Switch'Length
345 and then Arg (1 .. Subdirs_Switch'Length) = Subdirs_Switch
346 then
347 Subdirs :=
348 new String'(Arg (Subdirs_Switch'Length + 1 .. Arg'Last));
349
350 -- --no-backup
351
352 elsif Arg = "--no-backup" then
353 Opt.No_Backup := True;
354
355 -- -c
356
357 elsif Arg'Length >= 2 and then Arg (1 .. 2) = "-c" then
358 if File_Set then
359 Fail ("only one -P or -c switch may be specified");
360 end if;
361
362 if Arg'Length = 2 then
363 Pragmas_File_Expected := True;
364
365 if Next_Arg = Argument_Count then
366 Fail ("configuration pragmas file name missing");
367 end if;
368
369 else
370 File_Set := True;
371 File_Path := new String'(Arg (3 .. Arg'Last));
372 Create_Project := False;
373 end if;
374
375 -- -d
376
377 elsif Arg'Length >= 2 and then Arg (1 .. 2) = "-d" then
378 if Arg'Length = 2 then
379 Directory_Expected := True;
380
381 if Next_Arg = Argument_Count then
382 Fail ("directory name missing");
383 end if;
384
385 else
386 Add_Source_Directory (Arg (3 .. Arg'Last));
387 end if;
388
389 -- -D
390
391 elsif Arg'Length >= 2 and then Arg (1 .. 2) = "-D" then
392 if Arg'Length = 2 then
393 Dir_File_Name_Expected := True;
394
395 if Next_Arg = Argument_Count then
396 Fail ("directory list file name missing");
397 end if;
398
399 else
400 Get_Directories (Arg (3 .. Arg'Last));
401 end if;
402
403 -- -eL
404
405 elsif Arg = "-eL" then
406 Opt.Follow_Links_For_Files := True;
407 Opt.Follow_Links_For_Dirs := True;
408
409 -- -f
410
411 elsif Arg'Length >= 2 and then Arg (1 .. 2) = "-f" then
412 if Arg'Length = 2 then
413 Foreign_Pattern_Expected := True;
414
415 if Next_Arg = Argument_Count then
416 Fail ("foreign pattern missing");
417 end if;
418
419 else
420 Patterns.Append
421 (Arguments.Table (Arguments.Last).Foreign_Patterns,
422 new String'(Arg (3 .. Arg'Last)));
423 Check_Regular_Expression (Arg (3 .. Arg'Last));
424 end if;
425
426 -- -gnatep or -gnateD
427
428 elsif Arg'Length > 7 and then
429 (Arg (1 .. 7) = "-gnatep" or else Arg (1 .. 7) = "-gnateD")
430 then
431 Preprocessor_Switches.Append (new String'(Arg));
432
433 -- -h
434
435 elsif Arg = "-h" then
436 Usage_Needed := True;
437
438 -- -p
439
440 elsif Arg'Length >= 2 and then Arg (1 .. 2) = "-P" then
441 if File_Set then
442 Fail ("only one -c or -P switch may be specified");
443 end if;
444
445 if Arg'Length = 2 then
446 if Next_Arg = Argument_Count then
447 Fail ("project file name missing");
448
449 else
450 Project_File_Name_Expected := True;
451 end if;
452
453 else
454 File_Set := True;
455 File_Path := new String'(Arg (3 .. Arg'Last));
456 end if;
457
458 Create_Project := True;
459
460 -- -v
461
462 elsif Arg = "-v" then
463 if Opt.Verbose_Mode then
464 Very_Verbose := True;
465 else
466 Opt.Verbose_Mode := True;
467 end if;
468
469 -- -x
470
471 elsif Arg'Length >= 2 and then Arg (1 .. 2) = "-x" then
472 if Arg'Length = 2 then
473 Excluded_Pattern_Expected := True;
474
475 if Next_Arg = Argument_Count then
476 Fail ("excluded pattern missing");
477 end if;
478
479 else
480 Patterns.Append
481 (Arguments.Table (Arguments.Last).Excluded_Patterns,
482 new String'(Arg (3 .. Arg'Last)));
483 Check_Regular_Expression (Arg (3 .. Arg'Last));
484 end if;
485
486 -- Junk switch starting with minus
487
488 elsif Arg (1) = '-' then
489 Fail ("wrong switch: " & Arg);
490
491 -- Not a recognized switch, assume file name
492
493 else
494 Canonical_Case_File_Name (Arg);
495 Patterns.Append
496 (Arguments.Table (Arguments.Last).Name_Patterns,
497 new String'(Arg));
498 Check_Regular_Expression (Arg);
499 end if;
500 end if;
501 end;
502 end loop;
503 end Scan_Args;
504
505 -----------
506 -- Usage --
507 -----------
508
509 procedure Usage is
510 begin
511 if not Usage_Output then
512 Usage_Needed := False;
513 Usage_Output := True;
514 Write_Str ("Usage: ");
515 Osint.Write_Program_Name;
516 Write_Line (" [switches] naming-pattern [naming-patterns]");
517 Write_Line (" {--and [switches] naming-pattern [naming-patterns]}");
518 Write_Eol;
519 Write_Line ("switches:");
520
521 Display_Usage_Version_And_Help;
522
523 Write_Line (" --subdirs=dir real obj/lib/exec dirs are subdirs");
524 Write_Line (" --no-backup do not create backup of project file");
525 Write_Eol;
526
527 Write_Line (" --and use different patterns");
528 Write_Eol;
529
530 Write_Line (" -cfile create configuration pragmas file");
531 Write_Line (" -ddir use dir as one of the source " &
532 "directories");
533 Write_Line (" -Dfile get source directories from file");
534 Write_Line (" -eL follow symbolic links when processing " &
535 "project files");
536 Write_Line (" -fpat foreign pattern");
537 Write_Line (" -gnateDsym=v preprocess with symbol definition");
538 Write_Line (" -gnatep=data preprocess files with data file");
539 Write_Line (" -h output this help message");
540 Write_Line (" -Pproj update or create project file proj");
541 Write_Line (" -v verbose output");
542 Write_Line (" -v -v very verbose output");
543 Write_Line (" -xpat exclude pattern pat");
544 end if;
545 end Usage;
546
547 -- Start of processing for Gnatname
548
549 begin
550 -- Add the directory where gnatname is invoked in front of the
551 -- path, if gnatname is invoked with directory information.
552 -- Only do this if the platform is not VMS, where the notion of path
553 -- does not really exist.
554
555 if not Hostparm.OpenVMS then
556 declare
557 Command : constant String := Command_Name;
558
559 begin
560 for Index in reverse Command'Range loop
561 if Command (Index) = Directory_Separator then
562 declare
563 Absolute_Dir : constant String :=
564 Normalize_Pathname
565 (Command (Command'First .. Index));
566
567 PATH : constant String :=
568 Absolute_Dir &
569 Path_Separator &
570 Getenv ("PATH").all;
571
572 begin
573 Setenv ("PATH", PATH);
574 end;
575
576 exit;
577 end if;
578 end loop;
579 end;
580 end if;
581
582 -- Initialize tables
583
584 Arguments.Set_Last (0);
585 declare
586 New_Arguments : Argument_Data;
587 pragma Warnings (Off, New_Arguments);
588 -- Declaring this defaulted initialized object ensures
589 -- that the new allocated component of table Arguments
590 -- is correctly initialized.
591 begin
592 Arguments.Append (New_Arguments);
593 end;
594 Patterns.Init (Arguments.Table (1).Directories);
595 Patterns.Set_Last (Arguments.Table (1).Directories, 0);
596 Patterns.Init (Arguments.Table (1).Name_Patterns);
597 Patterns.Set_Last (Arguments.Table (1).Name_Patterns, 0);
598 Patterns.Init (Arguments.Table (1).Excluded_Patterns);
599 Patterns.Set_Last (Arguments.Table (1).Excluded_Patterns, 0);
600 Patterns.Init (Arguments.Table (1).Foreign_Patterns);
601 Patterns.Set_Last (Arguments.Table (1).Foreign_Patterns, 0);
602
603 Preprocessor_Switches.Set_Last (0);
604
605 -- Get the arguments
606
607 Scan_Args;
608
609 if Opt.Verbose_Mode then
610 Output_Version;
611 end if;
612
613 if Usage_Needed then
614 Usage;
615 end if;
616
617 -- If no Ada or foreign pattern was specified, print the usage and return
618
619 if Patterns.Last (Arguments.Table (Arguments.Last).Name_Patterns) = 0
620 and then
621 Patterns.Last (Arguments.Table (Arguments.Last).Foreign_Patterns) = 0
622 then
623 if Argument_Count = 0 then
624 Usage;
625 elsif not Usage_Output then
626 Try_Help;
627 end if;
628
629 return;
630 end if;
631
632 -- If no source directory was specified, use the current directory as the
633 -- unique directory. Note that if a file was specified with directory
634 -- information, the current directory is the directory of the specified
635 -- file.
636
637 if Patterns.Last
638 (Arguments.Table (Arguments.Last).Directories) = 0
639 then
640 Patterns.Append
641 (Arguments.Table (Arguments.Last).Directories, new String'("."));
642 end if;
643
644 -- Initialize
645
646 declare
647 Prep_Switches : Argument_List
648 (1 .. Integer (Preprocessor_Switches.Last));
649
650 begin
651 for Index in Prep_Switches'Range loop
652 Prep_Switches (Index) := Preprocessor_Switches.Table (Index);
653 end loop;
654
655 Prj.Makr.Initialize
656 (File_Path => File_Path.all,
657 Project_File => Create_Project,
658 Preproc_Switches => Prep_Switches,
659 Very_Verbose => Very_Verbose,
660 Flags => Gnatmake_Flags);
661 end;
662
663 -- Process each section successively
664
665 for J in 1 .. Arguments.Last loop
666 declare
667 Directories : Argument_List
668 (1 .. Integer
669 (Patterns.Last (Arguments.Table (J).Directories)));
670 Name_Patterns : Prj.Makr.Regexp_List
671 (1 .. Integer
672 (Patterns.Last (Arguments.Table (J).Name_Patterns)));
673 Excl_Patterns : Prj.Makr.Regexp_List
674 (1 .. Integer
675 (Patterns.Last (Arguments.Table (J).Excluded_Patterns)));
676 Frgn_Patterns : Prj.Makr.Regexp_List
677 (1 .. Integer
678 (Patterns.Last (Arguments.Table (J).Foreign_Patterns)));
679
680 begin
681 -- Build the Directories and Patterns arguments
682
683 for Index in Directories'Range loop
684 Directories (Index) :=
685 Arguments.Table (J).Directories.Table (Index);
686 end loop;
687
688 for Index in Name_Patterns'Range loop
689 Name_Patterns (Index) :=
690 Compile
691 (Arguments.Table (J).Name_Patterns.Table (Index).all,
692 Glob => True);
693 end loop;
694
695 for Index in Excl_Patterns'Range loop
696 Excl_Patterns (Index) :=
697 Compile
698 (Arguments.Table (J).Excluded_Patterns.Table (Index).all,
699 Glob => True);
700 end loop;
701
702 for Index in Frgn_Patterns'Range loop
703 Frgn_Patterns (Index) :=
704 Compile
705 (Arguments.Table (J).Foreign_Patterns.Table (Index).all,
706 Glob => True);
707 end loop;
708
709 -- Call Prj.Makr.Process where the real work is done
710
711 Prj.Makr.Process
712 (Directories => Directories,
713 Name_Patterns => Name_Patterns,
714 Excluded_Patterns => Excl_Patterns,
715 Foreign_Patterns => Frgn_Patterns);
716 end;
717 end loop;
718
719 -- Finalize
720
721 Prj.Makr.Finalize;
722
723 if Opt.Verbose_Mode then
724 Write_Eol;
725 end if;
726 end Gnatname;