|
View previous topic :: View next topic
|
| Author |
Message |
A_programmers
New User
Joined: 24 Mar 2010 Posts: 19 Location: USA
|
|
|
|
Dear All,
I read multiple forums but could not come to any conclusion.
I have mainframe file (& corresponding copybook layout). This file contains combination packed and binary fields. Before sending (sftp) this file to Windows; I want to convert all packed / binary fields into display format fields.
Any idea what is the best way to do it ?
1. Do we have any converter available which converts input packed copybook layout to output display copybook layout ?
2. Any COBOL Program / Sort which takes input file & copybook and converts to output display format ? |
|
| Back to top |
|
 |
Nic Clouston
Global Moderator
Joined: 10 May 2007 Posts: 2454 Location: Hampshire, UK
|
|
|
|
| A reasonably simple sort process will do it. Examples exist. |
|
| Back to top |
|
 |
Rohit Umarjikar
Global Moderator

Joined: 21 Sep 2010 Posts: 3109 Location: NYC,USA
|
|
|
|
| If it’s few fields then DFSORT/SYNCSORT can be used to convert them to any EDITed Zoned Decimal format but if it’s so many fields then write a COBOL program to write in readable format. |
|
| Back to top |
|
 |
sergeyken
Senior Member

Joined: 29 Apr 2008 Posts: 2263 Location: USA
|
|
|
|
| Rohit Umarjikar wrote: |
| If it’s few fields then DFSORT/SYNCSORT can be used to convert them to any EDITed Zoned Decimal format but if it’s so many fields then write a COBOL program to write in readable format. |
Yes, this is correct.
Only one problem exists: writing any COBOL program just to convert field formats takes about 50-100 times more efforts (and 100-300 times more lines of code, in total - including compilation and binder steps coding, and debugging) compared to doing the same via SORT control statements.
Using COBOL makes sense only when some other processing is required (or has been already implemented) via COBOL.
Writing a new COBOL code specifically to convert field formats is a good exercise for learning COBOL, but nothing else. |
|
| Back to top |
|
 |
sergeyken
Senior Member

