OSDN Git Service

* gcc-interface/Makefile.in (gnatlib-shared-default): Append
[pf3gnuchains/gcc-fork.git] / gcc / ada / a-strfix.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT RUN-TIME COMPONENTS                         --
4 --                                                                          --
5 --                    A D A . S T R I N G S . F I X E D                     --
6 --                                                                          --
7 --                                 B o d y                                  --
8 --                                                                          --
9 --          Copyright (C) 1992-2010, 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 ------------------------------------------------------------------------------
31
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
37 --  used a subunit for this procedure). The number of errors having to do with
38 --  bounds of function return results were also fixed, and use of & removed for
39 --  efficiency reasons.
40
41 with Ada.Strings.Maps; use Ada.Strings.Maps;
42 with Ada.Strings.Search;
43
44 package body Ada.Strings.Fixed is
45
46    ------------------------
47    -- Search Subprograms --
48    ------------------------
49
50    function Index
51      (Source  : String;
52       Pattern : String;
53       Going   : Direction := Forward;
54       Mapping : Maps.Character_Mapping := Maps.Identity) return Natural
55    renames Ada.Strings.Search.Index;
56
57    function Index
58      (Source  : String;
59       Pattern : String;
60       Going   : Direction := Forward;
61       Mapping : Maps.Character_Mapping_Function) return Natural
62    renames Ada.Strings.Search.Index;
63
64    function Index
65      (Source : String;
66       Set    : Maps.Character_Set;
67       Test   : Membership := Inside;
68       Going  : Direction  := Forward) return Natural
69    renames Ada.Strings.Search.Index;
70
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
100    function Index_Non_Blank
101      (Source : String;
102       From   : Positive;
103       Going  : Direction := Forward) return Natural
104    renames Ada.Strings.Search.Index_Non_Blank;
105
106    function Count
107      (Source  : String;
108       Pattern : String;
109       Mapping : Maps.Character_Mapping := Maps.Identity) return Natural
110    renames Ada.Strings.Search.Count;
111
112    function Count
113      (Source  : String;
114       Pattern : String;
115       Mapping : Maps.Character_Mapping_Function) return Natural
116    renames Ada.Strings.Search.Count;
117
118    function Count
119      (Source : String;
120       Set    : Maps.Character_Set) return Natural
121    renames Ada.Strings.Search.Count;
122
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
132    procedure Find_Token
133      (Source : String;
134       Set    : Maps.Character_Set;
135       Test   : Membership;
136       First  : out Positive;
137       Last   : out Natural)
138    renames Ada.Strings.Search.Find_Token;
139
140    ---------
141    -- "*" --
142    ---------
143
144    function "*"
145      (Left  : Natural;
146       Right : Character) return String
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 "*"
159      (Left  : Natural;
160       Right : String) return String
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
179      (Source  : String;
180       From    : Positive;
181       Through : Natural) return String
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
195          raise Index_Error;
196
197       else
198          declare
199             Front  : constant Integer := From - Source'First;
200             Result : String (1 .. Source'Length - (Through - From + 1));
201
202          begin
203             Result (1 .. Front) :=
204               Source (Source'First .. From - 1);
205             Result (Front + 1 .. Result'Last) :=
206               Source (Through + 1 .. Source'Last);
207
208             return Result;
209          end;
210       end if;
211    end Delete;
212
213    procedure Delete
214      (Source  : in out String;
215       From    : Positive;
216       Through : Natural;
217       Justify : Alignment := Left;
218       Pad     : Character := Space)
219    is
220    begin
221       Move (Source  => Delete (Source, From, Through),
222             Target  => Source,
223             Justify => Justify,
224             Pad     => Pad);
225    end Delete;
226
227    ----------
228    -- Head --
229    ----------
230
231    function Head
232      (Source : String;
233       Count  : Natural;
234       Pad    : Character := Space) return String
235    is
236       subtype Result_Type is String (1 .. Count);
237
238    begin
239       if Count < Source'Length then
240          return
241            Result_Type (Source (Source'First .. Source'First + Count - 1));
242
243       else
244          declare
245             Result : Result_Type;
246
247          begin
248             Result (1 .. Source'Length) := Source;
249
250             for J in Source'Length + 1 .. Count loop
251                Result (J) := Pad;
252             end loop;
253
254             return Result;
255          end;
256       end if;
257    end Head;
258
259    procedure Head
260      (Source  : in out String;
261       Count   : Natural;
262       Justify : Alignment := Left;
263       Pad     : Character := Space)
264    is
265    begin
266       Move (Source  => Head (Source, Count, Pad),
267             Target  => Source,
268             Drop    => Error,
269             Justify => Justify,
270             Pad     => Pad);
271    end Head;
272
273    ------------
274    -- Insert --
275    ------------
276
277    function Insert
278      (Source   : String;
279       Before   : Positive;
280       New_Item : String) return String
281    is
282       Result : String (1 .. Source'Length + New_Item'Length);
283       Front  : constant Integer := Before - Source'First;
284
285    begin
286       if Before not in Source'First .. Source'Last + 1 then
287          raise Index_Error;
288       end if;
289
290       Result (1 .. Front) :=
291         Source (Source'First .. Before - 1);
292       Result (Front + 1 .. Front + New_Item'Length) :=
293         New_Item;
294       Result (Front + New_Item'Length + 1 .. Result'Last) :=
295         Source (Before .. Source'Last);
296
297       return Result;
298    end Insert;
299
300    procedure Insert
301      (Source   : in out String;
302       Before   : Positive;
303       New_Item : String;
304       Drop     : Truncation := Error)
305    is
306    begin
307       Move (Source => Insert (Source, Before, New_Item),
308             Target => Source,
309             Drop   => Drop);
310    end Insert;
311
312    ----------
313    -- Move --
314    ----------
315
316    procedure Move
317      (Source  : String;
318       Target  : out String;
319       Drop    : Truncation := Error;
320       Justify : Alignment  := Left;
321       Pad     : Character  := Space)
322    is
323       Sfirst  : constant Integer := Source'First;
324       Slast   : constant Integer := Source'Last;
325       Slength : constant Integer := Source'Length;
326
327       Tfirst  : constant Integer := Target'First;
328       Tlast   : constant Integer := Target'Last;
329       Tlength : constant Integer := Target'Length;
330
331       function Is_Padding (Item : String) return Boolean;
332       --  Check if Item is all Pad characters, return True if so, False if not
333
334       function Is_Padding (Item : String) return Boolean is
335       begin
336          for J in Item'Range loop
337             if Item (J) /= Pad then
338                return False;
339             end if;
340          end loop;
341
342          return True;
343       end Is_Padding;
344
345    --  Start of processing for Move
346
347    begin
348       if Slength = Tlength then
349          Target := Source;
350
351       elsif Slength > Tlength then
352
353          case Drop is
354             when Left =>
355                Target := Source (Slast - Tlength + 1 .. Slast);
356
357             when Right =>
358                Target := Source (Sfirst .. Sfirst + Tlength - 1);
359
360             when Error =>
361                case Justify is
362                   when Left =>
363                      if Is_Padding (Source (Sfirst + Tlength .. Slast)) then
364                         Target :=
365                           Source (Sfirst .. Sfirst + Target'Length - 1);
366                      else
367                         raise Length_Error;
368                      end if;
369
370                   when Right =>
371                      if Is_Padding (Source (Sfirst .. Slast - Tlength)) then
372                         Target := Source (Slast - Tlength + 1 .. Slast);
373                      else
374                         raise Length_Error;
375                      end if;
376
377                   when Center =>
378                      raise Length_Error;
379                end case;
380
381          end case;
382
383       --  Source'Length < Target'Length
384
385       else
386          case Justify is
387             when Left =>
388                Target (Tfirst .. Tfirst + Slength - 1) := Source;
389
390                for I in Tfirst + Slength .. Tlast loop
391                   Target (I) := Pad;
392                end loop;
393
394             when Right =>
395                for I in Tfirst .. Tlast - Slength loop
396                   Target (I) := Pad;
397                end loop;
398
399                Target (Tlast - Slength + 1 .. Tlast) := Source;
400
401             when Center =>
402                declare
403                   Front_Pad   : constant Integer := (Tlength - Slength) / 2;
404                   Tfirst_Fpad : constant Integer := Tfirst + Front_Pad;
405
406                begin
407                   for I in Tfirst .. Tfirst_Fpad - 1 loop
408                      Target (I) := Pad;
409                   end loop;
410
411                   Target (Tfirst_Fpad .. Tfirst_Fpad + Slength - 1) := Source;
412
413                   for I in Tfirst_Fpad + Slength .. Tlast loop
414                      Target (I) := Pad;
415                   end loop;
416                end;
417          end case;
418       end if;
419    end Move;
420
421    ---------------
422    -- Overwrite --
423    ---------------
424
425    function Overwrite
426      (Source   : String;
427       Position : Positive;
428       New_Item : String) return String
429    is
430    begin
431       if Position not in Source'First .. Source'Last + 1 then
432          raise Index_Error;
433       end if;
434
435       declare
436          Result_Length : constant Natural :=
437                            Integer'Max
438                              (Source'Length,
439                               Position - Source'First + New_Item'Length);
440
441          Result : String (1 .. Result_Length);
442          Front  : constant Integer := Position - Source'First;
443
444       begin
445          Result (1 .. Front) :=
446            Source (Source'First .. Position - 1);
447          Result (Front + 1 .. Front + New_Item'Length) :=
448            New_Item;
449          Result (Front + New_Item'Length + 1 .. Result'Length) :=
450            Source (Position + New_Item'Length .. Source'Last);
451          return Result;
452       end;
453    end Overwrite;
454
455    procedure Overwrite
456      (Source   : in out String;
457       Position : Positive;
458       New_Item : String;
459       Drop     : Truncation := Right)
460    is
461    begin
462       Move (Source => Overwrite (Source, Position, New_Item),
463             Target => Source,
464             Drop   => Drop);
465    end Overwrite;
466
467    -------------------
468    -- Replace_Slice --
469    -------------------
470
471    function Replace_Slice
472      (Source : String;
473       Low    : Positive;
474       High   : Natural;
475       By     : String) return String
476    is
477    begin
478       if Low > Source'Last + 1 or else High < Source'First - 1 then
479          raise Index_Error;
480       end if;
481
482       if High >= Low then
483          declare
484             Front_Len : constant Integer :=
485                           Integer'Max (0, Low - Source'First);
486             --  Length of prefix of Source copied to result
487
488             Back_Len : constant Integer :=
489                          Integer'Max (0, Source'Last - High);
490             --  Length of suffix of Source copied to result
491
492             Result_Length : constant Integer :=
493                               Front_Len + By'Length + Back_Len;
494             --  Length of result
495
496             Result : String (1 .. Result_Length);
497
498          begin
499             Result (1 .. Front_Len) := Source (Source'First .. Low - 1);
500             Result (Front_Len + 1 .. Front_Len + By'Length) := By;
501             Result (Front_Len + By'Length + 1 .. Result'Length) :=
502               Source (High + 1 .. Source'Last);
503             return Result;
504          end;
505
506       else
507          return Insert (Source, Before => Low, New_Item => By);
508       end if;
509    end Replace_Slice;
510
511    procedure Replace_Slice
512      (Source   : in out String;
513       Low      : Positive;
514       High     : Natural;
515       By       : String;
516       Drop     : Truncation := Error;
517       Justify  : Alignment  := Left;
518       Pad      : Character  := Space)
519    is
520    begin
521       Move (Replace_Slice (Source, Low, High, By), Source, Drop, Justify, Pad);
522    end Replace_Slice;
523
524    ----------
525    -- Tail --
526    ----------
527
528    function Tail
529      (Source : String;
530       Count  : Natural;
531       Pad    : Character := Space) return String
532    is
533       subtype Result_Type is String (1 .. Count);
534
535    begin
536       if Count < Source'Length then
537          return Result_Type (Source (Source'Last - Count + 1 .. Source'Last));
538
539       --  Pad on left
540
541       else
542          declare
543             Result : Result_Type;
544
545          begin
546             for J in 1 .. Count - Source'Length loop
547                Result (J) := Pad;
548             end loop;
549
550             Result (Count - Source'Length + 1 .. Count) := Source;
551             return Result;
552          end;
553       end if;
554    end Tail;
555
556    procedure Tail
557      (Source  : in out String;
558       Count   : Natural;
559       Justify : Alignment := Left;
560       Pad     : Character := Space)
561    is
562    begin
563       Move (Source  => Tail (Source, Count, Pad),
564             Target  => Source,
565             Drop    => Error,
566             Justify => Justify,
567             Pad     => Pad);
568    end Tail;
569
570    ---------------
571    -- Translate --
572    ---------------
573
574    function Translate
575      (Source  : String;
576       Mapping : Maps.Character_Mapping) return String
577    is
578       Result : String (1 .. Source'Length);
579
580    begin
581       for J in Source'Range loop
582          Result (J - (Source'First - 1)) := Value (Mapping, Source (J));
583       end loop;
584
585       return Result;
586    end Translate;
587
588    procedure Translate
589      (Source  : in out String;
590       Mapping : Maps.Character_Mapping)
591    is
592    begin
593       for J in Source'Range loop
594          Source (J) := Value (Mapping, Source (J));
595       end loop;
596    end Translate;
597
598    function Translate
599      (Source  : String;
600       Mapping : Maps.Character_Mapping_Function) return String
601    is
602       Result : String (1 .. Source'Length);
603       pragma Unsuppress (Access_Check);
604
605    begin
606       for J in Source'Range loop
607          Result (J - (Source'First - 1)) := Mapping.all (Source (J));
608       end loop;
609
610       return Result;
611    end Translate;
612
613    procedure Translate
614      (Source  : in out String;
615       Mapping : Maps.Character_Mapping_Function)
616    is
617       pragma Unsuppress (Access_Check);
618    begin
619       for J in Source'Range loop
620          Source (J) := Mapping.all (Source (J));
621       end loop;
622    end Translate;
623
624    ----------
625    -- Trim --
626    ----------
627
628    function Trim
629      (Source : String;
630       Side   : Trim_End) return String
631    is
632       Low, High : Integer;
633
634    begin
635       Low := Index_Non_Blank (Source, Forward);
636
637       --  All blanks case
638
639       if Low = 0 then
640          return "";
641
642       --  At least one non-blank
643
644       else
645          High := Index_Non_Blank (Source, Backward);
646
647          case Side is
648             when Strings.Left =>
649                declare
650                   subtype Result_Type is String (1 .. Source'Last - Low + 1);
651
652                begin
653                   return Result_Type (Source (Low .. Source'Last));
654                end;
655
656             when Strings.Right =>
657                declare
658                   subtype Result_Type is String (1 .. High - Source'First + 1);
659
660                begin
661                   return Result_Type (Source (Source'First .. High));
662                end;
663
664             when Strings.Both =>
665                declare
666                   subtype Result_Type is String (1 .. High - Low + 1);
667
668                begin
669                   return Result_Type (Source (Low .. High));
670                end;
671          end case;
672       end if;
673    end Trim;
674
675    procedure Trim
676      (Source  : in out String;
677       Side    : Trim_End;
678       Justify : Alignment := Left;
679       Pad     : Character := Space)
680    is
681    begin
682       Move (Trim (Source, Side),
683             Source,
684             Justify => Justify,
685             Pad => Pad);
686    end Trim;
687
688    function Trim
689      (Source : String;
690       Left   : Maps.Character_Set;
691       Right  : Maps.Character_Set) return String
692    is
693       High, Low : Integer;
694
695    begin
696       Low := Index (Source, Set => Left, Test  => Outside, Going => Forward);
697
698       --  Case where source comprises only characters in Left
699
700       if Low = 0 then
701          return "";
702       end if;
703
704       High :=
705         Index (Source, Set => Right, Test  => Outside, Going => Backward);
706
707       --  Case where source comprises only characters in Right
708
709       if High = 0 then
710          return "";
711       end if;
712
713       declare
714          subtype Result_Type is String (1 .. High - Low + 1);
715
716       begin
717          return Result_Type (Source (Low .. High));
718       end;
719    end Trim;
720
721    procedure Trim
722      (Source  : in out String;
723       Left    : Maps.Character_Set;
724       Right   : Maps.Character_Set;
725       Justify : Alignment := Strings.Left;
726       Pad     : Character := Space)
727    is
728    begin
729       Move (Source  => Trim (Source, Left, Right),
730             Target  => Source,
731             Justify => Justify,
732             Pad     => Pad);
733    end Trim;
734
735 end Ada.Strings.Fixed;