OSDN Git Service

2012-01-10 Richard Guenther <rguenther@suse.de>
[pf3gnuchains/gcc-fork.git] / gcc / ada / i-cstrin.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT COMPILER COMPONENTS                         --
4 --                                                                          --
5 --                 I N T E R F A C E S . C . S T R I N G S                  --
6 --                                                                          --
7 --                                 B o d y                                  --
8 --                                                                          --
9 --          Copyright (C) 1992-2010, 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 ------------------------------------------------------------------------------
31
32 with System; use System;
33 with System.Storage_Elements; use System.Storage_Elements;
34
35 with Ada.Unchecked_Conversion;
36
37 package body Interfaces.C.Strings is
38
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.
43
44    function To_chars_ptr is
45       new Ada.Unchecked_Conversion (System.Parameters.C_Address, chars_ptr);
46
47    function To_Address is
48       new Ada.Unchecked_Conversion (chars_ptr, System.Parameters.C_Address);
49
50    -----------------------
51    -- Local Subprograms --
52    -----------------------
53
54    function Peek (From : chars_ptr) return char;
55    pragma Inline (Peek);
56    --  Given a chars_ptr value, obtain referenced character
57
58    procedure Poke (Value : char; Into : chars_ptr);
59    pragma Inline (Poke);
60    --  Given a chars_ptr, modify referenced Character value
61
62    function "+" (Left : chars_ptr; Right : size_t) return chars_ptr;
63    pragma Inline ("+");
64    --  Address arithmetic on chars_ptr value
65
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
68
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.
71
72    function Memory_Alloc (Size : size_t) return chars_ptr;
73    pragma Import (C, Memory_Alloc, System.Parameters.C_Malloc_Linkname);
74
75    procedure Memory_Free (Address : chars_ptr);
76    pragma Import (C, Memory_Free, "__gnat_free");
77
78    ---------
79    -- "+" --
80    ---------
81
82    function "+" (Left : chars_ptr; Right : size_t) return chars_ptr is
83    begin
84       return To_chars_ptr (To_Address (Left) + Storage_Offset (Right));
85    end "+";
86
87    ----------
88    -- Free --
89    ----------
90
91    procedure Free (Item : in out chars_ptr) is
92    begin
93       if Item = Null_Ptr then
94          return;
95       end if;
96
97       Memory_Free (Item);
98       Item := Null_Ptr;
99    end Free;
100
101    --------------------
102    -- New_Char_Array --
103    --------------------
104
105    function New_Char_Array (Chars : char_array) return chars_ptr is
106       Index   : size_t;
107       Pointer : chars_ptr;
108
109    begin
110       --  Get index of position of null. If Index > Chars'Last,
111       --  nul is absent and must be added explicitly.
112
113       Index := Position_Of_Nul (Into => Chars);
114       Pointer := Memory_Alloc ((Index - Chars'First + 1));
115
116       --  If nul is present, transfer string up to and including nul
117
118       if Index <= Chars'Last then
119          Update (Item   => Pointer,
120                  Offset => 0,
121                  Chars  => Chars (Chars'First .. Index),
122                  Check  => False);
123       else
124          --  If original string has no nul, transfer whole string and add
125          --  terminator explicitly.
126
127          Update (Item   => Pointer,
128                  Offset => 0,
129                  Chars  => Chars,
130                  Check  => False);
131          Poke (nul, Into => Pointer + size_t'(Chars'Length));
132       end if;
133
134       return Pointer;
135    end New_Char_Array;
136
137    ----------------
138    -- New_String --
139    ----------------
140
141    function New_String (Str : String) return chars_ptr is
142
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.
146
147       Result : constant chars_ptr := Memory_Alloc (Str'Length + 1);
148
149       Result_Array : char_array  (1 .. Str'Length + 1);
150       for Result_Array'Address use To_Address (Result);
151       pragma Import (Ada, Result_Array);
152
153       Count : size_t;
154
155    begin
156       To_C
157         (Item       => Str,
158          Target     => Result_Array,
159          Count      => Count,
160          Append_Nul => True);
161       return Result;
162    end New_String;
163
164    ----------
165    -- Peek --
166    ----------
167
168    function Peek (From : chars_ptr) return char is
169    begin
170       return char (From.all);
171    end Peek;
172
173    ----------
174    -- Poke --
175    ----------
176
177    procedure Poke (Value : char; Into : chars_ptr) is
178    begin
179       Into.all := Character (Value);
180    end Poke;
181
182    ---------------------
183    -- Position_Of_Nul --
184    ---------------------
185
186    function Position_Of_Nul (Into : char_array) return size_t is
187    begin
188       for J in Into'Range loop
189          if Into (J) = nul then
190             return J;
191          end if;
192       end loop;
193
194       return Into'Last + 1;
195    end Position_Of_Nul;
196
197    ------------
198    -- Strlen --
199    ------------
200
201    function Strlen (Item : chars_ptr) return size_t is
202       Item_Index : size_t := 0;
203
204    begin
205       if Item = Null_Ptr then
206          raise Dereference_Error;
207       end if;
208
209       loop
210          if Peek (Item + Item_Index) = nul then
211             return Item_Index;
212          end if;
213
214          Item_Index := Item_Index + 1;
215       end loop;
216    end Strlen;
217
218    ------------------
219    -- To_Chars_Ptr --
220    ------------------
221
222    function To_Chars_Ptr
223      (Item      : char_array_access;
224       Nul_Check : Boolean := False) return chars_ptr
225    is
226    begin
227       if Item = null then
228          return Null_Ptr;
229       elsif Nul_Check
230         and then Position_Of_Nul (Into => Item.all) > Item'Last
231       then
232          raise Terminator_Error;
233       else
234          return To_chars_ptr (Item (Item'First)'Address);
235       end if;
236    end To_Chars_Ptr;
237
238    ------------
239    -- Update --
240    ------------
241
242    procedure Update
243      (Item   : chars_ptr;
244       Offset : size_t;
245       Chars  : char_array;
246       Check  : Boolean := True)
247    is
248       Index : chars_ptr := Item + Offset;
249
250    begin
251       if Check and then Offset + Chars'Length  > Strlen (Item) then
252          raise Update_Error;
253       end if;
254
255       for J in Chars'Range loop
256          Poke (Chars (J), Into => Index);
257          Index := Index + size_t'(1);
258       end loop;
259    end Update;
260
261    procedure Update
262      (Item   : chars_ptr;
263       Offset : size_t;
264       Str    : String;
265       Check  : Boolean := True)
266    is
267    begin
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.
273
274       Update (Item, Offset, To_C (Str, Append_Nul => False), Check);
275    end Update;
276
277    -----------
278    -- Value --
279    -----------
280
281    function Value (Item : chars_ptr) return char_array is
282       Result : char_array (0 .. Strlen (Item));
283
284    begin
285       if Item = Null_Ptr then
286          raise Dereference_Error;
287       end if;
288
289       --  Note that the following loop will also copy the terminating Nul
290
291       for J in Result'Range loop
292          Result (J) := Peek (Item + J);
293       end loop;
294
295       return Result;
296    end Value;
297
298    function Value
299      (Item   : chars_ptr;
300       Length : size_t) return char_array
301    is
302    begin
303       if Item = Null_Ptr then
304          raise Dereference_Error;
305       end if;
306
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.
310
311       if Length = 0 then
312          raise Constraint_Error;
313       end if;
314
315       declare
316          Result : char_array (0 .. Length - 1);
317
318       begin
319          for J in Result'Range loop
320             Result (J) := Peek (Item + J);
321
322             if Result (J) = nul then
323                return Result (0 .. J);
324             end if;
325          end loop;
326
327          return Result;
328       end;
329    end Value;
330
331    function Value (Item : chars_ptr) return String is
332    begin
333       return To_Ada (Value (Item));
334    end Value;
335
336    function Value (Item : chars_ptr; Length : size_t) return String is
337       Result : char_array (0 .. Length);
338
339    begin
340       --  As per AI-00177, this is equivalent to:
341
342       --    To_Ada (Value (Item, Length) & nul);
343
344       if Item = Null_Ptr then
345          raise Dereference_Error;
346       end if;
347
348       for J in 0 .. Length - 1 loop
349          Result (J) := Peek (Item + J);
350
351          if Result (J) = nul then
352             return To_Ada (Result (0 .. J));
353          end if;
354       end loop;
355
356       Result (Length) := nul;
357       return To_Ada (Result);
358    end Value;
359
360 end Interfaces.C.Strings;