Welcome to my blog! This is my first post of this new year, 2021. Happy New Year to one and all 😄
In this post, we'll look at Level 3.3 of Master the Mainframe 2020. If you haven't registered for MTM2020 yet, then you're missing the fun 😐. Master the Mainframe has been a lot interesting this year (2020) as we are using Visual Studio Code (for the first time) to establish a connection with z/OS. Hit this link to register.
Level 3.3: REXX2: Nexxt Level Rexx is all about building complex logic and functionality using REXX. The task is to write a REXX Exec that acts as a generator, which when executed, will output Luhn-Algorithm compatible 16 digit numbers. The code shouldn't take any parameters though.
If you do not have prior experience in writing REXX exec's, do not worry at all.
- MTM2020 is the right place to get your hands on REXX. There are couple of challenges in Level 3 which will improve your REXX skills in the best way possible.
- Advertisement alert ⚠: I also recommend you to read a blog post of mine 😀 which is intended for beginners in REXX.
- Jim Barry's REXX tutorial is my personal favourite, so I recommend that as well.
It's time ⏰ to go further...
/**************************** REXX *********************************/ | |
/* This exec illustrates the use of "EXECIO 0 ..." to open, empty, */ | |
/* or close a file. It reads records from file indd, allocated */ | |
/* to 'sams.input.dataset', and writes selected records to file */ | |
/* outdd, allocated to 'sams.output.dataset'. In this example, the */ | |
/* data set 'smas.input.dataset' contains variable-length records */ | |
/* (RECFM = VB). */ | |
/*******************************************************************/ | |
"FREE FI(outdd)" | |
"FREE FI(indd)" | |
"ALLOC FI(indd) DA('MTM2020.PUBLIC.CUST16') SHR REUSE" | |
"ALLOC FI(outdd) DA('ZXXXXX.OUTPUT.CUSTOMER') SHR REUSE" | |
eofflag = 2 /* Return code to indicate end-of-file */ | |
return_code = 0 /* Initialize return code */ | |
in_ctr = 0 /* Initialize # of lines read */ | |
out_ctr = 0 /* Initialize # of lines written */ | |
/*******************************************************************/ | |
/* Open the indd file, but do not read any records yet. All */ | |
/* records will be read and processed within the loop body. */ | |
/*******************************************************************/ | |
"EXECIO 0 DISKR indd (OPEN" /* Open indd */ | |
/*******************************************************************/ | |
/* Now read all lines from indd, starting at line 1, and copy */ | |
/* selected lines to outdd. */ | |
/*******************************************************************/ | |
DO WHILE (return_code \= eofflag) /* Loop while not end-of-file */ | |
'EXECIO 1 DISKR indd' /* Read 1 line to the data stack */ | |
return_code = rc /* Save execio rc */ | |
IF return_code = 0 THEN /* Get a line ok? */ | |
DO /* Yes */ | |
in_ctr = in_ctr + 1 /* Increment input line ctr */ | |
PARSE PULL line.1 /* Pull line just read from stack*/ | |
IF LENGTH(line.1) > 10 then /* If line longer than 10 chars */ | |
DO | |
"EXECIO 1 DISKW outdd (STEM line." /* Write it to outdd */ | |
cc_digits = SUBSTR(line.1,3,19) | |
/* call INSPECT */ | |
out_ctr = out_ctr + 1 /* Increment output line ctr */ | |
END | |
END | |
END | |
"EXECIO 0 DISKR indd (FINIS" /* Close the input file, indd */ | |
IF out_ctr > 0 THEN /* Were any lines written to outdd?*/ | |
DO /* Yes. So outdd is now open */ | |
/****************************************************************/ | |
/* Since the outdd file is already open at this point, the */ | |
/* following "EXECIO 0 DISKW ..." command will close the file, */ | |
/* but will not empty it of the lines that have already been */ | |
/* written. The data set allocated to outdd will contain out_ctr*/ | |
/* lines. */ | |
/****************************************************************/ | |
"EXECIO 0 DISKW outdd (FINIS" /* Closes the open file, outdd */ | |
SAY 'File outdd now contains ' out_ctr' lines.' | |
END | |
ELSE /* Else no new lines have been */ | |
/* written to file outdd */ | |
DO /* Erase any old records from the file*/ | |
/****************************************************************/ | |
/* Since the outdd file is still closed at this point, the */ | |
/* following "EXECIO 0 DISKW " command will open the file, */ | |
/* write 0 records, and then close it. This will effectively */ | |
/* empty the data set allocated to outdd. Any old records that */ | |
/* were in this data set when this exec started will now be */ | |
/* deleted. */ | |
/****************************************************************/ | |
"EXECIO 0 DISKW outdd (OPEN FINIS" /*Empty the outdd file */ | |
SAY 'File outdd is now empty.' | |
END | |
"FREE FI(indd)" | |
"FREE FI(outdd)" | |
EXIT | |
INSPECT: | |
say 'inspecting' cc_digits | |
RETURN |
Defining ALLOC command for a dataset in REXX Exec is very much similar to defining a dataset in a JCL DD statement for I/O.
R in the DISKR is for Read. Similarly, W in the DISKW is for write. X in the DISKX will issue an error because there is no such thing as DISKX 😅. Just DISKW and DISKR.
There are three nested DO statetments here. The outermost loop is just a check to make sure there are more lines to read, the middle loop iterates through those lines, and the innermost loop checks if the length of the line is greater than 10 characters, before writing it to the output file.
What's the ask?
- REXX is a dynamically typed language. This means you are able to store several values of different types in a single variable during your code execution and no errors will occur.
- For example, consider the following 2 lines.
- In the second line, REXX actually understands the data by its usage. It automatically converts the type of the output from the second operand (substr() function) to perform the arithmetic operation.
- Step 9 in the challenge instructions list out some built-in functions which you may find useful to accomplish the task.
- SUBSTR – Substring – returns just the characters at a specific location within a string. There’s an example of this in action at line 40.
- LENGTH – Returns the total length, in characters, of a string.
- MATH OPERATORS – In particular, the // symbol, which returns the remainder after dividing by a number.
- RANDOM – is a built-in function in REXX and it is used to generate a random non-negative whole number between the min and max range that are provided as arguments.
What was my approach to finish this challenge 🤔?
/*-----------------------------------------------------------------*/ | |
/* Let's talk a little about the anatomy of a credit card: */ | |
/* */ | |
/* ------------------------------------------------ */ | |
/* | | */ | |
/* | | */ | |
/* | | */ | |
/* | | */ | |
/* | 5 3 0 4 4 6 4 2 1 2 3 4 5 6 7 8 | */ | |
/* | |____________| |___________________| | | */ | |
/* | | | | Checksum| */ | |
/* | | | Account Identifier | */ | |
/* | | BIN(Bank Identification Number) | */ | |
/* |MII(Major Industry Identifier) | */ | |
/* | | */ | |
/* ------------------------------------------------ */ | |
/* */ | |
/* The first number is Major Industry Identifier (MII), */ | |
/* which tells you what sort of institution issued the card. */ | |
/* */ | |
/* 1 and 2 are issued by the airlines. */ | |
/* 3 is issued by travel and entertainment */ | |
/* 4 and 5 are issued by banking and financial institutions */ | |
/* 6 is issued by merchandising and banking */ | |
/* 7 is issued by petroleum companies */ | |
/* 8 is issued by telecommunications companies */ | |
/* 9 is issued by national assignment */ | |
/* */ | |
/* The first six digits are the Issuer Identification Number (IIN) */ | |
/* These can be used to look up where the card originated from. */ | |
/* Here are a few you might recognize: */ | |
/* */ | |
/* Visa: 4***** */ | |
/* American Express (AMEX): 34**** or 37**** */ | |
/* Mastercard: 51**** to 55**** */ | |
/* */ | |
/* The seventh digit to the second-to-last digit is the customer */ | |
/* account number. Most companies use just 9 digits for the */ | |
/* account numbers, but it's possible to use up to 12. This means */ | |
/* that using the current algorithm for credit cards, the world */ | |
/* can issue about a trillion cards before it has to change the */ | |
/* system. */ | |
/* */ | |
/* The very last digit of a credit card is the check digit or */ | |
/* checksum. It is used to validate the credit card number using */ | |
/* the Luhn algorithm. */ | |
/*-----------------------------------------------------------------*/ |
Compound variables:
Some useful tips:
- Try this website to validate the 500 numbers you generate out of your code, to be Luhn-compatible or not.
- I recommend you to use Vista TN3270 terminal for this challenge to logon to the MTM system (IP: 192.86.32.153 PORT: 623) rather than VS code. Coding and running your REXX exec will be a lot easier in TN3270 terminal.
- Coding TRACE I in the 2nd line of your REXX Exec and executing the code will result in debugging mode. This might help you in understanding the program's flow, if things are not working out. More about TRACE can be found here.
- Bonus hint: While using DO loops to traverse across the even and odd positions of the 19 digit credit card number, you may have to step 2 times in each iteration. The syntax in such cases is as follows:
This comment has been removed by the author.
ReplyDeleteThank you for explaining in simple terms. I am a beginner and was struggling it.
ReplyDelete