PARSE.CMDLINE
From Pickwiki
HomePage>>SourceCode>>BasicSource>>SVN>>PARSE.CMDLINE
subroutine PARSE.CMDLINE(SENTENCE, MAT CMDLINE, OPTIONS)
* =======================================================================================
* @LIB: Parse the [[UniVerse]] Command line using a standardized format
* =======================================================================================
* 24.Mar.2009 james: Add '\' as a valid Quote character for command line options.
* 30.Oct.2007 jim: NOPARAM option to allow no-parameter flags before Arguments.
* DEBUG.FLAG now uses new LOCATE method: DEBUG CMDLINE to debug.
* 04.Sep.2007 jim: Handle CMD.VERB = 'RUN' so callers don't have to.
* 02.Jul.2007 jim: SINGLEPARAM option to allow Flags before Arguments, 'Unix-Style'; i.e.:
* -<flag> <param> ARG ARG ...
* (was for DISPLAY.DIFFS but now not used anymore ?)
* 30-Aug-2005 jra: Add OPTIONS.
* 14-Nov-2003 New syntax for 'COPY.TO.REV'; to be used for all future commands.
* =======================================================================================
*
* SENTENCE : Pass in @SENTENCE or really anything you want to parse.
*
* CMDLINE : Pass this array (so we don't have to put it in Global Common)
*
* OPTIONS : 'LONGFLAGS' : -TEST will be treated as one flag instead of '-T EST'.
* 'SINGLEPARAM' : -x will use only ONE following parameter.
* 'NOPARAM' : -x will be the flag with NO following parameter.
*
* =======================================================================================
*
* Note that this does a COMPLETE CHARACTER BY CHARACTER PARSE:
* this allows it to handle strings in quotes, strange file names, etc.
*
* Usage:
*
* %< -----------------------
* $include RMS.BP EQU.CMDLINE
* call PARSE.CMDLINE(@SENTENCE, MAT CMDLINE, Options)
* if CMD.HELP then
* print "<your help here>...
* stop
* end
* <etc...>
* %< -----------------------
*
* DSI 'Standardized' Syntax:
*
* <Verb> <Arg1> <Arg2> <-Flag1> <Param1> <-Flag2Param2> ( <Option1> <Option2>
*
* Examples:
* COPY.TO.REV FILE ITEM -T "TCL COMMAND" -F A (O P
*
* Guidelines:
* - Use ARGS for 'fixed position' parameters which are always required
* ALL ARGS are to be used BEFORE OPTIONS AND FLAGS ! (unlike Unix...)
* - Options and Flags are single characters unless 'LONGFLAGS' is used
* - Use '(' OPTIONS for options with no parameters (but '-' is always recommended)
* - Options do NOT need spaces or subsequent '('s, but they won't hurt.
* - Use '-' FLAGS for things with another value; i.e. the 'parameter'
* - Flags do NOT need spaces from their params, but they won't hurt.
* - Programs should check the 'CMD.HELP' flag after calling this and
* immediately display a help msg and exit if it's set.
*
* See 'RMS.BP COPY.TO.REV' for an example.
*
* Use: 'CMDLINE.TEST' to check your parameters and as an aid to writing your code.
*
* Note that since this program does a 'pure parse' of the command line, it only
* acknowledges '-', '(', and quotes when they START a string; therefore they
* can be embedded in Item-ID's without conflicting with the option parsing.
*
* =======================================================================================
$include RMS.BP RMS.COMMON ;* DEBUG.FLAG to check for 'c' flag.
* We need this to get at the EQU'ed names.
* (and although we don't need the 'dim'; it won't hurt):
$include RMS.BP EQU.CMDLINE
mat CMDLINE = '' ;* Clear out old COMMON's
PROCLINE = SENTENCE ;* Now passed in !
convert @VM to @FM in OPTIONS ;* Just in case caller used <1,-1> instead of <-1>
locate('LONGFLAGS', OPTIONS; LOC) then LONG.FLAGS = @TRUE else LONG.FLAGS = @FALSE
locate('NOPARAM', OPTIONS; LOC) then NOPARAM = @TRUE else NOPARAM = @FALSE
locate('SINGLEPARAM', OPTIONS; LOC) then SINGLEPARAM = @TRUE else SINGLEPARAM = @FALSE
CMD.HELP = @FALSE ;* Flag for '-H'
OPTIONS = @FALSE ;* After a '(' ALL are options
FLAGS = @FALSE ;* After a '-' are parameters or another Flag
POS = 1 ;* Position in PROCLINE
FLAG.PTR = 0 ;* Which FLAG we are on: keeps incrementing.
loop
gosub [[GetNextVal]]
while P # '' DO
* locate( "CMDLINE", DEBUG.FLAG; dummy) then
* print "P:":P: ; input j ; if j = 'D' then debug
* end
begin case
case CMD.VERB = '' ; CMD.VERB = P
case P[1,1] = '-' ; gosub [[StartNewFlag]]
case P[1,1] = '(' ; gosub [[StartOptions]]
case OPTIONS ; gosub [[AddOptions]]
case FLAGS
if P[1,1] = '-' then
gosub [[StartNewFlag]]
end else
FLAG.PARAM = P ; gosub [[AddFlagParameter]]
end
case 1 ; CMD.ARG.S<1,-1> = P
end case
repeat
* Handle 'RUN <file.BP> <program>' here so callers don't have to:
if CMD.VERB = 'RUN' and CMD.ARG.S<1, 1>'R#3' = '.BP' then
CMD.VERB = CMD.ARG.S<1, 2>
CMD.ARG.S = delete( CMD.ARG.S, 1, 1 ) ;* Delete the '.BP'
CMD.ARG.S = delete( CMD.ARG.S, 1, 1 ) ;* Delete the VERB (now in CMD.VERB)
end
* Finally set these convenience variables:
CMD.NUM.ARGS = dcount(CMD.ARG.S, @VM)
CMD.NUM.OPTIONS = dcount(CMD.OPTION.S, @VM)
CMD.NUM.FLAGS = dcount(CMD.FLAG.S, @VM)
return
[[StartOptions]]:
OPTIONS = 1
P = P[2,9999]
gosub [[AddOptions]]
return
[[AddOptions]]:
if P = 'H' or P = '?' then
CMD.HELP = 1
end
CMD.OPTION.S<1,-1> = P
return
[[StartNewFlag]]:
OPTIONS = @FALSE ;* Switch modes
FLAGS = @TRUE
if LONG.FLAGS then
FLAG = P
EXTRA = ''
end else
FLAG = P[2,1]
EXTRA = P[3,9999]
end
if FLAG[1,1] = 'H' or FLAG[1,1] = '?' then
CMD.HELP = @TRUE
end
* Now re-use the same position if the flag is the same:
locate FLAG in CMD.FLAG.S<1> setting OLD.PTR then
FLAG.PTR = OLD.PTR
end else
FLAG.PTR += 1
end
CMD.FLAG.S<1,FLAG.PTR> = FLAG
if EXTRA # '' then
FLAG.PARAM = EXTRA ; gosub [[AddFlagParameter]]
end
if NOPARAM then FLAGS = @FALSE
return
[[AddFlagParameter]]:
CMD.PARAM.S<1,FLAG.PTR,-1> = FLAG.PARAM
if SINGLEPARAM then ;* We've got one: so NO MORE for this flag:
FLAGS = @FALSE
end
return
* Everything within Quotes (single or double ?) is a single value too:
* old: VAL = field(PROCLINE,' ',I)
[[GetNextVal]]:
P = '' ;* This gets returned
loop
C = PROCLINE[POS, 1]
while POS <= len(PROCLINE) and C # " " do
if C = '"' or C = "'" or C = "\" then
gosub [[GetQuotedVal]]
end else
P := C
end
POS += 1
repeat
POS += 1 ;* Past the space
* Now get past MORE spaces for over-spaces lines (like a 'trim'):
loop
while PROCLINE[POS, 1] = ' ' do
POS += 1
repeat
return
[[GetQuotedVal]]:
Q = C ;* Look for matching 'Q'uote character
POS += 1 ;* Past the quote
loop
CHAR = PROCLINE[POS, 1]
while POS <= len(PROCLINE) and CHAR # Q do
P := CHAR
POS += 1 ;* Past the quote
repeat
return