#! python: #w#VIC options.py module # # Copyright 2002, 2003 by Timothy Rue <3seas@threeseas.net> # # VIC options.py module: version 0.5.1.python (BETA) # # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation version 2 # of the License. http://www.gnu.org/copyleft/gpl.html # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Or access http://www.gnu.org/copyleft/gpl.html ########################################################################## #August 29, 2003 made file IQ parseable 0.5.1 #July 24, 2003 initial release 0.5 # ########################################################################## ### ### Options Module ### ### Provides getopt-esque command line parsing ### For when the getopt just wont do ### ### Call like: ### args,options = getopt("-f oo -foo 36 -b -f \"no filename !!!\" -foo",['-f -foo:','-b -bar' ]) ### #s#system module import string #s#def getopt def getopt(input,format): return getOptions(input,format) #s#def getoptindex def getoptindex(opts,tag): for i in range(len(opts)): if (tag == opts[i][0]): return i return -1 #s#def splitArgs ### ### Given a 'command line' style string, split out each argument ### returning an array of strings. ### Words are white-space delimited (space,tab), but spaces ### may be contained within quotes. ### ### e.g.: splitArgs("a bee \"C = light\" d") => ['a', 'bee', 'C = light', 'd'] ### def splitArgs(arg_string,trim_quotes=1): cursor = 0 # position in the string start_word = 0 # position current word started at in_word = 0 # are we reading over a word or just whitespace in_quotes = 0 # are we processing a quoted string - ..."fooo bar"... arg_string = string.strip(arg_string) if (len(arg_string) == 0): return [] arg_list = [] # output list while (1): ### start/ending-points are quotes or whitespace if (arg_string[cursor] in ' \t<|>' or (arg_string[cursor] == '"' and (cursor == 0 or arg_string[cursor-1] != '\\'))): if (in_word and not in_quotes): ### found a space after a word not in quotes, so that finishes this arg new_word = arg_string[start_word:cursor] arg_list.append(new_word) in_word = 0 elif (arg_string[cursor] == '"' and (cursor == 0 or arg_string[cursor-1] != '\\')): if (in_quotes): # a quoted arg has closed the quotes in_quotes = 0 in_word = 0 new_word = arg_string[start_word:cursor] if (trim_quotes): new_word = new_word[1:len(new_word)] # trim quotes "..." else: new_word = new_word + '"' arg_list.append(new_word) else: # quotes have been opened in_quotes = 1 in_word = 1 start_word = cursor elif (not in_word): ### have hit non-space, non-quotes, so it must be an argument starting in_word = 1 start_word = cursor if (not in_quotes and arg_string[cursor] in "<|>"): arg_list.append(arg_string[cursor]) ### skip to next char cursor = cursor + 1 if (cursor == len(arg_string)): ### end of input if (in_word): ### We started a quoted string, but never finished it, e.g.: ... "foo new_word = arg_string[start_word:len(arg_string)] if (trim_quotes == 0): if (new_word[0] == '"'): new_word = new_word + '"' else: if (new_word[0] == '"'): new_word = new_word[1:len(new_word)] arg_list.append(new_word) break; ### The return list is one argument string per entry ### e.g.: ['foo','bar','she sells sea shells','1'] return arg_list #s#def getOptions ### ### Given a single-string argument list, and an options format ### parse out options and arguments from the full args. ### ### The format is similiar to the getopt module, except we ### can handle string options rather than just single word ### options. (without having to say "--option=8", just "-option 8") ### ### format: ### A list of (space speerated) synonym options, e.g.: ### [ '-a', '-? --help -h', '-f -file:', '-o:' ] ### ### As in getopt, if a ':' is appended to the option(s), that means ### we expect an argument. If a synonym string, only one colon allowed. ### def getOptions(arg_string,format): need_arg = 0 # flag to indicate last option wants a parameter the_switch = "" # remember the last option cursor = 0 # position in argument list args = [] # output argument options = [] # output options ### easy option if (len(arg_string) == 0): return [],[] ### split our arguments into a space-delimited list (watching quoted args) arg_list = splitArgs(arg_string) ### make each argument synonym list into a sub-list for independant searching format_lists = [] for i in range(len(format)): format_lists.append(format[i].split()) for j in range(len(format_lists[-1])): format_lists[-1][j] = string.replace(format_lists[-1][j],":","") #print "FORMAT_LIST: "+str(format_lists) ### Iterate through the arguments, splitting them out while (1): if (need_arg): new_pair = [ the_switch, arg_list[cursor] ] need_arg = 0 the_switch = "" options.append(new_pair) else: needle = arg_list[cursor] found = 0 for i in range(len(format)): for j in range(len(format_lists[i])): haystack = format_lists[i][j] if (haystack == needle): found = 1 if (format[i][-1] == ':'): ### does this option take an argument need_arg = 1 the_switch = haystack else: options.append([needle,'']) ### stop on first match i = len(format) break ### Just a simple argument (not a switch/option) if (not found): args.append(needle) cursor = cursor + 1 ### Processed all arguments if (cursor == len(arg_list)): if (need_arg): ### input ends with an assign option, but no option options.append([the_switch,'']) break ### should have all plain arguments in list ### and options is a list of option/value pairs ...,['-foo', '36'],... ### If the option was not an assign, then it's paired with '' ### e.g.: ...,['-bar',''],... return args,options #s#def splitOnPipes ### ###Given a compound command like seperated with pipes '|' ### Split it up into a list of seperate commands, but being ### careful not to split on pipes that are contained in ### duoble-quote-delimited strings ### def splitOnPipes(command): output = [] if (len(command) > 0): ### split into words, leaving quoted sections as one surrounded with quotes ### so "foo "bar" woot" -> ['foo','"bar"','woot'] command_list = splitArgs(command,0) out_command = "" cursor = 0 while (1): if (command_list[cursor] == '|'): output.append(out_command) out_command = "" else: if (len(out_command) > 0): out_command = out_command + ' ' out_command = out_command + command_list[cursor] cursor = cursor + 1 if (cursor == len(command_list)): if (len(out_command) > 0): output.append(out_command) break ### Output should be command list split about any pipes '|' return output ### #w#Simple testing/debugging main() ### #def main(): # args,options = getOptions("ai -f foo filename -pk chewing_gum --help -foo -s", \ # [ '-n:','-oi:','-f:','-sf:','-iq:','-id:','-ke:','-ip -i -op -o:','-s','-w','-u','-e','-? -help --help','-l','-s:','-pk:' ]) # # print "ARGS: "+str(args) # print "OPTS: "+str(options) # # #if (__name__ == "__main__"): # main()