/* REXX */ /* */ /* AUTHOR: Mark Zelden */ /* */ /* Last Updated 10/07/2013 */ /* */ help_start = HELP_INCL() /***************************************************************/ /* */ /* THIS EDIT MACRO CAN PERFORM 3 DIFFERENT FUNCTIONS: */ /* */ /* A) MOVE, COPY or SWAP data from one range of */ /* columns to another (default is MOVE). */ /* Excluded lines are always omitted. */ /* */ /* B) SHIFT data LEFT or RIGHT a specified */ /* number of columns - same as the "((" or "))" ISPF */ /* editor line commands. */ /* Excluded lines are always omitted. */ /* */ /* C) CUT (copy) data from specific columns into the */ /* ISPF Default Clipboard. This data can then be */ /* used with PASTE later on. */ /* Excluded lines are always omitted. */ /* */ /***************************************************************/ /* COMMAND SYNTAX: */ /* */ /* COLUTIL or COLUTIL ? - displays help */ /* */ /* MOVE FORMAT: */ /* */ /* COLUTIL begcol endcol tgtcol (MOVE) (.label1) (.label2) */ /* */ /* COPY FORMAT: */ /* */ /* COLUTIL begcol endcol tgtcol COPY (.label1) (.label2) */ /* */ /* SWAP FORMAT: */ /* */ /* COLUTIL begcol endcol tgtcol SWAP (.label1) (.label2) */ /* */ /* SHIFT FORMAT: */ /* */ /* COLUTIL amount (.label1) (.label2) */ /* */ /* CUT FORMAT: */ /* */ /* COLUTIL CUT begcol endcol (.label1) (.label2) */ /* */ /***************************************************************/ /* USAGE NOTES: */ /* */ /* ** NOTE 1: If you execute COLUTIL with no parms or with */ /* a parm of "?", the comment section of this */ /* code with syntax and usage notes will be */ /* displayed as "help" note lines. Use the */ /* "RESET" command to remove them. */ /* */ /* ** NOTE 2: If using line range labels for a MOVE */ /* operation - "MOVE" must be specified */ /* as the 4th positional parameter. */ /* */ /* ** NOTE 3: COPY, MOVE, SWAP, LEFT, RIGHT and CUT can all */ /* be abbreviated by using one or more of their */ /* characters. */ /* */ /* ** NOTE 4: Excluded lines are ALWAYS omitted. */ /* */ /* ** NOTE 5: On a SWAP operation, the length of the */ /* endcol-begcol determines to number of */ /* columns swapped starting with the tgtcol. */ /* For example, "COLUTIL 10 15 20 SWAP" will */ /* swap columns 10-15 with 20-25. */ /* */ /* ** NOTE 6: On a SWAP operation, if there are overlapping */ /* columns, for example: "COLUTIL 10 20 15 SWAP", */ /* columns 15-25 will replace 10-20, then */ /* the original data from columns 10-20 will */ /* replace columns 15-25. */ /* */ /* ** NOTE 7: On a CUT operation, if you have any existing */ /* data in the ISPF default clipboard, it will */ /* be overlaid. */ /* */ /* ** NOTE 8: On a CUT operation, ISPF considers the data */ /* changed due to the way the edit macro works. */ /* You must use "CANCEL" if you don't want the */ /* data in your edit session saved, although it */ /* is the same data as it was prior to the CUT. */ /* */ /***************************************************************/ /* MOVE EXAMPLES: */ /* COLUTIL 10 20 30 */ /* COLUTIL 45 55 10 M */ /* COLUTIL 45 55 10 MOVE */ /* COLUTIL 45 55 10 MOVE .A .B */ /* */ /* COPY EXAMPLES: */ /* COLUTIL 10 15 20 C */ /* COLUTIL 10 15 20 COPY */ /* COLUTIL 45 50 15 COPY .A .B */ /* */ /* SWAP EXAMPLES: */ /* COLUTIL 20 25 50 S */ /* COLUTIL 40 45 10 SWAP */ /* COLUTIL 45 50 15 SWAP .A .B */ /* */ /* SHIFT EXAMPLES: */ /* COLUTIL R 4 */ /* COLUTIL L 6 */ /* COLUTIL RIGHT 10 */ /* COLUTIL RIGHT 10 .A .B */ /* COLUTIL LEFT 12 */ /* COLUTIL LEFT 25 .A .B */ /* */ /* CUT EXAMPLES: */ /* COLUTIL C 10 15 */ /* COLUTIL CUT 68 68 */ /* COLUTIL CUT 30 40 .A .B */ /* */ /***************************************************************/ help_end = HELP_INCL() /* TRACE ?R */ Address ISREDIT "MACRO (begcol endcol tgtcol type label1 label2)" /* Address ISPEXEC "CONTROL ERRORS RETURN" */ /***********************************************/ /* VERIFY INPUT PARAMETERS */ /***********************************************/ begcol = Translate(begcol) /* chage to upper case if alpha */ "(width) = DATA_WIDTH " /* length of line */ width = Format(width) /* remove leading zeros */ shiftop = 'NO' /* shift operation flag */ cutop = 'NO' /* cut operation flag */ If begcol = '?' then do Call HELP_NOTELINES Exit 1 /* return cursor to command line */ End If begcol = '' then do zedsmsg = 'MISSING PARAMETER' zedlmsg = '"CUT" OR A SHIFT TYPE OR A BEGINNING COLUMN NUMBER', 'MUST BE SPECIFIED.' Address ISPEXEC "SETMSG MSG(ISRZ001)" /* msg - with alarm */ Call HELP_NOTELINES Exit 4 End Select When Datatype(begcol,Number) = 1 & endcol = '' then do zedsmsg = 'NO ENDING COLUMN' zedlmsg = 'AN ENDING COLUMN FOR THE', 'OPERATION MUST BE SPECIFIED.' Address ISPEXEC "SETMSG MSG(ISRZ001)" /* msg - with alarm */ Exit 12 End /* when */ When Datatype(begcol,Number) =1 & Datatype(endcol,Number) <>1 then do zedsmsg = 'END COLUMN NOT NUMERIC' zedlmsg = 'THE ENDING COLUMN FOR THE', 'OPERATION MUST BE NUMERIC.' Address ISPEXEC "SETMSG MSG(ISRZ001)" /* msg - with alarm */ Exit 12 End /* when */ When Datatype(begcol,Number) =1 & Datatype(endcol,Number) =1 then do If endcol < begcol then do zedsmsg = 'END COL < START COL' zedlmsg = 'THE ENDING COLUMN MUST BE GREATER THAN OR', 'EQUAL TO THE STARTING COLUMN.' Address ISPEXEC "SETMSG MSG(ISRZ001)" /* msg - with alarm */ Exit 12 End If tgtcol <> '' then do If Datatype(tgtcol,Number) <> 1 then do zedsmsg = 'TARGET COL NOT NUMERIC' zedlmsg = 'THE TARGET COLUMN FOR THE', 'OPERATION MUST BE NUMERIC.' Address ISPEXEC "SETMSG MSG(ISRZ001)" /* msg - with alarm */ Exit 12 End End If tgtcol = '' then do zedsmsg = 'NO TARGET COLUMN' zedlmsg = 'YOU MUST SPECIFY A TARGET COLUMN', 'FOR THE OPERATION.' Address ISPEXEC "SETMSG MSG(ISRZ001)" /* msg - with alarm */ Exit 12 End If type = '' then type = 'MOVE' else do type = Translate(type) /* change to upper case */ If Abbrev('MOVE',type,1) = 0 & , Abbrev('COPY',type,1) = 0 & , Abbrev('SWAP',type,1) = 0 then do zedsmsg = 'INVALID OPERATION' zedlmsg = 'OPERATION MUST BE "MOVE", "COPY", OR "SWAP".' Address ISPEXEC "SETMSG MSG(ISRZ001)" /* msg - with alarm */ Exit 12 End End /* else do */ If begcol < 1 | endcol < 1 | tgtcol < 1 then do zedsmsg = 'INVALID COLUMN NUMBER' zedlmsg = 'ALL COLUMN SPECIFICATIONS MUST BE' , 'BETWEEN 1 AND' width Address ISPEXEC "SETMSG MSG(ISRZ001)" /* msg - with alarm */ Exit 12 End If begcol > width | endcol > width | tgtcol > width then do zedsmsg = 'INVALID COLUMN NUMBER' zedlmsg = 'ALL COLUMN SPECIFICATIONS MUST BE' , 'BETWEEN 1 AND' width Address ISPEXEC "SETMSG MSG(ISRZ001)" /* msg - with alarm */ Exit 12 End If begcol = tgtcol then do zedsmsg = 'NO ACTION TAKEN' zedlmsg = 'THE STARTING COLUMN AND TARGET COLUMN', 'CAN NOT BE THE SAME.' Address ISPEXEC "SETMSG MSG(ISRZ001)" /* msg - with alarm */ Exit 12 End End /* when */ Otherwise /* shift or cut options being used */ If Abbrev('CUT',begcol,1) = 0 & , Abbrev('LEFT',begcol,1) = 0 & , Abbrev('RIGHT',begcol,1) = 0 then do zedsmsg = 'INVALID OPTION' zedlmsg = '"CUT" OR A SHIFT DIRECTION OF "LEFT" OR "RIGHT"', 'MUST BE SPECIFIED' Address ISPEXEC "SETMSG MSG(ISRZ001)" /* msg - with alarm */ Exit 12 End If (Abbrev('LEFT',begcol,1) <> 0 | , Abbrev('RIGHT',begcol,1) <> 0 ) & , endcol = '' then do zedsmsg = 'NO SHIFT AMOUNT' zedlmsg = 'A SHIFT AMOUNT FOR THE', 'OPERATION MUST BE SPECIFIED.' Address ISPEXEC "SETMSG MSG(ISRZ001)" /* msg - with alarm */ Exit 12 End If Abbrev('CUT',begcol,1) <> 0 & , endcol = '' then do zedsmsg = 'NO STARTING COLUMN' zedlmsg = 'A STARTING COLUMN FOR THE CUT', 'OPERATION MUST BE SPECIFIED.' Address ISPEXEC "SETMSG MSG(ISRZ001)" /* msg - with alarm */ Exit 12 End If Abbrev('CUT',begcol,1) <> 0 & , tgtcol = '' then do zedsmsg = 'NO ENDING COLUMN' zedlmsg = 'AN ENDING COLUMN FOR THE CUT', 'OPERATION MUST BE SPECIFIED.' Address ISPEXEC "SETMSG MSG(ISRZ001)" /* msg - with alarm */ Exit 12 End Else do If Abbrev('CUT',begcol,1) <> 0 then cutop = 'YES' else shiftop = 'YES' If Datatype(endcol,Number) <> 1 & shiftop = 'YES' then do zedsmsg = 'SHIFT AMOUNT NOT NUMERIC' zedlmsg = 'THE SHIFT AMOUNT SPECIFIED FOR THE', 'OPERATION MUST BE NUMERIC.' Address ISPEXEC "SETMSG MSG(ISRZ001)" /* msg - with alarm */ Exit 12 End If (endcol > width - 1 | endcol < 1) & shiftop = 'YES' then do zedsmsg = 'INVALID SHIFT AMOUNT' zedlmsg = 'THE SHIFT AMOUNT SPECIFIED MUST', 'BE BETWEEN 1 AND' width - 1 || '.' Address ISPEXEC "SETMSG MSG(ISRZ001)" /* msg - with alarm */ Exit 12 End If Datatype(endcol,Number) <> 1 & cutop = 'YES' then do zedsmsg = 'START COLUMN NOT NUMERIC' zedlmsg = 'THE STARTING COLUMN SPECIFIED FOR THE', 'CUT OPERATION MUST BE NUMERIC.' Address ISPEXEC "SETMSG MSG(ISRZ001)" /* msg - with alarm */ Exit 12 End If ((endcol > width | endcol < 1) | , (tgtcol > width | tgtcol < 1)) & , cutop = 'YES' then do zedsmsg = 'INVALID CUT COLUMNS' zedlmsg = 'THE CUT COLUMNS SPECIFIED MUST', 'BE BETWEEN 1 AND' width || '.' Address ISPEXEC "SETMSG MSG(ISRZ001)" /* msg - with alarm */ Exit 12 End If tgtcol < endcol & cutop = 'YES' then do zedsmsg = 'END COL < START COL' zedlmsg = 'THE ENDING COLUMN MUST BE GREATER THAN OR', 'EQUAL TO THE STARTING COLUMN.' Address ISPEXEC "SETMSG MSG(ISRZ001)" /* msg - with alarm */ Exit 12 End End /* else do */ End /* select */ /***********************************************/ /* SHIFT PROCESSING SETUP */ /***********************************************/ If shiftop = 'YES' then do label1 = tgtcol label2 = type shiftamt = endcol type = 'MOVE' /* shift is really a MOVE operation */ If Abbrev('LEFT',begcol,1) <> 0 then do /* left shift */ shifttyp = 'LEFT' begcol = shiftamt + 1 endcol = width tgtcol = 1 End Else do /* right shift */ shifttyp = 'RIGHT' begcol = 1 endcol = width tgtcol = shiftamt + 1 End End /* if shiftop = 'YES' */ /***********************************************/ /* CUT PROCESSING SETUP */ /***********************************************/ If cutop = 'YES' then do label2 = label1 label1 = type begcol = endcol endcol = tgtcol crpl1st = 'YES' /* "1st cut" flag to do "CUT REPLACE" */ "(saveln) = DISPLAY_LINES" End /* if cutop = 'YES' */ /***********************************************/ /* FIND OUT IF LABELS ARE BEING USED */ /***********************************************/ Call FIND_LABELS /***************************************************/ /* INITIALIZE VARIABLES NEEDED IN PROCESSING LOOP */ /***************************************************/ count = 0 /* count of processed lines */ tgtlen = endcol-begcol+1 /* length of operation */ /***********************************************/ /* BEGIN COLUMN PROCESSING LOOP */ /***********************************************/ Do until lastln = firstln-1 /* copy the data in the current line to variable 'data1' */ "(data1) = LINE "firstln "ISREDIT (chkexcl) = XSTATUS" firstln If chkexcl = "NX" then do count = count + 1 If cutop <> 'YES' then do /* move/copy/swap/shift operation */ tgtdata = Substr(data1,begcol,tgtlen) If shiftop = 'YES' & shifttyp = 'LEFT' then , /* clr for left */ data1 = Overlay(' ',data1,width-shiftamt,shiftamt+1) /*shift */ If Abbrev('MOVE',type,1) <> 0 then , /* clear data for */ data1 = Overlay(' ',data1,begcol,tgtlen) /* column MOVE */ If Abbrev('SWAP',type,1) <> 0 then do /* SWAP */ data2 = Substr(data1,tgtcol,tgtlen) /* the */ data1 = Overlay(data2,data1,begcol,tgtlen) /* data */ End data1 = Overlay(tgtdata,data1,tgtcol,tgtlen) /* COPY data */ End /* if cutop <> 'YES' */ Else do /* cut operation */ If begcol = 1 then data2 = data1 Else data2 = Overlay(' ',data1,1,begcol-1) data3 = Overlay(' ',data2,endcol+1,width-endcol) /* data for cut */ "LINE" firstln "= (data3)" If crpl1st = 'YES' then do /* first cut - replace clipboard */ "CURSOR = " firstln 1 "ISREDIT CUT .ZCSR .ZCSR REPLACE" crpl1st = 'NO' /* reset "1st cut" flag */ End Else do "CURSOR = " firstln 1 "ISREDIT CUT .ZCSR .ZCSR APPEND" End End /* else do */ End /* copy the modified line back into the current line */ "LINE" firstln "= (data1)" firstln = firstln + 1 End /* do until */ /***********************************************/ /* END COLUMN PROCESSING LOOP */ /***********************************************/ If cutop = 'YES' then do "(lastln2) = LINENUM .ZLAST" "UP MAX" If saveln <> 1 then "DOWN " saveln /* don't scroll if at top */ zedsmsg = count 'LINES CUT' zedlmsg = count 'LINES WERE CUT FROM COLUMNS' begcol || '-' || , endcol 'TO THE DEFAULT CLIPBOARD' Address ISPEXEC "SETMSG MSG(ISRZ000)" /* msg - no alarm */ Exit 1 /* return cursor to command line */ End If shiftop <> 'YES' then do If Abbrev('MOVE',type,1) <> 0 then msgtype = 'MOVED' If Abbrev('SWAP',type,1) <> 0 then msgtype = 'SWAPPED' else msgtype = 'COPIED' If tgtlen+tgtcol-1 <= width then do /* no truncation */ zedsmsg = count 'LINES CHANGED' zedlmsg = 'COLUMNS' begcol 'THROUGH' endcol 'ON' count , 'LINES WERE' msgtype 'TO COLUMN' tgtcol || '.' Address ISPEXEC "SETMSG MSG(ISRZ000)" /* msg - no alarm */ Exit 1 /* return cursor to command line */ End Else do zedsmsg = count 'LINES TRUNCATED' zedlmsg = 'COLUMNS' begcol 'THROUGH' endcol 'ON' count , 'LINES WERE' msgtype 'TO COLUMN' tgtcol 'AND TRUNCATED.' Address ISPEXEC "SETMSG MSG(ISRZ001)" /* msg - with alarm */ Exit 4 End End Else do /* total messages for shift */ zedsmsg = count 'LINES SHIFTED' zedlmsg = count 'LINES WERE SHIFTED' shiftamt 'COLUMNS' , 'TO THE' shifttyp || '.' Address ISPEXEC "SETMSG MSG(ISRZ000)" /* msg - no alarm */ Exit 1 /* return cursor to command line */ End /*********************************/ /* HELP SUB-ROUTINES */ /*********************************/ HELP_INCL: Return SIGL HELP_NOTELINES: "(helpln) = DISPLAY_LINES" Do hlp = help_end-1 to help_start+1 by -1 hline = Sourceline(hlp) "ISREDIT LINE_AFTER " helpln " = NOTELINE (hline)" End hline2 = '===================' hline3 = '=== H E L P ===' "ISREDIT LINE_AFTER " helpln " = NOTELINE (hline2)" "ISREDIT LINE_AFTER " helpln " = NOTELINE (hline3)" "ISREDIT LINE_AFTER " helpln " = NOTELINE (hline2)" Return /*********************************/ /* SUB-ROUTINE TO FIND LABELS */ /*********************************/ FIND_LABELS: Address ISPEXEC "CONTROL ERRORS RETURN" If label1 = '' then do firstln = 1 "(lastln) = LINENUM .ZLAST" End Else do If label2 = '' then label2 = label1 "(firstsv) = LINENUM" label1 If RC >= 8 then do zedsmsg = 'RANGE LABEL ERROR' zedlmsg = 'THE SPECIFIED RANGE LABEL "' || label1 '" WAS', 'NOT FOUND' Address ISPEXEC "SETMSG MSG(ISRZ001)" /* msg - with alarm */ Exit 12 End "(lastsv) = LINENUM" label2 If RC >= 8 then do zedsmsg = 'RANGE LABEL ERROR' zedlmsg = 'THE SPECIFIED RANGE LABEL "' || label2 '" WAS', 'NOT FOUND' Address ISPEXEC "SETMSG MSG(ISRZ001)" /* msg - with alarm */ Exit 12 End firstln = Min(firstsv,lastsv) lastln = Max(firstsv,lastsv) Address ISPEXEC "CONTROL ERRORS" End /* else do */ Return