2010-11-11 Jakub Jelinek <jakub@redhat.com>
[official-gcc.git] / gcc / ada / a-stwise.adb
blobadc8e5f621a56800fdd923aae15d1ee716e648ee
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT RUN-TIME COMPONENTS --
4 -- --
5 -- A D A . S T R I N G S . W I D E _ S E A R C H --
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 ------------------------------------------------------------------------------
32 with Ada.Strings.Wide_Maps; use Ada.Strings.Wide_Maps;
33 with System; use System;
35 package body Ada.Strings.Wide_Search is
37 -----------------------
38 -- Local Subprograms --
39 -----------------------
41 function Belongs
42 (Element : Wide_Character;
43 Set : Wide_Maps.Wide_Character_Set;
44 Test : Membership) return Boolean;
45 pragma Inline (Belongs);
46 -- Determines if the given element is in (Test = Inside) or not in
47 -- (Test = Outside) the given character set.
49 -------------
50 -- Belongs --
51 -------------
53 function Belongs
54 (Element : Wide_Character;
55 Set : Wide_Maps.Wide_Character_Set;
56 Test : Membership) return Boolean
58 begin
59 if Test = Inside then
60 return Is_In (Element, Set);
61 else
62 return not Is_In (Element, Set);
63 end if;
64 end Belongs;
66 -----------
67 -- Count --
68 -----------
70 function Count
71 (Source : Wide_String;
72 Pattern : Wide_String;
73 Mapping : Wide_Maps.Wide_Character_Mapping := Wide_Maps.Identity)
74 return Natural
76 PL1 : constant Integer := Pattern'Length - 1;
77 Num : Natural;
78 Ind : Natural;
79 Cur : Natural;
81 begin
82 if Pattern = "" then
83 raise Pattern_Error;
84 end if;
86 Num := 0;
87 Ind := Source'First;
89 -- Unmapped case
91 if Mapping'Address = Wide_Maps.Identity'Address then
92 while Ind <= Source'Last - PL1 loop
93 if Pattern = Source (Ind .. Ind + PL1) then
94 Num := Num + 1;
95 Ind := Ind + Pattern'Length;
96 else
97 Ind := Ind + 1;
98 end if;
99 end loop;
101 -- Mapped case
103 else
104 while Ind <= Source'Last - PL1 loop
105 Cur := Ind;
106 for K in Pattern'Range loop
107 if Pattern (K) /= Value (Mapping, Source (Cur)) then
108 Ind := Ind + 1;
109 goto Cont;
110 else
111 Cur := Cur + 1;
112 end if;
113 end loop;
115 Num := Num + 1;
116 Ind := Ind + Pattern'Length;
118 <<Cont>>
119 null;
120 end loop;
121 end if;
123 -- Return result
125 return Num;
126 end Count;
128 function Count
129 (Source : Wide_String;
130 Pattern : Wide_String;
131 Mapping : Wide_Maps.Wide_Character_Mapping_Function) return Natural
133 PL1 : constant Integer := Pattern'Length - 1;
134 Num : Natural;
135 Ind : Natural;
136 Cur : Natural;
138 begin
139 if Pattern = "" then
140 raise Pattern_Error;
141 end if;
143 -- Check for null pointer in case checks are off
145 if Mapping = null then
146 raise Constraint_Error;
147 end if;
149 Num := 0;
150 Ind := Source'First;
151 while Ind <= Source'Last - PL1 loop
152 Cur := Ind;
153 for K in Pattern'Range loop
154 if Pattern (K) /= Mapping (Source (Cur)) then
155 Ind := Ind + 1;
156 goto Cont;
157 else
158 Cur := Cur + 1;
159 end if;
160 end loop;
162 Num := Num + 1;
163 Ind := Ind + Pattern'Length;
165 <<Cont>>
166 null;
167 end loop;
169 return Num;
170 end Count;
172 function Count
173 (Source : Wide_String;
174 Set : Wide_Maps.Wide_Character_Set) return Natural
176 N : Natural := 0;
178 begin
179 for J in Source'Range loop
180 if Is_In (Source (J), Set) then
181 N := N + 1;
182 end if;
183 end loop;
185 return N;
186 end Count;
188 ----------------
189 -- Find_Token --
190 ----------------
192 procedure Find_Token
193 (Source : Wide_String;
194 Set : Wide_Maps.Wide_Character_Set;
195 From : Positive;
196 Test : Membership;
197 First : out Positive;
198 Last : out Natural)
200 begin
201 for J in From .. Source'Last loop
202 if Belongs (Source (J), Set, Test) then
203 First := J;
205 for K in J + 1 .. Source'Last loop
206 if not Belongs (Source (K), Set, Test) then
207 Last := K - 1;
208 return;
209 end if;
210 end loop;
212 -- Here if J indexes first char of token, and all chars after J
213 -- are in the token.
215 Last := Source'Last;
216 return;
217 end if;
218 end loop;
220 -- Here if no token found
222 First := From;
223 Last := 0;
224 end Find_Token;
226 procedure Find_Token
227 (Source : Wide_String;
228 Set : Wide_Maps.Wide_Character_Set;
229 Test : Membership;
230 First : out Positive;
231 Last : out Natural)
233 begin
234 for J in Source'Range loop
235 if Belongs (Source (J), Set, Test) then
236 First := J;
238 for K in J + 1 .. Source'Last loop
239 if not Belongs (Source (K), Set, Test) then
240 Last := K - 1;
241 return;
242 end if;
243 end loop;
245 -- Here if J indexes first char of token, and all chars after J
246 -- are in the token.
248 Last := Source'Last;
249 return;
250 end if;
251 end loop;
253 -- Here if no token found
255 First := Source'First;
256 Last := 0;
257 end Find_Token;
259 -----------
260 -- Index --
261 -----------
263 function Index
264 (Source : Wide_String;
265 Pattern : Wide_String;
266 Going : Direction := Forward;
267 Mapping : Wide_Maps.Wide_Character_Mapping := Wide_Maps.Identity)
268 return Natural
270 PL1 : constant Integer := Pattern'Length - 1;
271 Cur : Natural;
273 Ind : Integer;
274 -- Index for start of match check. This can be negative if the pattern
275 -- length is greater than the string length, which is why this variable
276 -- is Integer instead of Natural. In this case, the search loops do not
277 -- execute at all, so this Ind value is never used.
279 begin
280 if Pattern = "" then
281 raise Pattern_Error;
282 end if;
284 -- Forwards case
286 if Going = Forward then
287 Ind := Source'First;
289 -- Unmapped forward case
291 if Mapping'Address = Wide_Maps.Identity'Address then
292 for J in 1 .. Source'Length - PL1 loop
293 if Pattern = Source (Ind .. Ind + PL1) then
294 return Ind;
295 else
296 Ind := Ind + 1;
297 end if;
298 end loop;
300 -- Mapped forward case
302 else
303 for J in 1 .. Source'Length - PL1 loop
304 Cur := Ind;
306 for K in Pattern'Range loop
307 if Pattern (K) /= Value (Mapping, Source (Cur)) then
308 goto Cont1;
309 else
310 Cur := Cur + 1;
311 end if;
312 end loop;
314 return Ind;
316 <<Cont1>>
317 Ind := Ind + 1;
318 end loop;
319 end if;
321 -- Backwards case
323 else
324 -- Unmapped backward case
326 Ind := Source'Last - PL1;
328 if Mapping'Address = Wide_Maps.Identity'Address then
329 for J in reverse 1 .. Source'Length - PL1 loop
330 if Pattern = Source (Ind .. Ind + PL1) then
331 return Ind;
332 else
333 Ind := Ind - 1;
334 end if;
335 end loop;
337 -- Mapped backward case
339 else
340 for J in reverse 1 .. Source'Length - PL1 loop
341 Cur := Ind;
343 for K in Pattern'Range loop
344 if Pattern (K) /= Value (Mapping, Source (Cur)) then
345 goto Cont2;
346 else
347 Cur := Cur + 1;
348 end if;
349 end loop;
351 return Ind;
353 <<Cont2>>
354 Ind := Ind - 1;
355 end loop;
356 end if;
357 end if;
359 -- Fall through if no match found. Note that the loops are skipped
360 -- completely in the case of the pattern being longer than the source.
362 return 0;
363 end Index;
365 function Index
366 (Source : Wide_String;
367 Pattern : Wide_String;
368 Going : Direction := Forward;
369 Mapping : Wide_Maps.Wide_Character_Mapping_Function) return Natural
371 PL1 : constant Integer := Pattern'Length - 1;
372 Ind : Natural;
373 Cur : Natural;
375 begin
376 if Pattern = "" then
377 raise Pattern_Error;
378 end if;
380 -- Check for null pointer in case checks are off
382 if Mapping = null then
383 raise Constraint_Error;
384 end if;
386 -- If Pattern longer than Source it can't be found
388 if Pattern'Length > Source'Length then
389 return 0;
390 end if;
392 -- Forwards case
394 if Going = Forward then
395 Ind := Source'First;
396 for J in 1 .. Source'Length - PL1 loop
397 Cur := Ind;
399 for K in Pattern'Range loop
400 if Pattern (K) /= Mapping.all (Source (Cur)) then
401 goto Cont1;
402 else
403 Cur := Cur + 1;
404 end if;
405 end loop;
407 return Ind;
409 <<Cont1>>
410 Ind := Ind + 1;
411 end loop;
413 -- Backwards case
415 else
416 Ind := Source'Last - PL1;
417 for J in reverse 1 .. Source'Length - PL1 loop
418 Cur := Ind;
420 for K in Pattern'Range loop
421 if Pattern (K) /= Mapping.all (Source (Cur)) then
422 goto Cont2;
423 else
424 Cur := Cur + 1;
425 end if;
426 end loop;
428 return Ind;
430 <<Cont2>>
431 Ind := Ind - 1;
432 end loop;
433 end if;
435 -- Fall through if no match found. Note that the loops are skipped
436 -- completely in the case of the pattern being longer than the source.
438 return 0;
439 end Index;
441 function Index
442 (Source : Wide_String;
443 Set : Wide_Maps.Wide_Character_Set;
444 Test : Membership := Inside;
445 Going : Direction := Forward) return Natural
447 begin
448 -- Forwards case
450 if Going = Forward then
451 for J in Source'Range loop
452 if Belongs (Source (J), Set, Test) then
453 return J;
454 end if;
455 end loop;
457 -- Backwards case
459 else
460 for J in reverse Source'Range loop
461 if Belongs (Source (J), Set, Test) then
462 return J;
463 end if;
464 end loop;
465 end if;
467 -- Fall through if no match
469 return 0;
470 end Index;
472 function Index
473 (Source : Wide_String;
474 Pattern : Wide_String;
475 From : Positive;
476 Going : Direction := Forward;
477 Mapping : Wide_Maps.Wide_Character_Mapping := Wide_Maps.Identity)
478 return Natural
480 begin
481 if Going = Forward then
482 if From < Source'First then
483 raise Index_Error;
484 end if;
486 return
487 Index (Source (From .. Source'Last), Pattern, Forward, Mapping);
489 else
490 if From > Source'Last then
491 raise Index_Error;
492 end if;
494 return
495 Index (Source (Source'First .. From), Pattern, Backward, Mapping);
496 end if;
497 end Index;
499 function Index
500 (Source : Wide_String;
501 Pattern : Wide_String;
502 From : Positive;
503 Going : Direction := Forward;
504 Mapping : Wide_Maps.Wide_Character_Mapping_Function) return Natural
506 begin
507 if Going = Forward then
508 if From < Source'First then
509 raise Index_Error;
510 end if;
512 return Index
513 (Source (From .. Source'Last), Pattern, Forward, Mapping);
515 else
516 if From > Source'Last then
517 raise Index_Error;
518 end if;
520 return Index
521 (Source (Source'First .. From), Pattern, Backward, Mapping);
522 end if;
523 end Index;
525 function Index
526 (Source : Wide_String;
527 Set : Wide_Maps.Wide_Character_Set;
528 From : Positive;
529 Test : Membership := Inside;
530 Going : Direction := Forward) return Natural
532 begin
533 if Going = Forward then
534 if From < Source'First then
535 raise Index_Error;
536 end if;
538 return
539 Index (Source (From .. Source'Last), Set, Test, Forward);
541 else
542 if From > Source'Last then
543 raise Index_Error;
544 end if;
546 return
547 Index (Source (Source'First .. From), Set, Test, Backward);
548 end if;
549 end Index;
551 ---------------------
552 -- Index_Non_Blank --
553 ---------------------
555 function Index_Non_Blank
556 (Source : Wide_String;
557 Going : Direction := Forward) return Natural
559 begin
560 if Going = Forward then
561 for J in Source'Range loop
562 if Source (J) /= Wide_Space then
563 return J;
564 end if;
565 end loop;
567 else -- Going = Backward
568 for J in reverse Source'Range loop
569 if Source (J) /= Wide_Space then
570 return J;
571 end if;
572 end loop;
573 end if;
575 -- Fall through if no match
577 return 0;
578 end Index_Non_Blank;
580 function Index_Non_Blank
581 (Source : Wide_String;
582 From : Positive;
583 Going : Direction := Forward) return Natural
585 begin
586 if Going = Forward then
587 if From < Source'First then
588 raise Index_Error;
589 end if;
591 return
592 Index_Non_Blank (Source (From .. Source'Last), Forward);
594 else
595 if From > Source'Last then
596 raise Index_Error;
597 end if;
599 return
600 Index_Non_Blank (Source (Source'First .. From), Backward);
601 end if;
602 end Index_Non_Blank;
604 end Ada.Strings.Wide_Search;