Is it possible to assign a string of hexadecimal to a comp or binary declared variable?
Example:
01 COMP-VAR PIC 9(4) COMP.
MOVE X'04D2' TO COMP-VAR.
should output +1234.
Edited:
Sorry for the lack of the information, I just gave an example. The real scenario is that the data will come from an external source, a dataset. I need to store the data in an alphanumeric variable before I move it to a comp declared variable. My problem is that the data is incorrect when I move the alphanumeric data to the comp variable. Your help is very much appreciated.
I think you are looking for REDEFINES. Redefine the binary value as character, do the assignment
which will not violate any of the assignment rules and then use the binary representation in
subsequent operations. This program illustrates your example:
IDENTIFICATION DIVISION.
PROGRAM-ID. EXAMPLE.
DATA DIVISION.
WORKING-STORAGE SECTION.
01.
02 COMP-VAR PIC 9(4) COMP.
02 COMP-X REDEFINES COMP-VAR PIC X(2).
PROCEDURE DIVISION.
MOVE X'04D2' TO COMP-X
DISPLAY COMP-VAR
GOBACK
.
This displays 1234.
The larger question is why would you need to do this? I suspect that you are attempting to
read a file with multiple record formats in it. Based on some common record identifier you
need to read part of the record as character or as binary. Typically this is done a little
differently in COBOL.
Here is a larger example of what I mean. Suppose you have an input
record that is 3 bytes long. When the first byte is a 'B' it is telling you that the next two bytes should be
treated as a binary (COMP) value. When the first byte is an 'X' you need to read the next two
bytes as text (X) data. As an example this is what two records might look like:
X'E7C1C2'
X'C204D2'
The first record is a text record containing the value 'AB' (EBCDIC). The second record is binary containing
the value 1234. The program to process these records might look something like:
IDENTIFICATION DIVISION.
PROGRAM-ID. EXAMPLE.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 INPUT-RECORD.
02 REC-TCD PIC X.
88 REC-TCD-BIN VALUE 'B'.
88 REC-TCD-CHAR VALUE 'X'.
02 REC-DUMMY PIC X(2).
02 REC-COMP-VAR REDEFINES REC-DUMMY PIC 9(4) BINARY.
02 REC-CHAR-VAR REDEFINES REC-DUMMY PIC X(2).
PROCEDURE DIVISION.
*
* THIS IS A CHARACTER RECORD
*
MOVE X'E7C1C2' TO INPUT-RECORD
PERFORM DISPLAY-INPUT-RECORD
*
* THIS IS A BINARY RECORD
*
MOVE X'C204D2' TO INPUT-RECORD
PERFORM DISPLAY-INPUT-RECORD
GOBACK
.
DISPLAY-INPUT-RECORD.
EVALUATE TRUE
WHEN REC-TCD-BIN
DISPLAY 'REC TYPE: ' REC-TCD
' BINARY DATA: ' REC-COMP-VAR
WHEN REC-TCD-CHAR
DISPLAY 'REC TYPE: ' REC-TCD
' CHAR DATA : ' REC-CHAR-VAR
WHEN OTHER
DISPLAY 'UNKNOWN RECORD TYPE: ' REC-TCD
END-EVALUATE
.
The output from this program is:
******************************** Top of Data ***********************************
REC-TYPE: X CHAR DATA : AB
REC-TYPE: B BINARY DATA: 1234
******************************* Bottom of Data *********************************
Look at the INPUT-RECORD definition. The first byte determines how the rest of the
record is to be intrepreted. REC-DUMMY is generally defined as a "generic" buffer area
to be subsequently redefined. In the case of variable length input records, REC-DUMMY
is defined to be as long as the longest record variant so the subsequent REDEFINEs of it
do not "upset" the compiler. All data items following REC-DUMMY begin with the same level
number (02 in the example) and REDEFINE it to the the appropriate format. Subsequent
processing uses whatever record redefinition is appropaiate based on the value in REC-TCD.
Related
Moving data to COMP-3 fields after UNSTRING.
UNSTRING is working fine but I am not able to move data to COMP-3 fields without an S0C7 data exception abend.
I think it is an issue with storing data.
Below is my COBOL program.
IDENTIFICATION DIVISION.
PROGRAM-ID. ADDPROG.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 VALUEA PIC X(20) VALUE '64.99|64.99'.
01 NOA PIC S9(9)V9(02).
01 NOB PIC S9(9)V9(02).
01 NOC PIC S9(9)V99 COMP-3.
01 NOD PIC S9(9)V99 COMP-3.
PROCEDURE DIVISION.
000-MAIN.
DISPLAY "EARLIER".
DISPLAY 'NOA-' NOA.
DISPLAY 'NOB-' NOB.
DISPLAY "AFTER".
UNSTRING VALUEA
DELIMITED BY '|'
INTO NOA,NOB.
DISPLAY 'NOA-' NOA.
DISPLAY 'NOB-' NOB.
MOVE NOA TO NOC.
MOVE NOB TO NOD.
DISPLAY 'NOC-' NOC.
DISPLAY 'NOD-' NOD.
STOP RUN.
Output I am getting after compiling.
Please let me know is there any other way to move data to COMP-3 fields or to avoid this error.
Your code has two main problems. To see them you first have to understand that your UNSTRING into NOA and NOB works like any other character-to-character MOVE.
So it starts from the left and moves character after character until one field ends and if necessary adds some blanks to fill up the receiving field.
So problem one is that NOA contains the value left-justified while according to your PIC-clause it should be right-justified, so you would need an intermediate PIC X(12) JUSTIFIED RIGHT field that you UNSTRING to.
The second problem that is causing the S0C7 is that your PIC-clause does not include a decimal-point. The V specifies the implied position of the decimal point but it would not show on output nor is it handled correctly when parsing the field-contents. To have a field that correctly handles the decimal point you should have a PIC S9(9)V.9(02).
Please also see this question.
Like piet.t said, the UNSTRING statement is like a alphanumeric move. Therefore my suggestion is to:
make NOA and NOB be alphanumeric (PIC X(12)), and
change your move statements to include WITH CONVERSION so that it will convert the numeric data in the alphanumeric field into COMP-3.
Your decimal data field are wrong just have . Like 01 NOA PIC S9(9).(02) In them! Same with noc variabile then it should run.
To move data from a numeric field to a COMP-3 field, you need to make sure that the data in the numeric field is valid for the COMP-3 field. A COMP-3 field stores packed decimal data, which means that the digits of the number are packed into two-digit decimal fields. The decimal point is not stored, and the sign of the number is stored in the last nibble of the field.
I'm trying to write a COBOL module and having some variables in this file too:
IDENTIFICATION DIVISION.
PROGRAM-ID. UTIL.
DATA DIVISION.
LINKAGE SECTION.
01 MY_VAR PIC X(100).
DATA DIVISION.
WORKING-STORAGE SECTION.
01 RESULT PIC X(200) value SPACES.
PROCEDURE DIVISION USING MY_VAR.
STRING INPUT DELIMITED BY SPACE
' ' DELIMITED BY SIZE
MY_VAR BY SPACE
INTO RESULT
DISPLAY RESULT
EXIT PROGRAM.
For the input argument (MY_VAR) I use LINKAGE SECTION. I'm not sure how to use the WORKING-STORAGE SECTION statement to declare the RESULT variable.
How can I do that?
You should have 1 Data Division. Also, I think the order is not good for the Sections.
I advise looking at some Cobol documentation before coding.
IDENTIFICATION DIVISION.
PROGRAM-ID. UTIL.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 RESULT PIC X(200) value SPACES.
LINKAGE SECTION.
01 MY_VAR PIC X(100).
PROCEDURE DIVISION USING MY_VAR.
STRING INPUT DELIMITED BY SPACE
' ' DELIMITED BY SIZE
MY_VAR BY SPACE
INTO RESULT
DISPLAY RESULT
EXIT PROGRAM.
Are you using Cobol program on the mainframe of PC? If on PC - which Cobol program are you using?
If you are using a linkage section, first 2 bytes specify the length of the variable.
Also - I don't see the definition of the INPUT variable, unless INPUT is some kind of Cobol command (not recognized on the mainframe computers).
The correct syntax (on the mainframe) is:
LINKAGE SECTION.
01 link-parms.
05 LNK-PARM-LENGTH PIC S9999 COMP.
05 MY_VAR PIC X(100).
PROCEDURE DIVISION USING MY_VAR.
STRING INPUT DELIMITED BY SPACE
' ' DELIMITED BY SIZE
MY_VAR BY SPACE
INTO RESULT
DISPLAY RESULT
STOP RUN.
I have written a code to match the date given by user(instream data) with the date mentioned in an input file. When the date matches, the record is moved to an output file. The program ran successfully. Now i am inserting a header in output file by declaring a variable 'header' in working-storage section, moving the 'header' field to output record and writing the output record. Though it is running successfully i have a doubt. I looked for it everywhere but unable to find it. The problem is-
The concept of buffer tells us that while declaring File Description(FD) it creates a structure. The file description(FD) given with all the records and fields creates a buffer structure. Now all the read/write operation happens through it.
If a program processes more than one file, a record buffer must be defined for each file.
To process all the records in an INPUT file, we must ensure that each record instance is copied from the file, into the record buffer, when required.
To create an OUTPUT file containing data records, we must ensure that each record is placed in the record buffer and then transferred to the file.
To transfer a record from an input file to an output file we must read the record into the input record buffer, transfer it to the output record buffer and then write the data to the output file from the output record buffer.
So when i am giving the date separately and moving it to the output record it is SURELY not going into that buffer which i created using FD in output record. So how is it going there?? If it is creating its own buffer then all data can be moved directly, what is the need of declaring FD??
This is the link to see the concept of buffer
[1]: http://www.csis.ul.ie/cobol/course/SequentialFiles1.htm
This is my code as given below-JUST EMPHASIZE ON STATEMENTS IN SLASHES
IDENTIFICATION DIVISION.
PROGRAM-ID. TXNRPT02 .
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT D01-TXN-FILE ASSIGN TO DETLFILE
ORGANIZATION IS SEQUENTIAL
ACCESS MODE IS SEQUENTIAL
FILE STATUS IS WS-INSERT-FILE-STATUS1.
SELECT D02-TXN-FILE ASSIGN TO DATEOUT
ORGANIZATION IS SEQUENTIAL
ACCESS MODE IS SEQUENTIAL
FILE STATUS IS WS-INSERT-FILE-STATUS2.
DATA DIVISION.
FILE SECTION.
FD D01-TXN-FILE. // CREATES A BUFFER
01 D01-TXN-REC.
05 TXN-DATE PIC 9(8).
05 FILLER PIC X(1).
05 TXN-NUMBER PIC 9(5).
05 FILLER PIC X(1).
05 SBACCT-CODE PIC 9(5).
05 FILLER PIC X(1).
05 TXN-AMOUNT PIC 9(5)V9(2).
05 FILLER PIC X(52).
FD D02-TXN-FILE. //CREATES A BUFFER STRUCTURE IN OUTPUT FILE
01 D02-TXN-REC.
05 TXN-DATE1 PIC 9(8).
05 FILLER PIC X(1).
05 TXN-NUMBER1 PIC 9(5).
05 FILLER PIC X(1).
05 SBACCT-CODE1 PIC 9(5).
05 FILLER PIC X(1).
05 TXN-AMOUNT1 PIC 9(5)V9(2).
05 FILLER PIC X(52).
WORKING-STORAGE SECTION.
01 HEAD1 // declaring header
02 FILLER PIC X(20).
02 TEXT PIC X(40) VALUE 'REPORT OF BANK'
01 FILE-STATUS PIC X(02) VALUE '00'.
88 EOF VALUE '10'.
88 SUCCESS VALUE '00'.
01 WS-INSERT-FILE-STATUS1 PIC X(2).
01 WS-INSERT-FILE-STATUS2 PIC X(2).
01 WS-DATE PIC 9(8). // DATE TO BE ACCEPTED FROM INSTREAM DATA
PROCEDURE DIVISION.
MAIN-PARA.
ACCEPT WS-DATE.
PERFORM OPEN-PARA.
PERFORM INIT-PARA.
PERFORM PROCESS-PARA UNTIL EOF.
PERFORM CLOSE-PARA.
STOP RUN.
OPEN-PARA. // OPENS INPUT AND OUTPUT FILES
OPEN INPUT D01-TXN-FILE.
DISPLAY 'INFILE OPEN STATUS' , WS-INSERT-FILE-STATUS1.
OPEN OUTPUT D02-TXN-FILE.
DISPLAY 'OUTFILE OPEN STATUS' ,WS-INSERT-FILE-STATUS2.
INIT-PARA. // INITIALIZES BOTH RECORDS
INITIALIZE D01-TXN-REC.
INITIALIZE D02-TXN-REC.
PROCESS-PARA.
MOVE HEAD1 TO D02-TXN-REC. // MOVING HEADER TO OUTPUT RECORD
WRITE D02-TXN-REC. // WRITING THE HEADER
READ D01-TXN-FILE
AT END MOVE '10' TO FILE-STATUS
NOT AT END PERFORM OPPO-PARA
END-READ.
OPPO-PARA. //PERFORMS EQUAL OPERATION ON BOTH DATES
IF WS-DATE = TXN-DATE
MOVE D01-TXN-REC TO D02-TXN-REC
WRITE D02-TXN-REC
END-IF.
CLOSE-PARA. // CLOSING BOTH FILES
CLOSE D01-TXN-FILE, D02-TXN-FILE.
DISPLAY 'INFILE CLOSE STATUS' , WS-INSERT-FILE-STATUS1.
DISPLAY 'OUTFILE CLOSE STATUS' , WS-INSERT-FILE-STATUS2.
I think you are over-complicating things.
In the FILE SECTION you logically connect a record-layout to a file that will be read, or to a record which will be written (to a file).
No storage is allocated in your COBOL program by the definition of the FD or any 01-levels subordinate to an FD. You simply establish a "map" which will be used to understand the data read from a file, or to use to construct the data which you will write to a file.
When you OPEN a file, some run-time code does that work behind the scenes, and will make the address of the first byte of your record layout(s) under the FD equal to the first byte of the piece of storage that will be used as the "buffer".
A "buffer" in this context is just a piece of storage which is the same size as your BLKSIZE and which will be used, without you having to be aware of it, to store records before they are actually written to the physical output file.
What happens when you WRITE a record is that the record-pointer simply gets changed to the first available byte after the current record.
It is similar when you read.
Although installation-dependent, mostly you will have the default number of buffers for a simple sequential file, which is five. Once a buffer is full the, for an output file, the IO-subsystem will be told it has data available for writing, and the filling will continue, asynchronously, with the next buffer area. What this does is reduce the amount of time your COBOL program is waiting for IO to complete.
It is similar, which obvious reversals, for the READ of a sequential file.
As a beginner, you don't need to know what the buffering is doing. Just keep it conceptually simple. You OPEN, you READ, the record is "under" the FD. You continue doing that until end-of-file, then you CLOSE. At the same time (usually) you OPEN, you WRITE, and you CLOSE at the end. What gets written is the data that is under the FD for the output file.
Also review READ ... INTO ... and WRITE ... FROM .... The concept is the same, it is just that COBOL will "move" the data to the FD for you, rather than you having detailed record-layouts under the FD. Whether you use READ file or READ file INTO record-layout is usually down to local standards for your site - do it the way your team does it.
You have now added some code to your Question.
First thing, you are writing your header inside a loop. You will get one header per record, which is probably not what you want.
Secondly, you've changed to use the FILE STATUS but not fully grasped how it works yet. You don't need the AT END/NOT AT END. The COBOL IO will maintain the FILE STATUS field. When end-of-file is identified by the COBOL run-time the FILE STATUS field will be set to "10", "automatically" as far as you are concerned.
Thirdly, review your use of INITIALIZE. There is never any point in INITIALIZE on an input record. READ always advances the record-pointer. The storage INITIALIZEd is the storage before the record you read. Even if it was not, what is the point of INITIALIZE, just to read a record over the top of the initialised storage? Same with your output.
All that your use of INITIALIZE is doing is using CPU time. Yes, it is not at all uncommon that this happens, but that is no excuse for you to pick up bad habits as well.
I have the following variable in COBOL program which gets its value from a file, when it is read:
01 Employee-number PIC 09(8) comp
01 Employee-number-x redefines
Employee-number PIC x(04)
I have another variable in the same program:
01 D-element-number PIC 9(04)
Now,
Move Employee-number to D-element-number
Then I write this D-element-number to a file
value read from input file is :
0013
0024
so this value comes to Employee-number and Employee-number-x and I move this value to D-Element-number and write this variable to a output file.
But I get this in the output file:
4660
FFFF
4660
4660 is the decimal equivalent of X'1234'
But I want to see something like:
1234
FFFF
1234
How can I achieve this ?
I am allowed to change the definition of D-element-number but nothing else.
Assuming that when you have X'00001234' you want C'00001234', have a look here. http://ibmmainframes.com/viewtopic.php?p=234231#234231
Ignore the rest of the discussion for now, just concentrate on that post.
This is the key part:
PERFORM UNTIL X-WS-1000 > X-WS-1000-MAX
MOVE WS-1000-BYTE-TBL (X-WS-1000)
TO WS-PACKED-X (1:1)
MOVE WS-PACKED TO WS-DISPLAY
MOVE WS-DISPLAY-X TO WS-2000-BYTE-TBL (X-WS-2000)
SET X-WS-1000 UP BY 1
SET X-WS-2000 UP BY 1
END-PERFORM
You need the exact storage definitions to go with it (don't "correct" anything).
It works by getting the compiler to use the "unpack" instruction (UNPK). This one is working one byte at a time, so simple to explain.
X'12' (an example on-byte field) is put in a two-byte field. X'12ii' (where the value of ii is "irrelevant").
UNPK will then turn this "packed" number into a "zoned" number. A "Zone" is the first four bts of a byte, and for a Zoned number, the four bits are all set to one. So you get an F. Then you get the left-most digit from the first byte. Then you get the second output byte, first four bits set to F, then the second input digit.
Then the UNPK continues with the final byte, which contains one irrelevant digit, and an irrelevant sign. For a Zoned number, the sign and right-most digit occupy the same byte (the sign in the zone) so you get a whole byte of irrelevance.
X'12' -> X'12ii' -> X'F1F1ii'.
The first two bytes of the three-byte output are C'12'.
Nos, what is all fine for numbers, but letters make a mess:
X'AB' -> X'ABii' -> X'FAFBii'
Although F and a digits gives a displayable number, for F and a letter, the result does not mean much directly.
Now the INSPECT ... CONVERTING comes to the rescue: FA gets translated to C'A' (X'C1), and the same for the letters through to F.
Your results after the CONVERTING will be C'AB'.
Should give you enough to work on.
There are other methods, but this is a fair COBOL approximation to the classic Assembler technique with UNPK and a TRANSLATE (TR) and a table of translation values.
If you use your favourite search engine. you should be able to fine more methods, using calculation (more than one), table-lookups, I've even seen a 256-WHEN EVALUATE that "works", but I guess it is a little on the "slow" side.
Thinking further, you actually have a BCD (Binary Coded Decimal) don't you? This is a Packed Decimal, without the sign. You don't have any alphas in your field.
This is even simpler to convert.
01 the-converted-value PACKED-DECIMAL PIC 9(8)V9 VALUE ZERO.
01 FILLER REDEFINES the-converted-value.
05 the-binary-value PIC X(4).
05 FILLER PIC X.
MOVE Employee-number-x TO the-binary-value
MOVE the-converted-value TO D-element-number (with Gilbert's correction to PIC 9(8)).
The "decimal place" is the ii, the ignore value and ignore sign. You no longer need the INSPECT ... CONVERTING ... as you only have numeric digits. If you have a BCD...
A really good way for you to have answered your own question would have been to find out how the number was created in the binary field in the first place.
Didn't try this, but I think it might work:
01 WN-GROUP.
05 Employee-number PIC 9(8) comp.
05 PACKED-ZERO PIC 9(1) COMP-3 VALUE ZERO.
01 WN-PACKED redefines WN-GROUP PIC 9(9) COMP-3.
01 WN-UNPACKED PIC 9(9).
Then in your procedure:
MOVE your-number TO Employee-number
MOVE WN-PACKED TO WN-UNPACKED.
And finally you can move or display WN-PACKED(1:8).
I have a string for which I wish to tally the count of characters till a certain pattern of characters is found.
For example:
Give a string: askabanskarkartikrockstar
I would like to know how many characters are there before the kartik in the string.
In a normal scenario where I need to find the number of characters before, say k, in the given string, I would write the code somewhat as:
INSPECT WS-INPUT-STRING TALLYING CT-COUNTER FOR CHARACTERS BEFORE LT-K
Where
WS-INPUT-STRING is alphanumeric with a value of
askabanskarkartikrockstar,
CT-COUNTER is the counter used to count the number of characters
LT-K is a literal with the value k.
But here, if I wish to do the same for a sub-string, like kartik in the above example, would replacing the value of LT-K with kartik instead of just k work? If yes, is the same applicable for alphanumeric literals that have values in the form of hexadecimal numbers (for example, in a literal X(02) one stores a new-line character as x'0D25')?
I'm trying to implement the above code in zOS IBM mainframe v10. Thanks.
You have pretty much answered your own question... The answer is yes you can do this. Here is a working example program:
IDENTIFICATION DIVISION.
PROGRAM-ID. EXAMPLE.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-INPUT-STRING PIC X(80).
01 WS-COUNTER PIC 9(4).
01 WS-TAG PIC X(10).
PROCEDURE DIVISION.
MAIN-PARAGRAPH.
MOVE 'askabanskarkartikrockstar' TO WS-INPUT-STRING
MOVE ZERO TO WS-COUNTER
MOVE 'kartik' TO WS-TAG
INSPECT WS-INPUT-STRING
TALLYING WS-COUNTER
FOR CHARACTERS BEFORE WS-TAG(1:6)
DISPLAY WS-COUNTER
GOBACK
.
WS-COUNTER displays as 11, there are 11 characters before the WS-TAG string.
Notice that I defined WS-TAG as PIC X(10). This variable is longer than the actual tag value you are looking for. To prevent the INSPECT verb from trying to match on trailing spaces introduced by:
MOVE 'kartik' TO WS-TAG
I had to specify a reference modified value for INSPECT to search for. Had I simply used:
FOR CHARACTERS BEFORE WS-TAG
without reference modification, WS-COUNTER would have been 80 - the length of WS-INPUT-STRING. This is because the string 'kartik ' is not found and the counter tallies the length of the entire input string.
Another approach would be to specify the tag as a literal:
FOR CHARACTERS BEFORE 'kartik'
You can move hexadecimal constants into PIC X fields as follows:
MOVE X'0D25' TO WS-TAG
This occupies 2 characters so you would use WS-TAG(1:2) when INSPECTing it.
If you want to do "a lot" of this at once, then you'll find a PERFORM VARYING will be faster. It is more typing, and you have to think more, and there is more chance for error. But once you have one working, you just have to copy the code to reuse it.