If else in sort JCL - sorting

I have a two requirements:
I must concatenate some fields from a file in a Cobol program. The way i must concatenate is based on one of the aforementioned field. The concatenated fields must be outputted in a new file.
I must then sort this new file with a sort utility invoked by JCL.
The Issue
I need to sort same file for 2 conditions. I have tried with ifthen outrec build. How can I sort it in one pass?
Here is a source-code example :
ID DIVISION.
PROGRAM-ID. FOO.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
Select Infil assign to inp001.
Select Outfil assign to out001.
DATA DIVISION.
FILE SECTION.
FD Infil.
01 Main.
03 A.
05 ws-Pc. Pic x(1).
05 filler Pic x(5).
03 B. Pic x(4).
03 C. Pic x(4).
03 D. Pic 9(13)V99.
03 E. Pic x(13).
FD Outfil.
01 Temp Pic x(42).
WORKING-STORAGE SECTION.
01 file-flag Pic x(01).
88 file-end value 'Y'.
88 not-file-end value 'N'.
PROCEDURE DIVISION.
Open input Infil
Open output Outfil
read Infil
at end
set file-end to true
not at end
set not-file-end to true
end-read
Perform until file-end
If ws-Pc = 3
String A B C Delimited by size
into Temp
End-String
Else
String A B C E Delimited by size
into Temp
End-String
End-if
Write Temp
read Infil
at end
Set file-end to true
end-read
end-Perform.
end program foo.
Here is the logic I need for the sort utility :
If ws-Pc=3
Sort(fieldA,fieldB)
Else
Sort(fieldA,fieldB,fieldE)
End-if.

I can propose you three variations :
If you are sure that your last 13 characters are the same (spaces for instance) in the case without a field E (ws-pc equal to three) you can just have this sysin:
SORT FIELDS=(1,6,CH,A,7,4,CH,A),EQUALS
Indeed, thanks to the equals all your inputs will keep their relative order once sorted. For the case ws-pc=3 it will be sorted according to field A and B. Field E plays no importance because it is the same for all.
If you are not sure that the last 13 characters are the same you can do it yourself:
INREC IFTHEN=(WHEN=(1,1,CH,EQ,C'3'),BUILD=(1,14,13X))
SORT FIELDS=(1,6,CH,A,7,4,CH,A),EQUALS
This will force your last characters to be spaces.
If you don't want to use the "EQUALS" you can create your own ordering by appending a line number in the field E when it is unused. You then have to remove it.
INREC IFTHEN=(WHEN=(1,1,CH,EQ,C'3'),BUILD=(1,14,SEQNUM,13,ZD))
SORT FIELDS=(1,6,CH,A,7,4,CH,A)
OUTREC IFTHEN=(WHEN=(1,1,CH,EQ,C'3'),BUILD=(1,14,13X))

Related

String iteration programming

I'd like to write a function able to generate an array of string with iteration in Go programming language.
Enter a unique name for the signal path in the field titled Description. Since the field features an iterator, multiple, consecutively counted signal paths can be set-up by using curly brackets, for example "Source {1-16:2} {Left, Right} >"
The result is an array of string:
Source 01 Left >
Source 01 Right >
Source 02 Left >
Source 02 Right >
...
Source 16 Left >
Source 16 Right >
I could have an undefined curly brackets iterator in the string.
The first curly brackets {1-16:2} indicate 1-16 : increment value
from 1 to 16 :2 is the padding that means two digits
The second curly brackets [Left, Right} indicate a defined list of
value.
I don't have the code yet.
Today I have an UI interface where I have some optional fields to fill.
signal path : "Source" as the unique identifier (as string) (Mandatory)
counter : "16" increment value from 1 till 16 (as integer) (optional)
Source 1
Source 2
Source 3
...
Source 16
If I would like to create a signal path like this:
Source 01 Left >
Source 01 Right >
I need to do it manually. If I have 1000 signal path to create it will take hours with errors and if the counter > 0 then increment value will be added at the end of the signal path and no padding.
Now I am looking some help if any libraries could analyze my string iteration "Source {1-16:2} {Left, Right}" and generate the string as expected.
Best regards,
Youssef

mask the middle number using the JCL

