2016-04-27 Hristian Kirtchev <kirtchev@adacore.com>
[official-gcc.git] / gcc / ada / a-stwise.adb
blob09ac7830c8a2f7d40c47306440bd3521b1f9d861
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-2015, 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 -- RM 2005 A.4.3 (68/1) specifies that an exception must be raised if
256 -- Source'First is not positive and is assigned to First. Formulation
257 -- is slightly different in RM 2012, but the intent seems similar, so
258 -- we check explicitly for that condition.
260 if Source'First not in Positive then
261 raise Constraint_Error;
263 else
264 First := Source'First;
265 Last := 0;
266 end if;
267 end Find_Token;
269 -----------
270 -- Index --
271 -----------
273 function Index
274 (Source : Wide_String;
275 Pattern : Wide_String;
276 Going : Direction := Forward;
277 Mapping : Wide_Maps.Wide_Character_Mapping := Wide_Maps.Identity)
278 return Natural
280 PL1 : constant Integer := Pattern'Length - 1;
281 Cur : Natural;
283 Ind : Integer;
284 -- Index for start of match check. This can be negative if the pattern
285 -- length is greater than the string length, which is why this variable
286 -- is Integer instead of Natural. In this case, the search loops do not
287 -- execute at all, so this Ind value is never used.
289 begin
290 if Pattern = "" then
291 raise Pattern_Error;
292 end if;
294 -- Forwards case
296 if Going = Forward then
297 Ind := Source'First;
299 -- Unmapped forward case
301 if Mapping'Address = Wide_Maps.Identity'Address then
302 for J in 1 .. Source'Length - PL1 loop
303 if Pattern = Source (Ind .. Ind + PL1) then
304 return Ind;
305 else
306 Ind := Ind + 1;
307 end if;
308 end loop;
310 -- Mapped forward case
312 else
313 for J in 1 .. Source'Length - PL1 loop
314 Cur := Ind;
316 for K in Pattern'Range loop
317 if Pattern (K) /= Value (Mapping, Source (Cur)) then
318 goto Cont1;
319 else
320 Cur := Cur + 1;
321 end if;
322 end loop;
324 return Ind;
326 <<Cont1>>
327 Ind := Ind + 1;
328 end loop;
329 end if;
331 -- Backwards case
333 else
334 -- Unmapped backward case
336 Ind := Source'Last - PL1;
338 if Mapping'Address = Wide_Maps.Identity'Address then
339 for J in reverse 1 .. Source'Length - PL1 loop
340 if Pattern = Source (Ind .. Ind + PL1) then
341 return Ind;
342 else
343 Ind := Ind - 1;
344 end if;
345 end loop;
347 -- Mapped backward case
349 else
350 for J in reverse 1 .. Source'Length - PL1 loop
351 Cur := Ind;
353 for K in Pattern'Range loop
354 if Pattern (K) /= Value (Mapping, Source (Cur)) then
355 goto Cont2;
356 else
357 Cur := Cur + 1;
358 end if;
359 end loop;
361 return Ind;
363 <<Cont2>>
364 Ind := Ind - 1;
365 end loop;
366 end if;
367 end if;
369 -- Fall through if no match found. Note that the loops are skipped
370 -- completely in the case of the pattern being longer than the source.
372 return 0;
373 end Index;
375 function Index
376 (Source : Wide_String;
377 Pattern : Wide_String;
378 Going : Direction := Forward;
379 Mapping : Wide_Maps.Wide_Character_Mapping_Function) return Natural
381 PL1 : constant Integer := Pattern'Length - 1;
382 Ind : Natural;
383 Cur : Natural;
385 begin
386 if Pattern = "" then
387 raise Pattern_Error;
388 end if;
390 -- Check for null pointer in case checks are off
392 if Mapping = null then
393 raise Constraint_Error;
394 end if;
396 -- If Pattern longer than Source it can't be found
398 if Pattern'Length > Source'Length then
399 return 0;
400 end if;
402 -- Forwards case
404 if Going = Forward then
405 Ind := Source'First;
406 for J in 1 .. Source'Length - PL1 loop
407 Cur := Ind;
409 for K in Pattern'Range loop
410 if Pattern (K) /= Mapping.all (Source (Cur)) then
411 goto Cont1;
412 else
413 Cur := Cur + 1;
414 end if;
415 end loop;
417 return Ind;
419 <<Cont1>>
420 Ind := Ind + 1;
421 end loop;
423 -- Backwards case
425 else
426 Ind := Source'Last - PL1;
427 for J in reverse 1 .. Source'Length - PL1 loop
428 Cur := Ind;
430 for K in Pattern'Range loop
431 if Pattern (K) /= Mapping.all (Source (Cur)) then
432 goto Cont2;
433 else
434 Cur := Cur + 1;
435 end if;
436 end loop;
438 return Ind;
440 <<Cont2>>
441 Ind := Ind - 1;
442 end loop;
443 end if;
445 -- Fall through if no match found. Note that the loops are skipped
446 -- completely in the case of the pattern being longer than the source.
448 return 0;
449 end Index;
451 function Index
452 (Source : Wide_String;
453 Set : Wide_Maps.Wide_Character_Set;
454 Test : Membership := Inside;
455 Going : Direction := Forward) return Natural
457 begin
458 -- Forwards case
460 if Going = Forward then
461 for J in Source'Range loop
462 if Belongs (Source (J), Set, Test) then
463 return J;
464 end if;
465 end loop;
467 -- Backwards case
469 else
470 for J in reverse Source'Range loop
471 if Belongs (Source (J), Set, Test) then
472 return J;
473 end if;
474 end loop;
475 end if;
477 -- Fall through if no match
479 return 0;
480 end Index;
482 function Index
483 (Source : Wide_String;
484 Pattern : Wide_String;
485 From : Positive;
486 Going : Direction := Forward;
487 Mapping : Wide_Maps.Wide_Character_Mapping := Wide_Maps.Identity)
488 return Natural
490 begin
491 if Going = Forward then
492 if From < Source'First then
493 raise Index_Error;
494 end if;
496 return
497 Index (Source (From .. Source'Last), Pattern, Forward, Mapping);
499 else
500 if From > Source'Last then
501 raise Index_Error;
502 end if;
504 return
505 Index (Source (Source'First .. From), Pattern, Backward, Mapping);
506 end if;
507 end Index;
509 function Index
510 (Source : Wide_String;
511 Pattern : Wide_String;
512 From : Positive;
513 Going : Direction := Forward;
514 Mapping : Wide_Maps.Wide_Character_Mapping_Function) return Natural
516 begin
517 if Going = Forward then
518 if From < Source'First then
519 raise Index_Error;
520 end if;
522 return Index
523 (Source (From .. Source'Last), Pattern, Forward, Mapping);
525 else
526 if From > Source'Last then
527 raise Index_Error;
528 end if;
530 return Index
531 (Source (Source'First .. From), Pattern, Backward, Mapping);
532 end if;
533 end Index;
535 function Index
536 (Source : Wide_String;
537 Set : Wide_Maps.Wide_Character_Set;
538 From : Positive;
539 Test : Membership := Inside;
540 Going : Direction := Forward) return Natural
542 begin
543 if Going = Forward then
544 if From < Source'First then
545 raise Index_Error;
546 end if;
548 return
549 Index (Source (From .. Source'Last), Set, Test, Forward);
551 else
552 if From > Source'Last then
553 raise Index_Error;
554 end if;
556 return
557 Index (Source (Source'First .. From), Set, Test, Backward);
558 end if;
559 end Index;
561 ---------------------
562 -- Index_Non_Blank --
563 ---------------------
565 function Index_Non_Blank
566 (Source : Wide_String;
567 Going : Direction := Forward) return Natural
569 begin
570 if Going = Forward then
571 for J in Source'Range loop
572 if Source (J) /= Wide_Space then
573 return J;
574 end if;
575 end loop;
577 else -- Going = Backward
578 for J in reverse Source'Range loop
579 if Source (J) /= Wide_Space then
580 return J;
581 end if;
582 end loop;
583 end if;
585 -- Fall through if no match
587 return 0;
588 end Index_Non_Blank;
590 function Index_Non_Blank
591 (Source : Wide_String;
592 From : Positive;
593 Going : Direction := Forward) return Natural
595 begin
596 if Going = Forward then
597 if From < Source'First then
598 raise Index_Error;
599 end if;
601 return
602 Index_Non_Blank (Source (From .. Source'Last), Forward);
604 else
605 if From > Source'Last then
606 raise Index_Error;
607 end if;
609 return
610 Index_Non_Blank (Source (Source'First .. From), Backward);
611 end if;
612 end Index_Non_Blank;
614 end Ada.Strings.Wide_Search;