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