How to print decimal points in cobol? - cobol

I want the data to be in decimal format in the spool. How can I print the data with decimal points. I have used
Pic 99v99
for my data-definition, but it is not showing a decimal-point in the result when I DISPLAY it.
12.34 for the value of my data is displayed as 1234

The V in 99V99 is just an "invisible" decimal-point that sets the correct alignment for any fixed-point-operations. It has the advantage that it doesn't take up any additional memory. If you want a comma that is displayed use a PIC-clause like 99.99 which will
take up one more byte
only work with USAGE DISPLAY, not on COMP-fields
Note: When using DECIMAL-POINT IS COMMA you have to change the PIC-clause accordingly to: PIC 99,99

Related

Converting letters to numbers in a string that also contains numbers

I realize I have asked a similar question before, but the whole thing is more complicated than I thought.
To cut to the chase, I need to convert a string that contains numbers and letters into a string that only contains numbers, while keeping the numbers that were already there, in the right position.
The letters need to be converted to their corresponding position in the Alphabet + 9. So, A = 10, B= 11.... Z = 35.
So, basically, a string that looks like this:
'GB00LOYD1023456789A1B2'
will have to become:
'161100212429131023456789101112'.
I bolded the letters in both examples so you can see the difference more clearly. Depending on the input, the content will be longer or shorter than this example. Letters will be alternated by numbers and vice versa.
What's the best way to do this?
What's the best way to do this?
That is a matter of opinion.
The REPLACING option of the INSPECT verb requires the replacing and replaced character strings to be the same size, so that's right out because you need to replace one character with two. This is true at least for IBM COBOL.
A way to do this would be to loop through your input string and do a class check on each character. Something like...
01 Stuff.
05 in-posn pic s999 packed-decimal value +0.
05 out-posn pic s999 packed-decimal value +1.
05 in-string pic x(022) value 'GB00LOYD1023456789A1B2'.
05 out-string pic x(100) value spaces.
05 replacer pic x(002) value spaces.
perform varying in-posn from 1 by 1
until in-posn > length of in-string
if in-string(in-posn:1) alphabetic
evaluate in-string(in-posn:1)
when 'A' move '10' to replacer
when 'B' move '11' to replacer
.
.
.
when 'Z' move '35' to replacer
end-evaluate
string replacer delimited size
into out-string
pointer out-posn
end-string
else
string in-string(in-posn:1) delimited size
into out-string
pointer out-posn
end-string
end-if
end-perform
There are variations available. You could replace the evaluate with a couple of table lookups. You could store the length of in-string before beginning the loop. You could store in-string(in-posn:1) rather than hoping the compiler will do that for you.
This is just freehand but I think it conveys the idea.

Change display format from character mode to numeric mode

The value in variable VAR is -1, and when I am trying to write to a file, it gets displayed as J(character mode), which is equivalent to -1.
The VAR is defined in Cobol program copybook as below:
10 VAR PIC S9(1).
Is there any way, to change the display format from character "J" to -1, in the output file.
The information which I found by googling is below:
Value +0 Character {
Value -0 Character }
Value +1 Character A
To convert the zoned ASCII field which results from an EBCDIC to ASCII character translation to a leading sign numeric field, inspect the last digit in the field. If it's a "{" replace the last digit with a 0 and make the number positive. If it's an "A" replace the last digit with a 1 and make the number positive, if it's a "B" replace the last digit with a 2 and make the number positive, etc., etc. If the last digit is a "}" replace the last digit with a 0 and make the number negative. If it's a "J" replace the last digit with a 1 and make the number negative, if it's a "K" replace the last digit with a 2 and make the number negative, etc., etc. Follow these rules for all possible values. You could do this with a look-up table or with IF or CASE statements. Use whatever method suits you best for the language you are using. In most cases you should put the sign immediately before the first digit in the field. This is called a floating sign, and is what most PC programs expect. For example, if your field is 6 bytes, the value -123 should read " -123" not "- 123".
It might be simpler to move it to an EBCDIC output (display) field so that its just EBCDIC characters, and then convert that to ASCII and write it.
For example
10 VAR PIC S9(1).
10 WS-SEPSIGN PIC S9(1) SIGN IS LEADING SEPARATE.
10 WS-DISP REDEFINES WS-SEPSIGN
PIC XX.
MOVE VAR TO WS-SEPSIGN.
Then convert WS-OUT to ASCII using a standard lookup table and write it to the file.
If you are sending data from an EBCDIC machine to an ASCII machne, or vice versa, by far the best way is to only deal with character data. You can then let the transfer/communication mechanism do the ASCII/EBCDIC translation at record/file level.
Field-level translation is possible, but is much more prone to error (fields must be defined, accurately, for everything) and is slower (many translations versus one).
The SIGN clause is a very good way to do this. There is no need to REDEFINES the field (again you get to issues with field-definitions, two places to change if the size is changed).
There is a similar issue with decimal places where they exist. Where source and data definitions are not the same, an explicit decimal-point has to be provided, or a separate scaling-factor.
Both issues, and the original issue, can also be dealt with by using numeric-edited definitions.
01 transfer-record.
...
05 numeric-edited-VAR1 PIC +9.
...
With positive one, that will contain +1, with negative one, that will contain -1.
Take an amount field:
01 VAR2 PACKED-DECIMAL PIC S9(7)V99.
...
01 transfer-record.
...
05 numeric-edited-VAR2 PIC +9(7).99.
...
For 4567.89, positive, the new field will contain +0004567.79. For the same value, but negative, -0004567.79.
The code on the Source-machine is:
MOVE VAR1 TO numeric-edited-VAR1
MOVE VAR2 TO numeric-edited-VAR2
And on the target (in COBOL)
MOVE numeric-edited-VAR1 TO VAR1
MOVE numeric-edited-VAR2 TO VAR2
The code is the same if you use the SIGN clause for fields without decimal places (or with decimal places if you want the danger of being implicit about it).
Another thing with field-level translation is that Auditors don't/shouldn't like it. "The first thing you do when the data arrives is you change it? Really?" says the Auditor.

