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