1 ------------------------------------------------------------------------------
3 -- GNAT RUNTIME COMPONENTS --
5 -- A D A . S T R I N G S . F I X E D --
9 -- Copyright (C) 1992-2001 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 2, 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. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING. If not, write --
19 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
20 -- MA 02111-1307, USA. --
22 -- As a special exception, if other files instantiate generics from this --
23 -- unit, or you link this unit with other files to produce an executable, --
24 -- this unit does not by itself cause the resulting executable to be --
25 -- covered by the GNU General Public License. This exception does not --
26 -- however invalidate any other reasons why the executable file might be --
27 -- covered by the GNU Public License. --
29 -- GNAT was originally developed by the GNAT team at New York University. --
30 -- Extensive contributions were provided by Ada Core Technologies Inc. --
32 ------------------------------------------------------------------------------
34 -- Note: This code is derived from the ADAR.CSH public domain Ada 83
35 -- versions of the Appendix C string handling packages. One change is
36 -- to avoid the use of Is_In, so that we are not dependent on inlining.
37 -- Note that the search function implementations are to be found in the
38 -- auxiliary package Ada.Strings.Search. Also the Move procedure is
39 -- directly incorporated (ADAR used a subunit for this procedure). A
40 -- number of errors having to do with bounds of function return results
41 -- were also fixed, and use of & removed for efficiency reasons.
43 with Ada
.Strings
.Maps
; use Ada
.Strings
.Maps
;
44 with Ada
.Strings
.Search
;
46 package body Ada
.Strings
.Fixed
is
48 ------------------------
49 -- Search Subprograms --
50 ------------------------
55 Going
: in Direction
:= Forward
;
56 Mapping
: in Maps
.Character_Mapping
:= Maps
.Identity
)
58 renames Ada
.Strings
.Search
.Index
;
63 Going
: in Direction
:= Forward
;
64 Mapping
: in Maps
.Character_Mapping_Function
)
66 renames Ada
.Strings
.Search
.Index
;
70 Set
: in Maps
.Character_Set
;
71 Test
: in Membership
:= Inside
;
72 Going
: in Direction
:= Forward
)
74 renames Ada
.Strings
.Search
.Index
;
76 function Index_Non_Blank
78 Going
: in Direction
:= Forward
)
80 renames Ada
.Strings
.Search
.Index_Non_Blank
;
85 Mapping
: in Maps
.Character_Mapping
:= Maps
.Identity
)
87 renames Ada
.Strings
.Search
.Count
;
92 Mapping
: in Maps
.Character_Mapping_Function
)
94 renames Ada
.Strings
.Search
.Count
;
98 Set
: in Maps
.Character_Set
)
100 renames Ada
.Strings
.Search
.Count
;
104 Set
: in Maps
.Character_Set
;
105 Test
: in Membership
;
106 First
: out Positive;
108 renames Ada
.Strings
.Search
.Find_Token
;
116 Right
: in Character)
119 Result
: String (1 .. Left
);
122 for J
in Result
'Range loop
134 Result
: String (1 .. Left
* Right
'Length);
138 for J
in 1 .. Left
loop
139 Result
(Ptr
.. Ptr
+ Right
'Length - 1) := Right
;
140 Ptr
:= Ptr
+ Right
'Length;
153 Through
: in Natural)
157 if From
> Through
then
159 subtype Result_Type
is String (1 .. Source
'Length);
162 return Result_Type
(Source
);
165 elsif From
not in Source
'Range
166 or else Through
> Source
'Last
172 Front
: constant Integer := From
- Source
'First;
173 Result
: String (1 .. Source
'Length - (Through
- From
+ 1));
176 Result
(1 .. Front
) :=
177 Source
(Source
'First .. From
- 1);
178 Result
(Front
+ 1 .. Result
'Last) :=
179 Source
(Through
+ 1 .. Source
'Last);
187 (Source
: in out String;
189 Through
: in Natural;
190 Justify
: in Alignment
:= Left
;
191 Pad
: in Character := Space
)
194 Move
(Source
=> Delete
(Source
, From
, Through
),
207 Pad
: in Character := Space
)
210 subtype Result_Type
is String (1 .. Count
);
213 if Count
< Source
'Length then
215 Result_Type
(Source
(Source
'First .. Source
'First + Count
- 1));
219 Result
: Result_Type
;
222 Result
(1 .. Source
'Length) := Source
;
224 for J
in Source
'Length + 1 .. Count
loop
234 (Source
: in out String;
236 Justify
: in Alignment
:= Left
;
237 Pad
: in Character := Space
)
240 Move
(Source
=> Head
(Source
, Count
, Pad
),
253 Before
: in Positive;
254 New_Item
: in String)
257 Result
: String (1 .. Source
'Length + New_Item
'Length);
258 Front
: constant Integer := Before
- Source
'First;
261 if Before
not in Source
'First .. Source
'Last + 1 then
265 Result
(1 .. Front
) :=
266 Source
(Source
'First .. Before
- 1);
267 Result
(Front
+ 1 .. Front
+ New_Item
'Length) :=
269 Result
(Front
+ New_Item
'Length + 1 .. Result
'Last) :=
270 Source
(Before
.. Source
'Last);
276 (Source
: in out String;
277 Before
: in Positive;
278 New_Item
: in String;
279 Drop
: in Truncation
:= Error
)
282 Move
(Source
=> Insert
(Source
, Before
, New_Item
),
294 Drop
: in Truncation
:= Error
;
295 Justify
: in Alignment
:= Left
;
296 Pad
: in Character := Space
)
298 Sfirst
: constant Integer := Source
'First;
299 Slast
: constant Integer := Source
'Last;
300 Slength
: constant Integer := Source
'Length;
302 Tfirst
: constant Integer := Target
'First;
303 Tlast
: constant Integer := Target
'Last;
304 Tlength
: constant Integer := Target
'Length;
306 function Is_Padding
(Item
: String) return Boolean;
307 -- Check if Item is all Pad characters, return True if so, False if not
309 function Is_Padding
(Item
: String) return Boolean is
311 for J
in Item
'Range loop
312 if Item
(J
) /= Pad
then
320 -- Start of processing for Move
323 if Slength
= Tlength
then
326 elsif Slength
> Tlength
then
330 Target
:= Source
(Slast
- Tlength
+ 1 .. Slast
);
333 Target
:= Source
(Sfirst
.. Sfirst
+ Tlength
- 1);
338 if Is_Padding
(Source
(Sfirst
+ Tlength
.. Slast
)) then
340 Source
(Sfirst
.. Sfirst
+ Target
'Length - 1);
346 if Is_Padding
(Source
(Sfirst
.. Slast
- Tlength
)) then
347 Target
:= Source
(Slast
- Tlength
+ 1 .. Slast
);
358 -- Source'Length < Target'Length
363 Target
(Tfirst
.. Tfirst
+ Slength
- 1) := Source
;
365 for I
in Tfirst
+ Slength
.. Tlast
loop
370 for I
in Tfirst
.. Tlast
- Slength
loop
374 Target
(Tlast
- Slength
+ 1 .. Tlast
) := Source
;
378 Front_Pad
: constant Integer := (Tlength
- Slength
) / 2;
379 Tfirst_Fpad
: constant Integer := Tfirst
+ Front_Pad
;
382 for I
in Tfirst
.. Tfirst_Fpad
- 1 loop
386 Target
(Tfirst_Fpad
.. Tfirst_Fpad
+ Slength
- 1) := Source
;
388 for I
in Tfirst_Fpad
+ Slength
.. Tlast
loop
402 Position
: in Positive;
403 New_Item
: in String)
407 if Position
not in Source
'First .. Source
'Last + 1 then
412 Result_Length
: Natural :=
414 (Source
'Length, Position
- Source
'First + New_Item
'Length);
416 Result
: String (1 .. Result_Length
);
417 Front
: constant Integer := Position
- Source
'First;
420 Result
(1 .. Front
) :=
421 Source
(Source
'First .. Position
- 1);
422 Result
(Front
+ 1 .. Front
+ New_Item
'Length) :=
424 Result
(Front
+ New_Item
'Length + 1 .. Result
'Length) :=
425 Source
(Position
+ New_Item
'Length .. Source
'Last);
431 (Source
: in out String;
432 Position
: in Positive;
433 New_Item
: in String;
434 Drop
: in Truncation
:= Right
)
437 Move
(Source
=> Overwrite
(Source
, Position
, New_Item
),
446 function Replace_Slice
454 if Low
> Source
'Last + 1 or High
< Source
'First - 1 then
460 Front_Len
: constant Integer :=
461 Integer'Max (0, Low
- Source
'First);
462 -- Length of prefix of Source copied to result
464 Back_Len
: constant Integer :=
465 Integer'Max (0, Source
'Last - High
);
466 -- Length of suffix of Source copied to result
468 Result_Length
: constant Integer :=
469 Front_Len
+ By
'Length + Back_Len
;
472 Result
: String (1 .. Result_Length
);
475 Result
(1 .. Front_Len
) :=
476 Source
(Source
'First .. Low
- 1);
477 Result
(Front_Len
+ 1 .. Front_Len
+ By
'Length) :=
479 Result
(Front_Len
+ By
'Length + 1 .. Result
'Length) :=
480 Source
(High
+ 1 .. Source
'Last);
486 return Insert
(Source
, Before
=> Low
, New_Item
=> By
);
490 procedure Replace_Slice
491 (Source
: in out String;
495 Drop
: in Truncation
:= Error
;
496 Justify
: in Alignment
:= Left
;
497 Pad
: in Character := Space
)
500 Move
(Replace_Slice
(Source
, Low
, High
, By
), Source
, Drop
, Justify
, Pad
);
510 Pad
: in Character := Space
)
513 subtype Result_Type
is String (1 .. Count
);
516 if Count
< Source
'Length then
517 return Result_Type
(Source
(Source
'Last - Count
+ 1 .. Source
'Last));
523 Result
: Result_Type
;
526 for J
in 1 .. Count
- Source
'Length loop
530 Result
(Count
- Source
'Length + 1 .. Count
) := Source
;
537 (Source
: in out String;
539 Justify
: in Alignment
:= Left
;
540 Pad
: in Character := Space
)
543 Move
(Source
=> Tail
(Source
, Count
, Pad
),
556 Mapping
: in Maps
.Character_Mapping
)
559 Result
: String (1 .. Source
'Length);
562 for J
in Source
'Range loop
563 Result
(J
- (Source
'First - 1)) := Value
(Mapping
, Source
(J
));
570 (Source
: in out String;
571 Mapping
: in Maps
.Character_Mapping
)
574 for J
in Source
'Range loop
575 Source
(J
) := Value
(Mapping
, Source
(J
));
581 Mapping
: in Maps
.Character_Mapping_Function
)
584 Result
: String (1 .. Source
'Length);
585 pragma Unsuppress
(Access_Check
);
588 for J
in Source
'Range loop
589 Result
(J
- (Source
'First - 1)) := Mapping
.all (Source
(J
));
596 (Source
: in out String;
597 Mapping
: in Maps
.Character_Mapping_Function
)
599 pragma Unsuppress
(Access_Check
);
601 for J
in Source
'Range loop
602 Source
(J
) := Mapping
.all (Source
(J
));
618 Low
:= Index_Non_Blank
(Source
, Forward
);
625 -- At least one non-blank
628 High
:= Index_Non_Blank
(Source
, Backward
);
633 subtype Result_Type
is String (1 .. Source
'Last - Low
+ 1);
636 return Result_Type
(Source
(Low
.. Source
'Last));
639 when Strings
.Right
=>
641 subtype Result_Type
is String (1 .. High
- Source
'First + 1);
644 return Result_Type
(Source
(Source
'First .. High
));
649 subtype Result_Type
is String (1 .. High
- Low
+ 1);
652 return Result_Type
(Source
(Low
.. High
));
659 (Source
: in out String;
661 Justify
: in Alignment
:= Left
;
662 Pad
: in Character := Space
)
665 Move
(Trim
(Source
, Side
),
673 Left
: in Maps
.Character_Set
;
674 Right
: in Maps
.Character_Set
)
680 Low
:= Index
(Source
, Set
=> Left
, Test
=> Outside
, Going
=> Forward
);
682 -- Case where source comprises only characters in Left
689 Index
(Source
, Set
=> Right
, Test
=> Outside
, Going
=> Backward
);
691 -- Case where source comprises only characters in Right
698 subtype Result_Type
is String (1 .. High
- Low
+ 1);
701 return Result_Type
(Source
(Low
.. High
));
706 (Source
: in out String;
707 Left
: in Maps
.Character_Set
;
708 Right
: in Maps
.Character_Set
;
709 Justify
: in Alignment
:= Strings
.Left
;
710 Pad
: in Character := Space
)
713 Move
(Source
=> Trim
(Source
, Left
, Right
),
719 end Ada
.Strings
.Fixed
;