2015-05-01 Paolo Carlini <paolo.carlini@oracle.com>
[official-gcc.git] / gcc / ada / stringt.adb
blob5a0c89c7d04f5bd80eb71dae9f3d6711ca0ab597
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- S T R I N G T --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 1992-2013, 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 with Alloc;
33 with Namet; use Namet;
34 with Output; use Output;
35 with Table;
37 package body Stringt is
39 -- The following table stores the sequence of character codes for the
40 -- stored string constants. The entries are referenced from the
41 -- separate Strings table.
43 package String_Chars is new Table.Table (
44 Table_Component_Type => Char_Code,
45 Table_Index_Type => Int,
46 Table_Low_Bound => 0,
47 Table_Initial => Alloc.String_Chars_Initial,
48 Table_Increment => Alloc.String_Chars_Increment,
49 Table_Name => "String_Chars");
51 -- The String_Id values reference entries in the Strings table, which
52 -- contains String_Entry records that record the length of each stored
53 -- string and its starting location in the String_Chars table.
55 type String_Entry is record
56 String_Index : Int;
57 Length : Nat;
58 end record;
60 package Strings is new Table.Table (
61 Table_Component_Type => String_Entry,
62 Table_Index_Type => String_Id'Base,
63 Table_Low_Bound => First_String_Id,
64 Table_Initial => Alloc.Strings_Initial,
65 Table_Increment => Alloc.Strings_Increment,
66 Table_Name => "Strings");
68 -- Note: it is possible that two entries in the Strings table can share
69 -- string data in the String_Chars table, and in particular this happens
70 -- when Start_String is called with a parameter that is the last string
71 -- currently allocated in the table.
73 Strings_Last : String_Id := First_String_Id;
74 String_Chars_Last : Int := 0;
75 -- Strings_Last and String_Chars_Last are used by procedure Mark and
76 -- Release to get a snapshot of the tables and to restore them to their
77 -- previous situation.
79 -------------------------------
80 -- Add_String_To_Name_Buffer --
81 -------------------------------
83 procedure Add_String_To_Name_Buffer (S : String_Id) is
84 Len : constant Natural := Natural (String_Length (S));
86 begin
87 for J in 1 .. Len loop
88 Name_Buffer (Name_Len + J) :=
89 Get_Character (Get_String_Char (S, Int (J)));
90 end loop;
92 Name_Len := Name_Len + Len;
93 end Add_String_To_Name_Buffer;
95 ----------------
96 -- End_String --
97 ----------------
99 function End_String return String_Id is
100 begin
101 return Strings.Last;
102 end End_String;
104 ---------------------
105 -- Get_String_Char --
106 ---------------------
108 function Get_String_Char (Id : String_Id; Index : Int) return Char_Code is
109 begin
110 pragma Assert (Id in First_String_Id .. Strings.Last
111 and then Index in 1 .. Strings.Table (Id).Length);
113 return String_Chars.Table (Strings.Table (Id).String_Index + Index - 1);
114 end Get_String_Char;
116 ----------------
117 -- Initialize --
118 ----------------
120 procedure Initialize is
121 begin
122 String_Chars.Init;
123 Strings.Init;
125 -- Set up the null string
127 Start_String;
128 Null_String_Id := End_String;
129 end Initialize;
131 ----------
132 -- Lock --
133 ----------
135 procedure Lock is
136 begin
137 String_Chars.Locked := True;
138 Strings.Locked := True;
139 String_Chars.Release;
140 Strings.Release;
141 end Lock;
143 ----------
144 -- Mark --
145 ----------
147 procedure Mark is
148 begin
149 Strings_Last := Strings.Last;
150 String_Chars_Last := String_Chars.Last;
151 end Mark;
153 -------------
154 -- Release --
155 -------------
157 procedure Release is
158 begin
159 Strings.Set_Last (Strings_Last);
160 String_Chars.Set_Last (String_Chars_Last);
161 end Release;
163 ------------------
164 -- Start_String --
165 ------------------
167 -- Version to start completely new string
169 procedure Start_String is
170 begin
171 Strings.Append ((String_Index => String_Chars.Last + 1, Length => 0));
172 end Start_String;
174 -- Version to start from initially stored string
176 procedure Start_String (S : String_Id) is
177 begin
178 Strings.Increment_Last;
180 -- Case of initial string value is at the end of the string characters
181 -- table, so it does not need copying, instead it can be shared.
183 if Strings.Table (S).String_Index + Strings.Table (S).Length =
184 String_Chars.Last + 1
185 then
186 Strings.Table (Strings.Last).String_Index :=
187 Strings.Table (S).String_Index;
189 -- Case of initial string value must be copied to new string
191 else
192 Strings.Table (Strings.Last).String_Index :=
193 String_Chars.Last + 1;
195 for J in 1 .. Strings.Table (S).Length loop
196 String_Chars.Append
197 (String_Chars.Table (Strings.Table (S).String_Index + (J - 1)));
198 end loop;
199 end if;
201 -- In either case the result string length is copied from the argument
203 Strings.Table (Strings.Last).Length := Strings.Table (S).Length;
204 end Start_String;
206 -----------------------
207 -- Store_String_Char --
208 -----------------------
210 procedure Store_String_Char (C : Char_Code) is
211 begin
212 String_Chars.Append (C);
213 Strings.Table (Strings.Last).Length :=
214 Strings.Table (Strings.Last).Length + 1;
215 end Store_String_Char;
217 procedure Store_String_Char (C : Character) is
218 begin
219 Store_String_Char (Get_Char_Code (C));
220 end Store_String_Char;
222 ------------------------
223 -- Store_String_Chars --
224 ------------------------
226 procedure Store_String_Chars (S : String) is
227 begin
228 for J in S'First .. S'Last loop
229 Store_String_Char (Get_Char_Code (S (J)));
230 end loop;
231 end Store_String_Chars;
233 procedure Store_String_Chars (S : String_Id) is
235 -- We are essentially doing this:
237 -- for J in 1 .. String_Length (S) loop
238 -- Store_String_Char (Get_String_Char (S, J));
239 -- end loop;
241 -- but when the string is long it's more efficient to grow the
242 -- String_Chars table all at once.
244 S_First : constant Int := Strings.Table (S).String_Index;
245 S_Len : constant Int := String_Length (S);
246 Old_Last : constant Int := String_Chars.Last;
247 New_Last : constant Int := Old_Last + S_Len;
249 begin
250 String_Chars.Set_Last (New_Last);
251 String_Chars.Table (Old_Last + 1 .. New_Last) :=
252 String_Chars.Table (S_First .. S_First + S_Len - 1);
253 Strings.Table (Strings.Last).Length :=
254 Strings.Table (Strings.Last).Length + S_Len;
255 end Store_String_Chars;
257 ----------------------
258 -- Store_String_Int --
259 ----------------------
261 procedure Store_String_Int (N : Int) is
262 begin
263 if N < 0 then
264 Store_String_Char ('-');
265 Store_String_Int (-N);
267 else
268 if N > 9 then
269 Store_String_Int (N / 10);
270 end if;
272 Store_String_Char (Character'Val (Character'Pos ('0') + N mod 10));
273 end if;
274 end Store_String_Int;
276 --------------------------
277 -- String_Chars_Address --
278 --------------------------
280 function String_Chars_Address return System.Address is
281 begin
282 return String_Chars.Table (0)'Address;
283 end String_Chars_Address;
285 ------------------
286 -- String_Equal --
287 ------------------
289 function String_Equal (L, R : String_Id) return Boolean is
290 Len : constant Nat := Strings.Table (L).Length;
292 begin
293 if Len /= Strings.Table (R).Length then
294 return False;
295 else
296 for J in 1 .. Len loop
297 if Get_String_Char (L, J) /= Get_String_Char (R, J) then
298 return False;
299 end if;
300 end loop;
302 return True;
303 end if;
304 end String_Equal;
306 -----------------------------
307 -- String_From_Name_Buffer --
308 -----------------------------
310 function String_From_Name_Buffer return String_Id is
311 begin
312 Start_String;
314 for J in 1 .. Name_Len loop
315 Store_String_Char (Get_Char_Code (Name_Buffer (J)));
316 end loop;
318 return End_String;
319 end String_From_Name_Buffer;
321 -------------------
322 -- String_Length --
323 -------------------
325 function String_Length (Id : String_Id) return Nat is
326 begin
327 return Strings.Table (Id).Length;
328 end String_Length;
330 ---------------------------
331 -- String_To_Name_Buffer --
332 ---------------------------
334 procedure String_To_Name_Buffer (S : String_Id) is
335 begin
336 Name_Len := Natural (String_Length (S));
338 for J in 1 .. Name_Len loop
339 Name_Buffer (J) :=
340 Get_Character (Get_String_Char (S, Int (J)));
341 end loop;
342 end String_To_Name_Buffer;
344 ---------------------
345 -- Strings_Address --
346 ---------------------
348 function Strings_Address return System.Address is
349 begin
350 return Strings.Table (First_String_Id)'Address;
351 end Strings_Address;
353 ---------------
354 -- Tree_Read --
355 ---------------
357 procedure Tree_Read is
358 begin
359 String_Chars.Tree_Read;
360 Strings.Tree_Read;
361 end Tree_Read;
363 ----------------
364 -- Tree_Write --
365 ----------------
367 procedure Tree_Write is
368 begin
369 String_Chars.Tree_Write;
370 Strings.Tree_Write;
371 end Tree_Write;
373 ------------
374 -- Unlock --
375 ------------
377 procedure Unlock is
378 begin
379 String_Chars.Locked := False;
380 Strings.Locked := False;
381 end Unlock;
383 -------------------------
384 -- Unstore_String_Char --
385 -------------------------
387 procedure Unstore_String_Char is
388 begin
389 String_Chars.Decrement_Last;
390 Strings.Table (Strings.Last).Length :=
391 Strings.Table (Strings.Last).Length - 1;
392 end Unstore_String_Char;
394 ---------------------
395 -- Write_Char_Code --
396 ---------------------
398 procedure Write_Char_Code (Code : Char_Code) is
400 procedure Write_Hex_Byte (J : Char_Code);
401 -- Write single hex byte (value in range 0 .. 255) as two digits
403 --------------------
404 -- Write_Hex_Byte --
405 --------------------
407 procedure Write_Hex_Byte (J : Char_Code) is
408 Hexd : constant array (Char_Code range 0 .. 15) of Character :=
409 "0123456789abcdef";
410 begin
411 Write_Char (Hexd (J / 16));
412 Write_Char (Hexd (J mod 16));
413 end Write_Hex_Byte;
415 -- Start of processing for Write_Char_Code
417 begin
418 if Code in 16#20# .. 16#7E# then
419 Write_Char (Character'Val (Code));
421 else
422 Write_Char ('[');
423 Write_Char ('"');
425 if Code > 16#FF_FFFF# then
426 Write_Hex_Byte (Code / 2 ** 24);
427 end if;
429 if Code > 16#FFFF# then
430 Write_Hex_Byte ((Code / 2 ** 16) mod 256);
431 end if;
433 if Code > 16#FF# then
434 Write_Hex_Byte ((Code / 256) mod 256);
435 end if;
437 Write_Hex_Byte (Code mod 256);
438 Write_Char ('"');
439 Write_Char (']');
440 end if;
441 end Write_Char_Code;
443 ------------------------------
444 -- Write_String_Table_Entry --
445 ------------------------------
447 procedure Write_String_Table_Entry (Id : String_Id) is
448 C : Char_Code;
450 begin
451 if Id = No_String then
452 Write_Str ("no string");
454 else
455 Write_Char ('"');
457 for J in 1 .. String_Length (Id) loop
458 C := Get_String_Char (Id, J);
460 if C = Character'Pos ('"') then
461 Write_Str ("""""");
462 else
463 Write_Char_Code (C);
464 end if;
466 -- If string is very long, quit
468 if J >= 1000 then -- arbitrary limit
469 Write_Str ("""...etc (length = ");
470 Write_Int (String_Length (Id));
471 Write_Str (")");
472 return;
473 end if;
474 end loop;
476 Write_Char ('"');
477 end if;
478 end Write_String_Table_Entry;
480 end Stringt;