Joined: 29 Apr 2008 Posts: 2263 Location: USA
|
|
|
|
The only visible problem in using SORT control statements is: its requirement to specify actual field positions within the record. In COBOL, so called COPYBOOKs are used (I hope so?) for this purpose - to refer to any field of the record by its symbolic name.
In order to simplify this process in SORT approach, especially when hundreds of different files need to be converted and transferred, I had to write (already several times in my career) quite simple REXX code, to provide conversion of COBOL copybook(s) to their equivalent SORT symbol table(s). This has simplified the conversion process dramatically.
I had to re-create similar REXX scripts every time I left one company, and joined another one, for not to "violate the signed agreements on company copyright formalities for any created code". This rarely took longer than 30 minutes.
Just recently I had to created one of those scripts again. I can demonstrate it as an example; every version of those codes usually had specific limitations depending on possible variety of used records.
In each particular case it can be enhanced, to handle more specific record variations used by a particular company.
| Code: |
/* REXX */
XCOBSYM: /* conversion of COBOL layout to SORT symbol table */
/* limited version; to be enchanced to handle :
- OCCURS groups, on multiple levels
- REDEFINE groups
*/
Arg FromDD ToDD .
If FromDD = '' Then
FromDD = 'COBOLIN'
If ToDD = '' Then
ToDD = 'SYMOUT'
"EXECIO * DISKR" FromDD "(FINIS"
Lines = Queued()
Parse Source . . REXXNAME .
/*
*/
LongLine = ''
StemNum = 0
StemLine. = ''
Do x = 1 By 1 To Lines
Pull . =7 TestLine =73 .
If Left( TestLine, 1 ) ¬= '*' ,
& TestLine ¬= ' ' Then Do
TestLine = Space( TestLine, 1 )
LongLine = LongLine TestLine
If Right( TestLine, 1 ) = '.' Then Do
LongLine = Left( LongLine, Length(LongLine) - 1 )
StemNum = StemNum + 1
StemLine.StemNum = LongLine
LongLine = ''
End
End
End x
StemLine.0 = StemNum
Queue "*======================================================"
Queue "* Symbolic Names Table for SORT"
Queue "* Created by" REXXNAME "on" Date() "at" Time()
Queue "* from COBOL layout definition"
Queue "*======================================================"
Occurs.0 = 0
RedefLevel = 0
Do x = 1 By 1 To StemLine.0
Parse Var StemLine.x FLevel FName FDescr
If Level = '*' ,
| Descr = '' Then Do
Iterate x
End
Call ProcessQueue FLevel FName FDescr
End x
"EXECIO" Queued() "DISKW" ToDD "(FINIS"
Return 0
/**********************************************************************/
ProcessQueue: procedure expose Occurs. RedefLevel
Arg Level C_Name Descr
If RedefLevel > 0 Then Do
If Level + 0 > RedefLevel Then Do
Queue "*" Level C_Name Descr
Return 0
End
Else Do
RedefLevel = 0
/* Say "continue from:" Level C_Name Descr */
End
End
If Pos( 'REDEF', Descr ) > 0 Then Do
RedefLevel = Level + 0
Queue "*" Level C_Name Descr
End
Else Do
If Level = '88' Then Do
Return 0
End
Parse Var Descr . 'OCCURS' Array_Size .
NewLine = ''
Name = Translate( C_Name, '_', '-' )
If Left( Name, 3 ) = 'FD_' Then
Name = Substr( Name, 4 )
Parse Var Descr . 'PICTURE' PicValue LeftDescr
If PicValue = '' Then
Parse Var Descr . 'PIC' PicValue LeftDescr
If PicValue = '' Then Do
Queue "*" Level Name Descr
If Array_Size > '' Then Do /* OCCURS only - for the group */
Array_Level = Occurs.0 + 1
Occurs.Array_Level.Prefix = Level
Occurs.Array_Level.Count = Array_Size
Occurs.0 = Array_Level
If ¬ Datatype( Array_Size, 'W' ) ,
| Array_Size > 1 Then Do
Say "*" Name Descr
Say "* OCCURS clause not supported"
Say "* Program terminated. RC=8"
Exit 8
End
End
Else /* just dummy group */
Return 0
End
LongPic = ''
Do x = 1 By 1 While PicValue > ''
Parse Var PicValue PicChar +1 PicValue
If Left( PicValue, 1 ) = '(' Then Do
Parse Var PicValue '(' CharCount ')' PicValue
If ¬ Datatype( CharCount, 'W' ) Then Do
Say "*" Name Descr
Say "* bad size count:" PicChar"("CharCount")"PicValue
Say "* Program terminated. RC=12"
Exit 12
End
PicChar = Copies( PicChar, CharCount )
End
LongPic = LongPic || PicChar
End x
S_Count = 0
D_Count = 0
V_Count = 0
X_Count = 0
O_Count = 0
Do i = 1 By 1 While LongPic > ''
Parse Var LongPic Cx +1 LongPic
Select
When Cx = 'S' Then S_Count = S_Count + 1
When Cx = '9' Then D_Count = D_Count + 1
When Cx = 'V' Then V_Count = V_Count + 1
When Cx = 'X' Then X_Count = X_Count + 1
Otherwise O_Count = O_Count + 1
End /* Select */
End i
Select
When Pos( 'COMP-3', LeftDescr ) > 0 ,
| Pos( 'COMPUTATIONAL-3', LeftDescr ) > 0 Then Do
Size = (D_Count + 2) % 2
Type = "PD"
End
When Pos( 'COMP-1', LeftDescr ) > 0 ,
| Pos( 'COMPUTATIONAL-1', LeftDescr ) > 0 ,
| Pos( 'COMP', LeftDescr ) > 0 ,
| Pos( 'COMPUTATIONAL', LeftDescr ) > 0 Then Do
Size = 2 + 2 * (D_Count >= 5) + 4 * (D_Count >= 10)
Type = "BI"
End
When X_Count = 0 Then Do /* PIC S99999V99 */
Size = D_Count + O_Count
Type = "CH"
End
Otherwise /* some 'X' found -> not zoned decimal */
Size = S_Count + D_Count + X_Count + O_Count
Type = "CH"
End /* Select */
If Name = 'FILLER' Then Do
Queue "*" Level C_Name Descr
Queue "SKIP,"Size
End
Else Do
Queue "*" Level C_Name Descr
Queue Name",*,"Size","Type
End
End
Return 0
/**********************************************************************/
|
|
|
| Back to top |
|
 |
