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-2018, 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
=>
557 Format
: Packed_Format
;
558 Length
: Natural) return Packed_Decimal
560 Result
: Packed_Decimal
(1 .. Length
);
563 procedure Convert
(First
, Last
: Natural);
564 -- Convert the number in Val into a sequence of Decimal_Element values,
565 -- storing the result in Result (First .. Last). Raise Conversion_Error
566 -- if the value is too large to fit.
572 procedure Convert
(First
, Last
: Natural) is
576 while J
>= First
loop
577 Result
(J
) := Decimal_Element
(Val
mod 10);
582 for K
in First
.. J
- 1 loop
593 raise Conversion_Error
;
596 -- Start of processing for To_Packed
599 case Packed_Representation
is
601 if Format
= Packed_Unsigned
then
603 raise Conversion_Error
;
605 Result
(Length
) := 16#F#
;
610 Result
(Length
) := 16#C#
;
614 Result
(Length
) := 16#D#
;
618 Convert
(1, Length
- 1);
627 function Valid_Numeric
629 Format
: Display_Format
) return Boolean
632 if Item
'Length = 0 then
636 -- All character positions except first and last must be Digits.
637 -- This is true for all the formats.
639 for J
in Item
'First + 1 .. Item
'Last - 1 loop
640 if Item
(J
) not in COBOL_Digits
then
647 return Item
(Item
'First) in COBOL_Digits
648 and then Item
(Item
'Last) in COBOL_Digits
;
650 when Leading_Separate
=>
651 return (Item
(Item
'First) = COBOL_Plus
or else
652 Item
(Item
'First) = COBOL_Minus
)
653 and then Item
(Item
'Last) in COBOL_Digits
;
655 when Trailing_Separate
=>
656 return Item
(Item
'First) in COBOL_Digits
658 (Item
(Item
'Last) = COBOL_Plus
or else
659 Item
(Item
'Last) = COBOL_Minus
);
661 when Leading_Nonseparate
=>
662 return (Item
(Item
'First) in COBOL_Plus_Digits
or else
663 Item
(Item
'First) in COBOL_Minus_Digits
)
664 and then Item
(Item
'Last) in COBOL_Digits
;
666 when Trailing_Nonseparate
=>
667 return Item
(Item
'First) in COBOL_Digits
669 (Item
(Item
'Last) in COBOL_Plus_Digits
or else
670 Item
(Item
'Last) in COBOL_Minus_Digits
);
679 function Valid_Packed
680 (Item
: Packed_Decimal
;
681 Format
: Packed_Format
) return Boolean
684 case Packed_Representation
is
686 for J
in Item
'First .. Item
'Last - 1 loop
692 -- For unsigned, sign digit must be F
694 if Format
= Packed_Unsigned
then
695 return Item
(Item
'Last) = 16#F#
;
697 -- For signed, accept all standard and non-standard signs
700 return Item
(Item
'Last) in 16#A#
.. 16#F#
;
705 -------------------------
706 -- Decimal_Conversions --
707 -------------------------
709 package body Decimal_Conversions
is
711 ---------------------
712 -- Length (binary) --
713 ---------------------
715 -- Note that the tests here are all compile time tests
717 function Length
(Format
: Binary_Format
) return Natural is
718 pragma Unreferenced
(Format
);
720 if Num
'Digits <= 2 then
722 elsif Num
'Digits <= 4 then
724 elsif Num
'Digits <= 9 then
726 else -- Num'Digits in 10 .. 18
731 ----------------------
732 -- Length (display) --
733 ----------------------
735 function Length
(Format
: Display_Format
) return Natural is
737 if Format
= Leading_Separate
or else Format
= Trailing_Separate
then
738 return Num
'Digits + 1;
744 ---------------------
745 -- Length (packed) --
746 ---------------------
748 -- Note that the tests here are all compile time checks
751 (Format
: Packed_Format
) return Natural
753 pragma Unreferenced
(Format
);
755 case Packed_Representation
is
757 return (Num
'Digits + 2) / 2 * 2;
767 Format
: Binary_Format
) return Byte_Array
770 -- Note: all these tests are compile time tests
772 if Num
'Digits <= 2 then
773 return To_B1
(Integer_8
'Integer_Value (Item
));
775 elsif Num
'Digits <= 4 then
777 R
: B2
:= To_B2
(Integer_16
'Integer_Value (Item
));
784 elsif Num
'Digits <= 9 then
786 R
: B4
:= To_B4
(Integer_32
'Integer_Value (Item
));
793 else -- Num'Digits in 10 .. 18
795 R
: B8
:= To_B8
(Integer_64
'Integer_Value (Item
));
804 when Constraint_Error
=>
805 raise Conversion_Error
;
808 ---------------------------------
809 -- To_Binary (internal binary) --
810 ---------------------------------
812 function To_Binary
(Item
: Num
) return Binary
is
813 pragma Unsuppress
(Range_Check
);
815 return Binary
'Integer_Value (Item
);
817 when Constraint_Error
=>
818 raise Conversion_Error
;
821 -------------------------
822 -- To_Decimal (binary) --
823 -------------------------
827 Format
: Binary_Format
) return Num
829 pragma Unsuppress
(Range_Check
);
831 return Num
'Fixed_Value (Binary_To_Decimal
(Item
, Format
));
833 when Constraint_Error
=>
834 raise Conversion_Error
;
837 ----------------------------------
838 -- To_Decimal (internal binary) --
839 ----------------------------------
841 function To_Decimal
(Item
: Binary
) return Num
is
842 pragma Unsuppress
(Range_Check
);
844 return Num
'Fixed_Value (Item
);
846 when Constraint_Error
=>
847 raise Conversion_Error
;
850 --------------------------
851 -- To_Decimal (display) --
852 --------------------------
856 Format
: Display_Format
) return Num
858 pragma Unsuppress
(Range_Check
);
861 return Num
'Fixed_Value (Numeric_To_Decimal
(Item
, Format
));
863 when Constraint_Error
=>
864 raise Conversion_Error
;
867 ---------------------------------------
868 -- To_Decimal (internal long binary) --
869 ---------------------------------------
871 function To_Decimal
(Item
: Long_Binary
) return Num
is
872 pragma Unsuppress
(Range_Check
);
874 return Num
'Fixed_Value (Item
);
876 when Constraint_Error
=>
877 raise Conversion_Error
;
880 -------------------------
881 -- To_Decimal (packed) --
882 -------------------------
885 (Item
: Packed_Decimal
;
886 Format
: Packed_Format
) return Num
888 pragma Unsuppress
(Range_Check
);
890 return Num
'Fixed_Value (Packed_To_Decimal
(Item
, Format
));
892 when Constraint_Error
=>
893 raise Conversion_Error
;
902 Format
: Display_Format
) return Numeric
904 pragma Unsuppress
(Range_Check
);
908 (Integer_64
'Integer_Value (Item
),
912 when Constraint_Error
=>
913 raise Conversion_Error
;
920 function To_Long_Binary
(Item
: Num
) return Long_Binary
is
921 pragma Unsuppress
(Range_Check
);
923 return Long_Binary
'Integer_Value (Item
);
925 when Constraint_Error
=>
926 raise Conversion_Error
;
935 Format
: Packed_Format
) return Packed_Decimal
937 pragma Unsuppress
(Range_Check
);
941 (Integer_64
'Integer_Value (Item
),
945 when Constraint_Error
=>
946 raise Conversion_Error
;
955 Format
: Binary_Format
) return Boolean
958 pragma Unreferenced
(Val
);
960 Val
:= To_Decimal
(Item
, Format
);
963 when Conversion_Error
=>
967 ---------------------
968 -- Valid (display) --
969 ---------------------
973 Format
: Display_Format
) return Boolean
976 return Valid_Numeric
(Item
, Format
);
984 (Item
: Packed_Decimal
;
985 Format
: Packed_Format
) return Boolean
988 return Valid_Packed
(Item
, Format
);
991 end Decimal_Conversions
;
993 end Interfaces
.COBOL
;