OSDN Git Service

libitm: Remove unused code.
[pf3gnuchains/gcc-fork.git] / gcc / ada / g-catiio.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT RUN-TIME COMPONENTS                         --
4 --                                                                          --
5 --                G N A T . C A L E N D A R . T I M E _ I O                 --
6 --                                                                          --
7 --                                 B o d y                                  --
8 --                                                                          --
9 --                     Copyright (C) 1999-2010, AdaCore                     --
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 with Ada.Calendar;            use Ada.Calendar;
33 with Ada.Characters.Handling;
34 with Ada.Strings.Unbounded;   use Ada.Strings.Unbounded;
35 with Ada.Text_IO;
36
37 with GNAT.Case_Util;
38
39 package body GNAT.Calendar.Time_IO is
40
41    type Month_Name is
42      (January,
43       February,
44       March,
45       April,
46       May,
47       June,
48       July,
49       August,
50       September,
51       October,
52       November,
53       December);
54
55    function Month_Name_To_Number
56      (Str : String) return Ada.Calendar.Month_Number;
57    --  Converts a string that contains an abbreviated month name to a month
58    --  number. Constraint_Error is raised if Str is not a valid month name.
59    --  Comparison is case insensitive
60
61    type Padding_Mode is (None, Zero, Space);
62
63    type Sec_Number is mod 2 ** 64;
64    --  Type used to compute the number of seconds since 01/01/1970. A 32 bit
65    --  number will cover only a period of 136 years. This means that for date
66    --  past 2106 the computation is not possible. A 64 bits number should be
67    --  enough for a very large period of time.
68
69    -----------------------
70    -- Local Subprograms --
71    -----------------------
72
73    function Am_Pm (H : Natural) return String;
74    --  Return AM or PM depending on the hour H
75
76    function Hour_12 (H : Natural) return Positive;
77    --  Convert a 1-24h format to a 0-12 hour format
78
79    function Image (Str : String; Length : Natural := 0) return String;
80    --  Return Str capitalized and cut to length number of characters. If
81    --  length is 0, then no cut operation is performed.
82
83    function Image
84      (N       : Sec_Number;
85       Padding : Padding_Mode := Zero;
86       Length  : Natural := 0) return String;
87    --  Return image of N. This number is eventually padded with zeros or spaces
88    --  depending of the length required. If length is 0 then no padding occurs.
89
90    function Image
91      (N       : Natural;
92       Padding : Padding_Mode := Zero;
93       Length  : Natural := 0) return String;
94    --  As above with N provided in Integer format
95
96    -----------
97    -- Am_Pm --
98    -----------
99
100    function Am_Pm (H : Natural) return String is
101    begin
102       if H = 0 or else H > 12 then
103          return "PM";
104       else
105          return "AM";
106       end if;
107    end Am_Pm;
108
109    -------------
110    -- Hour_12 --
111    -------------
112
113    function Hour_12 (H : Natural) return Positive is
114    begin
115       if H = 0 then
116          return 12;
117       elsif H <= 12 then
118          return H;
119       else --  H > 12
120          return H - 12;
121       end if;
122    end Hour_12;
123
124    -----------
125    -- Image --
126    -----------
127
128    function Image
129      (Str    : String;
130       Length : Natural := 0) return String
131    is
132       use Ada.Characters.Handling;
133       Local : constant String :=
134                 To_Upper (Str (Str'First)) &
135                   To_Lower (Str (Str'First + 1 .. Str'Last));
136    begin
137       if Length = 0 then
138          return Local;
139       else
140          return Local (1 .. Length);
141       end if;
142    end Image;
143
144    -----------
145    -- Image --
146    -----------
147
148    function Image
149      (N       : Natural;
150       Padding : Padding_Mode := Zero;
151       Length  : Natural := 0) return String
152    is
153    begin
154       return Image (Sec_Number (N), Padding, Length);
155    end Image;
156
157    function Image
158      (N       : Sec_Number;
159       Padding : Padding_Mode := Zero;
160       Length  : Natural := 0) return String
161    is
162       function Pad_Char return String;
163
164       --------------
165       -- Pad_Char --
166       --------------
167
168       function Pad_Char return String is
169       begin
170          case Padding is
171             when None  => return "";
172             when Zero  => return "00";
173             when Space => return "  ";
174          end case;
175       end Pad_Char;
176
177       --  Local Declarations
178
179       NI  : constant String := Sec_Number'Image (N);
180       NIP : constant String := Pad_Char & NI (2 .. NI'Last);
181
182    --  Start of processing for Image
183
184    begin
185       if Length = 0 or else Padding = None then
186          return NI (2 .. NI'Last);
187       else
188          return NIP (NIP'Last - Length + 1 .. NIP'Last);
189       end if;
190    end Image;
191
192    -----------
193    -- Image --
194    -----------
195
196    function Image
197      (Date    : Ada.Calendar.Time;
198       Picture : Picture_String) return String
199    is
200       Padding : Padding_Mode := Zero;
201       --  Padding is set for one directive
202
203       Result : Unbounded_String;
204
205       Year       : Year_Number;
206       Month      : Month_Number;
207       Day        : Day_Number;
208       Hour       : Hour_Number;
209       Minute     : Minute_Number;
210       Second     : Second_Number;
211       Sub_Second : Second_Duration;
212
213       P : Positive;
214
215    begin
216       --  Get current time in split format
217
218       Split (Date, Year, Month, Day, Hour, Minute, Second, Sub_Second);
219
220       --  Null picture string is error
221
222       if Picture = "" then
223          raise Picture_Error with "null picture string";
224       end if;
225
226       --  Loop through characters of picture string, building result
227
228       Result := Null_Unbounded_String;
229       P := Picture'First;
230       while P <= Picture'Last loop
231
232          --  A directive has the following format "%[-_]."
233
234          if Picture (P) = '%' then
235             Padding := Zero;
236
237             if P = Picture'Last then
238                raise Picture_Error with "picture string ends with '%";
239             end if;
240
241             --  Check for GNU extension to change the padding
242
243             if Picture (P + 1) = '-' then
244                Padding := None;
245                P := P + 1;
246
247             elsif Picture (P + 1) = '_' then
248                Padding := Space;
249                P := P + 1;
250             end if;
251
252             if P = Picture'Last then
253                raise Picture_Error with "picture string ends with '- or '_";
254             end if;
255
256             case Picture (P + 1) is
257
258                --  Literal %
259
260                when '%' =>
261                   Result := Result & '%';
262
263                --  A newline
264
265                when 'n' =>
266                   Result := Result & ASCII.LF;
267
268                --  A horizontal tab
269
270                when 't' =>
271                   Result := Result & ASCII.HT;
272
273                --  Hour (00..23)
274
275                when 'H' =>
276                   Result := Result & Image (Hour, Padding, 2);
277
278                --  Hour (01..12)
279
280                when 'I' =>
281                   Result := Result & Image (Hour_12 (Hour), Padding, 2);
282
283                --  Hour ( 0..23)
284
285                when 'k' =>
286                   Result := Result & Image (Hour, Space, 2);
287
288                --  Hour ( 1..12)
289
290                when 'l' =>
291                   Result := Result & Image (Hour_12 (Hour), Space, 2);
292
293                --  Minute (00..59)
294
295                when 'M' =>
296                   Result := Result & Image (Minute, Padding, 2);
297
298                --  AM/PM
299
300                when 'p' =>
301                   Result := Result & Am_Pm (Hour);
302
303                --  Time, 12-hour (hh:mm:ss [AP]M)
304
305                when 'r' =>
306                   Result := Result &
307                     Image (Hour_12 (Hour), Padding, Length => 2) & ':' &
308                     Image (Minute, Padding, Length => 2) & ':' &
309                     Image (Second, Padding, Length => 2) & ' ' &
310                     Am_Pm (Hour);
311
312                --   Seconds since 1970-01-01  00:00:00 UTC
313                --   (a nonstandard extension)
314
315                when 's' =>
316                   declare
317                      --  Compute the number of seconds using Ada.Calendar.Time
318                      --  values rather than Julian days to account for Daylight
319                      --  Savings Time.
320
321                      Neg : Boolean  := False;
322                      Sec : Duration := Date - Time_Of (1970, 1, 1, 0.0);
323
324                   begin
325                      --  Avoid rounding errors and perform special processing
326                      --  for dates earlier than the Unix Epoc.
327
328                      if Sec > 0.0 then
329                         Sec := Sec - 0.5;
330                      elsif Sec < 0.0 then
331                         Neg := True;
332                         Sec := abs (Sec + 0.5);
333                      end if;
334
335                      --  Prepend a minus sign to the result since Sec_Number
336                      --  cannot handle negative numbers.
337
338                      if Neg then
339                         Result :=
340                           Result & "-" & Image (Sec_Number (Sec), None);
341                      else
342                         Result := Result & Image (Sec_Number (Sec), None);
343                      end if;
344                   end;
345
346                --  Second (00..59)
347
348                when 'S' =>
349                   Result := Result & Image (Second, Padding, Length => 2);
350
351                --  Milliseconds (3 digits)
352                --  Microseconds (6 digits)
353                --  Nanoseconds  (9 digits)
354
355                when 'i' | 'e' | 'o' =>
356                   declare
357                      Sub_Sec : constant Long_Integer :=
358                                  Long_Integer (Sub_Second * 1_000_000_000);
359
360                      Img1  : constant String := Sub_Sec'Img;
361                      Img2  : constant String :=
362                                "00000000" & Img1 (Img1'First + 1 .. Img1'Last);
363                      Nanos : constant String :=
364                                Img2 (Img2'Last - 8 .. Img2'Last);
365
366                   begin
367                      case Picture (P + 1) is
368                         when 'i' =>
369                            Result := Result &
370                              Nanos (Nanos'First .. Nanos'First + 2);
371
372                         when 'e' =>
373                            Result := Result &
374                              Nanos (Nanos'First .. Nanos'First + 5);
375
376                         when 'o' =>
377                            Result := Result & Nanos;
378
379                         when others =>
380                            null;
381                      end case;
382                   end;
383
384                --  Time, 24-hour (hh:mm:ss)
385
386                when 'T' =>
387                   Result := Result &
388                     Image (Hour, Padding, Length => 2)   & ':' &
389                     Image (Minute, Padding, Length => 2) & ':' &
390                     Image (Second, Padding, Length => 2);
391
392                --  Locale's abbreviated weekday name (Sun..Sat)
393
394                when 'a' =>
395                   Result := Result &
396                     Image (Day_Name'Image (Day_Of_Week (Date)), 3);
397
398                --  Locale's full weekday name, variable length
399                --  (Sunday..Saturday)
400
401                when 'A' =>
402                   Result := Result &
403                     Image (Day_Name'Image (Day_Of_Week (Date)));
404
405                --  Locale's abbreviated month name (Jan..Dec)
406
407                when 'b' | 'h' =>
408                   Result := Result &
409                     Image (Month_Name'Image (Month_Name'Val (Month - 1)), 3);
410
411                --  Locale's full month name, variable length
412                --  (January..December).
413
414                when 'B' =>
415                   Result := Result &
416                     Image (Month_Name'Image (Month_Name'Val (Month - 1)));
417
418                --  Locale's date and time (Sat Nov 04 12:02:33 EST 1989)
419
420                when 'c' =>
421                   case Padding is
422                      when Zero =>
423                         Result := Result & Image (Date, "%a %b %d %T %Y");
424                      when Space =>
425                         Result := Result & Image (Date, "%a %b %_d %_T %Y");
426                      when None =>
427                         Result := Result & Image (Date, "%a %b %-d %-T %Y");
428                   end case;
429
430                --   Day of month (01..31)
431
432                when 'd' =>
433                   Result := Result & Image (Day, Padding, 2);
434
435                --  Date (mm/dd/yy)
436
437                when 'D' | 'x' =>
438                   Result := Result &
439                               Image (Month, Padding, 2) & '/' &
440                               Image (Day, Padding, 2) & '/' &
441                               Image (Year, Padding, 2);
442
443                --  Day of year (001..366)
444
445                when 'j' =>
446                   Result := Result & Image (Day_In_Year (Date), Padding, 3);
447
448                --  Month (01..12)
449
450                when 'm' =>
451                   Result := Result & Image (Month, Padding, 2);
452
453                --  Week number of year with Sunday as first day of week
454                --  (00..53)
455
456                when 'U' =>
457                   declare
458                      Offset : constant Natural :=
459                                 (Julian_Day (Year, 1, 1) + 1) mod 7;
460
461                      Week : constant Natural :=
462                               1 + ((Day_In_Year (Date) - 1) + Offset) / 7;
463
464                   begin
465                      Result := Result & Image (Week, Padding, 2);
466                   end;
467
468                --  Day of week (0..6) with 0 corresponding to Sunday
469
470                when 'w' =>
471                   declare
472                      DOW : constant Natural range 0 .. 6 :=
473                              (if Day_Of_Week (Date) = Sunday
474                               then 0
475                               else Day_Name'Pos (Day_Of_Week (Date)));
476                   begin
477                      Result := Result & Image (DOW, Length => 1);
478                   end;
479
480                --  Week number of year with Monday as first day of week
481                --  (00..53)
482
483                when 'W' =>
484                   Result := Result & Image (Week_In_Year (Date), Padding, 2);
485
486                --  Last two digits of year (00..99)
487
488                when 'y' =>
489                   declare
490                      Y : constant Natural := Year - (Year / 100) * 100;
491                   begin
492                      Result := Result & Image (Y, Padding, 2);
493                   end;
494
495                --   Year (1970...)
496
497                when 'Y' =>
498                   Result := Result & Image (Year, None, 4);
499
500                when others =>
501                   raise Picture_Error with
502                     "unknown format character in picture string";
503
504             end case;
505
506             --  Skip past % and format character
507
508             P := P + 2;
509
510          --  Character other than % is copied into the result
511
512          else
513             Result := Result & Picture (P);
514             P := P + 1;
515          end if;
516       end loop;
517
518       return To_String (Result);
519    end Image;
520
521    --------------------------
522    -- Month_Name_To_Number --
523    --------------------------
524
525    function Month_Name_To_Number
526      (Str : String) return Ada.Calendar.Month_Number
527    is
528       subtype String3 is String (1 .. 3);
529       Abbrev_Upper_Month_Names :
530         constant array (Ada.Calendar.Month_Number) of String3 :=
531          ("JAN", "FEB", "MAR", "APR", "MAY", "JUN",
532           "JUL", "AUG", "SEP", "OCT", "NOV", "DEC");
533       --  Short version of the month names, used when parsing date strings
534
535       S                                                     : String := Str;
536
537    begin
538       GNAT.Case_Util.To_Upper (S);
539
540       for J in Abbrev_Upper_Month_Names'Range loop
541          if Abbrev_Upper_Month_Names (J) = S then
542             return J;
543          end if;
544       end loop;
545
546       return Abbrev_Upper_Month_Names'First;
547    end Month_Name_To_Number;
548
549    -----------
550    -- Value --
551    -----------
552
553    function Value (Date : String) return Ada.Calendar.Time is
554       D          : String (1 .. 21);
555       D_Length   : constant Natural := Date'Length;
556
557       Year   : Year_Number;
558       Month  : Month_Number;
559       Day    : Day_Number;
560       Hour   : Hour_Number;
561       Minute : Minute_Number;
562       Second : Second_Number;
563
564       procedure Extract_Date
565         (Year       : out Year_Number;
566          Month      : out Month_Number;
567          Day        : out Day_Number;
568          Time_Start : out Natural);
569       --  Try and extract a date value from string D. Time_Start is set to the
570       --  first character that could be the start of time data.
571
572       procedure Extract_Time
573         (Index       : Positive;
574          Hour        : out Hour_Number;
575          Minute      : out Minute_Number;
576          Second      : out Second_Number;
577          Check_Space : Boolean := False);
578       --  Try and extract a time value from string D starting from position
579       --  Index. Set Check_Space to True to check whether the character at
580       --  Index - 1 is a space. Raise Constraint_Error if the portion of D
581       --  corresponding to the date is not well formatted.
582
583       ------------------
584       -- Extract_Date --
585       ------------------
586
587       procedure Extract_Date
588         (Year       : out Year_Number;
589          Month      : out Month_Number;
590          Day        : out Day_Number;
591          Time_Start : out Natural)
592       is
593       begin
594          if D (3) = '-' or else D (3) = '/' then
595             if D_Length = 8 or else D_Length = 17 then
596
597                --  Formats are "yy*mm*dd" or "yy*mm*dd hh:mm:ss"
598
599                if D (6) /= D (3) then
600                   raise Constraint_Error;
601                end if;
602
603                Year  := Year_Number'Value ("20" & D (1 .. 2));
604                Month := Month_Number'Value       (D (4 .. 5));
605                Day   := Day_Number'Value         (D (7 .. 8));
606                Time_Start := 10;
607
608             elsif D_Length = 10 or else D_Length = 19 then
609
610                --  Formats are "mm*dd*yyyy" or "mm*dd*yyyy hh:mm:ss"
611
612                if D (6) /= D (3) then
613                   raise Constraint_Error;
614                end if;
615
616                Year  := Year_Number'Value  (D (7 .. 10));
617                Month := Month_Number'Value (D (1 .. 2));
618                Day   := Day_Number'Value   (D (4 .. 5));
619                Time_Start := 12;
620
621             elsif D_Length = 11 or else D_Length = 20 then
622
623                --  Formats are "dd*mmm*yyyy" or "dd*mmm*yyyy hh:mm:ss"
624
625                if D (7) /= D (3) then
626                   raise Constraint_Error;
627                end if;
628
629                Year  := Year_Number'Value  (D (8 .. 11));
630                Month := Month_Name_To_Number (D (4 .. 6));
631                Day   := Day_Number'Value   (D (1 .. 2));
632                Time_Start := 13;
633
634             else
635                raise Constraint_Error;
636             end if;
637
638          elsif D (3) = ' ' then
639             if D_Length = 11 or else D_Length = 20 then
640
641                --  Possible formats are "dd mmm yyyy", "dd mmm yyyy hh:mm:ss"
642
643                if D (7) /= ' ' then
644                   raise Constraint_Error;
645                end if;
646
647                Year  := Year_Number'Value  (D (8 .. 11));
648                Month := Month_Name_To_Number (D (4 .. 6));
649                Day   := Day_Number'Value   (D (1 .. 2));
650                Time_Start := 13;
651
652             else
653                raise Constraint_Error;
654             end if;
655
656          else
657             if D_Length = 8 or else D_Length = 17 then
658
659                --  Possible formats are "yyyymmdd" or "yyyymmdd hh:mm:ss"
660
661                Year  := Year_Number'Value (D (1 .. 4));
662                Month := Month_Number'Value (D (5 .. 6));
663                Day   := Day_Number'Value (D (7 .. 8));
664                Time_Start := 10;
665
666             elsif D_Length = 10 or else D_Length = 19 then
667
668                --  Possible formats are "yyyy*mm*dd" or "yyyy*mm*dd hh:mm:ss"
669
670                if (D (5) /= '-' and then D (5) /= '/')
671                  or else D (8) /= D (5)
672                then
673                   raise Constraint_Error;
674                end if;
675
676                Year  := Year_Number'Value (D (1 .. 4));
677                Month := Month_Number'Value (D (6 .. 7));
678                Day   := Day_Number'Value (D (9 .. 10));
679                Time_Start := 12;
680
681             elsif D_Length = 11 or else D_Length = 20 then
682
683                --  Possible formats are "yyyy*mmm*dd"
684
685                if (D (5) /= '-' and then D (5) /= '/')
686                  or else D (9) /= D (5)
687                then
688                   raise Constraint_Error;
689                end if;
690
691                Year  := Year_Number'Value (D (1 .. 4));
692                Month := Month_Name_To_Number (D (6 .. 8));
693                Day   := Day_Number'Value (D (10 .. 11));
694                Time_Start := 13;
695
696             elsif D_Length = 12 or else D_Length = 21 then
697
698                --  Formats are "mmm dd, yyyy" or "mmm dd, yyyy hh:mm:ss"
699
700                if D (4) /= ' '
701                  or else D (7) /= ','
702                  or else D (8) /= ' '
703                then
704                   raise Constraint_Error;
705                end if;
706
707                Year  := Year_Number'Value (D (9 .. 12));
708                Month := Month_Name_To_Number (D (1 .. 3));
709                Day   := Day_Number'Value (D (5 .. 6));
710                Time_Start := 14;
711
712             else
713                raise Constraint_Error;
714             end if;
715          end if;
716       end Extract_Date;
717
718       ------------------
719       -- Extract_Time --
720       ------------------
721
722       procedure Extract_Time
723         (Index       : Positive;
724          Hour        : out Hour_Number;
725          Minute      : out Minute_Number;
726          Second      : out Second_Number;
727          Check_Space : Boolean := False)
728       is
729       begin
730          --  If no time was specified in the string (do not allow trailing
731          --  character either)
732
733          if Index = D_Length + 2 then
734             Hour   := 0;
735             Minute := 0;
736             Second := 0;
737
738          else
739             --  Not enough characters left ?
740
741             if Index /= D_Length - 7 then
742                raise Constraint_Error;
743             end if;
744
745             if Check_Space and then D (Index - 1) /= ' ' then
746                raise Constraint_Error;
747             end if;
748
749             if D (Index + 2) /= ':' or else D (Index + 5) /= ':' then
750                raise Constraint_Error;
751             end if;
752
753             Hour   := Hour_Number'Value   (D (Index     .. Index + 1));
754             Minute := Minute_Number'Value (D (Index + 3 .. Index + 4));
755             Second := Second_Number'Value (D (Index + 6 .. Index + 7));
756          end if;
757       end Extract_Time;
758
759       --  Local Declarations
760
761       Time_Start : Natural := 1;
762
763    --  Start of processing for Value
764
765    begin
766       --  Length checks
767
768       if D_Length /= 8
769         and then D_Length /= 10
770         and then D_Length /= 11
771         and then D_Length /= 12
772         and then D_Length /= 17
773         and then D_Length /= 19
774         and then D_Length /= 20
775         and then D_Length /= 21
776       then
777          raise Constraint_Error;
778       end if;
779
780       --  After the correct length has been determined, it is safe to create
781       --  a local string copy in order to avoid String'First N arithmetic.
782
783       D (1 .. D_Length) := Date;
784
785       if D_Length /= 8 or else D (3) /= ':' then
786          Extract_Date (Year, Month, Day, Time_Start);
787          Extract_Time (Time_Start, Hour, Minute, Second, Check_Space => True);
788
789       else
790          declare
791             Discard : Second_Duration;
792             pragma Unreferenced (Discard);
793          begin
794             Split (Clock, Year, Month, Day, Hour, Minute, Second,
795                    Sub_Second => Discard);
796          end;
797
798          Extract_Time (1, Hour, Minute, Second, Check_Space => False);
799       end if;
800
801       --  Sanity checks
802
803       if not Year'Valid
804         or else not Month'Valid
805         or else not Day'Valid
806         or else not Hour'Valid
807         or else not Minute'Valid
808         or else not Second'Valid
809       then
810          raise Constraint_Error;
811       end if;
812
813       return Time_Of (Year, Month, Day, Hour, Minute, Second);
814    end Value;
815
816    --------------
817    -- Put_Time --
818    --------------
819
820    procedure Put_Time (Date : Ada.Calendar.Time; Picture : Picture_String) is
821    begin
822       Ada.Text_IO.Put (Image (Date, Picture));
823    end Put_Time;
824
825 end GNAT.Calendar.Time_IO;