regular expressions are great. But, it looks like
only the expression is possible, not any flags.
My question, how would I specify the LOCATE command
for these grep arguments: -i '\<word\>'
are you trying to do a mixed case search? if so, at the
command line you can enter the following to search for "word":
set case m i
/word
I have the "set case" statement set permanently in my .therc
profile so the editor is automatically in mixed case mode.
(set case will take additional parameters - depending upon
what you might want to do - check out the docs).
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Not as simple as a mixed case search for some string of
characters. Rather, a mixed case search for a string of
characters delimited by white space or any non-word
characters (comma, quote, dash, whatever 'start word'
and 'end word' controls the left-angle and right-angle
indicate. But in general, LOCATE takes regular
expressions, and I suppose in this case I could contrive a
regular expression that indicates the 4 characters 'word'
could be any case. But, if the flag '-i' were legal, it
would be so much easier. Another way to pute it, Regular
expressions are necessary but not sufficient.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
hmmm ... ok, sounds non-trivial. example? how bout writing a
macro to programmatically do what you want i.e. loop/extract
curline and then process via rexx parse or a custom filter.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Sure, I've done so in the past.
delims = '~`@#$%^&*()_-+={}[]:";'<>?,./'
do s = 1 to length(delims)
start = substr(delims,s,1)
do e = 1 to length...
end = substr...
look for start || word || end
blah blah blah
I could program all regular expressions in REXX.
What I hoped for is more grep-style capabilities so *I*
don't need to code such things in REXX.
And, of course, that capability would be desired in
anything that used locate target expressions, like ALL, or
CLOCATE (although I've never coded a CLOCATE in 20 years of
XEDIT/KEDIT usage), or FIND.
There isn't a COUNT command, but ALL -c RE/.../ might be an
alternative, although this might be a bit of a stretch.
I don't see many grep flags that I'd say would be *really*
useful, but -i seems like a really good one.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
As I see it, this RE searches for the next occurrance of a "word"
which is not a substring of some other word. This is a useful
capability. For example, variables in a programming language fall
under this definition of "word". The MVS ISPF Editor even has a
keyword option on its FIND (equivalent of LOCATE) command to restrict
searches in this manner.
A goodly time ago, I decided that I needed this capability in the
XEDIT environment (where there are no regular expressions). So I
wrote a macro named ALLVAR (All occurrances of a given variable
name). This macro accepts a single operand, which is the word
(variable name) to be searched for. It operates like the ALL
command.
I have attached a copy. Feel free to use it as-is, or adapt it to
your needs. I have also attached INCLUDE.THE, which is used by
ALLVAR.THE.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I'm sorry, but I don't see how to attach a file here, so I'll just cut-
and-paste them. Feel free to e-mail me at bobcruz-at-pacbell-dot-com
if this doesn't work for you. (Note that a third required macro,
GETARGET.THE is also included).
/*REXX ALLVAR.THE routine to find all occurrances of a variable */
/* whose name might be a substring of another variable name. */
OPTIONS NOEXT_COMMANDS_AS_FUNCS /* for Regina */ /*0.04*/
/* HISTORY: */
/* Ver? Who? When? What? */
/* ---- ---- ------- ----------------------------------------------- */
/* 0.01 RAC 28Apr00 Fixed bug where identifier which started at 0.01*/
/* the left margin or ended at the right 0.01*/
/* margin would not be found. 0.01*/
/* Fixed bug where identifiers longer than 5 0.01*/
/* characters would cause the generated XEDIT 0.01*/
/* search command to exceed 250 characters, so 0.01*/
/* the command would be truncated and yield 0.01*/
/* incorrect results. 0.01*/
/* Added tests for excess parameters and 0.01*/
/* unsupported options. 0.01*/
/* Added tests for identifier too long and 0.01*/
/* zone too narrow. 0.01*/
/* 0.02 RAC 26Oct00 Modified to run as .KEX as well as XEDIT; 0.02*/
/* Also improved error handling. 0.02*/
/* 0.03 RAC 19Feb02 Fixed bug when no records found 0.03*/
/* 0.04 RAC 12Nov02 Created Regina/THE version 0.04*/
/* 0.05 RAC 16Mar04 Changed message environment from 'XEDIT' 0.05*/
/* to <environ>; added "Case N" comments. 0.05*/
/* */
/* REQUIRES: */
/* INCLUDE.THE -- add line(s) to those shown */
/* 0.01*/
/*********************************************************************/
SIGNAL ON NOVALUE
globals = 'zone.' /* Original ZONE settings 0.02*/
globals = globals 'msgmode.' /* Original MSGMODE 0.02*/
globals = globals 'linend.' /* Original LINEND settings 0.02*/
globals = globals 'arbchar.' /* Original ARBCHAR settings 0.02*/
globals = globals 'cc' /* Completion code of this cmd 0.02*/
globals = globals 'identifier' /* Identifier to search for 0.02*/
globals = globals 'nn' /* number of occurrances 0.02*/
nn = '?unknown?' /* just in case used before set 0.02*/
environ = ADDRESS() /*0.05*/
PARSE ARG identifier xs '(' options
IF identifier = ''
THEN EXIT ErrMsg('ALLVAR001T Identifier missing -- Abending!', ,
environ ) /*0.05*/
IF xs <> '' /*0.01*/
THEN EXIT ErrMsg('ALLVAR002T Excess parameters, "'xs'" --
Abending!', , environ ) /*0.05*/
IF options <> '' /*0.01*/
THEN EXIT ErrMsg('ALLVAR003T Options, "'options'", not supported --
Abending!', , environ ) /*0.05*/
IF LENGTH( identifier ) > 234 /*0.01*/
THEN EXIT ErrMsg('ALLVAR004T
Identifier, "'identifier
,
|| '", is too long (exceeds 234 characters) --
Abending!', , environ ) /*0.05*/
'COMMAND EXTRACT/ZONE/' /*0.01*/
IF zone.2 - zone.1 + 1 < LENGTH( identifier ) /*0.01*/
THEN EXIT ErrMsg('ALLVAR104T
Identifier, "'identifier
,
|| '", is too long to fit within zone' zone.1
zone.2 '-- Abending!', , environ ) /*0.05*/
msgmode. = '' /* For KEXX */ /*0.02*/
'COMMAND EXTRACT/MSGMODE/' /* Preserve MSGMODE setting */
'COMMAND SET MSGMODE OFF'
/* NOTE: A refinement would be to assign these next three */
/* strings depending on the language (filetype). */
leading_delimiters = " ^&*("")-+%=|\;:'<>,./?{}[]~" /*no "!" 0.02*/
trailing_delimiters = " ^&*("")-+%=|\;:'<>,./?{}[]~" /*no "!" 0.04*/
dlm = "`" /*0.02*/
/* A further refinement would be to first remove literals and
comments 0.01*/
search_cmd = ''
cc = 2 /* no lines found (yet) */
/*----------------------------------------------------------------*/
/* Case 1: the zone is at least two columns wider than */
/* <old_symbol>, so that the identifier may appear */
/* with both a leading and trailing delimiter. */
/*----------------------------------------------------------------*/
/* Note: KEDIT has a limit of 12 items in a LOCATE (or ALL) 0.02*/
/* The variable <count> is used to insure that no more 0.02*/
/* than 12 items are in any one search command. 0.02*/
zone_width = zone.2 - zone.1 + 1
IF zone_width >= LENGTH( identifier ) + 2
THEN DO /*0.01*/
/* zone is wide enough for identifier plus both leading and
trailing characters 0.01*/
/* Step 1: find all occurrances of the variable within */
/* left margin + 1 to right margin - 1 */
IF LENGTH( target ) + LENGTH( addl_target ) + 1 > 238 |
count = 12 /*0.02*/
THEN DO /*0.01*/
CALL Search_For target /*0.01*/
count = 0 /*0.02*/
target = addl_target /*0.01*/
END /*0.01*/
ELSE target = target'|'addl_target /*0.01*/
count = count + 1 /*0.02*/
END jj
CALL Search_For target
END ii
END /* zone is wide enough for identifier plus both leading and
trailing characters 0.01*/
/*----------------------------------------------------------------*/
/* Cases 2 & 3: the zone is at least one column wider than */
/* <old_symbol>, so that either the left or right */
/* margin can act as a delimiter. */
/*----------------------------------------------------------------*/
IF zone_width >= LENGTH( identifier ) + 1 /*0.01*/
THEN DO
/* zone is wide enough for identifier plus either leading or
trailing character 0.01*/
/* Step 2: find all occurrances of the variable with a 0.01*/
/* suffix between left margin 0.01*/
/* and ( left margin + variable length + 1 ) 0.01*/
/* In this case, the left margin acts as a delimiter. 0.04*/
IF LENGTH( target ) + LENGTH( addl_target ) + 1 > 238 |
count = 12 /*0.02*/
THEN DO /*0.01*/
CALL Search_For target /*0.01*/
count = 0 /*0.02*/
target = addl_target /*0.01*/
END /*0.01*/
ELSE target = target'|'addl_target /*0.01*/
count = count + 1 /*0.02*/
END jj /*0.01*/
CALL Search_For target /*0.01*/
/* Step 3: find all occurrances of the variable with a 0.01*/
/* prefix between ( right margin - identifier length ) 0.01*/
/* and right margin 0.01*/
/* In this case, the right margin acts as a delimiter. 0.04*/
IF LENGTH( target ) + LENGTH( addl_target ) + 1 > 238 |
count = 12 /*0.02*/
THEN DO /*0.01*/
CALL Search_For target /*0.01*/
count = 0 /*0.02*/
target = addl_target /*0.01*/
END /*0.01*/
ELSE target = target'|'addl_target /*0.01*/
count = count + 1 /*0.02*/
END ii /*0.01*/
CALL Search_For target /*0.01*/
END /* zone is wide enough for identifier plus either leading or
trailing character 0.01*/
/*----------------------------------------------------------------*/
/* Case 4: the zone is exactly as wide as <old_symbol>, so that */
/* the left and right margins both act as delimiters. */
/*----------------------------------------------------------------*/
IF zone_width = LENGTH( identifier ) THEN DO /*0.01*/
/* zone is wide enough for identifier only */ /*0.01*/
/* Step 4: find all occurrances of the variable without 0.01*/
/* suffix or prefix between left and right margins 0.01*/
END /* zone is wide enough for identifier only */ /*0.01*/
nn = 0 /*0.03*/
IF cc = 0 /*0.01*/
THEN DO /* Count # lines found */ /*0.01*/
'-*' /*0.01*/
DO nn = 1 BY 1 UNTIL RC <> 0 /*0.01*/
'+1' /*0.01*/
END nn /*0.01*/
nn = nn - 1
'-* +1' /* position to first line shown */ /*0.01*/
END /*0.01*/
Terminate:
'COMMAND SET ZONE' zone.1 zone.2 /* Restore original ZONE settings
0.01*/
'COMMAND SET MSGMODE' msgmode.1 msgmode.2
'COMMAND SET LINEND' linend.1 /*0.02*/
'COMMAND SET ARBCHAR' arbchar.1 /*0.02*/
IF cc = 2
THEN 'EMSG DMSXCD546E Target not found' /*0.01*/
ELSE
IF cc = 0
THEN 'MSG ALLVAR209I Identifier "'identifier'" found on'
nn 'lines' /*0.01*/
EXIT cc
/*********************************************************************/
/* */
/* Search_For: search for ALL target(s) within unselected lines */
/* */
/*********************************************************************/
IF RC = 2 THEN /* target not found */ NOP /*0.02*/
ELSE DO /*0.02*/
IF RC = 0 THEN /* target has been acquired */ DO
IF search_cmd = '' THEN DO
cc = 0
search_cmd = 'INCLUDE'
END
END /* target has been acquired */
ELSE /* Processing Error */ DO /*0.02*/
cc = RC
'MSGMODE ON' /*0.02*/
CALL ERRMSG 'ALLVAR291T Unexpected return code' cc 'in line'
called_from 'from "'edit_cmd'"!' /*0.02*/
SIGNAL Terminate /*0.02*/
END /*0.02*/
END /*0.02*/
RETURN
/* _______________________ END OF ALLVAR.THE _______________________ */
/* REXX INCLUDE.THE -- Adds lines to the set produced by ALL */
OPTIONS NOEXT_COMMANDS_AS_FUNCS /* for Regina */
/* Syntax: */
/* INCLUDE { /? | ? | HELP } */
/* INCLUDE { FIRST [ ] } searchtarget */
/* { PRIOR [ ( _1_ | count ) ] } */
/* { NEXT [ ] } */
/* { LAST [ ] } */
/* { ALL } */
/* { TO limitarget [ ( _*_ | count ) ] } */
/* Where: */
/* ALL -- specifies that all lines within the current range */
/* which match the search <target> will be included */
/* */
/* FIRST -- specifies that up to <count> line(s) immediately */
/* following the top of the current range which match */
/* the <searchtarget> will be included. */
/* Searching is begun at the top of the current range, */
/* and proceeds downward, possibly as far as the bottom */
/* of the current range. */
/* A parenthesized <count> or <target> may follow, */
/* otherwise a default count of 1 is used for FIRST. */
/* */
/* PRIOR -- specifies that up to <count> lines preceeding the */
/* current line, within the current range, which match */
/* the search <target> will be excluded. */
/* A parenthesized <count> or <target> may follow, */
/* otherwise a default count of 1 is used for PRIOR. */
/* Searching is begun at the top of the current range, */
/* and proceeds downward, possibly as far as the bottom */
/* of the current range. */
/* The setting of WRAP is ignored. */
/* */
/* NEXT -- specifies that up to <count> lines following the */
/* current line, within the current range, which match */
/* the search <target> will be included. */
/* A parenthesized <count> or <target> may follow, */
/* otherwise a default count of 1 is used for NEXT. */
/* Searching is begun at the current line, and proceeds */
/* downward, possibly as far as the bottom of the */
/* current range. The setting of WRAP is ignored. */
/* */
/* LAST -- specifies that up to <count> line(s) immediately */
/* preceeding the bottom of the current range which */
/* match the search <target> will be included. */
/* A parenthesized <count> or <target> may follow, */
/* otherwise a count of 1 is used for LAST. */
/* Searching is begun at the bottom of the current */
/* range, and proceeds upward, possibly as far as the */
/* top of the current range. */
/* */
/* Note: if <count> is specified, it must be enclosed in parentheses*/
/* */
/* TO limitarget -- specifies that following line(s) which match */
/* the search target will be included, until <limitarget>*/
/* is reached. If <limitarget> is not found, no lines */
/* will be included. */
/* */
/* count -- specifies the number of lines to be included. */
/* The count must be an unsigned integer. */
/* That is, INCLUDE attempts to find <count> lines which */
/* match the <srchtarget> to be included. */
/* Count defaults to 1 for FIRST, LAST, PRIOR, and NEXT. */
/* Count defaults to "*" for TO. */
/* */
/* NOTE: if both TO <limitarget> and <count> are specified, */
/* INCLUDE stops with the first conditions which is */
/* satisfied. */
/* */
/* limitarget -- specifies the limit of the search for lines to */
/* be included. That is, INCLUDE will include all lines */
/* which occur between the current line and the limit */
/* line which match the <srchtarget>. If <limitarget> */
/* begins with a minus ("-"), searching will be conducted*/
/* in an upward direction; otherwise searching will be */
/* conducted in a downward direction. */
/* The setting of the WRAP option will affect this search*/
/* */
/* srchtarget -- specifies the target to be used to search for */
/* matching lines to be included. */
/* NOTE: <srchtarget> MUST *NOT* START WITH A LEFT-PARENTHESIS*/
/* ( "(" ) unless "(<count>)" is also specified!! */
/* NOTE: <srchtarget> may *not* start with a plus ("+") or */
/* minus ("-")! (This is because the direction of the */
/* search is determined by the */
/* ALL/PRIOR/NEXT/TO <limitarget>/FIRST/LAST keywords) */
/* */
/* RETURNS: */
/* 0 -- Normal: <count> lines containing the <searchtarget> */
/* were found, and either <count> was "*" or the process */
/* stopped when <count> lines had been found. */
/* 1 -- One or more lines containing the <searchtarget> were */
/* found, but <count> was not exhausted before the end of */
/* the searchable portion of the range was reached. */
/* 2 -- DMSXDC546E Target not found */
/* 5 -- DMSXDC520E Invalid operand: ... */
/* */
/*___________________________________________________________________*/
/* */
/* Rev Who? When? What? */
/* ----- ----- -------- ---------------------------------------------*/
/* 0.0 RAC 11/24/93 Original (did ALL lines) */
/* 0.1 RAC ? Added ALL/PRIOR/NEXT & count parameters */
/* 0.2 RAC 07/03/96 Added FIRST/LAST mode parameters */
/* 0.3 RAC 07/08/96 Added TO mode parameter */
/* 0.4 RAC 07/12/99 Converted to KEDIT for Windows 1.5 KEXX */
/* Added logic to require ALL be issued first, */
/* fixed logic for displaying message and */
/* returning to original line (marked) */
/* 0.5 RAC 08/20/99 Added support for label as a <srchtarget> */
/* 0.6 RAC 12/08/99 Corrected HELP for FIRST and LAST. */
/* 0.7 RAC 12/09/99 Added prereq for GETARGET. */
/* 0.8 RAC 10/26/00 Fixed bugs. */
/* 0.9 RAC 11/12/02 THE version (no RANGE support) */
/* */
/* Programming Notes: */
/* 1) In order to convert from XEDIT REXX to KEDIT for Windows, v1.5 */
/* KEXX, the following changes were made: */
/* a) all continued instructions were made into a single line */
/* b) the REXX comment on the first line was */
/* changed to a single-line KEX comment ("*" in column 1) */
/* c) all multi-line REXX comments were changed to single-line */
/* REXX comments */
/* d) changed "ª" to "\" when used as REXX unary Not operator */
/* e) changed "ª=" to "<>" when used as REXX Not-Equal operator */
/* f) changed "ª" to "^" when used as KEDIT string Not operator */
/* g) add "msgmode.2=''" prior to every "EXTRACT/MSGMODE/" because*/
/* 2nd parameter to MSGMODE is supported by XEDIT but not KEDIT*/
/* h) add logic to cause the alteration count to go up by only 1 */
/* for the entire execution of the macro if the macro makes */
/* any changes to the file (otherwise KEDIT counts every */
/* change made by the macro, and AUTOSAVEs may occur many */
/* times during the execution of the macro; even though a */
/* single UNDO will reverse all the changes made by the macro).*/
/* This yields XEDIT's behaviour. */
/* i) change PRESERVE and RESTORE to EXTRACT and SET for the */
/* editing environment settings being changed. This is */
/* necessary because KEDIT's PRESERVE/RESTORE stack is only */
/* one level deep! Be sure not to use EXIT after any editor */
/* settings have been changed, or they will not be restored! */
/* j) shorten lines longer than 250 characters */
/* k) break apart programs longer than 4000 characters */
/* l) reduce the maximum NUMERIC DIGITS to 50 */
/* m) remove STREAM() function */
/* n) remove NOTREADY */
/* o) provide the first argument for LINEIN(), LINEOUT(), LINES(),*/
/* CHARIN(), CHAROUT(), and CHARS() */
/* p) remove "@", "#", and "$" from symbol names (they shouldn't */
/* be there anyway!) */
/* */
/* 2) To convert to KEX for Windows, v1.0, the following additional */
/* changes must be made: */
/* a) Change binary constants ('1001'B) to hexadecimal ( '9'X) */
/* b) Remove CALL ON and CALL OFF */
/* c) Remove parenthesized symbol names in DROP statements: */
/* DROP (list_of_symbol_names) */
/* becomes: */
/* INTERPRET 'DROP' list_of_symbol_names */
/* c) Remove any CALL instructions and function invocations which */
/* invoke internal routines from INTERPRET instructions */
/* d) Remove PROCEDURE [EXPOSE] instructions */
/* e) Change SELECT WHEN [OTHERWISE] END instructions to a */
/* series of cascaded IF instructions: */
/* SELECT */
/* WHEN boolexpr1 THEN clause1 */
/* WHEN boolexpr2 THEN clause2 */
/* ... */
/* WHEN boolexprN THEN clauseN */
/* OTHERWISE clauseE */
/* END */
/* becomes: */
/* /* SELECT */ */
/* IF boolexpr1 THEN clause1 */
/* ELSE IF boolexpr2 THEN clause2 */
/* ... */
/* ELSE IF boolexprN THEN clauseN */
/* ELSE clauseE */
/* /* END */ */
/* f) Remove all forms of SIGNAL */
/* g) Remove all invocations of external routines */
/* h) Remove all invocations of these BIFs: */
/* i) B2X() */
/* ii) CHANGESTR() */
/* iii) CONDITION() */
/* iv) COUNTSTR() */
/* v) ERRORTEXT() */
/* vi) SOURCELINE() */
/* vii) SYMBOL() */
/* viii) TRACE() */
/* ix) VALUE() */
/* x) X2B() */
/* */
/* 3) To convert to KEX for DOS, v5.0, the following additional */
/* changes must be made: */
/* a) Remove all instructions other than IF, DO, ITERATE, LEAVE, */
/* EXIT, DROP, NOP */
/* b) Convert any WHILE or UNTIL clauses on DO instructions to */
/* LEAVE instructions */
/* c) Remove any <name> from ITERATE, LEAVE, or END */
/* */
/* */
token1 = LEFT( STRIP( ARG( 1 ) ), 1 )
token2 = LEFT( STRIP( ARG( 1 ) ), 2 )
token4 = TRANSLATE( LEFT( STRIP( ARG( 1 ) ), 4 ) )
IF token1 = '?' | token2 = '/?' | token4 = 'HELP' THEN DO
'XE EXCLUDE.KEX' /* Use comments for quick-and-dirty help 0.4*/
EXIT 0
END
/* 0.4 Check for unconditional prerequisites */ /*0.07*/
/* 0.4.1 Check for unconditionally required file(s) */ /*0.07*/
/* cc = MAX( Require( 'GETARGET.KEX' ), cc ) 0.08*/
/* Get mode of operation */
the_rest = ARG( 1 )
nn = VERIFY( TRANSLATE(
the_rest' ' ), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' ) - 1
PARSE ARG mode +(nn) the_rest
mode = TRANSLATE( mode ) /* fold to uppercase */
the_rest = STRIP( the_rest, 'L' ) /* remove optional leading space
(s) */
direction = '+' /* default to forward */
'EXTRACT/SIZE/'
SELECT /* Case of <mode> */
WHEN mode = 'ALL' THEN DO
count = size.1 /* could be every line in the file! */
limitarget = ''
END
WHEN WORDPOS( mode, 'PRIOR NEXT FIRST LAST' ) > 0 THEN DO
IF mode = 'PRIOR' | mode = 'LAST' THEN direction = '-' /*
backward */
END
WHEN mode = 'TO' THEN DO
/* Get limit target */
PARSE VALUE GeTarget( the_rest ) WITH target_type
remaining_length limitarget
IF target_type = 'I' THEN DO
'EMSG ***ERROR*** Limit target, "'LEFT( the_rest, LENGTH(
the_rest ) - remaining_length)'", is invalid!'
EXIT 5
END
the_rest = RIGHT( the_rest, remaining_length )
END
OTHERWISE DO
'EMSG ***ERROR*** First argument to INCLUDE must be one of "ALL
PRIOR NEXT FIRST LAST TO"!'
EXIT 13
END
END /* Case of <mode> */
IF WORDPOS( mode, 'PRIOR NEXT FIRST LAST TO' ) > 0 THEN DO
/* check for optional "( <count> )" */
IF LEFT( the_rest, 1 ) = '(' THEN /* count follows */ DO
PARSE VALUE the_rest WITH '(' count ')' the_rest
the_rest = STRIP( the_rest, 'L' )
count = STRIP( count )
IF count = '*'
THEN count = size.1 /* search up to every line in the file */
ELSE /* count should be unsigned integer */ DO
IF VERIFY( count, '0123456789' ) <> 0 THEN DO
'EMSG ***ERROR*** Count, "'count'", must be an unsigned
integer!'
EXIT 15
END
END
END
ELSE /* ( <count> ) not specified */ DO
/* Supply default value for <count> */
IF mode = 'TO'
THEN count = size.1 /* could be every line in the file! */
ELSE count = 1 /* Only 1 for FIRST/LAST/PRIOR/NEXT */
END
END /* check for optional "( <count> )" */
IF the_rest = '' THEN DO
'EMSG ***ERROR*** Search target is missing!'
EXIT 17
END
IF POS( LEFT( the_rest, 1 ), '+-' ) > 0 THEN DO
'EMSG ***ERROR*** Search target, "'the_rest'", starts with plus
or minus!'
EXIT 19
END
IF POS( LEFT( the_rest, 1 ), '.' ) > 0 THEN DO /*0.5 */
direction = '' /*0.5 */
count = 1 /* There may only be one of this label */ /*0.5 */
END /*0.5 */
PARSE VALUE GeTarget( direction || the_rest ) WITH target_type
remaining_length srchtarget
IF target_type = 'I' THEN DO
'EMSG ***ERROR*** Search target, "'the_rest'", is invalid!'
EXIT 5
END
IF remaining_length <> 0 THEN DO
'EMSG ***ERROR*** Search target, "'the_rest'", contains multiple
targets!'
EXIT 21
END
IF lo_level = 0 & hi_level = 0 THEN DO /*0.4 */
'EMSG ***ERROR*** ALL command must be issued prior to
INCLUDE!' /*0.4 */
EXIT 16 /*0.4 */
END /*0.4 */
IF mode = 'ALL' | mode = 'FIRST' THEN '-*'
IF mode = 'LAST' THEN '+*'
IF mode = 'TO' THEN DO
IF LEFT( limitarget, 1 ) = '-' THEN DO
'LOCATE' limitarget
/* 'RANGE +0 :'line.1 */ /*0.9 */
'LOCATE :'line.1
END
/* ELSE 'RANGE +0' limitarget */ /*0.9 */
END
'SET WRAP OFF' /* Prevents infinite loop */
/* NOTE: after this point, EXIT should no longer be used 0.1 */
/* to leave the macro, because the WRAP setting 0.1 */
/* would not be restored. Instead use SIGNAL Abort 0.1 */
/* to cause an orderly termination. 0.1 */
/* Note: STAY setting has no effect */
'SET SCOPE ALL' /* Operate on ALL lines in file */
'L' srchtarget
cc = RC
IF RC = 0 THEN /* target found */ DO
nn = 0 /* number of lines satisfying search criteria */
kk = 0 /* number of lines added to displayed set */
'SET MSGMODE OFF'
DO mm = 1 TO count WHILE RC = 0
nn = nn + 1
'EXTRACT/SELECT/'
IF select.1 < lo_level | select.1 > hi_level THEN
/* not previously displayed */ kk = kk + 1
'SET SELECT' lo_level '1'
'L' srchtarget
END
'SET MSGMODE ON' /*0.4 */
'MSG Included' kk 'of' nn 'lines with' the_rest
END
IF nn > 1 THEN DO
IF nn = count | count = size.1
THEN cc = 0
ELSE cc = 1
END
ELSE cc = 2
/* 'RANGE :'range.1 ':'range.2 */ /*0.9 */
IF stay.1 = 'ON' THEN DO /*0.4 */
'SET MSGMODE OFF' /* suppress "Not Found" message for */ /*0.4 */
/* original line, if it was excluded*/ /*0.4 */
':'line.1
IF RC <> 0 /* original current line was excluded */ /*0.4 */
THEN '-* +1' /* position to first displayed line */ /*0.4 */
END /*0.4 */
/* 'RESTORE' any editor settings we may have changed */
'SET MSGMODE' msgmode.1 msgmode.2
'SET WRAP' wrap.1
'SET SCOPE' scope.1
/* 1. Debugging Prologue */ /*0.07*/
_save_calls = _call_stack /*0.07*/
_call_stack = 'Require called from line' sigl 'in'
_call_stack /*0.07*/
/* use the following once the subroutine is debugged... */ /*0.07*/
_save_trace = TRACE( 'F' ) /* trace only failures, save old
setting 0.07*/
IF VERIFY( _save_trace, '?!NOF' ) <> 0 /*0.07*/
THEN /* begin debugging code */ DO /*0.07*/
SAY '==> Internal_Function called from' sigl 'with ' , /*0.07*/
|| ARG() 'arguments:' /*0.07*/
DO result = 1 TO ARG() /*0.07*/
SAY ' Argument' result ':= `'ARG(result)'`' /*0.07*/
END result /*0.07*/
DROP result /*0.07*/
END /* end debugging code */ /*0.07*/
/* 2. Function Logic */ /*0.07*/
PARSE UPPER ARG filespec /*0.07*/
IF STREAM( filespec, 'C', 'QUERY EXISTS' ) = '' THEN DO /*0.07*/
SAY 'INCLUD013T Required resource, "'filespec , /*0.07*/
|| '", is not available' /*0.07*/
cc = 16 /*0.07*/
END /*0.07*/
ELSE cc = 0 /*0.07*/
/* 3. Debugging Epilogue */ /*0.07*/
IF VERIFY( _save_trace, '?!NOF' ) <> 0 /*0.07*/
THEN /* begin debugging code */ DO /*0.07*/
SAY '==> Require returns `'cc'`' /*0.07*/
END /* end debugging code */ /*0.07*/
_call_stack = _save_calls /*0.07*/
RETURN cc /* ENDPROC Require */ /*0.07*/
/* _______________________ END OF INCLUDE.THE ______________________ */
/*REXX GETARGET.THE -- routine to parse a single XEDIT target */
OPTIONS NOEXT_COMMANDS_AS_FUNCS /* for Regina */
/* This routine was converted from GETARGET XEDIT, so changes to this
* routine may also have to be made to the source as well, and vice
versa
* Syntax:
* GeTarget( <argument> )
*
* Where:
* <argument> is a string whose leading characters are to be
* parsed for a valid XEDIT target
*
* Returns: <target_type> <remaining_length> <target>
* <target_type> is a type code --
* L = label
* AN = absolute number
* RN = relative number
* S = string
* I = invalid target
* <remaining_length> is the number of characters following the
* target, after any intervening blanks have been removed.
* In the case of an invalid target, this number reflects
* the number of characters following the point at which
* the syntax error was detected.
* <target> is described by the following syntax --
* { .<label> }
* { : <number> }
* { [+|-] <number> }
* { [+|-] [\] <delim><text>[<delim> --. }
* { .--------------------------------' }
* { `--> [ {&|"|"} [\] <delim><text><delim> ]... --. }
* { .-------------------------------------------' }
* { `--> [ {&|"|"} [\] <delim><text>{<delim>|eol} ] ] }
*
* Notes:
* In the above syntax, a space appears in those places where
* one or more blanks are allowed.
* In the above syntax, a number is terminated by the first
* non-digit encountered.
* The REXX construct, RIGHT( argument, remaining_length ) can be
* be used to obtain the portion of the argument following the
* target.
* The non-target portion of <argument> could not be returned in
* character form, because there is no delimiter which could
* be used to separate it from <target>.
*
*_____________________________________________________________________
*
* Rev Who? When? What?
* ----- ----- -------- ---------------------------------------------
* 0.0 RAC 03/04/97 Original
* 0.1 RAC 07/12/99 Converted to KEDIT 5 KEXX (not marked)
*
* Programming Notes:
* 1) In order to convert to KEX, the following changes were made:
* a) all SIGNAL instructions were commented out
* b) all continued instructions were made into a single line
* c) all single and multi-line REXX comments ("/*" to "*/" were
* changed to single-line KEX comments ("*" in column 1)
* d) changed "^" to "\" when used as REXX unary Not operator
* e) changed "^=" to "<>" when used as REXX Not-Equal operator
* f) changed "^" to "^" when used as KEDIT string Not operator
* g) add "msgmode.2 = ''" prior to every "EXTRACT/MSGMODE/" because
* 2nd parameter to MSGMODE is supported by XEDIT but not KEDIT.
*
*
*/
SIGNAL ON NOVALUE
arg1 = STRIP( ARG( 1 ) ) /* remove leading & trailing blanks */
char1 = LEFT( arg1, 1 ) /* first non-blank character */
SELECT /* Case of first non-blank character */
WHEN char1 = ':' THEN /* absolute number or string */ DO
IF POS( LEFT( STRIP( SUBSTR( arg1, 2), 'L' ),
1 ), '*0123456879' ) > 0
THEN type = 'AN' /* relative number */
ELSE type = 'S' /* string */
END /* absolute number or string */
WHEN POS(char1, '*0123456789') > 0 THEN type = 'RN' /* relative
number */
WHEN char1 = '.' THEN type = 'L' /* label */
WHEN POS( char1, '+-' ) > 0 THEN /* relative number or string */
DO
IF POS( LEFT( STRIP( SUBSTR( arg1, 2), 'L' ),
1 ), '*0123456879' ) > 0
THEN type = 'RN' /* relative number */
ELSE type = 'S' /* string */
END /* relative number or string */
WHEN char1 = ' ' THEN type = 'I' /* invalid */
OTHERWISE type = 'S' /* '^' or string delimiter */
END /* Case of first non-blank character */
SELECT /* Case of target type */
WHEN type = 'S' THEN DO
IF POS( char1, '+-' ) > 0 THEN /* leading optional direction
*/ DO
target = char1
arg1 = STRIP( SUBSTR( arg1, 2 ), 'L' )
char1 = LEFT( arg1, 1 ) /* next non-blank character */
END
ELSE target = ''
done = 0
/* Note: loop is entered with "arg1" stripped of leading
blanks */
/* and "char1" containing a copy of its first
character. */
DO ii = 1 BY 1 WHILE arg1 <> '' & \ done
IF char1 = ' ' THEN DO
type = 'I'
LEAVE ii
END
IF char1 = '^' THEN DO
target = target || char1
arg1 = STRIP( SUBSTR( arg1, 2 ), 'L' )
char1 = LEFT( arg1, 1 ) /* next non-blank character */
IF char1 = ' ' THEN DO
type = 'I'
LEAVE ii
END
END
PARSE VALUE arg1 WITH (char1) text (char1) arg1
target = target || char1 || text || char1
arg1 = STRIP( arg1, 'L' ) /* strip leading blanks */
char1 = LEFT( arg1, 1 ) /* next non-blank character */
IF POS( char1, '&|' ) = 0 THEN done = 1
ELSE /* another boolean term follows */ DO
target = target || char1
arg1 = STRIP( SUBSTR( arg1, 2 ), 'L' )
char1 = LEFT( arg1, 1 ) /* next non-blank character */
END
END /* until no more input, or end of target */
END /* type was String */
WHEN type = 'I' THEN /* Invalid type */ NOP
WHEN type = 'L' THEN /* Label */ DO
target = char1
arg1 = SUBSTR( arg1, 2 )
char1 = LEFT( arg1, 1 )
IF char1 = ' ' THEN type = 'I'
ELSE PARSE VALUE target || arg1 WITH target arg1
END
OTHERWISE /* type is number (either absolute or relative) or line#
*/ DO
target = ''
IF POS( char1, '+-:' ) > 0 THEN DO
target = char1 /* "+", "-", or ":" */
arg1 = STRIP( SUBSTR( arg1, 2 ), 'L' )
char1 = LEFT( arg1, 1 )
END
IF char1 = '*' THEN DO
target = target || char1
arg1 = STRIP( SUBSTR( arg1, 2 ), 'L' )
END
ELSE DO
nn = VERIFY( arg1, '0123456789' ) - 1 /* pos of 1st non-
digit */
IF nn = -1 THEN nn = LENGTH( arg1 ) /* all
numeric */
PARSE VALUE arg1 WITH num +(nn) arg1
target = target || num
arg1 = STRIP( arg1, 'L' ) /* strip leading
blanks */
END
END
END /* Case of target type */
RETURN type LENGTH( arg1 ) target
/* ______________________ END OF GETARGET.THE ______________________ */
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Logged In: YES
user_id=1614411
are you trying to do a mixed case search? if so, at the
command line you can enter the following to search for "word":
set case m i
/word
I have the "set case" statement set permanently in my .therc
profile so the editor is automatically in mixed case mode.
(set case will take additional parameters - depending upon
what you might want to do - check out the docs).
Logged In: YES
user_id=1587066
Not as simple as a mixed case search for some string of
characters. Rather, a mixed case search for a string of
characters delimited by white space or any non-word
characters (comma, quote, dash, whatever 'start word'
and 'end word' controls the left-angle and right-angle
indicate. But in general, LOCATE takes regular
expressions, and I suppose in this case I could contrive a
regular expression that indicates the 4 characters 'word'
could be any case. But, if the flag '-i' were legal, it
would be so much easier. Another way to pute it, Regular
expressions are necessary but not sufficient.
Logged In: YES
user_id=1614411
hmmm ... ok, sounds non-trivial. example? how bout writing a
macro to programmatically do what you want i.e. loop/extract
curline and then process via rexx parse or a custom filter.
Logged In: YES
user_id=1587066
Sure, I've done so in the past.
delims = '~`@#$%^&*()_-+={}[]:";'<>?,./'
do s = 1 to length(delims)
start = substr(delims,s,1)
do e = 1 to length...
end = substr...
look for start || word || end
blah blah blah
I could program all regular expressions in REXX.
What I hoped for is more grep-style capabilities so *I*
don't need to code such things in REXX.
And, of course, that capability would be desired in
anything that used locate target expressions, like ALL, or
CLOCATE (although I've never coded a CLOCATE in 20 years of
XEDIT/KEDIT usage), or FIND.
There isn't a COUNT command, but ALL -c RE/.../ might be an
alternative, although this might be a bit of a stretch.
I don't see many grep flags that I'd say would be *really*
useful, but -i seems like a really good one.
Logged In: YES
user_id=371416
As I see it, this RE searches for the next occurrance of a "word"
which is not a substring of some other word. This is a useful
capability. For example, variables in a programming language fall
under this definition of "word". The MVS ISPF Editor even has a
keyword option on its FIND (equivalent of LOCATE) command to restrict
searches in this manner.
A goodly time ago, I decided that I needed this capability in the
XEDIT environment (where there are no regular expressions). So I
wrote a macro named ALLVAR (All occurrances of a given variable
name). This macro accepts a single operand, which is the word
(variable name) to be searched for. It operates like the ALL
command.
I have attached a copy. Feel free to use it as-is, or adapt it to
your needs. I have also attached INCLUDE.THE, which is used by
ALLVAR.THE.
Logged In: YES
user_id=371416
I'm sorry, but I don't see how to attach a file here, so I'll just cut-
and-paste them. Feel free to e-mail me at bobcruz-at-pacbell-dot-com
if this doesn't work for you. (Note that a third required macro,
GETARGET.THE is also included).
/*REXX ALLVAR.THE routine to find all occurrances of a variable */
/* whose name might be a substring of another variable name. */
OPTIONS NOEXT_COMMANDS_AS_FUNCS /* for Regina */ /*0.04*/
/* HISTORY: */
/* Ver? Who? When? What? */
/* ---- ---- ------- ----------------------------------------------- */
/* 0.01 RAC 28Apr00 Fixed bug where identifier which started at 0.01*/
/* the left margin or ended at the right 0.01*/
/* margin would not be found. 0.01*/
/* Fixed bug where identifiers longer than 5 0.01*/
/* characters would cause the generated XEDIT 0.01*/
/* search command to exceed 250 characters, so 0.01*/
/* the command would be truncated and yield 0.01*/
/* incorrect results. 0.01*/
/* Added tests for excess parameters and 0.01*/
/* unsupported options. 0.01*/
/* Added tests for identifier too long and 0.01*/
/* zone too narrow. 0.01*/
/* 0.02 RAC 26Oct00 Modified to run as .KEX as well as XEDIT; 0.02*/
/* Also improved error handling. 0.02*/
/* 0.03 RAC 19Feb02 Fixed bug when no records found 0.03*/
/* 0.04 RAC 12Nov02 Created Regina/THE version 0.04*/
/* 0.05 RAC 16Mar04 Changed message environment from 'XEDIT' 0.05*/
/* to <environ>; added "Case N" comments. 0.05*/
/* */
/* REQUIRES: */
/* INCLUDE.THE -- add line(s) to those shown */
/* 0.01*/
/*********************************************************************/
SIGNAL ON NOVALUE
globals = 'zone.' /* Original ZONE settings 0.02*/
globals = globals 'msgmode.' /* Original MSGMODE 0.02*/
globals = globals 'linend.' /* Original LINEND settings 0.02*/
globals = globals 'arbchar.' /* Original ARBCHAR settings 0.02*/
globals = globals 'cc' /* Completion code of this cmd 0.02*/
globals = globals 'identifier' /* Identifier to search for 0.02*/
globals = globals 'nn' /* number of occurrances 0.02*/
nn = '?unknown?' /* just in case used before set 0.02*/
environ = ADDRESS() /*0.05*/
PARSE ARG identifier xs '(' options
IF identifier = ''
THEN EXIT ErrMsg('ALLVAR001T Identifier missing -- Abending!', ,
environ ) /*0.05*/
IF xs <> '' /*0.01*/
THEN EXIT ErrMsg('ALLVAR002T Excess parameters, "'xs'" --
Abending!', , environ ) /*0.05*/
IF options <> '' /*0.01*/
THEN EXIT ErrMsg('ALLVAR003T Options, "'options'", not supported --
Abending!', , environ ) /*0.05*/
IF LENGTH( identifier ) > 234 /*0.01*/
THEN EXIT ErrMsg('ALLVAR004T
Identifier, "'identifier
,
|| '", is too long (exceeds 234 characters) --
Abending!', , environ ) /*0.05*/
'COMMAND EXTRACT/ZONE/' /*0.01*/
IF zone.2 - zone.1 + 1 < LENGTH( identifier ) /*0.01*/
THEN EXIT ErrMsg('ALLVAR104T
Identifier, "'identifier
,
|| '", is too long to fit within zone' zone.1
zone.2 '-- Abending!', , environ ) /*0.05*/
msgmode. = '' /* For KEXX */ /*0.02*/
'COMMAND EXTRACT/MSGMODE/' /* Preserve MSGMODE setting */
'COMMAND SET MSGMODE OFF'
'COMMAND EXTRACT/LINEND/' /* Preserve LINEND setting 0.02*/
'COMMAND SET LINEND OFF' /*0.02*/
'COMMAND EXTRACT/ARBCHAR/' /* Preserve ARBCHAR setting 0.02*/
'COMMAND SET ARBCHAR OFF' /*0.02*/
/* NOTE: A refinement would be to assign these next three */
/* strings depending on the language (filetype). */
leading_delimiters = " ^&*("")-+%=|\;:'<>,./?{}[]~" /*no "!" 0.02*/
trailing_delimiters = " ^&*("")-+%=|\;:'<>,./?{}[]~" /*no "!" 0.04*/
dlm = "`" /*0.02*/
/* A further refinement would be to first remove literals and
comments 0.01*/
search_cmd = ''
cc = 2 /* no lines found (yet) */
/*----------------------------------------------------------------*/
/* Case 1: the zone is at least two columns wider than */
/* <old_symbol>, so that the identifier may appear */
/* with both a leading and trailing delimiter. */
/*----------------------------------------------------------------*/
/* Note: KEDIT has a limit of 12 items in a LOCATE (or ALL) 0.02*/
/* The variable <count> is used to insure that no more 0.02*/
/* than 12 items are in any one search command. 0.02*/
zone_width = zone.2 - zone.1 + 1
IF zone_width >= LENGTH( identifier ) + 2
THEN DO /*0.01*/
/* zone is wide enough for identifier plus both leading and
trailing characters 0.01*/
/* Step 1: find all occurrances of the variable within */
/* left margin + 1 to right margin - 1 */
DO ii = 1 TO LENGTH( leading_delimiters );
prefix = dlm || SUBSTR( leading_delimiters, ii, 1 ) /*0.02*/
suffix = SUBSTR( trailing_delimiters, 1, 1 ) || dlm /* first
one 0.02*/
target = prefix || identifier || suffix
count = 1 /*0.02*/
DO jj = 2 TO LENGTH( trailing_delimiters )
suffix = SUBSTR( trailing_delimiters, jj, 1 ) ||
dlm /*0.02*/
addl_target = prefix || identifier || suffix /*0.01*/
IF LENGTH( target ) + LENGTH( addl_target ) + 1 > 238 |
count = 12 /*0.02*/
THEN DO /*0.01*/
CALL Search_For target /*0.01*/
count = 0 /*0.02*/
target = addl_target /*0.01*/
END /*0.01*/
ELSE target = target'|'addl_target /*0.01*/
count = count + 1 /*0.02*/
END jj
CALL Search_For target
END ii
END /* zone is wide enough for identifier plus both leading and
trailing characters 0.01*/
/*----------------------------------------------------------------*/
/* Cases 2 & 3: the zone is at least one column wider than */
/* <old_symbol>, so that either the left or right */
/* margin can act as a delimiter. */
/*----------------------------------------------------------------*/
IF zone_width >= LENGTH( identifier ) + 1 /*0.01*/
THEN DO
/* zone is wide enough for identifier plus either leading or
trailing character 0.01*/
/* Step 2: find all occurrances of the variable with a 0.01*/
/* suffix between left margin 0.01*/
/* and ( left margin + variable length + 1 ) 0.01*/
/* In this case, the left margin acts as a delimiter. 0.04*/
left_mar = zone.1 /*0.01*/
right_mar = left_mar + LENGTH( identifier ) /*0.01*/
'COMMAND SET ZONE' left_mar right_mar /*0.01*/
prefix = dlm /*0.01*/
suffix = SUBSTR( trailing_delimiters, 1, 1 ) || dlm /*0.01*/
target = prefix || identifier || suffix /*0.01*/
count = 1 /*0.02*/
DO jj = 2 TO LENGTH( trailing_delimiters ); /*0.01*/
suffix = SUBSTR( trailing_delimiters, jj, 1 ) || dlm /*0.01*/
addl_target = prefix || identifier || suffix /*0.01*/
IF LENGTH( target ) + LENGTH( addl_target ) + 1 > 238 |
count = 12 /*0.02*/
THEN DO /*0.01*/
CALL Search_For target /*0.01*/
count = 0 /*0.02*/
target = addl_target /*0.01*/
END /*0.01*/
ELSE target = target'|'addl_target /*0.01*/
count = count + 1 /*0.02*/
END jj /*0.01*/
CALL Search_For target /*0.01*/
/* Step 3: find all occurrances of the variable with a 0.01*/
/* prefix between ( right margin - identifier length ) 0.01*/
/* and right margin 0.01*/
/* In this case, the right margin acts as a delimiter. 0.04*/
right_mar = zone.2 /*0.01*/
left_mar = right_mar - LENGTH( identifier ) /*0.01*/
'COMMAND SET ZONE' left_mar right_mar /*0.01*/
suffix = dlm /*0.02*/
prefix = dlm || SUBSTR( leading_delimiters, 1, 1 ) /*0.02*/
target = prefix || identifier || suffix /*0.01*/
count = 1 /*0.02*/
DO ii = 2 TO LENGTH( leading_delimiters ); /*0.01*/
prefix = dlm || SUBSTR( leading_delimiters, ii, 1 ) /*0.02*/
addl_target = prefix || identifier || suffix /*0.01*/
IF LENGTH( target ) + LENGTH( addl_target ) + 1 > 238 |
count = 12 /*0.02*/
THEN DO /*0.01*/
CALL Search_For target /*0.01*/
count = 0 /*0.02*/
target = addl_target /*0.01*/
END /*0.01*/
ELSE target = target'|'addl_target /*0.01*/
count = count + 1 /*0.02*/
END ii /*0.01*/
CALL Search_For target /*0.01*/
END /* zone is wide enough for identifier plus either leading or
trailing character 0.01*/
/*----------------------------------------------------------------*/
/* Case 4: the zone is exactly as wide as <old_symbol>, so that */
/* the left and right margins both act as delimiters. */
/*----------------------------------------------------------------*/
IF zone_width = LENGTH( identifier ) THEN DO /*0.01*/
/* zone is wide enough for identifier only */ /*0.01*/
/* Step 4: find all occurrances of the variable without 0.01*/
/* suffix or prefix between left and right margins 0.01*/
left_mar = zone.1 /*0.01*/
right_mar = zone.2 /*0.01*/
'COMMAND SET ZONE' left_mar right_mar /*0.01*/
prefix = dlm /*0.02*/
suffix = dlm /* first one */ /*0.02*/
target = prefix || identifier || suffix /*0.01*/
CALL Search_For target /*0.01*/
END /* zone is wide enough for identifier only */ /*0.01*/
nn = 0 /*0.03*/
IF cc = 0 /*0.01*/
THEN DO /* Count # lines found */ /*0.01*/
'-*' /*0.01*/
DO nn = 1 BY 1 UNTIL RC <> 0 /*0.01*/
'+1' /*0.01*/
END nn /*0.01*/
nn = nn - 1
'-* +1' /* position to first line shown */ /*0.01*/
END /*0.01*/
Terminate:
'COMMAND SET ZONE' zone.1 zone.2 /* Restore original ZONE settings
0.01*/
'COMMAND SET MSGMODE' msgmode.1 msgmode.2
'COMMAND SET LINEND' linend.1 /*0.02*/
'COMMAND SET ARBCHAR' arbchar.1 /*0.02*/
IF cc = 2
THEN 'EMSG DMSXCD546E Target not found' /*0.01*/
ELSE
IF cc = 0
THEN 'MSG ALLVAR209I Identifier "'identifier'" found on'
nn 'lines' /*0.01*/
EXIT cc
/*********************************************************************/
/* */
/* Search_For: search for ALL target(s) within unselected lines */
/* */
/*********************************************************************/
Search_For: PROCEDURE EXPOSE search_cmd sigl (globals) /*0.02*/
called_from = sigl /*0.02*/
edit_cmd = search_cmd 'ALL' ARG(1) /*0.02*/
''edit_cmd /*0.02*/
IF RC = 2 THEN /* target not found */ NOP /*0.02*/
ELSE DO /*0.02*/
IF RC = 0 THEN /* target has been acquired */ DO
IF search_cmd = '' THEN DO
cc = 0
search_cmd = 'INCLUDE'
END
END /* target has been acquired */
ELSE /* Processing Error */ DO /*0.02*/
cc = RC
'MSGMODE ON' /*0.02*/
CALL ERRMSG 'ALLVAR291T Unexpected return code' cc 'in line'
called_from 'from "'edit_cmd'"!' /*0.02*/
SIGNAL Terminate /*0.02*/
END /*0.02*/
END /*0.02*/
RETURN
/* _______________________ END OF ALLVAR.THE _______________________ */
/* REXX INCLUDE.THE -- Adds lines to the set produced by ALL */
OPTIONS NOEXT_COMMANDS_AS_FUNCS /* for Regina */
/* Syntax: */
/* INCLUDE { /? | ? | HELP } */
/* INCLUDE { FIRST [ ] } searchtarget */
/* { PRIOR [ ( _1_ | count ) ] } */
/* { NEXT [ ] } */
/* { LAST [ ] } */
/* { ALL } */
/* { TO limitarget [ ( _*_ | count ) ] } */
/* Where: */
/* ALL -- specifies that all lines within the current range */
/* which match the search <target> will be included */
/* */
/* FIRST -- specifies that up to <count> line(s) immediately */
/* following the top of the current range which match */
/* the <searchtarget> will be included. */
/* Searching is begun at the top of the current range, */
/* and proceeds downward, possibly as far as the bottom */
/* of the current range. */
/* A parenthesized <count> or <target> may follow, */
/* otherwise a default count of 1 is used for FIRST. */
/* */
/* PRIOR -- specifies that up to <count> lines preceeding the */
/* current line, within the current range, which match */
/* the search <target> will be excluded. */
/* A parenthesized <count> or <target> may follow, */
/* otherwise a default count of 1 is used for PRIOR. */
/* Searching is begun at the top of the current range, */
/* and proceeds downward, possibly as far as the bottom */
/* of the current range. */
/* The setting of WRAP is ignored. */
/* */
/* NEXT -- specifies that up to <count> lines following the */
/* current line, within the current range, which match */
/* the search <target> will be included. */
/* A parenthesized <count> or <target> may follow, */
/* otherwise a default count of 1 is used for NEXT. */
/* Searching is begun at the current line, and proceeds */
/* downward, possibly as far as the bottom of the */
/* current range. The setting of WRAP is ignored. */
/* */
/* LAST -- specifies that up to <count> line(s) immediately */
/* preceeding the bottom of the current range which */
/* match the search <target> will be included. */
/* A parenthesized <count> or <target> may follow, */
/* otherwise a count of 1 is used for LAST. */
/* Searching is begun at the bottom of the current */
/* range, and proceeds upward, possibly as far as the */
/* top of the current range. */
/* */
/* Note: if <count> is specified, it must be enclosed in parentheses*/
/* */
/* TO limitarget -- specifies that following line(s) which match */
/* the search target will be included, until <limitarget>*/
/* is reached. If <limitarget> is not found, no lines */
/* will be included. */
/* */
/* count -- specifies the number of lines to be included. */
/* The count must be an unsigned integer. */
/* That is, INCLUDE attempts to find <count> lines which */
/* match the <srchtarget> to be included. */
/* Count defaults to 1 for FIRST, LAST, PRIOR, and NEXT. */
/* Count defaults to "*" for TO. */
/* */
/* NOTE: if both TO <limitarget> and <count> are specified, */
/* INCLUDE stops with the first conditions which is */
/* satisfied. */
/* */
/* limitarget -- specifies the limit of the search for lines to */
/* be included. That is, INCLUDE will include all lines */
/* which occur between the current line and the limit */
/* line which match the <srchtarget>. If <limitarget> */
/* begins with a minus ("-"), searching will be conducted*/
/* in an upward direction; otherwise searching will be */
/* conducted in a downward direction. */
/* The setting of the WRAP option will affect this search*/
/* */
/* srchtarget -- specifies the target to be used to search for */
/* matching lines to be included. */
/* NOTE: <srchtarget> MUST *NOT* START WITH A LEFT-PARENTHESIS*/
/* ( "(" ) unless "(<count>)" is also specified!! */
/* NOTE: <srchtarget> may *not* start with a plus ("+") or */
/* minus ("-")! (This is because the direction of the */
/* search is determined by the */
/* ALL/PRIOR/NEXT/TO <limitarget>/FIRST/LAST keywords) */
/* */
/* RETURNS: */
/* 0 -- Normal: <count> lines containing the <searchtarget> */
/* were found, and either <count> was "*" or the process */
/* stopped when <count> lines had been found. */
/* 1 -- One or more lines containing the <searchtarget> were */
/* found, but <count> was not exhausted before the end of */
/* the searchable portion of the range was reached. */
/* 2 -- DMSXDC546E Target not found */
/* 5 -- DMSXDC520E Invalid operand: ... */
/* */
/*___________________________________________________________________*/
/* */
/* Rev Who? When? What? */
/* ----- ----- -------- ---------------------------------------------*/
/* 0.0 RAC 11/24/93 Original (did ALL lines) */
/* 0.1 RAC ? Added ALL/PRIOR/NEXT & count parameters */
/* 0.2 RAC 07/03/96 Added FIRST/LAST mode parameters */
/* 0.3 RAC 07/08/96 Added TO mode parameter */
/* 0.4 RAC 07/12/99 Converted to KEDIT for Windows 1.5 KEXX */
/* Added logic to require ALL be issued first, */
/* fixed logic for displaying message and */
/* returning to original line (marked) */
/* 0.5 RAC 08/20/99 Added support for label as a <srchtarget> */
/* 0.6 RAC 12/08/99 Corrected HELP for FIRST and LAST. */
/* 0.7 RAC 12/09/99 Added prereq for GETARGET. */
/* 0.8 RAC 10/26/00 Fixed bugs. */
/* 0.9 RAC 11/12/02 THE version (no RANGE support) */
/* */
/* Programming Notes: */
/* 1) In order to convert from XEDIT REXX to KEDIT for Windows, v1.5 */
/* KEXX, the following changes were made: */
/* a) all continued instructions were made into a single line */
/* b) the REXX comment on the first line was */
/* changed to a single-line KEX comment ("*" in column 1) */
/* c) all multi-line REXX comments were changed to single-line */
/* REXX comments */
/* d) changed "ª" to "\" when used as REXX unary Not operator */
/* e) changed "ª=" to "<>" when used as REXX Not-Equal operator */
/* f) changed "ª" to "^" when used as KEDIT string Not operator */
/* g) add "msgmode.2=''" prior to every "EXTRACT/MSGMODE/" because*/
/* 2nd parameter to MSGMODE is supported by XEDIT but not KEDIT*/
/* h) add logic to cause the alteration count to go up by only 1 */
/* for the entire execution of the macro if the macro makes */
/* any changes to the file (otherwise KEDIT counts every */
/* change made by the macro, and AUTOSAVEs may occur many */
/* times during the execution of the macro; even though a */
/* single UNDO will reverse all the changes made by the macro).*/
/* This yields XEDIT's behaviour. */
/* i) change PRESERVE and RESTORE to EXTRACT and SET for the */
/* editing environment settings being changed. This is */
/* necessary because KEDIT's PRESERVE/RESTORE stack is only */
/* one level deep! Be sure not to use EXIT after any editor */
/* settings have been changed, or they will not be restored! */
/* j) shorten lines longer than 250 characters */
/* k) break apart programs longer than 4000 characters */
/* l) reduce the maximum NUMERIC DIGITS to 50 */
/* m) remove STREAM() function */
/* n) remove NOTREADY */
/* o) provide the first argument for LINEIN(), LINEOUT(), LINES(),*/
/* CHARIN(), CHAROUT(), and CHARS() */
/* p) remove "@", "#", and "$" from symbol names (they shouldn't */
/* be there anyway!) */
/* */
/* 2) To convert to KEX for Windows, v1.0, the following additional */
/* changes must be made: */
/* a) Change binary constants ('1001'B) to hexadecimal ( '9'X) */
/* b) Remove CALL ON and CALL OFF */
/* c) Remove parenthesized symbol names in DROP statements: */
/* DROP (list_of_symbol_names) */
/* becomes: */
/* INTERPRET 'DROP' list_of_symbol_names */
/* c) Remove any CALL instructions and function invocations which */
/* invoke internal routines from INTERPRET instructions */
/* d) Remove PROCEDURE [EXPOSE] instructions */
/* e) Change SELECT WHEN [OTHERWISE] END instructions to a */
/* series of cascaded IF instructions: */
/* SELECT */
/* WHEN boolexpr1 THEN clause1 */
/* WHEN boolexpr2 THEN clause2 */
/* ... */
/* WHEN boolexprN THEN clauseN */
/* OTHERWISE clauseE */
/* END */
/* becomes: */
/* /* SELECT */ */
/* IF boolexpr1 THEN clause1 */
/* ELSE IF boolexpr2 THEN clause2 */
/* ... */
/* ELSE IF boolexprN THEN clauseN */
/* ELSE clauseE */
/* /* END */ */
/* f) Remove all forms of SIGNAL */
/* g) Remove all invocations of external routines */
/* h) Remove all invocations of these BIFs: */
/* i) B2X() */
/* ii) CHANGESTR() */
/* iii) CONDITION() */
/* iv) COUNTSTR() */
/* v) ERRORTEXT() */
/* vi) SOURCELINE() */
/* vii) SYMBOL() */
/* viii) TRACE() */
/* ix) VALUE() */
/* x) X2B() */
/* */
/* 3) To convert to KEX for DOS, v5.0, the following additional */
/* changes must be made: */
/* a) Remove all instructions other than IF, DO, ITERATE, LEAVE, */
/* EXIT, DROP, NOP */
/* b) Convert any WHILE or UNTIL clauses on DO instructions to */
/* LEAVE instructions */
/* c) Remove any <name> from ITERATE, LEAVE, or END */
/* */
/* */
SIGNAL ON NOVALUE
cc = 0 /*0.08*/
globals = '_call_stack' /*0.08*/
_call_stack = 'INCLUDE'
token1 = LEFT( STRIP( ARG( 1 ) ), 1 )
token2 = LEFT( STRIP( ARG( 1 ) ), 2 )
token4 = TRANSLATE( LEFT( STRIP( ARG( 1 ) ), 4 ) )
IF token1 = '?' | token2 = '/?' | token4 = 'HELP' THEN DO
'XE EXCLUDE.KEX' /* Use comments for quick-and-dirty help 0.4*/
EXIT 0
END
/* 0.4 Check for unconditional prerequisites */ /*0.07*/
/* 0.4.1 Check for unconditionally required file(s) */ /*0.07*/
/* cc = MAX( Require( 'GETARGET.KEX' ), cc ) 0.08*/
/* Get mode of operation */
the_rest = ARG( 1 )
nn = VERIFY( TRANSLATE(
the_rest' ' ), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' ) - 1
PARSE ARG mode +(nn) the_rest
mode = TRANSLATE( mode ) /* fold to uppercase */
the_rest = STRIP( the_rest, 'L' ) /* remove optional leading space
(s) */
direction = '+' /* default to forward */
'EXTRACT/SIZE/'
SELECT /* Case of <mode> */
WHEN mode = 'ALL' THEN DO
count = size.1 /* could be every line in the file! */
limitarget = ''
END
WHEN WORDPOS( mode, 'PRIOR NEXT FIRST LAST' ) > 0 THEN DO
IF mode = 'PRIOR' | mode = 'LAST' THEN direction = '-' /*
backward */
END
WHEN mode = 'TO' THEN DO
/* Get limit target */
PARSE VALUE GeTarget( the_rest ) WITH target_type
remaining_length limitarget
IF target_type = 'I' THEN DO
'EMSG ***ERROR*** Limit target, "'LEFT( the_rest, LENGTH(
the_rest ) - remaining_length)'", is invalid!'
EXIT 5
END
the_rest = RIGHT( the_rest, remaining_length )
END
OTHERWISE DO
'EMSG ***ERROR*** First argument to INCLUDE must be one of "ALL
PRIOR NEXT FIRST LAST TO"!'
EXIT 13
END
END /* Case of <mode> */
IF WORDPOS( mode, 'PRIOR NEXT FIRST LAST TO' ) > 0 THEN DO
/* check for optional "( <count> )" */
IF LEFT( the_rest, 1 ) = '(' THEN /* count follows */ DO
PARSE VALUE the_rest WITH '(' count ')' the_rest
the_rest = STRIP( the_rest, 'L' )
count = STRIP( count )
IF count = '*'
THEN count = size.1 /* search up to every line in the file */
ELSE /* count should be unsigned integer */ DO
IF VERIFY( count, '0123456789' ) <> 0 THEN DO
'EMSG ***ERROR*** Count, "'count'", must be an unsigned
integer!'
EXIT 15
END
END
END
ELSE /* ( <count> ) not specified */ DO
/* Supply default value for <count> */
IF mode = 'TO'
THEN count = size.1 /* could be every line in the file! */
ELSE count = 1 /* Only 1 for FIRST/LAST/PRIOR/NEXT */
END
END /* check for optional "( <count> )" */
IF the_rest = '' THEN DO
'EMSG ***ERROR*** Search target is missing!'
EXIT 17
END
IF POS( LEFT( the_rest, 1 ), '+-' ) > 0 THEN DO
'EMSG ***ERROR*** Search target, "'the_rest'", starts with plus
or minus!'
EXIT 19
END
IF POS( LEFT( the_rest, 1 ), '.' ) > 0 THEN DO /*0.5 */
direction = '' /*0.5 */
count = 1 /* There may only be one of this label */ /*0.5 */
END /*0.5 */
PARSE VALUE GeTarget( direction || the_rest ) WITH target_type
remaining_length srchtarget
IF target_type = 'I' THEN DO
'EMSG ***ERROR*** Search target, "'the_rest'", is invalid!'
EXIT 5
END
IF remaining_length <> 0 THEN DO
'EMSG ***ERROR*** Search target, "'the_rest'", contains multiple
targets!'
EXIT 21
END
/* Search logic ... */
msgmode.2 = '' /*0.4 */
'EXTRACT/MSGMODE/WRAP/SCOPE/' /* PRESERVE */ /*0.4 */
'EXTRACT/LINE/DISPLAY/STAY/' /*0.4 */
/* 'EXTRACT/RANGE/' */ /*0.9 */
lo_level = display.1
hi_level = display.2
IF lo_level = 0 & hi_level = 0 THEN DO /*0.4 */
'EMSG ***ERROR*** ALL command must be issued prior to
INCLUDE!' /*0.4 */
EXIT 16 /*0.4 */
END /*0.4 */
IF mode = 'ALL' | mode = 'FIRST' THEN '-*'
IF mode = 'LAST' THEN '+*'
IF mode = 'TO' THEN DO
IF LEFT( limitarget, 1 ) = '-' THEN DO
'LOCATE' limitarget
/* 'RANGE +0 :'line.1 */ /*0.9 */
'LOCATE :'line.1
END
/* ELSE 'RANGE +0' limitarget */ /*0.9 */
END
'SET WRAP OFF' /* Prevents infinite loop */
/* NOTE: after this point, EXIT should no longer be used 0.1 */
/* to leave the macro, because the WRAP setting 0.1 */
/* would not be restored. Instead use SIGNAL Abort 0.1 */
/* to cause an orderly termination. 0.1 */
/* Note: STAY setting has no effect */
'SET SCOPE ALL' /* Operate on ALL lines in file */
'L' srchtarget
cc = RC
IF RC = 0 THEN /* target found */ DO
nn = 0 /* number of lines satisfying search criteria */
kk = 0 /* number of lines added to displayed set */
'SET MSGMODE OFF'
DO mm = 1 TO count WHILE RC = 0
nn = nn + 1
'EXTRACT/SELECT/'
IF select.1 < lo_level | select.1 > hi_level THEN
/* not previously displayed */ kk = kk + 1
'SET SELECT' lo_level '1'
'L' srchtarget
END
'SET MSGMODE ON' /*0.4 */
'MSG Included' kk 'of' nn 'lines with' the_rest
END
IF nn > 1 THEN DO
IF nn = count | count = size.1
THEN cc = 0
ELSE cc = 1
END
ELSE cc = 2
/* 'RANGE :'range.1 ':'range.2 */ /*0.9 */
IF stay.1 = 'ON' THEN DO /*0.4 */
'SET MSGMODE OFF' /* suppress "Not Found" message for */ /*0.4 */
/* original line, if it was excluded*/ /*0.4 */
':'line.1
IF RC <> 0 /* original current line was excluded */ /*0.4 */
THEN '-* +1' /* position to first displayed line */ /*0.4 */
END /*0.4 */
/* 'RESTORE' any editor settings we may have changed */
'SET MSGMODE' msgmode.1 msgmode.2
'SET WRAP' wrap.1
'SET SCOPE' scope.1
EXIT cc
/****************************************************************0.07*/
/* 0.07*/
/* REQUIRE -- check for prerequisite file 0.07*/
/* 0.07*/
/****************************************************************0.07*/
Require: PROCEDURE EXPOSE (globals) sigl /*0.07*/
RETURN 0
/* 1. Debugging Prologue */ /*0.07*/
_save_calls = _call_stack /*0.07*/
_call_stack = 'Require called from line' sigl 'in'
_call_stack /*0.07*/
/* use the following once the subroutine is debugged... */ /*0.07*/
_save_trace = TRACE( 'F' ) /* trace only failures, save old
setting 0.07*/
IF VERIFY( _save_trace, '?!NOF' ) <> 0 /*0.07*/
THEN /* begin debugging code */ DO /*0.07*/
SAY '==> Internal_Function called from' sigl 'with ' , /*0.07*/
|| ARG() 'arguments:' /*0.07*/
DO result = 1 TO ARG() /*0.07*/
SAY ' Argument' result ':= `'ARG(result)'`' /*0.07*/
END result /*0.07*/
DROP result /*0.07*/
END /* end debugging code */ /*0.07*/
/* 2. Function Logic */ /*0.07*/
PARSE UPPER ARG filespec /*0.07*/
IF STREAM( filespec, 'C', 'QUERY EXISTS' ) = '' THEN DO /*0.07*/
SAY 'INCLUD013T Required resource, "'filespec , /*0.07*/
|| '", is not available' /*0.07*/
cc = 16 /*0.07*/
END /*0.07*/
ELSE cc = 0 /*0.07*/
/* 3. Debugging Epilogue */ /*0.07*/
IF VERIFY( _save_trace, '?!NOF' ) <> 0 /*0.07*/
THEN /* begin debugging code */ DO /*0.07*/
SAY '==> Require returns `'cc'`' /*0.07*/
END /* end debugging code */ /*0.07*/
_call_stack = _save_calls /*0.07*/
RETURN cc /* ENDPROC Require */ /*0.07*/
/* _______________________ END OF INCLUDE.THE ______________________ */
/*REXX GETARGET.THE -- routine to parse a single XEDIT target */
OPTIONS NOEXT_COMMANDS_AS_FUNCS /* for Regina */
/* This routine was converted from GETARGET XEDIT, so changes to this
* routine may also have to be made to the source as well, and vice
versa
* Syntax:
* GeTarget( <argument> )
*
* Where:
* <argument> is a string whose leading characters are to be
* parsed for a valid XEDIT target
*
* Returns: <target_type> <remaining_length> <target>
* <target_type> is a type code --
* L = label
* AN = absolute number
* RN = relative number
* S = string
* I = invalid target
* <remaining_length> is the number of characters following the
* target, after any intervening blanks have been removed.
* In the case of an invalid target, this number reflects
* the number of characters following the point at which
* the syntax error was detected.
* <target> is described by the following syntax --
* { .<label> }
* { : <number> }
* { [+|-] <number> }
* { [+|-] [\] <delim><text>[<delim> --. }
* { .--------------------------------' }
* { `--> [ {&|"|"} [\] <delim><text><delim> ]... --. }
* { .-------------------------------------------' }
* { `--> [ {&|"|"} [\] <delim><text>{<delim>|eol} ] ] }
*
* Notes:
* In the above syntax, a space appears in those places where
* one or more blanks are allowed.
* In the above syntax, a number is terminated by the first
* non-digit encountered.
* The REXX construct, RIGHT( argument, remaining_length ) can be
* be used to obtain the portion of the argument following the
* target.
* The non-target portion of <argument> could not be returned in
* character form, because there is no delimiter which could
* be used to separate it from <target>.
*
*_____________________________________________________________________
*
* Rev Who? When? What?
* ----- ----- -------- ---------------------------------------------
* 0.0 RAC 03/04/97 Original
* 0.1 RAC 07/12/99 Converted to KEDIT 5 KEXX (not marked)
*
* Programming Notes:
* 1) In order to convert to KEX, the following changes were made:
* a) all SIGNAL instructions were commented out
* b) all continued instructions were made into a single line
* c) all single and multi-line REXX comments ("/*" to "*/" were
* changed to single-line KEX comments ("*" in column 1)
* d) changed "^" to "\" when used as REXX unary Not operator
* e) changed "^=" to "<>" when used as REXX Not-Equal operator
* f) changed "^" to "^" when used as KEDIT string Not operator
* g) add "msgmode.2 = ''" prior to every "EXTRACT/MSGMODE/" because
* 2nd parameter to MSGMODE is supported by XEDIT but not KEDIT.
*
*
*/
SIGNAL ON NOVALUE
arg1 = STRIP( ARG( 1 ) ) /* remove leading & trailing blanks */
char1 = LEFT( arg1, 1 ) /* first non-blank character */
SELECT /* Case of first non-blank character */
WHEN char1 = ':' THEN /* absolute number or string */ DO
IF POS( LEFT( STRIP( SUBSTR( arg1, 2), 'L' ),
1 ), '*0123456879' ) > 0
THEN type = 'AN' /* relative number */
ELSE type = 'S' /* string */
END /* absolute number or string */
WHEN POS(char1, '*0123456789') > 0 THEN type = 'RN' /* relative
number */
WHEN char1 = '.' THEN type = 'L' /* label */
WHEN POS( char1, '+-' ) > 0 THEN /* relative number or string */
DO
IF POS( LEFT( STRIP( SUBSTR( arg1, 2), 'L' ),
1 ), '*0123456879' ) > 0
THEN type = 'RN' /* relative number */
ELSE type = 'S' /* string */
END /* relative number or string */
WHEN char1 = ' ' THEN type = 'I' /* invalid */
OTHERWISE type = 'S' /* '^' or string delimiter */
END /* Case of first non-blank character */
SELECT /* Case of target type */
WHEN type = 'S' THEN DO
IF POS( char1, '+-' ) > 0 THEN /* leading optional direction
*/ DO
target = char1
arg1 = STRIP( SUBSTR( arg1, 2 ), 'L' )
char1 = LEFT( arg1, 1 ) /* next non-blank character */
END
ELSE target = ''
done = 0
/* Note: loop is entered with "arg1" stripped of leading
blanks */
/* and "char1" containing a copy of its first
character. */
DO ii = 1 BY 1 WHILE arg1 <> '' & \ done
IF char1 = ' ' THEN DO
type = 'I'
LEAVE ii
END
IF char1 = '^' THEN DO
target = target || char1
arg1 = STRIP( SUBSTR( arg1, 2 ), 'L' )
char1 = LEFT( arg1, 1 ) /* next non-blank character */
IF char1 = ' ' THEN DO
type = 'I'
LEAVE ii
END
END
PARSE VALUE arg1 WITH (char1) text (char1) arg1
target = target || char1 || text || char1
arg1 = STRIP( arg1, 'L' ) /* strip leading blanks */
char1 = LEFT( arg1, 1 ) /* next non-blank character */
IF POS( char1, '&|' ) = 0 THEN done = 1
ELSE /* another boolean term follows */ DO
target = target || char1
arg1 = STRIP( SUBSTR( arg1, 2 ), 'L' )
char1 = LEFT( arg1, 1 ) /* next non-blank character */
END
END /* until no more input, or end of target */
END /* type was String */
WHEN type = 'I' THEN /* Invalid type */ NOP
WHEN type = 'L' THEN /* Label */ DO
target = char1
arg1 = SUBSTR( arg1, 2 )
char1 = LEFT( arg1, 1 )
IF char1 = ' ' THEN type = 'I'
ELSE PARSE VALUE target || arg1 WITH target arg1
END
OTHERWISE /* type is number (either absolute or relative) or line#
*/ DO
target = ''
IF POS( char1, '+-:' ) > 0 THEN DO
target = char1 /* "+", "-", or ":" */
arg1 = STRIP( SUBSTR( arg1, 2 ), 'L' )
char1 = LEFT( arg1, 1 )
END
IF char1 = '*' THEN DO
target = target || char1
arg1 = STRIP( SUBSTR( arg1, 2 ), 'L' )
END
ELSE DO
nn = VERIFY( arg1, '0123456789' ) - 1 /* pos of 1st non-
digit */
IF nn = -1 THEN nn = LENGTH( arg1 ) /* all
numeric */
PARSE VALUE arg1 WITH num +(nn) arg1
target = target || num
arg1 = STRIP( arg1, 'L' ) /* strip leading
blanks */
END
END
END /* Case of target type */
RETURN type LENGTH( arg1 ) target
/* ______________________ END OF GETARGET.THE ______________________ */