What's wrong with this alphanumeric to numeric move?

When I move a number in a PIC X to a PIC 9 the numeric field's value is 0.
FOO, a PIC X(400), has '1' in the first byte and spaces in the remaining 399. Moving into the PIC 9(02) BAR like so
DISPLAY FOO
MOVE FOO to BAR
DISPLAY BAR
yields
1
0
Why is BAR 0 instead of 1? [Edit: originally, 'What is happening?']
Postscript: NealB says "Do not write programs that rely on obscure truncation rules and/or
data type coercion. Be precise and explicit in what you are doing."
That made me realize I really want COMPUTE BAR AS FUNCTION NUMVAL(FOO) wrapped in a NUMERIC test, not a MOVE.
Data MOVEment in COBOL is a complex subject - but here is
a simplified answer to your question. Some data movement rules
are straight forward and conform to what one might expect. Others are somewhat bizzar and may vary with
compiler option, vendor and possibly among editions of the COBOL standard (74, 85, 2002).
With the above in mind, here is an explanation of what happend in your example.
When something 'large' is
MOVEd into something 'small' truncation must occur. This is what happened when BAR was MOVEd to FOO. How that
truncation occurs is determined by the receving item
data type. When the receiving item is character data (PIC X), the rightmost characters will be truncated from the sending field.
For numeric data the leftmost digits are truncated from the sending field. This behaviour is pretty much universal for all COBOL
compilers.
As a consequense of these rules:
When a long 'X' field (BAR) starting with a '1' followed by a bunch of space characters is MOVEd
into a shorter 'X' field the leftmost characters are transferred. This is why the '1' would be preserved when moving to another PIC X
item.
When a long 'X' field (BAR) is moved to a '9' (numeric) datatype the rightmost characters are moved first. This is why '1' was lost, it was never
moved, the last two spaces in BAR were.
So far simple enough... The next bit is more complicated. Exactly what happens is vendor, version, compiler option and character set
specific. For the remainder of this example I will assume EBCDIC character sets and the IBM Enterprise COBOL compiler are being used. I
also assume your program displayed b0 and not 0b.
It is universally legal in COBOL to move PIC X data to PIC 9 fields provided the PIC X field contains only digits. Most
COBOL compilers only look at the lower 4 bits of a PIC 9 field when determining its numeric value. An exception is the least
significant digit where the sign, or lack of one, is stored. For unsigned numerics the upper 4 bits of the least significant digit
are set to 1's (hex F) as a result of the MOVE (coercion follows different rules for signed fields). The lower 4 bits are MOVEd without
coercion. So, what happens when a space character is moved into a PIC 9 field? The hex
representation of a SPACE is '40' (ebcdic). The upper 4 bits, '4', are flipped to 'F' and the lower 4 bits are moved as they are. This results in the
least significant digit (lsd) containing 'F0' hex. This just happens to be the unsigned numeric representation for the digit '0' in a PIC 9 data item.
The remaining leading digits are moved as they are (ie. '40' hex). The net result is that FOO displays as
b0. However, if you were to do anything other that 'MOVE' or 'DISPLAY' FOO, the upper 4 bits of the remaining 'digits' may be coerced to zeroes as a
result. This would flip their display characteristics from spaces to zeros.
The following example COBOL program and its output illustrates these points.
IDENTIFICATION DIVISION.
PROGRAM-ID. EXAMPLE.
DATA DIVISION.
WORKING-STORAGE SECTION.
01.
05 BAR PIC X(10).
05 FOO PIC 9(2).
05 FOOX PIC X(2).
PROCEDURE DIVISION.
MOVE '1 ' TO BAR
MOVE BAR TO FOO
MOVE BAR TO FOOX
DISPLAY 'FOO : >' FOO '< Leftmost trunctaion + lsd coercion'
DISPLAY 'FOOX: >' FOOX '< Righmost truncation'
ADD ZERO TO FOO
DISPLAY 'FOO : >' FOO '< full numeric coercion'
GOBACK
.
Output:
FOO : > 0< Leftmost trunctaion, lsd coercion
FOOX: >1 < Righmost truncation
FOO : >00< full numeric coercion
Final words... Best not to have to know anything about this sort to thing. Do not write programs that rely on obscure truncation
rules and/or data type coercion. Be precise and explicit in what you are doing.
Firstly, why do you think it might be useful to MOVE a 400-byte field to a two-byte field? You are going to get a "certain amount(!)" of "truncation" with that (and the amount of truncation is certain, at 398 bytes). Do you know which part of your 400 bytes is going to be truncated? I'd guess not.
For an alpha-numeric "sending" item (what you have), the (maximum) number of bytes used is the maximum number of bytes in a numeric field (18/31 depending on compiler/compiler option). Those bytes are taken from the right of the alpha-numeric field.
You have, therefore, MOVEd the rightmost 18/31 digits to the two-digit receiving field. You have already explained that you have "1" and 399 spaces, so you have MOVEd 18/31 spaces to your two-digit numeric field.
Your numeric field is "unsigned" (PIC 9(2) not PIC S9(2) or with a SIGN SEPARATE). For an unsigned field (which is a field with "no operational sign") a COBOL compiler should generate code to ensure that the field contains no sign.
This code will turn the right-most space in your PIC 9(2) into a "0" because and ASCII space is X'20' and an EBCDIC space is X'40'. The "sign" is embedded in the right-most byte of a USAGE DISPLAY numeric field, and and no other data but the sign is changed during the MOVE. The 2 or 4 of X'2n' or X'4n' is, without regard to its value, obliterated to the bit-pattern for an "unsign" (the lack of an "operational sign"). An "unsign" followed by a numeric digit (which is the '0' left over from the space) will, obviously, appear as a zero.
Now, you show a single "1" for your 400-byte field and a single 0 for your two-byte numeric.
What I do is this:
DISPLAY
">"
the-first-field-name
"<"
">"
the-second-field-name
"<"
...
or
DISPLAY
">"
the-first-field-name
"<"
DISPLAY
">"
the-second-field-name
"<"
...
If you had done that, you should find 1 followed by 399 spaces for your first field (as you would expect) and space followed by zero for your second field, which you didn't expect.
If you want to specifically see this in operation:
FOO PIC X(400) JUST RIGHT.
MOVE "1" TO FOO
MOVE FOO TO BAR
DISPLAY
">"
FOO
"<"
DISPLAY
">"
BAR
"<"
And you should see what you "almost" expect. You probably want the leading zero as well (the level-number 05 is an example, whatever level-number you are using will work).
05 BAR PIC 99.
05 FILLER REDEFINES BAR.
10 BAR-FIRST-BYTE PIC X.
88 BAR-FIRST-BYTE-SPACE VALUE SPACE.
10 FILLER PIC X.
...
IF BAR-FIRST-BYTE-SPACE
MOVE ZERO TO BAR-FIRST-BYTE
END-IF
Depending on your compiler and how close it is to ANSI Standard (and which ANSI Standard) your results may differ (if so, try to get a better compiler), but:
Don't MOVE alpha-numeric which are longer than the maximum a numeric can be to a numeric;
Note that in the MOVE alpha-numeric to numeric it is the right-most bytes of the alpha-numeric which are actually moved first;
An "unsigned" numeric should/must always remain unsigned;
Always check for compiler diagnostics and correct the code so that no diagnostics are produced (where possible);
When showing examples, it is highly important to show the actual results the computer produced, not the results as interpreted by a human. " 0" is not the same as "0 " is not the same as "0".
EDIT: Looking at TS's other questions, I think Enterprise COBOL is a safe bet. This message would have been issued by the compiler:
IGYPG3112-W Alphanumeric or national sending field "FOO" exceeded 18 digits. The rightmost 18 characters were used as the sender.
Note, the "18 digits" would have been "31 digits" with compiler option ARITH(EXTEND).
Even though it is a lowly "W" which only gives a Return Code of 4, not bothering to read it is not good practice, and if you had read it you'd not have needed to ask the question - although perhaps you'd still not know how you ended up with " 0", but that is another thing.
I gather you expect the 9(2) value to show up as "1" instead of "0" and you are confused as to why it does not?
You are moving values from left to right when you move from an X value (unless the destination value changes things). So the 9 value has a space in it. To simplify it, moving "X(2) value '1 '" to a 9(2) value literally moves those characters. The space makes what is in the 9(2) invalid, so the COBOL compiler does with it what it knows to do, return 0. In other words, defining the 9(2) as it does tells the compiler to interpret the data in a different way.
If you want the 9(2) to show up as "1", you have to present the data in the right way to the 9(2). A 9(2) with a value of 1 has the characters "01". Untested:
03 FOO PIC X(2) value '1'.
03 TEXT-01 PIC X(2) JUSTIFIED RIGHT.
03 NUMB-01 REDEFINES TEXT-01 PIC 9(2).
03 BAR PIC 9(2).
DISPLAY FOO.
MOVE FOO TO TEXT-01.
INSPECT TEXT-01 REPLACING LEADING ' ' BY '0'.
MOVE NUMB-01 TO BAR.
DISPLAY BAR.
Using the NUMERIC test against BAR in your example should fail as well...

