1 ------------------------------------------------------------------------------
3 -- GNAT RUN-TIME COMPONENTS --
5 -- A D A . S T R I N G S . W I D E _ W I D E _ S E A R C H --
9 -- Copyright (C) 1992-2009, Free Software Foundation, Inc. --
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. --
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. --
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/>. --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
30 ------------------------------------------------------------------------------
32 with Ada
.Strings
.Wide_Wide_Maps
; use Ada
.Strings
.Wide_Wide_Maps
;
33 with System
; use System
;
35 package body Ada
.Strings
.Wide_Wide_Search
is
37 -----------------------
38 -- Local Subprograms --
39 -----------------------
42 (Element
: Wide_Wide_Character
;
43 Set
: Wide_Wide_Maps
.Wide_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.
54 (Element
: Wide_Wide_Character
;
55 Set
: Wide_Wide_Maps
.Wide_Wide_Character_Set
;
56 Test
: Membership
) return Boolean
60 return Is_In
(Element
, Set
);
62 return not Is_In
(Element
, Set
);
71 (Source
: Wide_Wide_String
;
72 Pattern
: Wide_Wide_String
;
73 Mapping
: Wide_Wide_Maps
.Wide_Wide_Character_Mapping
:=
74 Wide_Wide_Maps
.Identity
)
77 PL1
: constant Integer := Pattern
'Length - 1;
92 if Mapping
'Address = Wide_Wide_Maps
.Identity
'Address then
93 while Ind
<= Source
'Last - PL1
loop
94 if Pattern
= Source
(Ind
.. Ind
+ PL1
) then
96 Ind
:= Ind
+ Pattern
'Length;
105 while Ind
<= Source
'Last - PL1
loop
107 for K
in Pattern
'Range loop
108 if Pattern
(K
) /= Value
(Mapping
, Source
(Cur
)) then
117 Ind
:= Ind
+ Pattern
'Length;
130 (Source
: Wide_Wide_String
;
131 Pattern
: Wide_Wide_String
;
132 Mapping
: Wide_Wide_Maps
.Wide_Wide_Character_Mapping_Function
)
135 PL1
: constant Integer := Pattern
'Length - 1;
145 -- Check for null pointer in case checks are off
147 if Mapping
= null then
148 raise Constraint_Error
;
153 while Ind
<= Source
'Last - PL1
loop
155 for K
in Pattern
'Range loop
156 if Pattern
(K
) /= Mapping
(Source
(Cur
)) then
165 Ind
:= Ind
+ Pattern
'Length;
175 (Source
: Wide_Wide_String
;
176 Set
: Wide_Wide_Maps
.Wide_Wide_Character_Set
) return Natural
181 for J
in Source
'Range loop
182 if Is_In
(Source
(J
), Set
) then
195 (Source
: Wide_Wide_String
;
196 Set
: Wide_Wide_Maps
.Wide_Wide_Character_Set
;
198 First
: out Positive;
202 for J
in Source
'Range loop
203 if Belongs
(Source
(J
), Set
, Test
) then
206 for K
in J
+ 1 .. Source
'Last loop
207 if not Belongs
(Source
(K
), Set
, Test
) then
213 -- Here if J indexes first char of token, and all chars after J
221 -- Here if no token found
223 First
:= Source
'First;
232 (Source
: Wide_Wide_String
;
233 Pattern
: Wide_Wide_String
;
234 Going
: Direction
:= Forward
;
235 Mapping
: Wide_Wide_Maps
.Wide_Wide_Character_Mapping
:=
236 Wide_Wide_Maps
.Identity
)
239 PL1
: constant Integer := Pattern
'Length - 1;
243 -- Index for start of match check. This can be negative if the pattern
244 -- length is greater than the string length, which is why this variable
245 -- is Integer instead of Natural. In this case, the search loops do not
246 -- execute at all, so this Ind value is never used.
255 if Going
= Forward
then
258 -- Unmapped forward case
260 if Mapping
'Address = Wide_Wide_Maps
.Identity
'Address then
261 for J
in 1 .. Source
'Length - PL1
loop
262 if Pattern
= Source
(Ind
.. Ind
+ PL1
) then
269 -- Mapped forward case
272 for J
in 1 .. Source
'Length - PL1
loop
275 for K
in Pattern
'Range loop
276 if Pattern
(K
) /= Value
(Mapping
, Source
(Cur
)) then
293 -- Unmapped backward case
295 Ind
:= Source
'Last - PL1
;
297 if Mapping
'Address = Wide_Wide_Maps
.Identity
'Address then
298 for J
in reverse 1 .. Source
'Length - PL1
loop
299 if Pattern
= Source
(Ind
.. Ind
+ PL1
) then
306 -- Mapped backward case
309 for J
in reverse 1 .. Source
'Length - PL1
loop
312 for K
in Pattern
'Range loop
313 if Pattern
(K
) /= Value
(Mapping
, Source
(Cur
)) then
328 -- Fall through if no match found. Note that the loops are skipped
329 -- completely in the case of the pattern being longer than the source.
335 (Source
: Wide_Wide_String
;
336 Pattern
: Wide_Wide_String
;
337 Going
: Direction
:= Forward
;
338 Mapping
: Wide_Wide_Maps
.Wide_Wide_Character_Mapping_Function
)
341 PL1
: constant Integer := Pattern
'Length - 1;
350 -- Check for null pointer in case checks are off
352 if Mapping
= null then
353 raise Constraint_Error
;
356 -- If Pattern longer than Source it can't be found
358 if Pattern
'Length > Source
'Length then
364 if Going
= Forward
then
366 for J
in 1 .. Source
'Length - PL1
loop
369 for K
in Pattern
'Range loop
370 if Pattern
(K
) /= Mapping
.all (Source
(Cur
)) then
386 Ind
:= Source
'Last - PL1
;
387 for J
in reverse 1 .. Source
'Length - PL1
loop
390 for K
in Pattern
'Range loop
391 if Pattern
(K
) /= Mapping
.all (Source
(Cur
)) then
405 -- Fall through if no match found. Note that the loops are skipped
406 -- completely in the case of the pattern being longer than the source.
412 (Source
: Wide_Wide_String
;
413 Set
: Wide_Wide_Maps
.Wide_Wide_Character_Set
;
414 Test
: Membership
:= Inside
;
415 Going
: Direction
:= Forward
) return Natural
420 if Going
= Forward
then
421 for J
in Source
'Range loop
422 if Belongs
(Source
(J
), Set
, Test
) then
430 for J
in reverse Source
'Range loop
431 if Belongs
(Source
(J
), Set
, Test
) then
437 -- Fall through if no match
443 (Source
: Wide_Wide_String
;
444 Pattern
: Wide_Wide_String
;
446 Going
: Direction
:= Forward
;
447 Mapping
: Wide_Wide_Maps
.Wide_Wide_Character_Mapping
:=
448 Wide_Wide_Maps
.Identity
)
452 if Going
= Forward
then
453 if From
< Source
'First then
458 Index
(Source
(From
.. Source
'Last), Pattern
, Forward
, Mapping
);
461 if From
> Source
'Last then
466 Index
(Source
(Source
'First .. From
), Pattern
, Backward
, Mapping
);
471 (Source
: Wide_Wide_String
;
472 Pattern
: Wide_Wide_String
;
474 Going
: Direction
:= Forward
;
475 Mapping
: Wide_Wide_Maps
.Wide_Wide_Character_Mapping_Function
)
479 if Going
= Forward
then
480 if From
< Source
'First then
485 (Source
(From
.. Source
'Last), Pattern
, Forward
, Mapping
);
488 if From
> Source
'Last then
493 (Source
(Source
'First .. From
), Pattern
, Backward
, Mapping
);
498 (Source
: Wide_Wide_String
;
499 Set
: Wide_Wide_Maps
.Wide_Wide_Character_Set
;
501 Test
: Membership
:= Inside
;
502 Going
: Direction
:= Forward
) return Natural
505 if Going
= Forward
then
506 if From
< Source
'First then
511 Index
(Source
(From
.. Source
'Last), Set
, Test
, Forward
);
514 if From
> Source
'Last then
519 Index
(Source
(Source
'First .. From
), Set
, Test
, Backward
);
523 ---------------------
524 -- Index_Non_Blank --
525 ---------------------
527 function Index_Non_Blank
528 (Source
: Wide_Wide_String
;
529 Going
: Direction
:= Forward
) return Natural
532 if Going
= Forward
then
533 for J
in Source
'Range loop
534 if Source
(J
) /= Wide_Wide_Space
then
539 else -- Going = Backward
540 for J
in reverse Source
'Range loop
541 if Source
(J
) /= Wide_Wide_Space
then
547 -- Fall through if no match
552 function Index_Non_Blank
553 (Source
: Wide_Wide_String
;
555 Going
: Direction
:= Forward
) return Natural
558 if Going
= Forward
then
559 if From
< Source
'First then
564 Index_Non_Blank
(Source
(From
.. Source
'Last), Forward
);
567 if From
> Source
'Last then
572 Index_Non_Blank
(Source
(Source
'First .. From
), Backward
);
576 end Ada
.Strings
.Wide_Wide_Search
;