sergeyken
Senior Member

Joined: 29 Apr 2008 Posts: 2263 Location: USA
|
|
|
|
Some typo in the copied code above, sorry...
Not extremely important, but misleading.
| Code: |
. . . . . . . . . . . .
Occurs.0 = 0
RedefLevel = 0
Do x = 1 By 1 To StemLine.0
Parse Var StemLine.x FLevel FName FDescr
If FLevel = '*' ,
| FDescr = '' Then Do
Iterate x
End
Call ProcessQueue FLevel FName FDescr
. . . . . . . . . . . . . . . .
|
|
|
| Back to top |
|
 |
A_programmers
New User
Joined: 24 Mar 2010 Posts: 19 Location: USA
|
|
|
|
Nic Clouston.
Writing SORT step for 70+ files with different layouts is cumbersome. As for every PD / Binary field we need to first calculate location of every field in input and output. Also manual calculation to convert size of field into target format.
I thought this is standard requirement which every one needs; why IBM has not provided any standard utility.
Rohit Umarjikar.
Personally I feel creating output copybook layout with unpacked fields; then moving input fields to output copybook is also the solution. SORT might get complex after we add additional filtering criteria or want to change fields.
sergeyken,
In mainframe if you open copybook using file manager / fileaid; it gives you starting position of every field.
Also; listing of the program should give starting position of every field. (I have not tried this.)
I strongly feel this is where mainframe is lagging. Even for standard requirement there is no library functions available. Where java is growing with lot of reusable libraries. |
|
| Back to top |
|
 |
enrico-sorichetti
Superior Member

Joined: 14 Mar 2007 Posts: 10900 Location: italy
|
|
|
|
| Quote: |
| Even for standard requirement there is no library functions available. |
making <binary> fields readable might be a common/standard requirement,
| Quote: |
why IBM has not provided any standard utility.
|
You would still have to provide for each field ,
source position, source length, source type
destination position, destination length, destination type
no library function /utility will do the above by itself
providing the above info would be as cumbersome as writing the sort control cards or the cobol file layouts |
|
| Back to top |
|
 |
Rohit Umarjikar
Global Moderator

Joined: 21 Sep 2010 Posts: 3109 Location: NYC,USA
|
|
|
|
| Quote: |
| Personally I feel creating output copybook layout with unpacked fields; then moving input fields to output copybook is also the solution. |
That is what I meant by writing a COBOL program which reusable for many datasets with different copybooks. It’s a clean way To maintain and achieve the results. Many years back we had written standard subprograms which will convert the comp and pd values to readable format, you could write that one and call it across many fields. |
|
| Back to top |
|
 |
Phrzby Phil
Senior Member
Joined: 31 Oct 2006 Posts: 1054 Location: Richmond, Virginia
|
|
|
|
I have done this as suggested above with an unpacked version of the copybook (easy to create).
MOVE CORRESPONDING is helpful, except as I remember does not handle OCCURS items.
Another reason to use a program as opposed to a utility is that if (when) there are errors (and when are there not?), tracing back to the source, especially by someone other than the converting person, is more straightforward. |
|
| Back to top |
|
 |
Marso
REXX Moderator

Joined: 13 Mar 2006 Posts: 1356 Location: Israel
|
|
|
|
| A_programmers wrote: |
| I have mainframe file (& corresponding copybook layout). This file contains combination packed and binary fields. Before sending (sftp) this file to Windows; I want to convert all packed / binary fields into display format fields. |
| A_programmers wrote: |
| Writing SORT step for 70+ files with different layouts is cumbersome. |
Your question was about ONE file, but when provided with a solution you start talking about 70+ files !
This means you have been wasting our time.
Please don't do that !  |
|
| Back to top |
|
 |
