Add an UNSPEC_PROLOGUE_USE to prevent the link register from being considered dead.
[official-gcc.git] / gcc / ada / a-strsea.adb
blob3a60883c470f3eea7bd868975e0843241c4adfc4
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT RUNTIME COMPONENTS --
4 -- --
5 -- A D A . S T R I N G S . S E A R C H --
6 -- --
7 -- B o d y --
8 -- --
9 -- --
10 -- Copyright (C) 1992,1993,1994,1995,1996 Free Software Foundation, Inc. --
11 -- --
12 -- GNAT is free software; you can redistribute it and/or modify it under --
13 -- terms of the GNU General Public License as published by the Free Soft- --
14 -- ware Foundation; either version 2, or (at your option) any later ver- --
15 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
16 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
17 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
18 -- for more details. You should have received a copy of the GNU General --
19 -- Public License distributed with GNAT; see file COPYING. If not, write --
20 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
21 -- MA 02111-1307, USA. --
22 -- --
23 -- As a special exception, if other files instantiate generics from this --
24 -- unit, or you link this unit with other files to produce an executable, --
25 -- this unit does not by itself cause the resulting executable to be --
26 -- covered by the GNU General Public License. This exception does not --
27 -- however invalidate any other reasons why the executable file might be --
28 -- covered by the GNU Public License. --
29 -- --
30 -- GNAT was originally developed by the GNAT team at New York University. --
31 -- Extensive contributions were provided by Ada Core Technologies Inc. --
32 -- --
33 ------------------------------------------------------------------------------
35 -- Note: This code is derived from the ADAR.CSH public domain Ada 83
36 -- versions of the Appendix C string handling packages (code extracted
37 -- from Ada.Strings.Fixed). A significant change is that we optimize the
38 -- case of identity mappings for Count and Index, and also Index_Non_Blank
39 -- is specialized (rather than using the general Index routine).
42 with Ada.Strings.Maps; use Ada.Strings.Maps;
44 package body Ada.Strings.Search is
46 -----------------------
47 -- Local Subprograms --
48 -----------------------
50 function Belongs
51 (Element : Character;
52 Set : Maps.Character_Set;
53 Test : Membership)
54 return Boolean;
55 pragma Inline (Belongs);
56 -- Determines if the given element is in (Test = Inside) or not in
57 -- (Test = Outside) the given character set.
59 -------------
60 -- Belongs --
61 -------------
63 function Belongs
64 (Element : Character;
65 Set : Maps.Character_Set;
66 Test : Membership)
67 return Boolean
69 begin
70 if Test = Inside then
71 return Is_In (Element, Set);
72 else
73 return not Is_In (Element, Set);
74 end if;
75 end Belongs;
77 -----------
78 -- Count --
79 -----------
81 function Count
82 (Source : in String;
83 Pattern : in String;
84 Mapping : in Maps.Character_Mapping := Maps.Identity)
85 return Natural
87 N : Natural;
88 J : Natural;
90 Mapped_Source : String (Source'Range);
92 begin
93 for J in Source'Range loop
94 Mapped_Source (J) := Value (Mapping, Source (J));
95 end loop;
97 if Pattern = "" then
98 raise Pattern_Error;
99 end if;
101 N := 0;
102 J := Source'First;
104 while J <= Source'Last - (Pattern'Length - 1) loop
105 if Mapped_Source (J .. J + (Pattern'Length - 1)) = Pattern then
106 N := N + 1;
107 J := J + Pattern'Length;
108 else
109 J := J + 1;
110 end if;
111 end loop;
113 return N;
114 end Count;
116 function Count
117 (Source : in String;
118 Pattern : in String;
119 Mapping : in Maps.Character_Mapping_Function)
120 return Natural
122 Mapped_Source : String (Source'Range);
123 N : Natural;
124 J : Natural;
126 begin
127 if Pattern = "" then
128 raise Pattern_Error;
129 end if;
131 -- We make sure Access_Check is unsuppressed so that the Mapping.all
132 -- call will generate a friendly Constraint_Error if the value for
133 -- Mapping is uninitialized (and hence null).
135 declare
136 pragma Unsuppress (Access_Check);
138 begin
139 for J in Source'Range loop
140 Mapped_Source (J) := Mapping.all (Source (J));
141 end loop;
142 end;
144 N := 0;
145 J := Source'First;
147 while J <= Source'Last - (Pattern'Length - 1) loop
148 if Mapped_Source (J .. J + (Pattern'Length - 1)) = Pattern then
149 N := N + 1;
150 J := J + Pattern'Length;
151 else
152 J := J + 1;
153 end if;
154 end loop;
156 return N;
157 end Count;
159 function Count
160 (Source : in String;
161 Set : in Maps.Character_Set)
162 return Natural
164 N : Natural := 0;
166 begin
167 for J in Source'Range loop
168 if Is_In (Source (J), Set) then
169 N := N + 1;
170 end if;
171 end loop;
173 return N;
174 end Count;
176 ----------------
177 -- Find_Token --
178 ----------------
180 procedure Find_Token
181 (Source : in String;
182 Set : in Maps.Character_Set;
183 Test : in Membership;
184 First : out Positive;
185 Last : out Natural)
187 begin
188 for J in Source'Range loop
189 if Belongs (Source (J), Set, Test) then
190 First := J;
192 for K in J + 1 .. Source'Last loop
193 if not Belongs (Source (K), Set, Test) then
194 Last := K - 1;
195 return;
196 end if;
197 end loop;
199 -- Here if J indexes 1st char of token, and all chars
200 -- after J are in the token
202 Last := Source'Last;
203 return;
204 end if;
205 end loop;
207 -- Here if no token found
209 First := Source'First;
210 Last := 0;
211 end Find_Token;
213 -----------
214 -- Index --
215 -----------
217 function Index
218 (Source : in String;
219 Pattern : in String;
220 Going : in Direction := Forward;
221 Mapping : in Maps.Character_Mapping := Maps.Identity)
222 return Natural
224 Cur_Index : Natural;
225 Mapped_Source : String (Source'Range);
228 begin
229 if Pattern = "" then
230 raise Pattern_Error;
231 end if;
233 for J in Source'Range loop
234 Mapped_Source (J) := Value (Mapping, Source (J));
235 end loop;
237 -- Forwards case
239 if Going = Forward then
240 for J in 1 .. Source'Length - Pattern'Length + 1 loop
241 Cur_Index := Source'First + J - 1;
243 if Pattern = Mapped_Source
244 (Cur_Index .. Cur_Index + Pattern'Length - 1)
245 then
246 return Cur_Index;
247 end if;
248 end loop;
250 -- Backwards case
252 else
253 for J in reverse 1 .. Source'Length - Pattern'Length + 1 loop
254 Cur_Index := Source'First + J - 1;
256 if Pattern = Mapped_Source
257 (Cur_Index .. Cur_Index + Pattern'Length - 1)
258 then
259 return Cur_Index;
260 end if;
261 end loop;
262 end if;
264 -- Fall through if no match found. Note that the loops are skipped
265 -- completely in the case of the pattern being longer than the source.
267 return 0;
268 end Index;
270 function Index (Source : in String;
271 Pattern : in String;
272 Going : in Direction := Forward;
273 Mapping : in Maps.Character_Mapping_Function)
274 return Natural
276 Mapped_Source : String (Source'Range);
277 Cur_Index : Natural;
279 begin
280 if Pattern = "" then
281 raise Pattern_Error;
282 end if;
284 -- We make sure Access_Check is unsuppressed so that the Mapping.all
285 -- call will generate a friendly Constraint_Error if the value for
286 -- Mapping is uninitialized (and hence null).
288 declare
289 pragma Unsuppress (Access_Check);
291 begin
292 for J in Source'Range loop
293 Mapped_Source (J) := Mapping.all (Source (J));
294 end loop;
295 end;
297 -- Forwards case
299 if Going = Forward then
300 for J in 1 .. Source'Length - Pattern'Length + 1 loop
301 Cur_Index := Source'First + J - 1;
303 if Pattern = Mapped_Source
304 (Cur_Index .. Cur_Index + Pattern'Length - 1)
305 then
306 return Cur_Index;
307 end if;
308 end loop;
310 -- Backwards case
312 else
313 for J in reverse 1 .. Source'Length - Pattern'Length + 1 loop
314 Cur_Index := Source'First + J - 1;
316 if Pattern = Mapped_Source
317 (Cur_Index .. Cur_Index + Pattern'Length - 1)
318 then
319 return Cur_Index;
320 end if;
321 end loop;
322 end if;
324 return 0;
325 end Index;
327 function Index
328 (Source : in String;
329 Set : in Maps.Character_Set;
330 Test : in Membership := Inside;
331 Going : in Direction := Forward)
332 return Natural
334 begin
335 -- Forwards case
337 if Going = Forward then
338 for J in Source'Range loop
339 if Belongs (Source (J), Set, Test) then
340 return J;
341 end if;
342 end loop;
344 -- Backwards case
346 else
347 for J in reverse Source'Range loop
348 if Belongs (Source (J), Set, Test) then
349 return J;
350 end if;
351 end loop;
352 end if;
354 -- Fall through if no match
356 return 0;
357 end Index;
359 ---------------------
360 -- Index_Non_Blank --
361 ---------------------
363 function Index_Non_Blank
364 (Source : in String;
365 Going : in Direction := Forward)
366 return Natural
368 begin
369 if Going = Forward then
370 for J in Source'Range loop
371 if Source (J) /= ' ' then
372 return J;
373 end if;
374 end loop;
376 else -- Going = Backward
377 for J in reverse Source'Range loop
378 if Source (J) /= ' ' then
379 return J;
380 end if;
381 end loop;
382 end if;
384 -- Fall through if no match
386 return 0;
388 end Index_Non_Blank;
390 end Ada.Strings.Search;