1------------------------------------------------------------------------------
2--                                                                          --
3--                         GNAT COMPILER COMPONENTS                         --
4--                                                                          --
5--                             S W I T C H - B                              --
6--                                                                          --
7--                                 B o d y                                  --
8--                                                                          --
9--          Copyright (C) 2001-2011, 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
26with Debug;  use Debug;
27with Osint;  use Osint;
28with Opt;    use Opt;
29
30with System.WCh_Con; use System.WCh_Con;
31
32package body Switch.B is
33
34   --------------------------
35   -- Scan_Binder_Switches --
36   --------------------------
37
38   procedure Scan_Binder_Switches (Switch_Chars : String) is
39      Max : constant Integer := Switch_Chars'Last;
40      Ptr : Integer          := Switch_Chars'First;
41      C   : Character        := ' ';
42
43      function Get_Optional_Filename return String_Ptr;
44      --  If current character is '=', return a newly allocated string that
45      --  contains the remainder of the current switch (after the '='), else
46      --  return null.
47
48      function Get_Stack_Size (S : Character) return Int;
49      --  Used for -d and -D to scan stack size including handling k/m. S is
50      --  set to 'd' or 'D' to indicate the switch being scanned.
51
52      ---------------------------
53      -- Get_Optional_Filename --
54      ---------------------------
55
56      function Get_Optional_Filename return String_Ptr is
57         Result : String_Ptr;
58
59      begin
60         if Ptr <= Max and then Switch_Chars (Ptr) = '=' then
61            if Ptr = Max then
62               Bad_Switch (Switch_Chars);
63            else
64               Result := new String'(Switch_Chars (Ptr + 1 .. Max));
65               Ptr := Max + 1;
66               return Result;
67            end if;
68         end if;
69
70         return null;
71      end Get_Optional_Filename;
72
73      --------------------
74      -- Get_Stack_Size --
75      --------------------
76
77      function Get_Stack_Size (S : Character) return Int is
78         Result : Int;
79
80      begin
81         Scan_Pos (Switch_Chars, Max, Ptr, Result, S);
82
83         --  In the following code, we enable overflow checking since the
84         --  multiplication by K or M may cause overflow, which is an error.
85
86         declare
87            pragma Unsuppress (Overflow_Check);
88
89         begin
90            --  Check for additional character 'k' (for kilobytes) or 'm' (for
91            --  Megabytes), but only if we have not reached the end of the
92            --  switch string. Note that if this appears before the end of the
93            --  string we will get an error when we test to make sure that the
94            --  string is exhausted (at the end of the case).
95
96            if Ptr <= Max then
97               if Switch_Chars (Ptr) = 'k' then
98                  Result := Result * 1024;
99                  Ptr := Ptr + 1;
100
101               elsif Switch_Chars (Ptr) = 'm' then
102                  Result := Result * (1024 * 1024);
103                  Ptr := Ptr + 1;
104               end if;
105            end if;
106
107         exception
108            when Constraint_Error =>
109               Osint.Fail ("numeric value out of range for switch: " & S);
110         end;
111
112         return Result;
113      end Get_Stack_Size;
114
115   --  Start of processing for Scan_Binder_Switches
116
117   begin
118      --  Skip past the initial character (must be the switch character)
119
120      if Ptr = Max then
121         Bad_Switch (Switch_Chars);
122      else
123         Ptr := Ptr + 1;
124      end if;
125
126      --  A little check, "gnat" at the start of a switch is not allowed except
127      --  for the compiler
128
129      if Switch_Chars'Last >= Ptr + 3
130        and then Switch_Chars (Ptr .. Ptr + 3) = "gnat"
131      then
132         Osint.Fail ("invalid switch: """ & Switch_Chars & """"
133                     & " (gnat not needed here)");
134      end if;
135
136      --  Loop to scan through switches given in switch string
137
138      Check_Switch : begin
139         C := Switch_Chars (Ptr);
140
141         case C is
142
143         --  Processing for a switch
144
145         when 'a' =>
146            Ptr := Ptr + 1;
147            Use_Pragma_Linker_Constructor := True;
148
149         --  Processing for A switch
150
151         when 'A' =>
152            Ptr := Ptr + 1;
153            Output_ALI_List := True;
154            ALI_List_Filename := Get_Optional_Filename;
155
156         --  Processing for b switch
157
158         when 'b' =>
159            Ptr := Ptr + 1;
160            Brief_Output := True;
161
162         --  Processing for c switch
163
164         when 'c' =>
165            Ptr := Ptr + 1;
166            Check_Only := True;
167
168         --  Processing for d switch
169
170         when 'd' =>
171
172            if Ptr = Max then
173               Bad_Switch (Switch_Chars);
174            end if;
175
176            Ptr := Ptr + 1;
177            C := Switch_Chars (Ptr);
178
179            --  Case where character after -d is a digit (default stack size)
180
181            if C in '0' .. '9' then
182
183               --  In this case, we process the default primary stack size
184
185               Default_Stack_Size := Get_Stack_Size ('d');
186
187            --  Case where character after -d is not digit (debug flags)
188
189            else
190               --  Note: for the debug switch, the remaining characters in this
191               --  switch field must all be debug flags, since all valid switch
192               --  characters are also valid debug characters. This switch is
193               --  not documented on purpose because it is only used by the
194               --  implementors.
195
196               --  Loop to scan out debug flags
197
198               loop
199                  C := Switch_Chars (Ptr);
200
201                  if C in 'a' .. 'z' or else C in 'A' .. 'Z' then
202                     Set_Debug_Flag (C);
203                  else
204                     Bad_Switch (Switch_Chars);
205                  end if;
206
207                  Ptr := Ptr + 1;
208                  exit when Ptr > Max;
209               end loop;
210            end if;
211
212         --  Processing for D switch
213
214         when 'D' =>
215            if Ptr = Max then
216               Bad_Switch (Switch_Chars);
217            end if;
218
219            Ptr := Ptr + 1;
220            Default_Sec_Stack_Size := Get_Stack_Size ('D');
221
222         --  Processing for e switch
223
224         when 'e' =>
225            Ptr := Ptr + 1;
226            Elab_Dependency_Output := True;
227
228         --  Processing for E switch
229
230         when 'E' =>
231            Ptr := Ptr + 1;
232            Exception_Tracebacks := True;
233
234         --  Processing for F switch
235
236         when 'F' =>
237            Ptr := Ptr + 1;
238            Force_Checking_Of_Elaboration_Flags := True;
239
240         --  Processing for g switch
241
242         when 'g' =>
243            Ptr := Ptr + 1;
244
245            if Ptr <= Max then
246               C := Switch_Chars (Ptr);
247
248               if C in '0' .. '3' then
249                  Debugger_Level :=
250                    Character'Pos
251                      (Switch_Chars (Ptr)) - Character'Pos ('0');
252                  Ptr := Ptr + 1;
253               end if;
254
255            else
256               Debugger_Level := 2;
257            end if;
258
259         --  Processing for h switch
260
261         when 'h' =>
262            Ptr := Ptr + 1;
263            Usage_Requested := True;
264
265         --  Processing for H switch
266
267         when 'H' =>
268            if Ptr = Max then
269               Bad_Switch (Switch_Chars);
270            end if;
271
272            Ptr := Ptr + 1;
273            Scan_Nat (Switch_Chars, Max, Ptr, Heap_Size, C);
274
275            if Heap_Size /= 32 and then Heap_Size /= 64 then
276               Bad_Switch (Switch_Chars);
277            end if;
278
279         --  Processing for i switch
280
281         when 'i' =>
282            if Ptr = Max then
283               Bad_Switch (Switch_Chars);
284            end if;
285
286            Ptr := Ptr + 1;
287            C := Switch_Chars (Ptr);
288
289            if C in '1' .. '5'
290              or else C = '8'
291              or else C = 'p'
292              or else C = 'f'
293              or else C = 'n'
294              or else C = 'w'
295            then
296               Identifier_Character_Set := C;
297               Ptr := Ptr + 1;
298            else
299               Bad_Switch (Switch_Chars);
300            end if;
301
302         --  Processing for K switch
303
304         when 'K' =>
305            Ptr := Ptr + 1;
306            Output_Linker_Option_List := True;
307
308         --  Processing for l switch
309
310         when 'l' =>
311            Ptr := Ptr + 1;
312            Elab_Order_Output := True;
313
314         --  Processing for m switch
315
316         when 'm' =>
317            if Ptr = Max then
318               Bad_Switch (Switch_Chars);
319            end if;
320
321            Ptr := Ptr + 1;
322            Scan_Pos (Switch_Chars, Max, Ptr, Maximum_Messages, C);
323
324         --  Processing for n switch
325
326         when 'n' =>
327            Ptr := Ptr + 1;
328            Bind_Main_Program := False;
329
330            --  Note: The -L option of the binder also implies -n, so
331            --  any change here must also be reflected in the processing
332            --  for -L that is found in Gnatbind.Scan_Bind_Arg.
333
334         --  Processing for o switch
335
336         when 'o' =>
337            Ptr := Ptr + 1;
338
339            if Output_File_Name_Present then
340               Osint.Fail ("duplicate -o switch");
341            else
342               Output_File_Name_Present := True;
343            end if;
344
345         --  Processing for O switch
346
347         when 'O' =>
348            Ptr := Ptr + 1;
349            Output_Object_List := True;
350            Object_List_Filename := Get_Optional_Filename;
351
352         --  Processing for p switch
353
354         when 'p' =>
355            Ptr := Ptr + 1;
356            Pessimistic_Elab_Order := True;
357
358         --  Processing for P switch
359
360         when 'P' =>
361            Ptr := Ptr + 1;
362            CodePeer_Mode := True;
363
364         --  Processing for q switch
365
366         when 'q' =>
367            Ptr := Ptr + 1;
368            Quiet_Output := True;
369
370         --  Processing for r switch
371
372         when 'r' =>
373            Ptr := Ptr + 1;
374            List_Restrictions := True;
375
376         --  Processing for R switch
377
378         when 'R' =>
379            Ptr := Ptr + 1;
380            List_Closure := True;
381
382         --  Processing for s switch
383
384         when 's' =>
385            Ptr := Ptr + 1;
386            All_Sources := True;
387            Check_Source_Files := True;
388
389         --  Processing for t switch
390
391         when 't' =>
392            Ptr := Ptr + 1;
393            Tolerate_Consistency_Errors := True;
394
395         --  Processing for T switch
396
397         when 'T' =>
398            if Ptr = Max then
399               Bad_Switch (Switch_Chars);
400            end if;
401
402            Ptr := Ptr + 1;
403            Time_Slice_Set := True;
404            Scan_Nat (Switch_Chars, Max, Ptr, Time_Slice_Value, C);
405            Time_Slice_Value := Time_Slice_Value * 1_000;
406
407         --  Processing for u switch
408
409         when 'u' =>
410            if Ptr = Max then
411               Bad_Switch (Switch_Chars);
412            end if;
413
414            Ptr := Ptr + 1;
415            Dynamic_Stack_Measurement := True;
416            Scan_Nat
417              (Switch_Chars,
418               Max,
419               Ptr,
420               Dynamic_Stack_Measurement_Array_Size,
421               C);
422
423         --  Processing for v switch
424
425         when 'v' =>
426            Ptr := Ptr + 1;
427            Verbose_Mode := True;
428
429         --  Processing for w switch
430
431         when 'w' =>
432            if Ptr = Max then
433               Bad_Switch (Switch_Chars);
434            end if;
435
436            --  For the binder we only allow suppress/error cases
437
438            Ptr := Ptr + 1;
439
440            case Switch_Chars (Ptr) is
441               when 'e' =>
442                  Warning_Mode := Treat_As_Error;
443
444               when 's' =>
445                  Warning_Mode := Suppress;
446
447               when others =>
448                  Bad_Switch (Switch_Chars);
449            end case;
450
451            Ptr := Ptr + 1;
452
453         --  Processing for W switch
454
455         when 'W' =>
456            Ptr := Ptr + 1;
457
458            if Ptr > Max then
459               Bad_Switch (Switch_Chars);
460            end if;
461
462            begin
463               Wide_Character_Encoding_Method :=
464                 Get_WC_Encoding_Method (Switch_Chars (Ptr));
465            exception
466               when Constraint_Error =>
467                  Bad_Switch (Switch_Chars);
468            end;
469
470            Wide_Character_Encoding_Method_Specified := True;
471
472            Upper_Half_Encoding :=
473              Wide_Character_Encoding_Method in WC_Upper_Half_Encoding_Method;
474
475            Ptr := Ptr + 1;
476
477         --  Processing for x switch
478
479         when 'x' =>
480            Ptr := Ptr + 1;
481            All_Sources := False;
482            Check_Source_Files := False;
483
484         --  Processing for X switch
485
486         when 'X' =>
487            if Ptr = Max then
488               Bad_Switch (Switch_Chars);
489            end if;
490
491            Ptr := Ptr + 1;
492            Scan_Pos (Switch_Chars, Max, Ptr, Default_Exit_Status, C);
493
494         --  Processing for y switch
495
496         when 'y' =>
497            Ptr := Ptr + 1;
498            Leap_Seconds_Support := True;
499
500         --  Processing for z switch
501
502         when 'z' =>
503            Ptr := Ptr + 1;
504            No_Main_Subprogram := True;
505
506         --  Processing for Z switch
507
508         when 'Z' =>
509            Ptr := Ptr + 1;
510            Zero_Formatting := True;
511
512         --  Processing for --RTS
513
514         when '-' =>
515
516            if Ptr + 4 <= Max and then
517              Switch_Chars (Ptr + 1 .. Ptr + 3) = "RTS"
518            then
519               Ptr := Ptr + 4;
520
521               if Switch_Chars (Ptr) /= '=' or else Ptr = Max then
522                  Osint.Fail ("missing path for --RTS");
523
524               else
525                  --  Valid --RTS switch
526
527                  Opt.No_Stdinc := True;
528                  Opt.RTS_Switch := True;
529
530                  declare
531                     Src_Path_Name : constant String_Ptr :=
532                                       Get_RTS_Search_Dir
533                                         (Switch_Chars
534                                           (Ptr + 1 .. Switch_Chars'Last),
535                                          Include);
536                     Lib_Path_Name : constant String_Ptr :=
537                                       Get_RTS_Search_Dir
538                                         (Switch_Chars
539                                           (Ptr + 1 .. Switch_Chars'Last),
540                                          Objects);
541
542                  begin
543                     if Src_Path_Name /= null and then
544                       Lib_Path_Name /= null
545                     then
546                        --  Set the RTS_*_Path_Name variables, so that the
547                        --  correct directories will be set when a subsequent
548                        --  call Osint.Add_Default_Search_Dirs is made.
549
550                        RTS_Src_Path_Name := Src_Path_Name;
551                        RTS_Lib_Path_Name := Lib_Path_Name;
552
553                        Ptr := Max + 1;
554
555                     elsif  Src_Path_Name = null
556                       and then Lib_Path_Name = null
557                     then
558                        Osint.Fail ("RTS path not valid: missing " &
559                                    "adainclude and adalib directories");
560                     elsif Src_Path_Name = null then
561                        Osint.Fail ("RTS path not valid: missing " &
562                                    "adainclude directory");
563                     elsif  Lib_Path_Name = null then
564                        Osint.Fail ("RTS path not valid: missing " &
565                                    "adalib directory");
566                     end if;
567                  end;
568               end if;
569
570            else
571               Bad_Switch (Switch_Chars);
572            end if;
573
574         --  Anything else is an error (illegal switch character)
575
576         when others =>
577            Bad_Switch (Switch_Chars);
578         end case;
579
580         if Ptr <= Max then
581            Bad_Switch (Switch_Chars);
582         end if;
583      end Check_Switch;
584   end Scan_Binder_Switches;
585
586end Switch.B;
587