don.leahy
Active Member
Joined: 06 Jul 2010 Posts: 767 Location: Whitby, ON, Canada
|
|
|
|
Our shop uses INSYNC, a product from Macro4 to convert files from one format to another. It’s competitors (File aid from Compuware and File Manager from IBM) likely have similar capabilities.
I also have an automated process that converts COBOL copybooks to DFSORT symbols and then generates the BUILD statement to convert the file. I tend to prefer the INSYNC approach now. |
|
| Back to top |
|
 |
sergeyken
Senior Member

Joined: 29 Apr 2008 Posts: 2263 Location: USA
|
|
|
|
Whenever the SORT symbols table is automatically created from the COBOL copybook, then any conversion of any dataset to printable format (e.g. suitable to FTP to other platforms) becomes just a piece of cake. With new conversion features of nowadays utilities creating a new COBOL program for each dataset conversion is possible, but seems to be a sort of masochism.
In my experience a typical JCL to convert a particular file looks like this
| Code: |
//CONVERT EXEC CONV2FTP, standard procedure
// LAYOUT='&SYSUID..COPYBOOK(INRECORD)',
// SOURCE='&SYSUID..TESTDATA',
// OUTPUT='&SYSUID..CONVDATA'
//CONVERT.SYSIN DD *
SORT FIELDS=COPY
*
OUTREC BUILD=(FIELD_PIC20X, PIC X(20).
FLAG_PIC1X, PIC X.
FIELD_9_5, PIC 9(5).
ZD,EDIT=(TTTTT),
FIELD_S9_5, PIC S9(5).
ZD,EDIT=(STTTTT),SIGNS=(,-),
FIELD_S9_5V2, PIC S9(5)V99.
ZD,EDIT=(STTTTT.TT),SIGNS=(,-),
COMP3_9_4, PIC 9(4) COMP-3.
PD,EDIT=(TTTT),
COMP3_S9_8, PIC S9(8) COMP-3.
PD,EDIT=(STTTTTTTT),SIGNS=(,-),
COMP3_S9_8V2, PIC S9(8)V99 COMP-3.
PD,EDIT=(STTTTTTTT.TT),SIGNS=(,-),
COMP_9_4, PIC 9(4) COMP.
BI,EDIT=(TTTT),
COMP_S9_8, PIC S9(8) COMP.
FI,EDIT=(STTTTTTTT),SIGNS=(,-),
COMP_S9_5V2, PIC S9(8)V99 COMP.
FI,EDIT=(STTTTTTTT.TT),SIGNS=(,-),
DATE_YYDDD_PACKED, PIC 99999 COMP-3.
Y2U,DT=(4MD-),
DATE_YYMMDD_PACKED, PIC 999999 COMP-3.
Y2V,DT=(4MD-),
DATE_YYYYMMDD_PACKED, PIC 99999999 COMP-3.
Y4V,DT=(4MD-),
DATE_YYDDD, PIC 99999.
Y2T,DT=(4MD-),
DATE_YYMMDD, PIC 999999.
Y2T,DT=(4MD-),
DATE_YYYYMMDD, PIC 99999999.
Y4T,DT=(4MD-),
TIME_HHMM_PACKED, PIC 9999 COMP-3.
PD,EDIT=(TT.TT),
TIME_HHMMSS_PACKED, PIC 999999 COMP-3.
PD,EDIT=(TT.TT.TT),
TIME_HHMM, PIC 9999.
ZD,EDIT=(TT.TT),
TIME_HHMMSS, PIC 999999.
ZD,EDIT=(TT.TT.TT))
*
END
//* |
Assuming we have input record copybook INRECORD as follows
| Code: |
*
01 TEST-COBOL-DATA.
05 CHARACTER-DATA.
10 FIELD-PIC20X PIC X(20).
10 FLAG-PIC1X PIC X.
*
05 NUMERIC-DATA.
10 FIELD-9-5 PIC 9(5).
10 FIELD-S9-5 PIC S9(5).
10 FIELD-S9-5V2 PIC S9(5)V99.
*
05 DECIMAL-DATA.
10 COMP3-9-4 PIC 9(4) COMP-3.
10 COMP3-S9-8 PIC S9(8) COMP-3.
10 COMP3-S9-8V2 PIC S9(8)V99 COMP-3.
*
05 BINARY-DATA.
10 COMP-9-4 PIC 9(4) COMP.
10 COMP-S9-8 PIC S9(8) COMP.
10 COMP-S9-5V2 PIC S9(8)V99 COMP.
*
05 DATE-DATA.
10 DATE-YYDDD-PACKED PIC 99999 COMP-3.
10 DATE-YYMMDD-PACKED PIC 999999 COMP-3.
10 DATE-YYYYMMDD-PACKED PIC 99999999 COMP-3.
10 DATE-YYDDD PIC 99999.
10 DATE-YYMMDD PIC 999999.
10 DATE-YYYYMMDD PIC 99999999.
*
05 TIME-DATA.
10 TIME-HHMM-PACKED PIC 9999 COMP-3.
10 TIME-HHMMSS-PACKED PIC 999999 COMP-3.
10 TIME-HHMM PIC 9999.
10 TIME-HHMMSS PIC 999999.
* |
|
|
| Back to top |
|
 |
