1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
5 -- I N T E R F A C E S . C . S T R I N G S --
9 -- Copyright (C) 1992-2017, 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 ------------------------------------------------------------------------------
32 with System
; use System
;
33 with System
.Storage_Elements
; use System
.Storage_Elements
;
35 with Ada
.Unchecked_Conversion
;
37 package body Interfaces
.C
.Strings
is
39 -- Note that the type chars_ptr has a pragma No_Strict_Aliasing in the
40 -- spec, to prevent any assumptions about aliasing for values of this type,
41 -- since arbitrary addresses can be converted, and it is quite likely that
42 -- this type will in fact be used for aliasing values of other types.
44 function To_chars_ptr
is
45 new Ada
.Unchecked_Conversion
(System
.Parameters
.C_Address
, chars_ptr
);
47 function To_Address
is
48 new Ada
.Unchecked_Conversion
(chars_ptr
, System
.Parameters
.C_Address
);
50 -----------------------
51 -- Local Subprograms --
52 -----------------------
54 function Peek
(From
: chars_ptr
) return char
;
56 -- Given a chars_ptr value, obtain referenced character
58 procedure Poke
(Value
: char
; Into
: chars_ptr
);
60 -- Given a chars_ptr, modify referenced Character value
62 function "+" (Left
: chars_ptr
; Right
: size_t
) return chars_ptr
;
64 -- Address arithmetic on chars_ptr value
66 function Position_Of_Nul
(Into
: char_array
) return size_t
;
67 -- Returns position of the first Nul in Into or Into'Last + 1 if none
69 -- We can't use directly System.Memory because the categorization is not
70 -- compatible, so we directly import here the malloc and free routines.
72 function Memory_Alloc
(Size
: size_t
) return chars_ptr
;
73 pragma Import
(C
, Memory_Alloc
, System
.Parameters
.C_Malloc_Linkname
);
75 procedure Memory_Free
(Address
: chars_ptr
);
76 pragma Import
(C
, Memory_Free
, "__gnat_free");
82 function "+" (Left
: chars_ptr
; Right
: size_t
) return chars_ptr
is
84 return To_chars_ptr
(To_Address
(Left
) + Storage_Offset
(Right
));
91 procedure Free
(Item
: in out chars_ptr
) is
93 if Item
= Null_Ptr
then
105 function New_Char_Array
(Chars
: char_array
) return chars_ptr
is
110 -- Get index of position of null. If Index > Chars'Last,
111 -- nul is absent and must be added explicitly.
113 Index
:= Position_Of_Nul
(Into
=> Chars
);
114 Pointer
:= Memory_Alloc
((Index
- Chars
'First + 1));
116 -- If nul is present, transfer string up to and including nul
118 if Index
<= Chars
'Last then
119 Update
(Item
=> Pointer
,
121 Chars
=> Chars
(Chars
'First .. Index
),
124 -- If original string has no nul, transfer whole string and add
125 -- terminator explicitly.
127 Update
(Item
=> Pointer
,
131 Poke
(nul
, Into
=> Pointer
+ size_t
'(Chars'Length));
141 function New_String (Str : String) return chars_ptr is
143 -- It's important that this subprogram uses the heap directly to compute
144 -- the result, and doesn't copy the string on the stack, otherwise its
145 -- use is limited when used from tasks on large strings.
147 Result : constant chars_ptr := Memory_Alloc (Str'Length + 1);
149 Result_Array : char_array (1 .. Str'Length + 1);
150 for Result_Array'Address use To_Address (Result);
151 pragma Import (Ada, Result_Array);
158 Target => Result_Array,
168 function Peek (From : chars_ptr) return char is
170 return char (From.all);
177 procedure Poke (Value : char; Into : chars_ptr) is
179 Into.all := Character (Value);
182 ---------------------
183 -- Position_Of_Nul --
184 ---------------------
186 function Position_Of_Nul (Into : char_array) return size_t is
188 for J in Into'Range loop
189 if Into (J) = nul then
194 return Into'Last + 1;
201 function Strlen (Item : chars_ptr) return size_t is
202 Item_Index : size_t := 0;
205 if Item = Null_Ptr then
206 raise Dereference_Error;
210 if Peek (Item + Item_Index) = nul then
214 Item_Index := Item_Index + 1;
222 function To_Chars_Ptr
223 (Item : char_array_access;
224 Nul_Check : Boolean := False) return chars_ptr
230 and then Position_Of_Nul (Into => Item.all) > Item'Last
232 raise Terminator_Error;
234 return To_chars_ptr (Item (Item'First)'Address);
246 Check : Boolean := True)
248 Index : chars_ptr := Item + Offset;
251 if Check and then Offset + Chars'Length > Strlen (Item) then
255 for J in Chars'Range loop
256 Poke (Chars (J), Into => Index);
257 Index := Index + size_t'(1);
265 Check
: Boolean := True)
268 -- Note: in RM 95, the Append_Nul => False parameter is omitted. But
269 -- this has the unintended consequence of truncating the string after
270 -- an update. As discussed in Ada 2005 AI-242, this was unintended,
271 -- and should be corrected. Since this is a clear error, it seems
272 -- appropriate to apply the correction in Ada 95 mode as well.
274 Update
(Item
, Offset
, To_C
(Str
, Append_Nul
=> False), Check
);
281 function Value
(Item
: chars_ptr
) return char_array
is
282 Result
: char_array
(0 .. Strlen
(Item
));
285 if Item
= Null_Ptr
then
286 raise Dereference_Error
;
289 -- Note that the following loop will also copy the terminating Nul
291 for J
in Result
'Range loop
292 Result
(J
) := Peek
(Item
+ J
);
300 Length
: size_t
) return char_array
303 if Item
= Null_Ptr
then
304 raise Dereference_Error
;
307 -- ACATS cxb3010 checks that Constraint_Error gets raised when Length
308 -- is 0. Seems better to check that Length is not null before declaring
309 -- an array with size_t bounds of 0 .. Length - 1 anyway.
312 raise Constraint_Error
;
316 Result
: char_array
(0 .. Length
- 1);
319 for J
in Result
'Range loop
320 Result
(J
) := Peek
(Item
+ J
);
322 if Result
(J
) = nul
then
323 return Result
(0 .. J
);
331 function Value
(Item
: chars_ptr
) return String is
333 return To_Ada
(Value
(Item
));
336 function Value
(Item
: chars_ptr
; Length
: size_t
) return String is
337 Result
: char_array
(0 .. Length
);
340 -- As per AI-00177, this is equivalent to:
342 -- To_Ada (Value (Item, Length) & nul);
344 if Item
= Null_Ptr
then
345 raise Dereference_Error
;
348 for J
in 0 .. Length
- 1 loop
349 Result
(J
) := Peek
(Item
+ J
);
351 if Result
(J
) = nul
then
352 return To_Ada
(Result
(0 .. J
));
356 Result
(Length
) := nul
;
357 return To_Ada
(Result
);
360 end Interfaces
.C
.Strings
;