]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/ada/libgnat/a-strfix.adb
[Ada] Address potentially uninitialized variables and dead code
[thirdparty/gcc.git] / gcc / ada / libgnat / a-strfix.adb
CommitLineData
d23b8f57
RK
1------------------------------------------------------------------------------
2-- --
3084fecd 3-- GNAT RUN-TIME COMPONENTS --
d23b8f57
RK
4-- --
5-- A D A . S T R I N G S . F I X E D --
6-- --
7-- B o d y --
8-- --
1d005acc 9-- Copyright (C) 1992-2019, Free Software Foundation, Inc. --
d23b8f57
RK
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- --
748086b7 13-- ware Foundation; either version 3, or (at your option) any later ver- --
d23b8f57
RK
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 --
748086b7 16-- or FITNESS FOR A PARTICULAR PURPOSE. --
d23b8f57 17-- --
748086b7
JJ
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/>. --
d23b8f57
RK
26-- --
27-- GNAT was originally developed by the GNAT team at New York University. --
71ff80dc 28-- Extensive contributions were provided by Ada Core Technologies Inc. --
d23b8f57
RK
29-- --
30------------------------------------------------------------------------------
31
9de61fcb
RD
32-- Note: This code is derived from the ADAR.CSH public domain Ada 83 versions
33-- of the Appendix C string handling packages. One change is to avoid the use
34-- of Is_In, so that we are not dependent on inlining. Note that the search
35-- function implementations are to be found in the auxiliary package
36-- Ada.Strings.Search. Also the Move procedure is directly incorporated (ADAR
8fc789c8 37-- used a subunit for this procedure). The number of errors having to do with
9de61fcb
RD
38-- bounds of function return results were also fixed, and use of & removed for
39-- efficiency reasons.
d23b8f57
RK
40
41with Ada.Strings.Maps; use Ada.Strings.Maps;
42with Ada.Strings.Search;
43
44package body Ada.Strings.Fixed is
45
46 ------------------------
47 -- Search Subprograms --
48 ------------------------
49
50 function Index
4e45e7a9
RD
51 (Source : String;
52 Pattern : String;
53 Going : Direction := Forward;
54 Mapping : Maps.Character_Mapping := Maps.Identity) return Natural
d23b8f57
RK
55 renames Ada.Strings.Search.Index;
56
57 function Index
4e45e7a9
RD
58 (Source : String;
59 Pattern : String;
60 Going : Direction := Forward;
61 Mapping : Maps.Character_Mapping_Function) return Natural
d23b8f57
RK
62 renames Ada.Strings.Search.Index;
63
64 function Index
4e45e7a9
RD
65 (Source : String;
66 Set : Maps.Character_Set;
67 Test : Membership := Inside;
68 Going : Direction := Forward) return Natural
d23b8f57
RK
69 renames Ada.Strings.Search.Index;
70
4e45e7a9
RD
71 function Index
72 (Source : String;
73 Pattern : String;
74 From : Positive;
75 Going : Direction := Forward;
76 Mapping : Maps.Character_Mapping := Maps.Identity) return Natural
77 renames Ada.Strings.Search.Index;
78
79 function Index
80 (Source : String;
81 Pattern : String;
82 From : Positive;
83 Going : Direction := Forward;
84 Mapping : Maps.Character_Mapping_Function) return Natural
85 renames Ada.Strings.Search.Index;
86
87 function Index
88 (Source : String;
89 Set : Maps.Character_Set;
90 From : Positive;
91 Test : Membership := Inside;
92 Going : Direction := Forward) return Natural
93 renames Ada.Strings.Search.Index;
94
95 function Index_Non_Blank
96 (Source : String;
97 Going : Direction := Forward) return Natural
98 renames Ada.Strings.Search.Index_Non_Blank;
99
d23b8f57 100 function Index_Non_Blank
4e45e7a9
RD
101 (Source : String;
102 From : Positive;
103 Going : Direction := Forward) return Natural
d23b8f57
RK
104 renames Ada.Strings.Search.Index_Non_Blank;
105
106 function Count
4e45e7a9
RD
107 (Source : String;
108 Pattern : String;
109 Mapping : Maps.Character_Mapping := Maps.Identity) return Natural
d23b8f57
RK
110 renames Ada.Strings.Search.Count;
111
112 function Count
4e45e7a9
RD
113 (Source : String;
114 Pattern : String;
115 Mapping : Maps.Character_Mapping_Function) return Natural
d23b8f57
RK
116 renames Ada.Strings.Search.Count;
117
118 function Count
4e45e7a9
RD
119 (Source : String;
120 Set : Maps.Character_Set) return Natural
d23b8f57
RK
121 renames Ada.Strings.Search.Count;
122
af31bffb
AC
123 procedure Find_Token
124 (Source : String;
125 Set : Maps.Character_Set;
126 From : Positive;
127 Test : Membership;
128 First : out Positive;
129 Last : out Natural)
130 renames Ada.Strings.Search.Find_Token;
131
d23b8f57 132 procedure Find_Token
4e45e7a9
RD
133 (Source : String;
134 Set : Maps.Character_Set;
135 Test : Membership;
d23b8f57
RK
136 First : out Positive;
137 Last : out Natural)
138 renames Ada.Strings.Search.Find_Token;
139
140 ---------
141 -- "*" --
142 ---------
143
144 function "*"
4e45e7a9
RD
145 (Left : Natural;
146 Right : Character) return String
d23b8f57
RK
147 is
148 Result : String (1 .. Left);
149
150 begin
151 for J in Result'Range loop
152 Result (J) := Right;
153 end loop;
154
155 return Result;
156 end "*";
157
158 function "*"
4e45e7a9
RD
159 (Left : Natural;
160 Right : String) return String
d23b8f57
RK
161 is
162 Result : String (1 .. Left * Right'Length);
163 Ptr : Integer := 1;
164
165 begin
166 for J in 1 .. Left loop
167 Result (Ptr .. Ptr + Right'Length - 1) := Right;
168 Ptr := Ptr + Right'Length;
169 end loop;
170
171 return Result;
172 end "*";
173
174 ------------
175 -- Delete --
176 ------------
177
178 function Delete
4e45e7a9
RD
179 (Source : String;
180 From : Positive;
181 Through : Natural) return String
d23b8f57
RK
182 is
183 begin
184 if From > Through then
185 declare
186 subtype Result_Type is String (1 .. Source'Length);
187
188 begin
189 return Result_Type (Source);
190 end;
191
192 elsif From not in Source'Range
193 or else Through > Source'Last
194 then
a6b13d32
AC
195 pragma Annotate
196 (CodePeer, False_Positive,
197 "test always false", "self fullfilling prophecy");
198
4962dc44
ES
199 -- In most cases this raises an exception, but the case of deleting
200 -- a null string at the end of the current one is a special-case, and
201 -- reflects the equivalence with Replace_String (RM A.4.3 (86/3)).
202
203 if From = Source'Last + 1 and then From = Through then
204 return Source;
205 else
206 raise Index_Error;
207 end if;
d23b8f57
RK
208
209 else
210 declare
211 Front : constant Integer := From - Source'First;
212 Result : String (1 .. Source'Length - (Through - From + 1));
213
214 begin
215 Result (1 .. Front) :=
216 Source (Source'First .. From - 1);
217 Result (Front + 1 .. Result'Last) :=
218 Source (Through + 1 .. Source'Last);
219
220 return Result;
221 end;
222 end if;
223 end Delete;
224
225 procedure Delete
226 (Source : in out String;
4e45e7a9
RD
227 From : Positive;
228 Through : Natural;
229 Justify : Alignment := Left;
230 Pad : Character := Space)
d23b8f57
RK
231 is
232 begin
233 Move (Source => Delete (Source, From, Through),
234 Target => Source,
235 Justify => Justify,
236 Pad => Pad);
237 end Delete;
238
239 ----------
240 -- Head --
241 ----------
242
243 function Head
4e45e7a9
RD
244 (Source : String;
245 Count : Natural;
246 Pad : Character := Space) return String
d23b8f57
RK
247 is
248 subtype Result_Type is String (1 .. Count);
249
250 begin
251 if Count < Source'Length then
252 return
253 Result_Type (Source (Source'First .. Source'First + Count - 1));
254
255 else
256 declare
257 Result : Result_Type;
258
259 begin
260 Result (1 .. Source'Length) := Source;
261
262 for J in Source'Length + 1 .. Count loop
263 Result (J) := Pad;
264 end loop;
265
266 return Result;
267 end;
268 end if;
269 end Head;
270
271 procedure Head
272 (Source : in out String;
4e45e7a9
RD
273 Count : Natural;
274 Justify : Alignment := Left;
275 Pad : Character := Space)
d23b8f57
RK
276 is
277 begin
278 Move (Source => Head (Source, Count, Pad),
279 Target => Source,
280 Drop => Error,
281 Justify => Justify,
282 Pad => Pad);
283 end Head;
284
285 ------------
286 -- Insert --
287 ------------
288
289 function Insert
4e45e7a9
RD
290 (Source : String;
291 Before : Positive;
292 New_Item : String) return String
d23b8f57
RK
293 is
294 Result : String (1 .. Source'Length + New_Item'Length);
295 Front : constant Integer := Before - Source'First;
296
297 begin
298 if Before not in Source'First .. Source'Last + 1 then
299 raise Index_Error;
300 end if;
301
302 Result (1 .. Front) :=
303 Source (Source'First .. Before - 1);
304 Result (Front + 1 .. Front + New_Item'Length) :=
305 New_Item;
306 Result (Front + New_Item'Length + 1 .. Result'Last) :=
307 Source (Before .. Source'Last);
308
309 return Result;
310 end Insert;
311
312 procedure Insert
313 (Source : in out String;
4e45e7a9
RD
314 Before : Positive;
315 New_Item : String;
316 Drop : Truncation := Error)
d23b8f57
RK
317 is
318 begin
319 Move (Source => Insert (Source, Before, New_Item),
320 Target => Source,
321 Drop => Drop);
322 end Insert;
323
324 ----------
325 -- Move --
326 ----------
327
328 procedure Move
4e45e7a9 329 (Source : String;
d23b8f57 330 Target : out String;
4e45e7a9
RD
331 Drop : Truncation := Error;
332 Justify : Alignment := Left;
333 Pad : Character := Space)
d23b8f57
RK
334 is
335 Sfirst : constant Integer := Source'First;
336 Slast : constant Integer := Source'Last;
337 Slength : constant Integer := Source'Length;
338
339 Tfirst : constant Integer := Target'First;
340 Tlast : constant Integer := Target'Last;
341 Tlength : constant Integer := Target'Length;
342
343 function Is_Padding (Item : String) return Boolean;
344 -- Check if Item is all Pad characters, return True if so, False if not
345
346 function Is_Padding (Item : String) return Boolean is
347 begin
348 for J in Item'Range loop
349 if Item (J) /= Pad then
350 return False;
351 end if;
352 end loop;
353
354 return True;
355 end Is_Padding;
356
357 -- Start of processing for Move
358
359 begin
360 if Slength = Tlength then
361 Target := Source;
362
363 elsif Slength > Tlength then
d23b8f57
RK
364 case Drop is
365 when Left =>
366 Target := Source (Slast - Tlength + 1 .. Slast);
367
368 when Right =>
369 Target := Source (Sfirst .. Sfirst + Tlength - 1);
370
371 when Error =>
372 case Justify is
373 when Left =>
374 if Is_Padding (Source (Sfirst + Tlength .. Slast)) then
375 Target :=
376 Source (Sfirst .. Sfirst + Target'Length - 1);
377 else
378 raise Length_Error;
379 end if;
380
381 when Right =>
382 if Is_Padding (Source (Sfirst .. Slast - Tlength)) then
383 Target := Source (Slast - Tlength + 1 .. Slast);
384 else
385 raise Length_Error;
386 end if;
387
388 when Center =>
389 raise Length_Error;
390 end case;
d23b8f57
RK
391 end case;
392
393 -- Source'Length < Target'Length
394
395 else
396 case Justify is
397 when Left =>
398 Target (Tfirst .. Tfirst + Slength - 1) := Source;
399
400 for I in Tfirst + Slength .. Tlast loop
401 Target (I) := Pad;
402 end loop;
403
404 when Right =>
405 for I in Tfirst .. Tlast - Slength loop
406 Target (I) := Pad;
407 end loop;
408
409 Target (Tlast - Slength + 1 .. Tlast) := Source;
410
411 when Center =>
412 declare
413 Front_Pad : constant Integer := (Tlength - Slength) / 2;
414 Tfirst_Fpad : constant Integer := Tfirst + Front_Pad;
415
416 begin
417 for I in Tfirst .. Tfirst_Fpad - 1 loop
418 Target (I) := Pad;
419 end loop;
420
421 Target (Tfirst_Fpad .. Tfirst_Fpad + Slength - 1) := Source;
422
423 for I in Tfirst_Fpad + Slength .. Tlast loop
424 Target (I) := Pad;
425 end loop;
426 end;
427 end case;
428 end if;
429 end Move;
430
431 ---------------
432 -- Overwrite --
433 ---------------
434
435 function Overwrite
4e45e7a9
RD
436 (Source : String;
437 Position : Positive;
438 New_Item : String) return String
d23b8f57
RK
439 is
440 begin
441 if Position not in Source'First .. Source'Last + 1 then
442 raise Index_Error;
443 end if;
444
445 declare
fbf5a39b 446 Result_Length : constant Natural :=
15f0f591
AC
447 Integer'Max
448 (Source'Length,
449 Position - Source'First + New_Item'Length);
d23b8f57
RK
450
451 Result : String (1 .. Result_Length);
452 Front : constant Integer := Position - Source'First;
453
454 begin
455 Result (1 .. Front) :=
456 Source (Source'First .. Position - 1);
457 Result (Front + 1 .. Front + New_Item'Length) :=
458 New_Item;
459 Result (Front + New_Item'Length + 1 .. Result'Length) :=
460 Source (Position + New_Item'Length .. Source'Last);
461 return Result;
462 end;
463 end Overwrite;
464
465 procedure Overwrite
466 (Source : in out String;
4e45e7a9
RD
467 Position : Positive;
468 New_Item : String;
469 Drop : Truncation := Right)
d23b8f57
RK
470 is
471 begin
472 Move (Source => Overwrite (Source, Position, New_Item),
473 Target => Source,
474 Drop => Drop);
475 end Overwrite;
476
477 -------------------
478 -- Replace_Slice --
479 -------------------
480
481 function Replace_Slice
4e45e7a9
RD
482 (Source : String;
483 Low : Positive;
484 High : Natural;
485 By : String) return String
d23b8f57
RK
486 is
487 begin
d1ced162 488 if Low > Source'Last + 1 or else High < Source'First - 1 then
d23b8f57
RK
489 raise Index_Error;
490 end if;
491
492 if High >= Low then
493 declare
494 Front_Len : constant Integer :=
15f0f591 495 Integer'Max (0, Low - Source'First);
d23b8f57
RK
496 -- Length of prefix of Source copied to result
497
47e11d08 498 Back_Len : constant Integer :=
15f0f591 499 Integer'Max (0, Source'Last - High);
d23b8f57
RK
500 -- Length of suffix of Source copied to result
501
502 Result_Length : constant Integer :=
15f0f591 503 Front_Len + By'Length + Back_Len;
d23b8f57
RK
504 -- Length of result
505
506 Result : String (1 .. Result_Length);
507
508 begin
47e11d08
AC
509 Result (1 .. Front_Len) := Source (Source'First .. Low - 1);
510 Result (Front_Len + 1 .. Front_Len + By'Length) := By;
d23b8f57
RK
511 Result (Front_Len + By'Length + 1 .. Result'Length) :=
512 Source (High + 1 .. Source'Last);
d23b8f57
RK
513 return Result;
514 end;
515
516 else
517 return Insert (Source, Before => Low, New_Item => By);
518 end if;
519 end Replace_Slice;
520
521 procedure Replace_Slice
522 (Source : in out String;
4e45e7a9
RD
523 Low : Positive;
524 High : Natural;
525 By : String;
526 Drop : Truncation := Error;
527 Justify : Alignment := Left;
528 Pad : Character := Space)
d23b8f57
RK
529 is
530 begin
531 Move (Replace_Slice (Source, Low, High, By), Source, Drop, Justify, Pad);
532 end Replace_Slice;
533
534 ----------
535 -- Tail --
536 ----------
537
538 function Tail
4e45e7a9
RD
539 (Source : String;
540 Count : Natural;
541 Pad : Character := Space) return String
d23b8f57
RK
542 is
543 subtype Result_Type is String (1 .. Count);
544
545 begin
546 if Count < Source'Length then
547 return Result_Type (Source (Source'Last - Count + 1 .. Source'Last));
548
549 -- Pad on left
550
551 else
552 declare
553 Result : Result_Type;
554
555 begin
556 for J in 1 .. Count - Source'Length loop
557 Result (J) := Pad;
558 end loop;
559
560 Result (Count - Source'Length + 1 .. Count) := Source;
561 return Result;
562 end;
563 end if;
564 end Tail;
565
566 procedure Tail
567 (Source : in out String;
4e45e7a9
RD
568 Count : Natural;
569 Justify : Alignment := Left;
570 Pad : Character := Space)
d23b8f57
RK
571 is
572 begin
573 Move (Source => Tail (Source, Count, Pad),
574 Target => Source,
575 Drop => Error,
576 Justify => Justify,
577 Pad => Pad);
578 end Tail;
579
580 ---------------
581 -- Translate --
582 ---------------
583
584 function Translate
4e45e7a9
RD
585 (Source : String;
586 Mapping : Maps.Character_Mapping) return String
d23b8f57
RK
587 is
588 Result : String (1 .. Source'Length);
589
590 begin
591 for J in Source'Range loop
592 Result (J - (Source'First - 1)) := Value (Mapping, Source (J));
593 end loop;
594
595 return Result;
596 end Translate;
597
598 procedure Translate
599 (Source : in out String;
4e45e7a9 600 Mapping : Maps.Character_Mapping)
d23b8f57
RK
601 is
602 begin
603 for J in Source'Range loop
604 Source (J) := Value (Mapping, Source (J));
605 end loop;
606 end Translate;
607
608 function Translate
4e45e7a9
RD
609 (Source : String;
610 Mapping : Maps.Character_Mapping_Function) return String
d23b8f57
RK
611 is
612 Result : String (1 .. Source'Length);
613 pragma Unsuppress (Access_Check);
614
615 begin
616 for J in Source'Range loop
617 Result (J - (Source'First - 1)) := Mapping.all (Source (J));
618 end loop;
619
620 return Result;
621 end Translate;
622
623 procedure Translate
624 (Source : in out String;
4e45e7a9 625 Mapping : Maps.Character_Mapping_Function)
d23b8f57
RK
626 is
627 pragma Unsuppress (Access_Check);
628 begin
629 for J in Source'Range loop
630 Source (J) := Mapping.all (Source (J));
631 end loop;
632 end Translate;
633
634 ----------
635 -- Trim --
636 ----------
637
638 function Trim
4e45e7a9
RD
639 (Source : String;
640 Side : Trim_End) return String
d23b8f57 641 is
d23b8f57 642 begin
3815f967
AC
643 case Side is
644 when Strings.Left =>
645 declare
646 Low : constant Natural := Index_Non_Blank (Source, Forward);
647 begin
648 -- All blanks case
d23b8f57 649
3815f967
AC
650 if Low = 0 then
651 return "";
652 end if;
d23b8f57 653
d23b8f57
RK
654 declare
655 subtype Result_Type is String (1 .. Source'Last - Low + 1);
d23b8f57
RK
656 begin
657 return Result_Type (Source (Low .. Source'Last));
658 end;
3815f967
AC
659 end;
660
661 when Strings.Right =>
662 declare
663 High : constant Natural := Index_Non_Blank (Source, Backward);
664 begin
665 -- All blanks case
666
667 if High = 0 then
668 return "";
669 end if;
d23b8f57 670
d23b8f57
RK
671 declare
672 subtype Result_Type is String (1 .. High - Source'First + 1);
d23b8f57
RK
673 begin
674 return Result_Type (Source (Source'First .. High));
675 end;
3815f967
AC
676 end;
677
678 when Strings.Both =>
679 declare
680 Low : constant Natural := Index_Non_Blank (Source, Forward);
681 begin
682 -- All blanks case
683
684 if Low = 0 then
685 return "";
686 end if;
d23b8f57 687
d23b8f57 688 declare
3815f967
AC
689 High : constant Natural :=
690 Index_Non_Blank (Source, Backward);
d23b8f57 691 subtype Result_Type is String (1 .. High - Low + 1);
d23b8f57
RK
692 begin
693 return Result_Type (Source (Low .. High));
694 end;
3815f967
AC
695 end;
696 end case;
d23b8f57
RK
697 end Trim;
698
699 procedure Trim
700 (Source : in out String;
4e45e7a9
RD
701 Side : Trim_End;
702 Justify : Alignment := Left;
703 Pad : Character := Space)
d23b8f57
RK
704 is
705 begin
706 Move (Trim (Source, Side),
707 Source,
708 Justify => Justify,
709 Pad => Pad);
710 end Trim;
711
712 function Trim
4e45e7a9
RD
713 (Source : String;
714 Left : Maps.Character_Set;
715 Right : Maps.Character_Set) return String
d23b8f57
RK
716 is
717 High, Low : Integer;
718
719 begin
720 Low := Index (Source, Set => Left, Test => Outside, Going => Forward);
721
722 -- Case where source comprises only characters in Left
723
724 if Low = 0 then
725 return "";
726 end if;
727
728 High :=
729 Index (Source, Set => Right, Test => Outside, Going => Backward);
730
731 -- Case where source comprises only characters in Right
732
733 if High = 0 then
734 return "";
735 end if;
736
737 declare
738 subtype Result_Type is String (1 .. High - Low + 1);
739
740 begin
741 return Result_Type (Source (Low .. High));
742 end;
743 end Trim;
744
745 procedure Trim
746 (Source : in out String;
4e45e7a9
RD
747 Left : Maps.Character_Set;
748 Right : Maps.Character_Set;
749 Justify : Alignment := Strings.Left;
750 Pad : Character := Space)
d23b8f57
RK
751 is
752 begin
753 Move (Source => Trim (Source, Left, Right),
754 Target => Source,
755 Justify => Justify,
756 Pad => Pad);
757 end Trim;
758
759end Ada.Strings.Fixed;