Merge from the pain train
[official-gcc.git] / gcc / ada / a-strsea.adb
blobc4e4d5db54bc411acf0b4bf513fa85d69412977b
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 -- Copyright (C) 1992-2005 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 2, 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. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING. If not, write --
19 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
20 -- MA 02111-1307, USA. --
21 -- --
22 -- As a special exception, if other files instantiate generics from this --
23 -- unit, or you link this unit with other files to produce an executable, --
24 -- this unit does not by itself cause the resulting executable to be --
25 -- covered by the GNU General Public License. This exception does not --
26 -- however invalidate any other reasons why the executable file might be --
27 -- covered by the GNU Public License. --
28 -- --
29 -- GNAT was originally developed by the GNAT team at New York University. --
30 -- Extensive contributions were provided by Ada Core Technologies Inc. --
31 -- --
32 ------------------------------------------------------------------------------
34 -- Note: This code is derived from the ADAR.CSH public domain Ada 83
35 -- versions of the Appendix C string handling packages (code extracted
36 -- from Ada.Strings.Fixed). A significant change is that we optimize the
37 -- case of identity mappings for Count and Index, and also Index_Non_Blank
38 -- is specialized (rather than using the general Index routine).
41 with Ada.Strings.Maps; use Ada.Strings.Maps;
43 package body Ada.Strings.Search is
45 -----------------------
46 -- Local Subprograms --
47 -----------------------
49 function Belongs
50 (Element : Character;
51 Set : Maps.Character_Set;
52 Test : Membership) return Boolean;
53 pragma Inline (Belongs);
54 -- Determines if the given element is in (Test = Inside) or not in
55 -- (Test = Outside) the given character set.
57 -------------
58 -- Belongs --
59 -------------
61 function Belongs
62 (Element : Character;
63 Set : Maps.Character_Set;
64 Test : Membership) return Boolean
66 begin
67 if Test = Inside then
68 return Is_In (Element, Set);
69 else
70 return not Is_In (Element, Set);
71 end if;
72 end Belongs;
74 -----------
75 -- Count --
76 -----------
78 function Count
79 (Source : String;
80 Pattern : String;
81 Mapping : Maps.Character_Mapping := Maps.Identity) return Natural
83 N : Natural;
84 J : Natural;
86 Mapped_Source : String (Source'Range);
88 begin
89 for J in Source'Range loop
90 Mapped_Source (J) := Value (Mapping, Source (J));
91 end loop;
93 if Pattern = "" then
94 raise Pattern_Error;
95 end if;
97 N := 0;
98 J := Source'First;
100 while J <= Source'Last - (Pattern'Length - 1) loop
101 if Mapped_Source (J .. J + (Pattern'Length - 1)) = Pattern then
102 N := N + 1;
103 J := J + Pattern'Length;
104 else
105 J := J + 1;
106 end if;
107 end loop;
109 return N;
110 end Count;
112 function Count
113 (Source : String;
114 Pattern : String;
115 Mapping : Maps.Character_Mapping_Function) return Natural
117 Mapped_Source : String (Source'Range);
118 N : Natural;
119 J : Natural;
121 begin
122 if Pattern = "" then
123 raise Pattern_Error;
124 end if;
126 -- We make sure Access_Check is unsuppressed so that the Mapping.all
127 -- call will generate a friendly Constraint_Error if the value for
128 -- Mapping is uninitialized (and hence null).
130 declare
131 pragma Unsuppress (Access_Check);
133 begin
134 for J in Source'Range loop
135 Mapped_Source (J) := Mapping.all (Source (J));
136 end loop;
137 end;
139 N := 0;
140 J := Source'First;
142 while J <= Source'Last - (Pattern'Length - 1) loop
143 if Mapped_Source (J .. J + (Pattern'Length - 1)) = Pattern then
144 N := N + 1;
145 J := J + Pattern'Length;
146 else
147 J := J + 1;
148 end if;
149 end loop;
151 return N;
152 end Count;
154 function Count
155 (Source : String;
156 Set : Maps.Character_Set) return Natural
158 N : Natural := 0;
160 begin
161 for J in Source'Range loop
162 if Is_In (Source (J), Set) then
163 N := N + 1;
164 end if;
165 end loop;
167 return N;
168 end Count;
170 ----------------
171 -- Find_Token --
172 ----------------
174 procedure Find_Token
175 (Source : String;
176 Set : Maps.Character_Set;
177 Test : Membership;
178 First : out Positive;
179 Last : out Natural)
181 begin
182 for J in Source'Range loop
183 if Belongs (Source (J), Set, Test) then
184 First := J;
186 for K in J + 1 .. Source'Last loop
187 if not Belongs (Source (K), Set, Test) then
188 Last := K - 1;
189 return;
190 end if;
191 end loop;
193 -- Here if J indexes 1st char of token, and all chars
194 -- after J are in the token
196 Last := Source'Last;
197 return;
198 end if;
199 end loop;
201 -- Here if no token found
203 First := Source'First;
204 Last := 0;
205 end Find_Token;
207 -----------
208 -- Index --
209 -----------
211 function Index
212 (Source : String;
213 Pattern : String;
214 Going : Direction := Forward;
215 Mapping : Maps.Character_Mapping := Maps.Identity) return Natural
217 Cur_Index : Natural;
218 Mapped_Source : String (Source'Range);
221 begin
222 if Pattern = "" then
223 raise Pattern_Error;
224 end if;
226 for J in Source'Range loop
227 Mapped_Source (J) := Value (Mapping, Source (J));
228 end loop;
230 -- Forwards case
232 if Going = Forward then
233 for J in 1 .. Source'Length - Pattern'Length + 1 loop
234 Cur_Index := Source'First + J - 1;
236 if Pattern = Mapped_Source
237 (Cur_Index .. Cur_Index + Pattern'Length - 1)
238 then
239 return Cur_Index;
240 end if;
241 end loop;
243 -- Backwards case
245 else
246 for J in reverse 1 .. Source'Length - Pattern'Length + 1 loop
247 Cur_Index := Source'First + J - 1;
249 if Pattern = Mapped_Source
250 (Cur_Index .. Cur_Index + Pattern'Length - 1)
251 then
252 return Cur_Index;
253 end if;
254 end loop;
255 end if;
257 -- Fall through if no match found. Note that the loops are skipped
258 -- completely in the case of the pattern being longer than the source.
260 return 0;
261 end Index;
263 function Index
264 (Source : String;
265 Pattern : String;
266 Going : Direction := Forward;
267 Mapping : Maps.Character_Mapping_Function) return Natural
269 Mapped_Source : String (Source'Range);
270 Cur_Index : Natural;
272 begin
273 if Pattern = "" then
274 raise Pattern_Error;
275 end if;
277 -- We make sure Access_Check is unsuppressed so that the Mapping.all
278 -- call will generate a friendly Constraint_Error if the value for
279 -- Mapping is uninitialized (and hence null).
281 declare
282 pragma Unsuppress (Access_Check);
283 begin
284 for J in Source'Range loop
285 Mapped_Source (J) := Mapping.all (Source (J));
286 end loop;
287 end;
289 -- Forwards case
291 if Going = Forward then
292 for J in 1 .. Source'Length - Pattern'Length + 1 loop
293 Cur_Index := Source'First + J - 1;
295 if Pattern = Mapped_Source
296 (Cur_Index .. Cur_Index + Pattern'Length - 1)
297 then
298 return Cur_Index;
299 end if;
300 end loop;
302 -- Backwards case
304 else
305 for J in reverse 1 .. Source'Length - Pattern'Length + 1 loop
306 Cur_Index := Source'First + J - 1;
308 if Pattern = Mapped_Source
309 (Cur_Index .. Cur_Index + Pattern'Length - 1)
310 then
311 return Cur_Index;
312 end if;
313 end loop;
314 end if;
316 return 0;
317 end Index;
319 function Index
320 (Source : String;
321 Set : Maps.Character_Set;
322 Test : Membership := Inside;
323 Going : Direction := Forward) return Natural
325 begin
326 -- Forwards case
328 if Going = Forward then
329 for J in Source'Range loop
330 if Belongs (Source (J), Set, Test) then
331 return J;
332 end if;
333 end loop;
335 -- Backwards case
337 else
338 for J in reverse Source'Range loop
339 if Belongs (Source (J), Set, Test) then
340 return J;
341 end if;
342 end loop;
343 end if;
345 -- Fall through if no match
347 return 0;
348 end Index;
350 function Index
351 (Source : String;
352 Pattern : String;
353 From : Positive;
354 Going : Direction := Forward;
355 Mapping : Maps.Character_Mapping := Maps.Identity) return Natural
357 begin
358 if Going = Forward then
359 if From < Source'First then
360 raise Index_Error;
361 end if;
363 return
364 Index (Source (From .. Source'Last), Pattern, Forward, Mapping);
366 else
367 if From > Source'Last then
368 raise Index_Error;
369 end if;
371 return
372 Index (Source (Source'First .. From), Pattern, Backward, Mapping);
373 end if;
374 end Index;
376 function Index
377 (Source : String;
378 Pattern : String;
379 From : Positive;
380 Going : Direction := Forward;
381 Mapping : Maps.Character_Mapping_Function) return Natural
383 begin
384 if Going = Forward then
385 if From < Source'First then
386 raise Index_Error;
387 end if;
389 return Index
390 (Source (From .. Source'Last), Pattern, Forward, Mapping);
392 else
393 if From > Source'Last then
394 raise Index_Error;
395 end if;
397 return Index
398 (Source (Source'First .. From), Pattern, Backward, Mapping);
399 end if;
400 end Index;
402 function Index
403 (Source : String;
404 Set : Maps.Character_Set;
405 From : Positive;
406 Test : Membership := Inside;
407 Going : Direction := Forward) return Natural
409 begin
410 if Going = Forward then
411 if From < Source'First then
412 raise Index_Error;
413 end if;
415 return
416 Index (Source (From .. Source'Last), Set, Test, Forward);
418 else
419 if From > Source'Last then
420 raise Index_Error;
421 end if;
423 return
424 Index (Source (Source'First .. From), Set, Test, Backward);
425 end if;
426 end Index;
428 ---------------------
429 -- Index_Non_Blank --
430 ---------------------
432 function Index_Non_Blank
433 (Source : String;
434 Going : Direction := Forward) return Natural
436 begin
437 if Going = Forward then
438 for J in Source'Range loop
439 if Source (J) /= ' ' then
440 return J;
441 end if;
442 end loop;
444 else -- Going = Backward
445 for J in reverse Source'Range loop
446 if Source (J) /= ' ' then
447 return J;
448 end if;
449 end loop;
450 end if;
452 -- Fall through if no match
454 return 0;
455 end Index_Non_Blank;
457 function Index_Non_Blank
458 (Source : String;
459 From : Positive;
460 Going : Direction := Forward) return Natural
462 begin
463 if Going = Forward then
464 if From < Source'First then
465 raise Index_Error;
466 end if;
468 return
469 Index_Non_Blank (Source (From .. Source'Last), Forward);
471 else
472 if From > Source'Last then
473 raise Index_Error;
474 end if;
476 return
477 Index_Non_Blank (Source (Source'First .. From), Backward);
478 end if;
479 end Index_Non_Blank;
481 end Ada.Strings.Search;