PR target/82524
[official-gcc.git] / gcc / ada / output.adb
blob33a08055db5dba9ab5c9613feeb769439bd4b1cd
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- O U T P U T --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 1992-2017, 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. --
17 -- --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
21 -- --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
26 -- --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
29 -- --
30 ------------------------------------------------------------------------------
32 package body Output is
34 Buffer : String (1 .. Buffer_Max + 1) := (others => '*');
35 for Buffer'Alignment use 4;
36 -- Buffer used to build output line. We do line buffering because it is
37 -- needed for the support of the debug-generated-code option (-gnatD). Note
38 -- any attempt to write more output to a line than can fit in the buffer
39 -- will be silently ignored. The alignment clause improves the efficiency
40 -- of the save/restore procedures.
42 Next_Col : Positive range 1 .. Buffer'Length + 1 := 1;
43 -- Column about to be written
45 Current_FD : File_Descriptor := Standout;
46 -- File descriptor for current output
48 Special_Output_Proc : Output_Proc := null;
49 -- Record argument to last call to Set_Special_Output. If this is
50 -- non-null, then we are in special output mode.
52 Indentation_Amount : constant Positive := 3;
53 -- Number of spaces to output for each indentation level
55 Indentation_Limit : constant Positive := 40;
56 -- Indentation beyond this number of spaces wraps around
58 pragma Assert (Indentation_Limit < Buffer_Max / 2);
59 -- Make sure this is substantially shorter than the line length
61 Cur_Indentation : Natural := 0;
62 -- Number of spaces to indent each line
64 -----------------------
65 -- Local_Subprograms --
66 -----------------------
68 procedure Flush_Buffer;
69 -- Flush buffer if non-empty and reset column counter
71 ---------------------------
72 -- Cancel_Special_Output --
73 ---------------------------
75 procedure Cancel_Special_Output is
76 begin
77 Special_Output_Proc := null;
78 end Cancel_Special_Output;
80 ------------
81 -- Column --
82 ------------
84 function Column return Pos is
85 begin
86 return Pos (Next_Col);
87 end Column;
89 ----------------------
90 -- Delete_Last_Char --
91 ----------------------
93 procedure Delete_Last_Char is
94 begin
95 if Next_Col /= 1 then
96 Next_Col := Next_Col - 1;
97 end if;
98 end Delete_Last_Char;
100 ------------------
101 -- Flush_Buffer --
102 ------------------
104 procedure Flush_Buffer is
105 Write_Error : exception;
106 -- Raised if Write fails
108 ------------------
109 -- Write_Buffer --
110 ------------------
112 procedure Write_Buffer (Buf : String);
113 -- Write out Buf, either using Special_Output_Proc, or the normal way
114 -- using Write. Raise Write_Error if Write fails (presumably due to disk
115 -- full). Write_Error is not used in the case of Special_Output_Proc.
117 procedure Write_Buffer (Buf : String) is
118 begin
119 -- If Special_Output_Proc has been set, then use it
121 if Special_Output_Proc /= null then
122 Special_Output_Proc.all (Buf);
124 -- If output is not set, then output to either standard output
125 -- or standard error.
127 elsif Write (Current_FD, Buf'Address, Buf'Length) /= Buf'Length then
128 raise Write_Error;
130 end if;
131 end Write_Buffer;
133 Len : constant Natural := Next_Col - 1;
135 -- Start of processing for Flush_Buffer
137 begin
138 if Len /= 0 then
139 begin
140 -- If there's no indentation, or if the line is too long with
141 -- indentation, or if it's a blank line, just write the buffer.
143 if Cur_Indentation = 0
144 or else Cur_Indentation + Len > Buffer_Max
145 or else Buffer (1 .. Len) = (1 => ASCII.LF)
146 then
147 Write_Buffer (Buffer (1 .. Len));
149 -- Otherwise, construct a new buffer with preceding spaces, and
150 -- write that.
152 else
153 declare
154 Indented_Buffer : constant String :=
155 (1 .. Cur_Indentation => ' ') &
156 Buffer (1 .. Len);
157 begin
158 Write_Buffer (Indented_Buffer);
159 end;
160 end if;
162 exception
163 when Write_Error =>
165 -- If there are errors with standard error just quit. Otherwise
166 -- set the output to standard error before reporting a failure
167 -- and quitting.
169 if Current_FD /= Standerr then
170 Current_FD := Standerr;
171 Next_Col := 1;
172 Write_Line ("fatal error: disk full");
173 end if;
175 OS_Exit (2);
176 end;
178 -- Buffer is now empty
180 Next_Col := 1;
181 end if;
182 end Flush_Buffer;
184 -------------------
185 -- Ignore_Output --
186 -------------------
188 procedure Ignore_Output (S : String) is
189 begin
190 null;
191 end Ignore_Output;
193 ------------
194 -- Indent --
195 ------------
197 procedure Indent is
198 begin
199 -- The "mod" in the following assignment is to cause a wrap around in
200 -- the case where there is too much indentation.
202 Cur_Indentation :=
203 (Cur_Indentation + Indentation_Amount) mod Indentation_Limit;
204 end Indent;
206 ---------------
207 -- Last_Char --
208 ---------------
210 function Last_Char return Character is
211 begin
212 if Next_Col /= 1 then
213 return Buffer (Next_Col - 1);
214 else
215 return ASCII.NUL;
216 end if;
217 end Last_Char;
219 -------------
220 -- Outdent --
221 -------------
223 procedure Outdent is
224 begin
225 -- The "mod" here undoes the wrap around from Indent above
227 Cur_Indentation :=
228 (Cur_Indentation - Indentation_Amount) mod Indentation_Limit;
229 end Outdent;
231 ---------------------------
232 -- Restore_Output_Buffer --
233 ---------------------------
235 procedure Restore_Output_Buffer (S : Saved_Output_Buffer) is
236 begin
237 Next_Col := S.Next_Col;
238 Cur_Indentation := S.Cur_Indentation;
239 Buffer (1 .. Next_Col - 1) := S.Buffer (1 .. Next_Col - 1);
240 end Restore_Output_Buffer;
242 ------------------------
243 -- Save_Output_Buffer --
244 ------------------------
246 function Save_Output_Buffer return Saved_Output_Buffer is
247 S : Saved_Output_Buffer;
248 begin
249 S.Buffer (1 .. Next_Col - 1) := Buffer (1 .. Next_Col - 1);
250 S.Next_Col := Next_Col;
251 S.Cur_Indentation := Cur_Indentation;
252 Next_Col := 1;
253 Cur_Indentation := 0;
254 return S;
255 end Save_Output_Buffer;
257 ------------------------
258 -- Set_Special_Output --
259 ------------------------
261 procedure Set_Special_Output (P : Output_Proc) is
262 begin
263 Special_Output_Proc := P;
264 end Set_Special_Output;
266 ----------------
267 -- Set_Output --
268 ----------------
270 procedure Set_Output (FD : File_Descriptor) is
271 begin
272 if Special_Output_Proc = null then
273 Flush_Buffer;
274 end if;
276 Current_FD := FD;
277 end Set_Output;
279 ------------------------
280 -- Set_Standard_Error --
281 ------------------------
283 procedure Set_Standard_Error is
284 begin
285 Set_Output (Standerr);
286 end Set_Standard_Error;
288 -------------------------
289 -- Set_Standard_Output --
290 -------------------------
292 procedure Set_Standard_Output is
293 begin
294 Set_Output (Standout);
295 end Set_Standard_Output;
297 -------
298 -- w --
299 -------
301 procedure w (C : Character) is
302 begin
303 Write_Char (''');
304 Write_Char (C);
305 Write_Char (''');
306 Write_Eol;
307 end w;
309 procedure w (S : String) is
310 begin
311 Write_Str (S);
312 Write_Eol;
313 end w;
315 procedure w (V : Int) is
316 begin
317 Write_Int (V);
318 Write_Eol;
319 end w;
321 procedure w (B : Boolean) is
322 begin
323 if B then
324 w ("True");
325 else
326 w ("False");
327 end if;
328 end w;
330 procedure w (L : String; C : Character) is
331 begin
332 Write_Str (L);
333 Write_Char (' ');
334 w (C);
335 end w;
337 procedure w (L : String; S : String) is
338 begin
339 Write_Str (L);
340 Write_Char (' ');
341 w (S);
342 end w;
344 procedure w (L : String; V : Int) is
345 begin
346 Write_Str (L);
347 Write_Char (' ');
348 w (V);
349 end w;
351 procedure w (L : String; B : Boolean) is
352 begin
353 Write_Str (L);
354 Write_Char (' ');
355 w (B);
356 end w;
358 ----------------
359 -- Write_Char --
360 ----------------
362 procedure Write_Char (C : Character) is
363 begin
364 pragma Assert (Next_Col in Buffer'Range);
365 if Next_Col = Buffer'Length then
366 Write_Eol;
367 end if;
369 if C = ASCII.LF then
370 Write_Eol;
371 else
372 Buffer (Next_Col) := C;
373 Next_Col := Next_Col + 1;
374 end if;
375 end Write_Char;
377 ---------------
378 -- Write_Eol --
379 ---------------
381 procedure Write_Eol is
382 begin
383 -- Remove any trailing spaces
385 while Next_Col > 1 and then Buffer (Next_Col - 1) = ' ' loop
386 Next_Col := Next_Col - 1;
387 end loop;
389 Buffer (Next_Col) := ASCII.LF;
390 Next_Col := Next_Col + 1;
391 Flush_Buffer;
392 end Write_Eol;
394 ---------------------------
395 -- Write_Eol_Keep_Blanks --
396 ---------------------------
398 procedure Write_Eol_Keep_Blanks is
399 begin
400 Buffer (Next_Col) := ASCII.LF;
401 Next_Col := Next_Col + 1;
402 Flush_Buffer;
403 end Write_Eol_Keep_Blanks;
405 ----------------------
406 -- Write_Erase_Char --
407 ----------------------
409 procedure Write_Erase_Char (C : Character) is
410 begin
411 if Next_Col /= 1 and then Buffer (Next_Col - 1) = C then
412 Next_Col := Next_Col - 1;
413 end if;
414 end Write_Erase_Char;
416 ---------------
417 -- Write_Int --
418 ---------------
420 procedure Write_Int (Val : Int) is
421 -- Type Int has one extra negative number (i.e. two's complement), so we
422 -- work with negative numbers here. Otherwise, negating Int'First will
423 -- overflow.
425 subtype Nonpositive is Int range Int'First .. 0;
426 procedure Write_Abs (Val : Nonpositive);
427 -- Write out the absolute value of Val
429 procedure Write_Abs (Val : Nonpositive) is
430 begin
431 if Val < -9 then
432 Write_Abs (Val / 10); -- Recursively write higher digits
433 end if;
435 Write_Char (Character'Val (-(Val rem 10) + Character'Pos ('0')));
436 end Write_Abs;
438 begin
439 if Val < 0 then
440 Write_Char ('-');
441 Write_Abs (Val);
442 else
443 Write_Abs (-Val);
444 end if;
445 end Write_Int;
447 ----------------
448 -- Write_Line --
449 ----------------
451 procedure Write_Line (S : String) is
452 begin
453 Write_Str (S);
454 Write_Eol;
455 end Write_Line;
457 ------------------
458 -- Write_Spaces --
459 ------------------
461 procedure Write_Spaces (N : Nat) is
462 begin
463 for J in 1 .. N loop
464 Write_Char (' ');
465 end loop;
466 end Write_Spaces;
468 ---------------
469 -- Write_Str --
470 ---------------
472 procedure Write_Str (S : String) is
473 begin
474 for J in S'Range loop
475 Write_Char (S (J));
476 end loop;
477 end Write_Str;
479 end Output;