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-2015, 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
) return Natural
76 PL1
: constant Integer := Pattern
'Length - 1;
91 if Mapping
'Address = Wide_Wide_Maps
.Identity
'Address then
92 while Ind
<= Source
'Last - PL1
loop
93 if Pattern
= Source
(Ind
.. Ind
+ PL1
) then
95 Ind
:= Ind
+ Pattern
'Length;
104 while Ind
<= Source
'Last - PL1
loop
106 for K
in Pattern
'Range loop
107 if Pattern
(K
) /= Value
(Mapping
, Source
(Cur
)) then
116 Ind
:= Ind
+ Pattern
'Length;
129 (Source
: Wide_Wide_String
;
130 Pattern
: Wide_Wide_String
;
131 Mapping
: Wide_Wide_Maps
.Wide_Wide_Character_Mapping_Function
)
134 PL1
: constant Integer := Pattern
'Length - 1;
144 -- Check for null pointer in case checks are off
146 if Mapping
= null then
147 raise Constraint_Error
;
152 while Ind
<= Source
'Last - PL1
loop
154 for K
in Pattern
'Range loop
155 if Pattern
(K
) /= Mapping
(Source
(Cur
)) then
164 Ind
:= Ind
+ Pattern
'Length;
174 (Source
: Wide_Wide_String
;
175 Set
: Wide_Wide_Maps
.Wide_Wide_Character_Set
) return Natural
180 for J
in Source
'Range loop
181 if Is_In
(Source
(J
), Set
) then
194 (Source
: Wide_Wide_String
;
195 Set
: Wide_Wide_Maps
.Wide_Wide_Character_Set
;
198 First
: out Positive;
202 for J
in From
.. Source
'Last 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
228 (Source
: Wide_Wide_String
;
229 Set
: Wide_Wide_Maps
.Wide_Wide_Character_Set
;
231 First
: out Positive;
235 for J
in Source
'Range loop
236 if Belongs
(Source
(J
), Set
, Test
) then
239 for K
in J
+ 1 .. Source
'Last loop
240 if not Belongs
(Source
(K
), Set
, Test
) then
246 -- Here if J indexes first char of token, and all chars after J
254 -- Here if no token found
256 -- RM 2005 A.4.3 (68/1) specifies that an exception must be raised if
257 -- Source'First is not positive and is assigned to First. Formulation
258 -- is slightly different in RM 2012, but the intent seems similar, so
259 -- we check explicitly for that condition.
261 if Source
'First not in Positive then
262 raise Constraint_Error
;
265 First
:= Source
'First;
275 (Source
: Wide_Wide_String
;
276 Pattern
: Wide_Wide_String
;
277 Going
: Direction
:= Forward
;
278 Mapping
: Wide_Wide_Maps
.Wide_Wide_Character_Mapping
:=
279 Wide_Wide_Maps
.Identity
) return Natural
281 PL1
: constant Integer := Pattern
'Length - 1;
285 -- Index for start of match check. This can be negative if the pattern
286 -- length is greater than the string length, which is why this variable
287 -- is Integer instead of Natural. In this case, the search loops do not
288 -- execute at all, so this Ind value is never used.
297 if Going
= Forward
then
300 -- Unmapped forward case
302 if Mapping
'Address = Wide_Wide_Maps
.Identity
'Address then
303 for J
in 1 .. Source
'Length - PL1
loop
304 if Pattern
= Source
(Ind
.. Ind
+ PL1
) then
311 -- Mapped forward case
314 for J
in 1 .. Source
'Length - PL1
loop
317 for K
in Pattern
'Range loop
318 if Pattern
(K
) /= Value
(Mapping
, Source
(Cur
)) then
335 -- Unmapped backward case
337 Ind
:= Source
'Last - PL1
;
339 if Mapping
'Address = Wide_Wide_Maps
.Identity
'Address then
340 for J
in reverse 1 .. Source
'Length - PL1
loop
341 if Pattern
= Source
(Ind
.. Ind
+ PL1
) then
348 -- Mapped backward case
351 for J
in reverse 1 .. Source
'Length - PL1
loop
354 for K
in Pattern
'Range loop
355 if Pattern
(K
) /= Value
(Mapping
, Source
(Cur
)) then
370 -- Fall through if no match found. Note that the loops are skipped
371 -- completely in the case of the pattern being longer than the source.
377 (Source
: Wide_Wide_String
;
378 Pattern
: Wide_Wide_String
;
379 Going
: Direction
:= Forward
;
380 Mapping
: Wide_Wide_Maps
.Wide_Wide_Character_Mapping_Function
)
383 PL1
: constant Integer := Pattern
'Length - 1;
392 -- Check for null pointer in case checks are off
394 if Mapping
= null then
395 raise Constraint_Error
;
398 -- If Pattern longer than Source it can't be found
400 if Pattern
'Length > Source
'Length then
406 if Going
= Forward
then
408 for J
in 1 .. Source
'Length - PL1
loop
411 for K
in Pattern
'Range loop
412 if Pattern
(K
) /= Mapping
.all (Source
(Cur
)) then
428 Ind
:= Source
'Last - PL1
;
429 for J
in reverse 1 .. Source
'Length - PL1
loop
432 for K
in Pattern
'Range loop
433 if Pattern
(K
) /= Mapping
.all (Source
(Cur
)) then
447 -- Fall through if no match found. Note that the loops are skipped
448 -- completely in the case of the pattern being longer than the source.
454 (Source
: Wide_Wide_String
;
455 Set
: Wide_Wide_Maps
.Wide_Wide_Character_Set
;
456 Test
: Membership
:= Inside
;
457 Going
: Direction
:= Forward
) return Natural
462 if Going
= Forward
then
463 for J
in Source
'Range loop
464 if Belongs
(Source
(J
), Set
, Test
) then
472 for J
in reverse Source
'Range loop
473 if Belongs
(Source
(J
), Set
, Test
) then
479 -- Fall through if no match
485 (Source
: Wide_Wide_String
;
486 Pattern
: Wide_Wide_String
;
488 Going
: Direction
:= Forward
;
489 Mapping
: Wide_Wide_Maps
.Wide_Wide_Character_Mapping
:=
490 Wide_Wide_Maps
.Identity
) return Natural
493 if Going
= Forward
then
494 if From
< Source
'First then
499 Index
(Source
(From
.. Source
'Last), Pattern
, Forward
, Mapping
);
502 if From
> Source
'Last then
507 Index
(Source
(Source
'First .. From
), Pattern
, Backward
, Mapping
);
512 (Source
: Wide_Wide_String
;
513 Pattern
: Wide_Wide_String
;
515 Going
: Direction
:= Forward
;
516 Mapping
: Wide_Wide_Maps
.Wide_Wide_Character_Mapping_Function
)
520 if Going
= Forward
then
521 if From
< Source
'First then
526 (Source
(From
.. Source
'Last), Pattern
, Forward
, Mapping
);
529 if From
> Source
'Last then
534 (Source
(Source
'First .. From
), Pattern
, Backward
, Mapping
);
539 (Source
: Wide_Wide_String
;
540 Set
: Wide_Wide_Maps
.Wide_Wide_Character_Set
;
542 Test
: Membership
:= Inside
;
543 Going
: Direction
:= Forward
) return Natural
546 if Going
= Forward
then
547 if From
< Source
'First then
552 Index
(Source
(From
.. Source
'Last), Set
, Test
, Forward
);
555 if From
> Source
'Last then
560 Index
(Source
(Source
'First .. From
), Set
, Test
, Backward
);
564 ---------------------
565 -- Index_Non_Blank --
566 ---------------------
568 function Index_Non_Blank
569 (Source
: Wide_Wide_String
;
570 Going
: Direction
:= Forward
) return Natural
573 if Going
= Forward
then
574 for J
in Source
'Range loop
575 if Source
(J
) /= Wide_Wide_Space
then
580 else -- Going = Backward
581 for J
in reverse Source
'Range loop
582 if Source
(J
) /= Wide_Wide_Space
then
588 -- Fall through if no match
593 function Index_Non_Blank
594 (Source
: Wide_Wide_String
;
596 Going
: Direction
:= Forward
) return Natural
599 if Going
= Forward
then
600 if From
< Source
'First then
605 Index_Non_Blank
(Source
(From
.. Source
'Last), Forward
);
608 if From
> Source
'Last then
613 Index_Non_Blank
(Source
(Source
'First .. From
), Backward
);
617 end Ada
.Strings
.Wide_Wide_Search
;