3d5766df70353aa00b91d081eb55668bbbcd7c6b
[gcc.git] / gcc / ada / gprcmd.adb
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- G P R C M D --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2002-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 ------------------------------------------------------------------------------
26
27 -- A utility used by Makefile.generic to handle multi-language builds.
28 -- gprcmd provides a set of commands so that the makefiles do not need
29 -- to depend on unix utilities not available on all targets.
30
31 -- The list of commands recognized by gprcmd are:
32
33 -- pwd display current directory
34 -- to_lower display next argument in lower case
35 -- to_absolute convert pathnames to absolute directories when needed
36 -- cat dump contents of a given file
37 -- extend handle recursive directories ("/**" notation)
38 -- deps post process dependency makefiles
39 -- stamp copy file time stamp from file1 to file2
40
41 with Ada.Characters.Handling; use Ada.Characters.Handling;
42 with Ada.Command_Line; use Ada.Command_Line;
43 with Ada.Text_IO; use Ada.Text_IO;
44 with GNAT.OS_Lib; use GNAT.OS_Lib;
45 with GNAT.Directory_Operations; use GNAT.Directory_Operations;
46 with GNAT.Regpat; use GNAT.Regpat;
47 with Gnatvsn;
48
49 procedure Gprcmd is
50
51 -- ??? comments are thin throughout this unit
52
53 Version : constant String :=
54 "GPRCMD " & Gnatvsn.Gnat_Version_String &
55 " Copyright 2002-2003, Ada Core Technologies Inc.";
56
57 procedure Cat (File : String);
58 -- Print the contents of file on standard output.
59 -- If the file cannot be read, exit the process with an error code.
60
61 procedure Check_Args (Condition : Boolean);
62 -- If Condition is false, print the usage, and exit the process.
63
64 procedure Deps (Objext : String; File : String; GCC : Boolean);
65 -- Process $(CC) dependency file. If GCC is True, add a rule so that make
66 -- will not complain when a file is removed/added. If GCC is False, add a
67 -- rule to recompute the dependency file when needed
68
69 procedure Extend (Dir : String);
70 -- If Dir ends with /**, Put all subdirs recursively on standard output,
71 -- otherwise put Dir.
72
73 procedure Usage;
74 -- Display the command line options and exit the process.
75
76 procedure Copy_Time_Stamp (From, To : String);
77 -- Copy file time stamp from file From to file To.
78
79 ---------
80 -- Cat --
81 ---------
82
83 procedure Cat (File : String) is
84 FD : File_Descriptor;
85 Buffer : String_Access;
86 Length : Integer;
87
88 begin
89 FD := Open_Read (File, Fmode => Binary);
90
91 if FD = Invalid_FD then
92 OS_Exit (2);
93 end if;
94
95 Length := Integer (File_Length (FD));
96 Buffer := new String (1 .. Length);
97 Length := Read (FD, Buffer.all'Address, Length);
98 Close (FD);
99 Put (Buffer.all);
100 Free (Buffer);
101 end Cat;
102
103 ----------------
104 -- Check_Args --
105 ----------------
106
107 procedure Check_Args (Condition : Boolean) is
108 begin
109 if not Condition then
110 Usage;
111 end if;
112 end Check_Args;
113
114 ---------------------
115 -- Copy_Time_Stamp --
116 ---------------------
117
118 procedure Copy_Time_Stamp (From, To : String) is
119 function Copy_Attributes
120 (From, To : String;
121 Mode : Integer) return Integer;
122 pragma Import (C, Copy_Attributes, "__gnat_copy_attribs");
123 -- Mode = 0 - copy only time stamps.
124 -- Mode = 1 - copy time stamps and read/write/execute attributes
125
126 FD : File_Descriptor;
127
128 begin
129 if not Is_Regular_File (From) then
130 return;
131 end if;
132
133 FD := Create_File (To, Fmode => Binary);
134
135 if FD = Invalid_FD then
136 OS_Exit (2);
137 end if;
138
139 Close (FD);
140
141 if Copy_Attributes (From & ASCII.NUL, To & ASCII.NUL, 0) /= 0 then
142 OS_Exit (2);
143 end if;
144 end Copy_Time_Stamp;
145
146 ----------
147 -- Deps --
148 ----------
149
150 procedure Deps (Objext : String; File : String; GCC : Boolean) is
151 Colon : constant String := ':' & ASCII.LF;
152 NL : constant String := (1 => ASCII.LF);
153 Base : constant String := ' ' & Base_Name (File) & ": ";
154 FD : File_Descriptor;
155 Buffer : String_Access;
156 Length : Integer;
157 Obj_Regexp : constant Pattern_Matcher :=
158 Compile ("^.*\" & Objext & ": ");
159 Matched : Match_Array (0 .. 0);
160 Start : Natural;
161 First : Natural;
162 Last : Natural;
163
164 begin
165 FD := Open_Read_Write (File, Fmode => Binary);
166
167 if FD = Invalid_FD then
168 return;
169 end if;
170
171 Length := Integer (File_Length (FD));
172 Buffer := new String (1 .. Length);
173 Length := Read (FD, Buffer.all'Address, Length);
174
175 if GCC then
176 Lseek (FD, 0, Seek_End);
177 else
178 Close (FD);
179 FD := Create_File (File, Fmode => Binary);
180 end if;
181
182 Start := Buffer'First;
183
184 while Start <= Buffer'Last loop
185
186 -- Parse Buffer line by line
187
188 while Start < Buffer'Last
189 and then (Buffer (Start) = ASCII.CR
190 or else Buffer (Start) = ASCII.LF)
191 loop
192 Start := Start + 1;
193 end loop;
194
195 Last := Start;
196
197 while Last < Buffer'Last
198 and then Buffer (Last + 1) /= ASCII.CR
199 and then Buffer (Last + 1) /= ASCII.LF
200 loop
201 Last := Last + 1;
202 end loop;
203
204 Match (Obj_Regexp, Buffer (Start .. Last), Matched);
205
206 if GCC then
207 if Matched (0) = No_Match then
208 First := Start;
209 else
210 First := Matched (0).Last + 1;
211 end if;
212
213 Length := Write (FD, Buffer (First)'Address, Last - First + 1);
214
215 if Start = Last or else Buffer (Last) = '\' then
216 Length := Write (FD, NL (1)'Address, NL'Length);
217 else
218 Length := Write (FD, Colon (1)'Address, Colon'Length);
219 end if;
220
221 else
222 if Matched (0) = No_Match then
223 First := Start;
224 else
225 Length :=
226 Write (FD, Buffer (Start)'Address,
227 Matched (0).Last - Start - 1);
228 Length := Write (FD, Base (Base'First)'Address, Base'Length);
229 First := Matched (0).Last + 1;
230 end if;
231
232 Length := Write (FD, Buffer (First)'Address, Last - First + 1);
233 Length := Write (FD, NL (1)'Address, NL'Length);
234 end if;
235
236 Start := Last + 1;
237 end loop;
238
239 Close (FD);
240 Free (Buffer);
241 end Deps;
242
243 ------------
244 -- Extend --
245 ------------
246
247 procedure Extend (Dir : String) is
248
249 procedure Recursive_Extend (D : String);
250 -- Recursively display all subdirectories of D.
251
252 ----------------------
253 -- Recursive_Extend --
254 ----------------------
255
256 procedure Recursive_Extend (D : String) is
257 Iter : Dir_Type;
258 Buffer : String (1 .. 8192);
259 Last : Natural;
260
261 begin
262 Open (Iter, D);
263
264 loop
265 Read (Iter, Buffer, Last);
266
267 exit when Last = 0;
268
269 if Buffer (1 .. Last) /= "."
270 and then Buffer (1 .. Last) /= ".."
271 then
272 declare
273 Abs_Dir : constant String := D & Buffer (1 .. Last);
274
275 begin
276 if Is_Directory (Abs_Dir)
277 and then not Is_Symbolic_Link (Abs_Dir)
278 then
279 Put (' ' & Abs_Dir);
280 Recursive_Extend (Abs_Dir & '/');
281 end if;
282 end;
283 end if;
284 end loop;
285
286 Close (Iter);
287
288 exception
289 when Directory_Error =>
290 null;
291 end Recursive_Extend;
292
293 -- Start of processing for Extend
294
295 begin
296 if Dir'Length < 3
297 or else (Dir (Dir'Last - 2) /= '/'
298 and then Dir (Dir'Last - 2) /= Directory_Separator)
299 or else Dir (Dir'Last - 1 .. Dir'Last) /= "**"
300 then
301 Put (Dir);
302 return;
303 end if;
304
305 declare
306 D : constant String := Dir (Dir'First .. Dir'Last - 2);
307 begin
308 Put (D);
309 Recursive_Extend (D);
310 end;
311 end Extend;
312
313 -----------
314 -- Usage --
315 -----------
316
317 procedure Usage is
318 begin
319 Put_Line (Standard_Error, "usage: gprcmd cmd [arguments]");
320 Put_Line (Standard_Error, "where cmd is one of the following commands:");
321 Put_Line (Standard_Error, " pwd " &
322 "display current directory");
323 Put_Line (Standard_Error, " to_lower " &
324 "display next argument in lower case");
325 Put_Line (Standard_Error, " to_absolute " &
326 "convert pathnames to absolute " &
327 "directories when needed");
328 Put_Line (Standard_Error, " cat " &
329 "dump contents of a given file");
330 Put_Line (Standard_Error, " extend " &
331 "handle recursive directories " &
332 "(""/**"" notation)");
333 Put_Line (Standard_Error, " deps " &
334 "post process dependency makefiles");
335 Put_Line (Standard_Error, " stamp " &
336 "copy file time stamp from file1 to file2");
337 OS_Exit (1);
338 end Usage;
339
340 -- Start of processing for Gprcmd
341
342 begin
343 Check_Args (Argument_Count > 0);
344
345 declare
346 Cmd : constant String := Argument (1);
347
348 begin
349 if Cmd = "-v" then
350 Put_Line (Standard_Error, Version);
351 Usage;
352
353 elsif Cmd = "pwd" then
354 Put (Format_Pathname (Get_Current_Dir, UNIX));
355
356 elsif Cmd = "cat" then
357 Check_Args (Argument_Count = 2);
358 Cat (Argument (2));
359
360 elsif Cmd = "to_lower" then
361 Check_Args (Argument_Count >= 2);
362
363 for J in 2 .. Argument_Count loop
364 Put (To_Lower (Argument (J)));
365
366 if J < Argument_Count then
367 Put (' ');
368 end if;
369 end loop;
370
371 elsif Cmd = "to_absolute" then
372 Check_Args (Argument_Count > 2);
373
374 declare
375 Dir : constant String := Argument (2);
376
377 begin
378 for J in 3 .. Argument_Count loop
379 if Is_Absolute_Path (Argument (J)) then
380 Put (Format_Pathname (Argument (J), UNIX));
381 else
382 Put (Format_Pathname (Normalize_Pathname (Argument (J), Dir),
383 UNIX));
384 end if;
385
386 if J < Argument_Count then
387 Put (' ');
388 end if;
389 end loop;
390 end;
391
392 elsif Cmd = "extend" then
393 Check_Args (Argument_Count >= 2);
394
395 declare
396 Dir : constant String := Argument (2);
397
398 begin
399 for J in 3 .. Argument_Count loop
400 if Is_Absolute_Path (Argument (J)) then
401 Extend (Format_Pathname (Argument (J), UNIX));
402 else
403 Extend
404 (Format_Pathname (Normalize_Pathname (Argument (J), Dir),
405 UNIX));
406 end if;
407
408 if J < Argument_Count then
409 Put (' ');
410 end if;
411 end loop;
412 end;
413
414 elsif Cmd = "deps" then
415 Check_Args (Argument_Count in 3 .. 4);
416 Deps (Argument (2), Argument (3), GCC => Argument_Count = 4);
417
418 elsif Cmd = "stamp" then
419 Check_Args (Argument_Count = 3);
420 Copy_Time_Stamp (Argument (2), Argument (3));
421 end if;
422 end;
423 end Gprcmd;