1 ------------------------------------------------------------------------------
3 -- GNAT RUN-TIME COMPONENTS --
5 -- I N T E R F A C E S . C O B O L --
9 -- Copyright (C) 1992-2009, 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 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. --
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. --
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/>. --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
30 ------------------------------------------------------------------------------
32 -- The body of Interfaces.COBOL is implementation independent (i.e. the same
33 -- version is used with all versions of GNAT). The specialization to a
34 -- particular COBOL format is completely contained in the private part of
37 with Interfaces; use Interfaces;
38 with System; use System;
39 with Ada.Unchecked_Conversion;
41 package body Interfaces.COBOL is
43 -----------------------------------------------
44 -- Declarations for External Binary Handling --
45 -----------------------------------------------
47 subtype B1 is Byte_Array (1 .. 1);
48 subtype B2 is Byte_Array (1 .. 2);
49 subtype B4 is Byte_Array (1 .. 4);
50 subtype B8 is Byte_Array (1 .. 8);
51 -- Representations for 1,2,4,8 byte binary values
53 function To_B1 is new Ada.Unchecked_Conversion (Integer_8, B1);
54 function To_B2 is new Ada.Unchecked_Conversion (Integer_16, B2);
55 function To_B4 is new Ada.Unchecked_Conversion (Integer_32, B4);
56 function To_B8 is new Ada.Unchecked_Conversion (Integer_64, B8);
57 -- Conversions from native binary to external binary
59 function From_B1 is new Ada.Unchecked_Conversion (B1, Integer_8);
60 function From_B2 is new Ada.Unchecked_Conversion (B2, Integer_16);
61 function From_B4 is new Ada.Unchecked_Conversion (B4, Integer_32);
62 function From_B8 is new Ada.Unchecked_Conversion (B8, Integer_64);
63 -- Conversions from external binary to signed native binary
65 function From_B1U is new Ada.Unchecked_Conversion (B1, Unsigned_8);
66 function From_B2U is new Ada.Unchecked_Conversion (B2, Unsigned_16);
67 function From_B4U is new Ada.Unchecked_Conversion (B4, Unsigned_32);
68 function From_B8U is new Ada.Unchecked_Conversion (B8, Unsigned_64);
69 -- Conversions from external binary to unsigned native binary
71 -----------------------
72 -- Local Subprograms --
73 -----------------------
75 function Binary_To_Decimal
77 Format : Binary_Format) return Integer_64;
78 -- This function converts a numeric value in the given format to its
79 -- corresponding integer value. This is the non-generic implementation
80 -- of Decimal_Conversions.To_Decimal. The generic routine does the
81 -- final conversion to the fixed-point format.
83 function Numeric_To_Decimal
85 Format : Display_Format) return Integer_64;
86 -- This function converts a numeric value in the given format to its
87 -- corresponding integer value. This is the non-generic implementation
88 -- of Decimal_Conversions.To_Decimal. The generic routine does the
89 -- final conversion to the fixed-point format.
91 function Packed_To_Decimal
92 (Item : Packed_Decimal;
93 Format : Packed_Format) return Integer_64;
94 -- This function converts a packed value in the given format to its
95 -- corresponding integer value. This is the non-generic implementation
96 -- of Decimal_Conversions.To_Decimal. The generic routine does the
97 -- final conversion to the fixed-point format.
99 procedure Swap (B : in out Byte_Array; F : Binary_Format);
100 -- Swaps the bytes if required by the binary format F
104 Format : Display_Format;
105 Length : Natural) return Numeric;
106 -- This function converts the given integer value into display format,
107 -- using the given format, with the length in bytes of the result given
108 -- by the last parameter. This is the non-generic implementation of
109 -- Decimal_Conversions.To_Display. The conversion of the item from its
110 -- original decimal format to Integer_64 is done by the generic routine.
114 Format : Packed_Format;
115 Length : Natural) return Packed_Decimal;
116 -- This function converts the given integer value into packed format,
117 -- using the given format, with the length in digits of the result given
118 -- by the last parameter. This is the non-generic implementation of
119 -- Decimal_Conversions.To_Display. The conversion of the item from its
120 -- original decimal format to Integer_64 is done by the generic routine.
122 function Valid_Numeric
124 Format : Display_Format) return Boolean;
125 -- This is the non-generic implementation of Decimal_Conversions.Valid
126 -- for the display case.
128 function Valid_Packed
129 (Item : Packed_Decimal;
130 Format : Packed_Format) return Boolean;
131 -- This is the non-generic implementation of Decimal_Conversions.Valid
132 -- for the packed case.
134 -----------------------
135 -- Binary_To_Decimal --
136 -----------------------
138 function Binary_To_Decimal
140 Format : Binary_Format) return Integer_64
142 Len : constant Natural := Item'Length;
146 if Format in Binary_Unsigned_Format then
147 return Integer_64 (From_B1U (Item));
149 return Integer_64 (From_B1 (Item));
159 if Format in Binary_Unsigned_Format then
160 return Integer_64 (From_B2U (R));
162 return Integer_64 (From_B2 (R));
173 if Format in Binary_Unsigned_Format then
174 return Integer_64 (From_B4U (R));
176 return Integer_64 (From_B4 (R));
187 if Format in Binary_Unsigned_Format then
188 return Integer_64 (From_B8U (R));
190 return Integer_64 (From_B8 (R));
194 -- Length is not 1, 2, 4 or 8
197 raise Conversion_Error;
199 end Binary_To_Decimal;
201 ------------------------
202 -- Numeric_To_Decimal --
203 ------------------------
205 -- The following assumptions are made in the coding of this routine:
207 -- The range of COBOL_Digits is compact and the ten values
208 -- represent the digits 0-9 in sequence
210 -- The range of COBOL_Plus_Digits is compact and the ten values
211 -- represent the digits 0-9 in sequence with a plus sign.
213 -- The range of COBOL_Minus_Digits is compact and the ten values
214 -- represent the digits 0-9 in sequence with a minus sign.
216 -- The COBOL_Minus_Digits set is disjoint from COBOL_Digits
218 -- These assumptions are true for all COBOL representations we know of
220 function Numeric_To_Decimal
222 Format : Display_Format) return Integer_64
224 pragma Unsuppress (Range_Check);
225 Sign : COBOL_Character := COBOL_Plus;
226 Result : Integer_64 := 0;
229 if not Valid_Numeric (Item, Format) then
230 raise Conversion_Error;
233 for J in Item'Range loop
235 K : constant COBOL_Character := Item (J);
238 if K in COBOL_Digits then
239 Result := Result * 10 +
240 (COBOL_Character'Pos (K) -
241 COBOL_Character'Pos (COBOL_Digits'First));
243 elsif K in COBOL_Plus_Digits then
244 Result := Result * 10 +
245 (COBOL_Character'Pos (K) -
246 COBOL_Character'Pos (COBOL_Plus_Digits'First));
248 elsif K in COBOL_Minus_Digits then
249 Result := Result * 10 +
250 (COBOL_Character'Pos (K) -
251 COBOL_Character'Pos (COBOL_Minus_Digits'First));
254 -- Only remaining possibility is COBOL_Plus or COBOL_Minus
262 if Sign = COBOL_Plus then
269 when Constraint_Error =>
270 raise Conversion_Error;
272 end Numeric_To_Decimal;
274 -----------------------
275 -- Packed_To_Decimal --
276 -----------------------
278 function Packed_To_Decimal
279 (Item : Packed_Decimal;
280 Format : Packed_Format) return Integer_64
282 pragma Unsuppress (Range_Check);
283 Result : Integer_64 := 0;
284 Sign : constant Decimal_Element := Item (Item'Last);
287 if not Valid_Packed (Item, Format) then
288 raise Conversion_Error;
291 case Packed_Representation is
293 for J in Item'First .. Item'Last - 1 loop
294 Result := Result * 10 + Integer_64 (Item (J));
297 if Sign = 16#0B# or else Sign = 16#0D# then
305 when Constraint_Error =>
306 raise Conversion_Error;
307 end Packed_To_Decimal;
313 procedure Swap (B : in out Byte_Array; F : Binary_Format) is
314 Little_Endian : constant Boolean :=
315 System.Default_Bit_Order = System.Low_Order_First;
318 -- Return if no swap needed
322 if not Little_Endian then
327 if Little_Endian then
335 -- Here a swap is needed
338 Len : constant Natural := B'Length;
341 for J in 1 .. Len / 2 loop
343 Temp : constant Byte := B (J);
346 B (J) := B (Len + 1 - J);
347 B (Len + 1 - J) := Temp;
353 -----------------------
354 -- To_Ada (function) --
355 -----------------------
357 function To_Ada (Item : Alphanumeric) return String is
358 Result : String (Item'Range);
361 for J in Item'Range loop
362 Result (J) := COBOL_To_Ada (Item (J));
368 ------------------------
369 -- To_Ada (procedure) --
370 ------------------------
373 (Item : Alphanumeric;
380 if Item'Length > Target'Length then
381 raise Constraint_Error;
384 Last_Val := Target'First - 1;
385 for J in Item'Range loop
386 Last_Val := Last_Val + 1;
387 Target (Last_Val) := COBOL_To_Ada (Item (J));
393 -------------------------
394 -- To_COBOL (function) --
395 -------------------------
397 function To_COBOL (Item : String) return Alphanumeric is
398 Result : Alphanumeric (Item'Range);
401 for J in Item'Range loop
402 Result (J) := Ada_To_COBOL (Item (J));
408 --------------------------
409 -- To_COBOL (procedure) --
410 --------------------------
414 Target : out Alphanumeric;
420 if Item'Length > Target'Length then
421 raise Constraint_Error;
424 Last_Val := Target'First - 1;
425 for J in Item'Range loop
426 Last_Val := Last_Val + 1;
427 Target (Last_Val) := Ada_To_COBOL (Item (J));
439 Format : Display_Format;
440 Length : Natural) return Numeric
442 Result : Numeric (1 .. Length);
443 Val : Integer_64 := Item;
445 procedure Convert (First, Last : Natural);
446 -- Convert the number in Val into COBOL_Digits, storing the result
447 -- in Result (First .. Last). Raise Conversion_Error if too large.
449 procedure Embed_Sign (Loc : Natural);
450 -- Used for the nonseparate formats to embed the appropriate sign
451 -- at the specified location (i.e. at Result (Loc))
457 procedure Convert (First, Last : Natural) is
462 while J >= First loop
465 (COBOL_Character'Pos (COBOL_Digits'First) +
466 Integer (Val mod 10));
470 for K in First .. J - 1 loop
471 Result (J) := COBOL_Digits'First;
481 raise Conversion_Error;
488 procedure Embed_Sign (Loc : Natural) is
489 Digit : Natural range 0 .. 9;
492 Digit := COBOL_Character'Pos (Result (Loc)) -
493 COBOL_Character'Pos (COBOL_Digits'First);
498 (COBOL_Character'Pos (COBOL_Plus_Digits'First) + Digit);
502 (COBOL_Character'Pos (COBOL_Minus_Digits'First) + Digit);
506 -- Start of processing for To_Display
512 raise Conversion_Error;
517 when Leading_Separate =>
519 Result (1) := COBOL_Minus;
522 Result (1) := COBOL_Plus;
527 when Trailing_Separate =>
529 Result (Length) := COBOL_Minus;
532 Result (Length) := COBOL_Plus;
535 Convert (1, Length - 1);
537 when Leading_Nonseparate =>
542 when Trailing_Nonseparate =>
558 Format : Packed_Format;
559 Length : Natural) return Packed_Decimal
561 Result : Packed_Decimal (1 .. Length);
564 procedure Convert (First, Last : Natural);
565 -- Convert the number in Val into a sequence of Decimal_Element values,
566 -- storing the result in Result (First .. Last). Raise Conversion_Error
567 -- if the value is too large to fit.
573 procedure Convert (First, Last : Natural) is
577 while J >= First loop
578 Result (J) := Decimal_Element (Val mod 10);
583 for K in First .. J - 1 loop
594 raise Conversion_Error;
597 -- Start of processing for To_Packed
600 case Packed_Representation is
602 if Format = Packed_Unsigned then
604 raise Conversion_Error;
606 Result (Length) := 16#F#;
611 Result (Length) := 16#C#;
615 Result (Length) := 16#D#;
619 Convert (1, Length - 1);
628 function Valid_Numeric
630 Format : Display_Format) return Boolean
633 if Item'Length = 0 then
637 -- All character positions except first and last must be Digits.
638 -- This is true for all the formats.
640 for J in Item'First + 1 .. Item'Last - 1 loop
641 if Item (J) not in COBOL_Digits then
648 return Item (Item'First) in COBOL_Digits
649 and then Item (Item'Last) in COBOL_Digits;
651 when Leading_Separate =>
652 return (Item (Item'First) = COBOL_Plus or else
653 Item (Item'First) = COBOL_Minus)
654 and then Item (Item'Last) in COBOL_Digits;
656 when Trailing_Separate =>
657 return Item (Item'First) in COBOL_Digits
659 (Item (Item'Last) = COBOL_Plus or else
660 Item (Item'Last) = COBOL_Minus);
662 when Leading_Nonseparate =>
663 return (Item (Item'First) in COBOL_Plus_Digits or else
664 Item (Item'First) in COBOL_Minus_Digits)
665 and then Item (Item'Last) in COBOL_Digits;
667 when Trailing_Nonseparate =>
668 return Item (Item'First) in COBOL_Digits
670 (Item (Item'Last) in COBOL_Plus_Digits or else
671 Item (Item'Last) in COBOL_Minus_Digits);
680 function Valid_Packed
681 (Item : Packed_Decimal;
682 Format : Packed_Format) return Boolean
685 case Packed_Representation is
687 for J in Item'First .. Item'Last - 1 loop
693 -- For unsigned, sign digit must be F
695 if Format = Packed_Unsigned then
696 return Item (Item'Last) = 16#F#;
698 -- For signed, accept all standard and non-standard signs
701 return Item (Item'Last) in 16#A# .. 16#F#;
706 -------------------------
707 -- Decimal_Conversions --
708 -------------------------
710 package body Decimal_Conversions is
712 ---------------------
713 -- Length (binary) --
714 ---------------------
716 -- Note that the tests here are all compile time tests
718 function Length (Format : Binary_Format) return Natural is
719 pragma Unreferenced (Format);
721 if Num'Digits <= 2 then
723 elsif Num'Digits <= 4 then
725 elsif Num'Digits <= 9 then
727 else -- Num'Digits in 10 .. 18
732 ----------------------
733 -- Length (display) --
734 ----------------------
736 function Length (Format : Display_Format) return Natural is
738 if Format = Leading_Separate or else Format = Trailing_Separate then
739 return Num'Digits + 1;
745 ---------------------
746 -- Length (packed) --
747 ---------------------
749 -- Note that the tests here are all compile time checks
752 (Format : Packed_Format) return Natural
754 pragma Unreferenced (Format);
756 case Packed_Representation is
758 return (Num'Digits + 2) / 2 * 2;
768 Format : Binary_Format) return Byte_Array
771 -- Note: all these tests are compile time tests
773 if Num'Digits <= 2 then
774 return To_B1 (Integer_8'Integer_Value (Item));
776 elsif Num'Digits <= 4 then
778 R : B2 := To_B2 (Integer_16'Integer_Value (Item));
785 elsif Num'Digits <= 9 then
787 R : B4 := To_B4 (Integer_32'Integer_Value (Item));
794 else -- Num'Digits in 10 .. 18
796 R : B8 := To_B8 (Integer_64'Integer_Value (Item));
805 when Constraint_Error =>
806 raise Conversion_Error;
809 ---------------------------------
810 -- To_Binary (internal binary) --
811 ---------------------------------
813 function To_Binary (Item : Num) return Binary is
814 pragma Unsuppress (Range_Check);
816 return Binary'Integer_Value (Item);
818 when Constraint_Error =>
819 raise Conversion_Error;
822 -------------------------
823 -- To_Decimal (binary) --
824 -------------------------
828 Format : Binary_Format) return Num
830 pragma Unsuppress (Range_Check);
832 return Num'Fixed_Value (Binary_To_Decimal (Item, Format));
834 when Constraint_Error =>
835 raise Conversion_Error;
838 ----------------------------------
839 -- To_Decimal (internal binary) --
840 ----------------------------------
842 function To_Decimal (Item : Binary) return Num is
843 pragma Unsuppress (Range_Check);
845 return Num'Fixed_Value (Item);
847 when Constraint_Error =>
848 raise Conversion_Error;
851 --------------------------
852 -- To_Decimal (display) --
853 --------------------------
857 Format : Display_Format) return Num
859 pragma Unsuppress (Range_Check);
862 return Num'Fixed_Value (Numeric_To_Decimal (Item, Format));
864 when Constraint_Error =>
865 raise Conversion_Error;
868 ---------------------------------------
869 -- To_Decimal (internal long binary) --
870 ---------------------------------------
872 function To_Decimal (Item : Long_Binary) return Num is
873 pragma Unsuppress (Range_Check);
875 return Num'Fixed_Value (Item);
877 when Constraint_Error =>
878 raise Conversion_Error;
881 -------------------------
882 -- To_Decimal (packed) --
883 -------------------------
886 (Item : Packed_Decimal;
887 Format : Packed_Format) return Num
889 pragma Unsuppress (Range_Check);
891 return Num'Fixed_Value (Packed_To_Decimal (Item, Format));
893 when Constraint_Error =>
894 raise Conversion_Error;
903 Format : Display_Format) return Numeric
905 pragma Unsuppress (Range_Check);
909 (Integer_64'Integer_Value (Item),
913 when Constraint_Error =>
914 raise Conversion_Error;
921 function To_Long_Binary (Item : Num) return Long_Binary is
922 pragma Unsuppress (Range_Check);
924 return Long_Binary'Integer_Value (Item);
926 when Constraint_Error =>
927 raise Conversion_Error;
936 Format : Packed_Format) return Packed_Decimal
938 pragma Unsuppress (Range_Check);
942 (Integer_64'Integer_Value (Item),
946 when Constraint_Error =>
947 raise Conversion_Error;
956 Format : Binary_Format) return Boolean
959 pragma Unreferenced (Val);
961 Val := To_Decimal (Item, Format);
964 when Conversion_Error =>
968 ---------------------
969 -- Valid (display) --
970 ---------------------
974 Format : Display_Format) return Boolean
977 return Valid_Numeric (Item, Format);
985 (Item : Packed_Decimal;
986 Format : Packed_Format) return Boolean
989 return Valid_Packed (Item, Format);
992 end Decimal_Conversions;
994 end Interfaces.COBOL;