1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 1992-2013, Free Software Foundation, Inc. --
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. --
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. --
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/>. --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
30 ------------------------------------------------------------------------------
33 with Namet
; use Namet
;
34 with Output
; use Output
;
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
,
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
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
));
87 for J
in 1 .. Len
loop
88 Name_Buffer
(Name_Len
+ J
) :=
89 Get_Character
(Get_String_Char
(S
, Int
(J
)));
92 Name_Len
:= Name_Len
+ Len
;
93 end Add_String_To_Name_Buffer
;
99 function End_String
return String_Id
is
104 ---------------------
105 -- Get_String_Char --
106 ---------------------
108 function Get_String_Char
(Id
: String_Id
; Index
: Int
) return Char_Code
is
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);
120 procedure Initialize
is
125 -- Set up the null string
128 Null_String_Id
:= End_String
;
137 String_Chars
.Locked
:= True;
138 Strings
.Locked
:= True;
139 String_Chars
.Release
;
149 Strings_Last
:= Strings
.Last
;
150 String_Chars_Last
:= String_Chars
.Last
;
159 Strings
.Set_Last
(Strings_Last
);
160 String_Chars
.Set_Last
(String_Chars_Last
);
167 -- Version to start completely new string
169 procedure Start_String
is
171 Strings
.Append
((String_Index
=> String_Chars
.Last
+ 1, Length
=> 0));
174 -- Version to start from initially stored string
176 procedure Start_String
(S
: String_Id
) is
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
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
192 Strings
.Table
(Strings
.Last
).String_Index
:=
193 String_Chars
.Last
+ 1;
195 for J
in 1 .. Strings
.Table
(S
).Length
loop
197 (String_Chars
.Table
(Strings
.Table
(S
).String_Index
+ (J
- 1)));
201 -- In either case the result string length is copied from the argument
203 Strings
.Table
(Strings
.Last
).Length
:= Strings
.Table
(S
).Length
;
206 -----------------------
207 -- Store_String_Char --
208 -----------------------
210 procedure Store_String_Char
(C
: Char_Code
) is
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
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
228 for J
in S
'First .. S
'Last loop
229 Store_String_Char
(Get_Char_Code
(S
(J
)));
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));
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
;
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
264 Store_String_Char
('-');
265 Store_String_Int
(-N
);
269 Store_String_Int
(N
/ 10);
272 Store_String_Char
(Character'Val (Character'Pos ('0') + N
mod 10));
274 end Store_String_Int
;
276 --------------------------
277 -- String_Chars_Address --
278 --------------------------
280 function String_Chars_Address
return System
.Address
is
282 return String_Chars
.Table
(0)'Address;
283 end String_Chars_Address
;
289 function String_Equal
(L
, R
: String_Id
) return Boolean is
290 Len
: constant Nat
:= Strings
.Table
(L
).Length
;
293 if Len
/= Strings
.Table
(R
).Length
then
296 for J
in 1 .. Len
loop
297 if Get_String_Char
(L
, J
) /= Get_String_Char
(R
, J
) then
306 -----------------------------
307 -- String_From_Name_Buffer --
308 -----------------------------
310 function String_From_Name_Buffer
return String_Id
is
314 for J
in 1 .. Name_Len
loop
315 Store_String_Char
(Get_Char_Code
(Name_Buffer
(J
)));
319 end String_From_Name_Buffer
;
325 function String_Length
(Id
: String_Id
) return Nat
is
327 return Strings
.Table
(Id
).Length
;
330 ---------------------------
331 -- String_To_Name_Buffer --
332 ---------------------------
334 procedure String_To_Name_Buffer
(S
: String_Id
) is
336 Name_Len
:= Natural (String_Length
(S
));
338 for J
in 1 .. Name_Len
loop
340 Get_Character
(Get_String_Char
(S
, Int
(J
)));
342 end String_To_Name_Buffer
;
344 ---------------------
345 -- Strings_Address --
346 ---------------------
348 function Strings_Address
return System
.Address
is
350 return Strings
.Table
(First_String_Id
)'Address;
357 procedure Tree_Read
is
359 String_Chars
.Tree_Read
;
367 procedure Tree_Write
is
369 String_Chars
.Tree_Write
;
379 String_Chars
.Locked
:= False;
380 Strings
.Locked
:= False;
383 -------------------------
384 -- Unstore_String_Char --
385 -------------------------
387 procedure Unstore_String_Char
is
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
407 procedure Write_Hex_Byte
(J
: Char_Code
) is
408 Hexd
: constant array (Char_Code
range 0 .. 15) of Character :=
411 Write_Char
(Hexd
(J
/ 16));
412 Write_Char
(Hexd
(J
mod 16));
415 -- Start of processing for Write_Char_Code
418 if Code
in 16#
20#
.. 16#
7E#
then
419 Write_Char
(Character'Val (Code
));
425 if Code
> 16#FF_FFFF#
then
426 Write_Hex_Byte
(Code
/ 2 ** 24);
429 if Code
> 16#FFFF#
then
430 Write_Hex_Byte
((Code
/ 2 ** 16) mod 256);
433 if Code
> 16#FF#
then
434 Write_Hex_Byte
((Code
/ 256) mod 256);
437 Write_Hex_Byte
(Code
mod 256);
443 ------------------------------
444 -- Write_String_Table_Entry --
445 ------------------------------
447 procedure Write_String_Table_Entry
(Id
: String_Id
) is
451 if Id
= No_String
then
452 Write_Str
("no string");
457 for J
in 1 .. String_Length
(Id
) loop
458 C
:= Get_String_Char
(Id
, J
);
460 if C
= Character'Pos ('"') then
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
));
478 end Write_String_Table_Entry
;