2005-01-22 Thomas Koenig <Thomas.Koenig@online.de>
[official-gcc.git] / gcc / ada / a-strsea.adb
blob62089c31f8e2f1d201e2983a31eaccb0153afe60
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-2004 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);
284 begin
285 for J in Source'Range loop
286 Mapped_Source (J) := Mapping.all (Source (J));
287 end loop;
288 end;
290 -- Forwards case
292 if Going = Forward then
293 for J in 1 .. Source'Length - Pattern'Length + 1 loop
294 Cur_Index := Source'First + J - 1;
296 if Pattern = Mapped_Source
297 (Cur_Index .. Cur_Index + Pattern'Length - 1)
298 then
299 return Cur_Index;
300 end if;
301 end loop;
303 -- Backwards case
305 else
306 for J in reverse 1 .. Source'Length - Pattern'Length + 1 loop
307 Cur_Index := Source'First + J - 1;
309 if Pattern = Mapped_Source
310 (Cur_Index .. Cur_Index + Pattern'Length - 1)
311 then
312 return Cur_Index;
313 end if;
314 end loop;
315 end if;
317 return 0;
318 end Index;
320 function Index
321 (Source : String;
322 Set : Maps.Character_Set;
323 Test : Membership := Inside;
324 Going : Direction := Forward) return Natural
326 begin
327 -- Forwards case
329 if Going = Forward then
330 for J in Source'Range loop
331 if Belongs (Source (J), Set, Test) then
332 return J;
333 end if;
334 end loop;
336 -- Backwards case
338 else
339 for J in reverse Source'Range loop
340 if Belongs (Source (J), Set, Test) then
341 return J;
342 end if;
343 end loop;
344 end if;
346 -- Fall through if no match
348 return 0;
349 end Index;
351 ---------------------
352 -- Index_Non_Blank --
353 ---------------------
355 function Index_Non_Blank
356 (Source : String;
357 Going : Direction := Forward) return Natural
359 begin
360 if Going = Forward then
361 for J in Source'Range loop
362 if Source (J) /= ' ' then
363 return J;
364 end if;
365 end loop;
367 else -- Going = Backward
368 for J in reverse Source'Range loop
369 if Source (J) /= ' ' then
370 return J;
371 end if;
372 end loop;
373 end if;
375 -- Fall through if no match
377 return 0;
379 end Index_Non_Blank;
381 end Ada.Strings.Search;