sergeyken
Senior Member

Joined: 29 Apr 2008 Posts: 2263 Location: USA
|
|
|
|
Exactly in the same manner the output format can be easily changed to, let's say, CSV file:
| Code: |
//CONVERT EXEC CONV2FTP, standard procedure
// LAYOUT='&SYSUID..COPYBOOK(INRECORD)',
// SOURCE='&SYSUID..TESTDATA',
// OUTPUT='&SYSUID..CSVDATA'
//CONVERT.SYSIN DD *
*
SORT FIELDS=COPY
*
OUTREC BUILD=(C'"',
FIELD_PIC20X, PIC X(20).
C'","',FLAG_PIC1X, PIC X.
C'","',FIELD_9_5, PIC 9(5).
ZD,EDIT=(IIIIT),
C'","',FIELD_S9_5, PIC S9(5).
ZD,EDIT=(SIIIIT),SIGNS=(,-),
C'","',FIELD_S9_5V2, PIC S9(5)V99.
ZD,EDIT=(SIIIII.TT),SIGNS=(,-),
C'","',COMP3_9_4, PIC 9(4) COMP-3.
PD,EDIT=(IIIT),
C'","',COMP3_S9_8, PIC S9(8) COMP-3.
PD,EDIT=(SIIIIIIIT),SIGNS=(,-),
C'","',COMP3_S9_8V2, PIC S9(8)V99 COMP-3.
PD,EDIT=(SIIIIIIII.TT),SIGNS=(,-),
C'","',COMP_9_4, PIC 9(4) COMP.
BI,EDIT=(IIIT),
C'","',COMP_S9_8, PIC S9(8) COMP.
FI,EDIT=(SIIIIIIIT),SIGNS=(,-),
C'","',COMP_S9_5V2, PIC S9(8)V99 COMP.
FI,EDIT=(SIIIIIIII.TT),SIGNS=(,-),
C'","',DATE_YYDDD_PACKED, PIC 99999 COMP-3.
Y2U,DT=(4MD-),
C'","',DATE_YYMMDD_PACKED, PIC 999999 COMP-3.
Y2V,DT=(4MD-),
C'","',DATE_YYYYMMDD_PACKED, PIC 99999999 COMP-3.
Y4V,DT=(4MD-),
C'","',DATE_YYDDD, PIC 99999.
Y2T,DT=(4MD-),
C'","',DATE_YYMMDD, PIC 999999.
Y2T,DT=(4MD-),
C'","',DATE_YYYYMMDD, PIC 99999999.
Y4T,DT=(4MD-),
C'","',TIME_HHMM_PACKED, PIC 9999 COMP-3.
PD,EDIT=(TT.TT),
C'","',TIME_HHMMSS_PACKED, PIC 999999 COMP-3.
PD,EDIT=(TT.TT.TT),
C'","',TIME_HHMM, PIC 9999.
ZD,EDIT=(TT.TT),
C'","',TIME_HHMMSS, PIC 999999.
ZD,EDIT=(TT.TT.TT),
C'"')
*
OUTFIL FTOV,
BUILD=(1,239,SQZ=(SHIFT=LEFT))
*
END
//* |
|
|
| Back to top |
|
 |
|
|
 |
All times are GMT + 6 Hours |
|