mapping from xml to cobol field

I need to pass LOW-VALUES(am not very sure what kind would that be), as default for a copybook field, to the backend team. I use a wtx transform which converts xml to cobol
15 :abc PIC X(15).
From the mainframe team I got this as sample for the field.
X'000000000000000000000000000000'
However when I use this rule, it fails because the number of characters is above 15. How can I pass the LOW-VALUES?
my rule map for the above cobol field
="X'000000000000000000000000000000'"
error meesage
Map: Output: abc Field:123 Group:outputcbl
Size of input item is greater than size of output item.
LOW-VALUE in COBOL is a figurative constant. The value of this constant
is the character having the lowest ordinal position in the collating sequence used.
Assuming the character set in use is EBCDIC (as indicated in one of your comments to another answer)
and the collating sequence has not
been overridden (probably a good assumption), a LOW-VALUE corresponds to binary zeros.
A PIC X(15) data item in COBOL occupies 15 bytes. Use a transformation that translates this
field into 15 bytes of binary zeros. The COBOL application will see this a LOW-VALUE.
Note: The value your 'Mainframe team' gave you is a hexadecimal string representation for 15 bytes of binary zeros.
Low-values is simply all Hex zeros, so if you resize your rule map to contain 15 hex digits, all zero, you should be fine.