i have requrement like this. could you please help any one help me?
i have 16 digit length fileld in my input file. if more than 13 digit length then first 4 digit as it is and last 4 digits as it is and mask the remaining the number
if less than 13 then keep the number as it is.
example
IP file
0000359681243354
0000359681243354
810176733
OP
00003̶5̶9̶6̶8̶1̶2̶4̶3354
00003̶5̶9̶6̶8̶1̶2̶4̶3354
810176733
Edit 1:
As per #NicC's suggestions in the Comments section of this answer, you may try the following code:
INREC IFTHEN=(WHEN=INIT,BUILD=(1,16)),
IFTHEN=(WHEN=(13,1,CH,NE,X'40',AND,13,1,CH,NE,X'00'),OVERLAY=(5:8C'-'))
SORT FIELDS=COPY
Alternatively, you may also try the following code.
Firstly, we use OUTFIL with FTOV,VLTRIM=C' ' to convert the input records to VB with an RDW. This is helpful because we can access the RDW to get the length of data upto first nonblank character. But, how to access the RDW? See next step.
Secondly, we build a record in T2 file, with actual data, followed by the length of the data (RDW is in 1,2,BI. Subtract 4 from 1,2,BI to get the length of data).
Lastly, use INREC IFTHEN to check if the length of the data is GE 13 or not. Format data as required.
Note: Following code needs to be changed for DD names, position of the 16 digit length field and other input fields in the record.
//STEP1 EXEC PGM=ICETOOL
//TOOLMSG DD SYSOUT=*
//DFSMSG DD SYSOUT=*
//IN DD DSN=... input file (FB)
//TEMP1 DD DSN=&&TEMP1,UNIT=SYSDA,SPACE=(CYL,(5,5)),DISP=(,PASS)
//TEMP2 DD DSN=&&TEMP2,UNIT=SYSDA,SPACE=(CYL,(5,5)),DISP=(,PASS)
//OUT DD DSN=... output file (FB)
//TOOLIN DD *
COPY FROM(IN) USING(CTL1)
COPY FROM(TEMP1) TO(TEMP2) USING(CTL2)
COPY FROM(TEMP2) TO(OUT) USING(CTL3)
/*
//CTL1CNTL DD *
OUTFIL FNAMES=TEMP1,FTOV,VLTRIM=C' '
/*
//CTL2CNTL DD *
OUTFIL FNAMES=TEMP2,VTOF,
BUILD=(5,16,X,1,2,BI,SUB,+4,TO=ZD,LENGTH=2)
/*
//CTL3CNTL DD *
INREC IFTHEN=(WHEN=(18,2,ZD,GE,13),BUILD=(1:1,4,5:8C'-',13:13,4),
IFTHEN=(WHEN=(18,2,ZD,LT,13),BUILD=(1:1,6))
SORT FIELDS=COPY

Hexadecimal string representation to hexadecimal

I am currently working with UDP packets and I need to craft and send custom data. Because it is easier for me to read I work with strings representing hexadecimal values. I have something like this :
a = "12"
b = "15"
header = "c56b4040003300" + a + "800401" + b + "90000000"
Now, what I want to do is converting my header variable into hexadecimal (but not with the hexadecimal value of every character in header). It means that if I write my header variable in a file and I open it with a hexadecimal editor, I want to see
c5 6b 40 40 00 33 00 12 80 04 01 15 90 00 00 00
I don't have a good knowledge of ruby and I couldn't find a way to do it so far. The pack function converts characters in hexa but not hexadecimal string representation as hexadecimal value. And doing something like
header = "\xc5\x6b\x40\x40\x00\x33\x00\x" + a + "\x80\x04\x01\x" + b + "\x90\x00\x00\x00"
will throw me an error saying "invalid hex escape" (which make sense).
So if you have a solution to this problem please tell me (if possible without using any external library)
require 'strscan'
s = StringScanner.new('hexstring here')
s.scan(/../).map { |x| x.hex.chr }.join
String#to_i takes a base argument that will do what you want:
["c56b4040003300", a, "800401", b, "90000000"].join.to_i(16)
But it may not make sense to represent your data as an large integer. If you just want a blob of binary data, you can concatenate everything together and use Array#pack:
[["c56b4040003300", a, "800401", b, "90000000"].join].pack('H*')
Or you can pack the individual components and concatenate the results:
["c56b4040003300", a, "800401", b, "90000000"].map { |s| [s].pack('H*') }.join
Or you can just work with an array of bytes throughout your program:
bytes = "c56b4040003300".scan(/../)
bytes << a
bytes.concat "800401".scan(/../)
bytes << b
bytes.concat "90000000".scan(/../)
bytes.unpack('H*' * bytes.size)
Hope that helps!

JOINKEYS REFORMAT field for a VB file for F2 is not working

I am trying to right and left outer join these two RECFM VB files but
I don't get anything from the F2 file.
//STEP2000 EXEC PGM=SORT
//* JOIN
//*
//SYSOUT DD SYSOUT=*
//*
//SORTJNF1 DD DSN=YXX122.TEMP.EXPORT.TYPEN,
// DISP=SHR
//*
//SORTJNF2 DD DSN=YXX122.TEMP.EXPORT.TYPEC,
// DISP=SHR
//*
//SORTOUT DD DSN=YXX122.DYXX122.EXPORT.XSUM,
// DISP=(NEW,CATLG,DELETE),
// UNIT=(DEV,2),
// SPACE=(CYL,(150,20),RLSE),
// DCB=(RECFM=VB,LRECL=304,BLKSIZE=0)
//*
//SYSIN DD *
SORT FIELDS=COPY
JOINKEYS FILES=F1,
FIELDS=(13,4,A,18,5,A,17,1,A,23,1,A,33,8,A,41,4,A)
JOINKEYS FILES=F2,
FIELDS=(13,4,A,18,5,A,17,1,A,23,1,A,33,8,A,41,4,A)
JOIN UNPAIRED,F1,F2
REFORMAT FIELDS=(F1:5,300)
OUTFIL FTOV
//
The problem is I can't find how the REFORMAT FIELDS the F2 file.
I tried with REFORMAT FIELDS=(F1:5,300,F2:5,300) but the outfile was with a length of 600.
I will like to know how to have both file F1 and F2 in my SORTOUT file with a VB length 304.
Any idea on how to fix this problem?
It turns out you have DFSORT, not SyncSORT which makes things simpler, as you can definitely use the Match Marker ? in the REFORMAT statement. Up-to-date SyncSORT may have the Match Marker as an undocumented feature.
Putting all the unmatched records on one OUTFIL may be confusing (you won't know which input they have come from).
This conceptualises your join (where the Output is the joined data, and b represents blank).
F1
A
C
E
F2
B
C
F
Output
Ab
bB
Eb
bF
So if you want B and F you need to specify some data from F2. You also need to identify the "blanks" so that you know which part of the REFORMAT record currently has data in (DFSORT has a Match Marker for this, SyncSORT does not).
For that you need to identify one byte which can never be blank in the record. If that is not possible, one byte which can never be another given value (which you specify on FILL= on the REFORMAT). Failing that, two or more bytes with the same characteristics. As a final fail-safe you can check the entire part of the REFORMAT record from one file or the other for blank.
Since you want V-type output, you could make your REFORMAT record variable:
REFORMAT FIELDS=(F1:1,4,?,F1:5,300,F2:5)
And use VLTRIM on OUTFIL.
Or fixed:
REFORMAT FIELDS=(F1:5,300,F2:5,300)
And use FTOV with VLTRIM on OUTFIL.
Then you need some code, which tests the byte/bytes/partofdata you have chosen for being space/thevalueyouhavechosen and uses BUILD to create a record which contains the data you want (plus trailing blanks/values which will be killed by the VLTRIM).
IFTHEN=(WHEN=(logicalexpression),
BUILD=(1,4,5,300)),
IFTHEN=(WHEN=NONE,
BUILD=(1,4,305,300))
Or
IFTHEN=(WHEN=(logicalexpression),
BUILD=(1,300)),
IFTHEN=(WHEN=NONE,
BUILD=(301,300))
Here's some code which does what you want. Probably. I can't test it with SyncSORT.
Data:
F1
A 11111111111111111111111111111111111
C 2222222222222222222222
E 3
F2
B 4444444444444444
C 55555555555555555555555555
F 6666666666666
Code:
OPTION COPY
JOINKEYS F1=INA,FIELDS=(5,1,A),SORTED,NOSEQCK
JOINKEYS F2=INB,FIELDS=(5,1,A),SORTED,NOSEQCK
JOIN UNPAIRED,F1,F2,ONLY
REFORMAT FIELDS=(F1:1,4,F1:5,76,F2:5)
OUTFIL FNAMES=EXT,VLTRIM=C' ',
IFTHEN=(WHEN=(81,1,CH,EQ,C'2'),
BUILD=(1,4,82)),
IFTHEN=(WHEN=NONE,
BUILD=(1,4,5,76))
The Match Marker, ?, will be set to 1 for unmatched F2, 2 for unmatched F2 and B for matched records (which you won't get, because of the ONLY on the JOIN statement).
This presumes your data is already in sequence. Remove the SORTED,NOSEQCK for data which is not in sequence.
I've used an LRECL of 80 and a simple key and some simple data.
Output:
For EXT:
A 11111111111111111111111111111111111
B 4444444444444444
E 3
F 6666666666666
SORTOUT would show the unchanged REFORMAT record. That is for you to see how it works. You can remove the FNAMES=EXT or remove the SORTOUT from the JCL when you understand everything.
The F1:1,4 ensures that the REFORMAT record is variable-length. The 5,300 should use blank-padding for shorter records. That's why you need the VLTRIM later. The F2:5 says "file two, position five, to the end of the file two record".
If your data can have genuine trailing blanks, you'll have to use FILL= and VLTRIM= for the same character.
IFTHEN=(WHEN=(logicalexpression) processing finishes when an IFTHEN is true. So the combination in the code is effectively an IF/ELSE.
See also this, Compare two files and write it to "match" and "nomatch" files and Sync sort, Unpaired records of File1 have spaces for no records in F2 file. Can we replace those specific column's spaces by ZEROS? for further examples.

Search a string and alter /replace string after "="

Suppose I am in following directory A/B/C/prop and need to check e0and e1 files out of other 100 files.In these two file i have following entries:
$DBConnection_target=targetname
$DBConnection_source1=sourcename
I need to change targetname and sourcename only and string that will be used, taken from Keyboard(read).
These string may occur more than 2-3 times.
You can use sed to perform the replacements in the two files, e0 and e1, as shown below:
# set what you want the source and target to be changed to here:
newSource=foo
newTarget=bar
sed -i 's/\($DBConnection_target\)=.*$/\1='"$newTarget"'/;s/\($DBConnection_source1\)=.*$/\1='"$newSource"'/' e0 e1

Resources