Is --- Cobol picture valid

I'm running some tests on Cobol pictures and wondering if --- is a valid picture. Am I right in saying that this picture accepts values in the range of -99 through to +99. If it is valid then it is possible for the picture to accept 3 spaces as a value?
For example:
12 would return 12
1 would return 1
Cheers
Yes --- is a valid PICTURE clause. The variable corresponding to this PICTURE will accept assignments of numeric values in the range -99 through to +99. It cannot be assigned non-numerics (space for example). However, if you were to DISPLAY this variable after assigning a numeric value to it, leading zeros will be replaced by spaces. Consequently, if you MOVE ZERO to this item it will DISPLAY only spaces. Attempting to MOVE SPACES to this item will result in a compile error (incompatible data types). This last bit may seem a little counter intutive, but remember that this type of PICTURE clause implies a USAGE of display - basically items defined in this manner are used to 'pretty print' numbers. About the only operations you can preform with USAGE DISPLAY items is MOVE to or from and DISPLAY them.
EDIT - Response to Comment
A PICTURE of ---X(2) is invalid. The chart below illustrates combinations and the order that symbols may appear in a PICTURE string. Notice that parenthesis are not in the chart. Logically you can replace them with the corresponding number of occurences of the preceding character before reading the string. For example X(3) is read as XXX. If you really want to parse out a PICTURE string properly, you can use this chart to construct a BNF grammar specifically for them.
If this is a numeric picture, it won't accept spaces.

Resources