/* _______________________________________________________________________________ _______________________________________________________________________________ Title: argp - Argument Options Parser Parse an argument string with options and get keys and values. _______________________________________________________________________________ _______________________________________________________________________________ License: (C) Copyright 2009, 2010 Tuncay This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . (see lgplv3.png) See the file COPYING.txt and COPYING.LESSER.txt for license and copying conditions. About: Description About the idea Introduction: Sometimes we need to work with many optional parameters. Some of the parameters may be just logical flags only (true/false). If the function have too many such parameters, the usability is endangered. To workaround that disgrace, we can make one option string to the function. From now on, this string contains all parameters. This is comparable to the commandline. It must be parsed to find all parts. Writing such parsers could become difficult and slow down the complete process. The parsing is tried to be made with one regex call only (with some other non dramatic lines). As long as the string is keeped simple, there should be no problem. But with growing complexity, with different values of subparameters, it is a pain to make the difference. Who needs this?: This is not a parser for command line arguments of programs or scripts. It is similiar to Windows or Unix/Linux command line arguments, but different in some ways and less powerful. This library is for those ahk developers, who needs to write user defined functions with many options. With the parsing of just one real function parameter, it can be avoided to have a bunch of function parameters. What it can do for you: The source will be parsed and all found options are given over to specified variables. The other work parsing these generated variables is left to the user. * *Pro:* A standardized, simple and fast way of options handling. * *Contra:* It isn`t a well known official standard. History: This library is rewritten from scratch and the old BUG or LIMITATION is not present anymore. Not only that. It does work in a completly another way. After searching the web, I found a regular expression made by Richard Hauer at regexlib.com. I have modified it and now it is the backbone of my functions. One deserved credit goes to him. The name of the library is changed again, from args to argp. The chosen name argp is a GNU C library for parsing arguments of programs. This AutoHotkey library is named like it, but there is no compatibility with the GNU C library. The name is an abbreviation for "ARGument Parser". Links: * Discussion: [http://www.autohotkey.com/forum/viewtopic.php?p=310409] * License: [http://www.gnu.org/licenses/lgpl-3.0.html] * Wikipedia - LGPL: [http://en.wikipedia.org/wiki/GNU_Lesser_General_Public_License] Date: 2010-01-30 Revision: 3.0 Status: Release Credits: * Tuncay, [tuncay.d@gmx.de] (Author) * Richard Hauer [http://regexlib.com/REDetails.aspx?regexp_id=1220] (Author of original Regular Expression) License: GNU Lesser General Public License 3.0 or higher [http://www.gnu.org/licenses/lgpl-3.0.html] Category: String Manipulation Type: Library Tested AutoHotkey Version: 1.0.48.05 Tested Platform: 2000/XP Standalone (such as no need for extern file or library): Yes StdLibConform (such as use of prefix and no globals use): Yes Related: *Other Community Solutions* * Parameters and switches parser by Yook: [http://www.autohotkey.com/forum/viewtopic.php?t=50885] * [function] Parse by majkinetor: [http://www.autohotkey.com/forum/viewtopic.php?t=49261] * options.ahkl - an options object for AutoHotkey_L by ahklerner: [http://www.autohotkey.com/forum/viewtopic.php?t=49430] About: Usage How to use the functions Syntax: > count := argp_parse( source [, maxcount, keyname1, value1, ... keyname32, value32] ) > > optlist := argp_getopt( source [, keylist, caseSense, value1, ... value32] ) There are two independently working functions. They have the same regular expression at the core, but the functionality and interface differs. One creates variables for each key name and the other one returns a list with names, checking against another list of possible names (either with case sense on or off and, removing dublicates). After calling one of the functions, the variables or the list must be parsed. This is left to be done by the user. For the beginner, it is recommended to use argp_getopt() and then check with InStr() if a name exists in resulting list (with surrounding spaces). No globals are created, no special objects or frameworks are needed. Installation: Just name the library to "argp.ahk" and put it into the standard or user library folder. A call of one of these functions in this library will lead to automatically include it into the script at call time. The folder should reside under one of these paths: > %A_MyDocuments%\AutoHotkey\Lib\ ; User library. > path-to-the-currently-running-AutoHotkey.exe\Lib\ ; Standard library. Alternatively you can include this library at any position of your script with the #include command: > #Include argp.ahk Example 1: This is part of parsing the options parameter from hypotetical function set_clipboard(). The code demonstrates some aspects only, and it`s not optimized. (Code) ; Set default values prior to parsing argument string. opt_wait_use := false opt_errorlevel_set := false ; Analyze the variable argument for existence of options namely "wait" and "errorlevel". ; Save the value of "wait" into variable wait_value. ; After that, a new list with option names is get and saved into variable optlist. optlist := argp_getopt(argument, "wait errorlevel", false, wait_value) ; Now, parse the list and set options for programs usage. If InStr(optlist, " wait ") { opt_wait_use := true opt_wait_value := wait_value } If InStr(optlist, " errorlevel ") { opt_errorlevel_set := true } (End) If the set_clipboard() function was called with following options > "-w:2" Then the following variables are set > opt_wait_use := true > opt_wait_value := 2 > opt_errorlevel_set := false Example 2: The next example shall show how to translate an usual function to argp_getopt() powered function. One function could look like this (very boring I know): (Code) display(sentence = "hello world", caseMod = 0, html = 0) { If (caseMod = 1) StringUpper, sentence, sentence, T Else If (caseMod = 2) StringUpper, sentence, sentence Else If (caseMod = 3) StringLower, sentence, sentence If ( html) Transform, sentence, HTML, %sentence% MsgBox %sentence% } (End) A call could look like this > display("hello world", 1, 1) Next code is one possible version with argp (Code) display(options) { ; Default values of options. sentence = hello world ; Parsing options. optlist := argp_getopt(options, "sentence caseMod html", false, sentence_value, caseMod_value) Loop, Parse, optlist, %A_Space%, %A_Space% { If ("sentence" = A_LoopField) sentence := sentence_value Else If ("caseMod" = A_LoopField) { If (caseMod_value = 1) StringUpper, sentence, sentence, T Else If (caseMod_value = 2) StringUpper, sentence, sentence Else If (caseMod_value = 3) StringLower, sentence, sentence } Else If ("html" = A_LoopField) Transform, sentence, HTML, %sentence% } MsgBox %sentence% } (End) Lets see how a call could look now > display("-caseMod 2 -html") What is done there? First we have changed from multiple function parameters to single parameter. All the necessary default parameters are set in the function body. Then the argp_getopt() is used to parse options variable. The third parameter (here set to false) is for doing the parse without case sensitivity. All the parameters after that, are variables for holding possible values of the options. That is, because every option can have its own value. After this process, the resulting optlist variable holds the found names of options (given are the three "sentence caseMod html"). As a next step, this optlist variable must be parsed manually for checking which options are found actually and doing the right actions. In this example, a Loop, Parse command is chosen. There are other possibilities like multiple InStr() checks. About: Specification Argument string format Basic structure: Any option must begin either with a hypghen "-" or slash "/", to be recognized as an option. It doesn`t matter which of the two is used. The following character or word until next option or space is the key name of that option. In example: > -a -b and > -a-b would be resolved to these keys > a > b Although space is not required, you can write without it. Normally parts in string that are not recognized as options should be ignored. In such a case, the resulting variable and value is allways empty. Values added to keys: Every option can have its own assigned value. The value can be delimited from its key name with a space " ", a double colon ":" or an equality sign "=". If it is enclosed in quotes, then no delimiter is needed. The value is read until one space is found (or another option starts). In example: > -a test1 -b would be resolved to these keys > a > b Where "a" holds the value "test1". Normally spaces around a value are lost. The value can be optionally enclosed between a pair of single or double quotes. That way spaces inside the quotes are saved. > -a:'foo -bar ' -B -c hello world would be resolved to these keys > a > B > c Where a holds the value "foo -bar " and c the value "hello". If a value contains one of these characters -, /, :, =, ' or ", then it is best to enclose the whole value between quotes (single or double). Dublicate keys: argp_parse() and argp_getopt() treat duplicate definitions of option names in different ways. argp_parse() sees every key separately. And argp_getopt() sees the first definition only. This is important if they have values. In example: > -a:foo -a:bar -A would argp_getopt() resolve to > a > A where a would holds the value "foo" and A would have an empty value. In contrast argp_parse() resolves to > a > a > A first a holds "foo" and second a holds "bar". Again, the last A have an empty value. Key naming: These characters in key name are allowed: a-z, A-Z, 0-9, _, ., ?, ! and @. Some examples: > -a > -test > /test.example > /? > -64 > -@section The one special value without key name: There is one exception in argp_parse() function only. Any string before first option is treated as a special value without a key name. That value is parsed like any other value. In example: > hello -a would be resolved to these keys > a The key "a" does have an empty value and the first special value "hello" is saved in ErrorLevel. This is supported by argp_parse() function exclusively. */ /* Func: argp_parse Get optional keys and values as separate variables. Syntax: > count := argp_parse( args [, maxcount, n1, v1, ... n32, v32] ) Parameters: args - *Variable* [string] input: Source String variable with options to parse. See above at "Specification", which is a description about the format. maxcount - *Optional* [integer] input: Specifies how many options to get. Anything below '1' or above '32' defaults to '32'. n1-n32 - *Variable Optional* [string] output: Stores the key name of option into variable. Variable n1 would hold first found name of option (i.e. "A"). v1-v32 - *Variable Optional* [string] output: Stores the value of an option into variable. Variable v1 would hold value of first found option (i.e. "33"). Returns: Number of retrieved options, or '0' otherwise. Remarks: maxcount can be set to an integer value between 1 and 32. That restricts the number of options to extract from source string. In example, if specified to 8, then the first 8 options are seen and the rest is ignored. This is an optimization. Maximum possible of 6 options to parse is faster than to parse 26 options. Plus, there are special optimizations to 8, 16 and 32, so they are faster in execution against values near to them. These values (8, 16, 32) are highly recommended. ErrorLevel: ErrorLevel is set to the first special value without key name. Otherwise it is empty. With following example: > get -i it would hold "get". With next example > -i get ErrorLevel would be empty. Examples: (Code) options = -A='33' -i /f:c:\test -time:5:10 -x /date:11:08:2009 count := argp_parse(options, 8, n1, v1, n2, v2, n3, v3, n4, v4, n5, v5, n6, v6, n7, v7, n8, v8) Text = ( Number of options in source (options): %count% Name of key 3 (n3): %n3% Value of key 3 (v3): %v3% ) MsgBox %Text% (End) *Output:* (Code) Number of options in source (options): 6 Name of key 3 (n3): f Value of key 3 (v3): c:\test (End) */ argp_parse(ByRef _args, _maxcount=32, ByRef _n1="", ByRef _v1="", ByRef _n2="", ByRef _v2="", ByRef _n3="", ByRef _v3="", ByRef _n4="", ByRef _v4="", ByRef _n5="", ByRef _v5="", ByRef _n6="", ByRef _v6="", ByRef _n7="", ByRef _v7="", ByRef _n8="", ByRef _v8="", ByRef _n9="", ByRef _v9="", ByRef _n10="", ByRef _v10="", ByRef _n11="", ByRef _v11="", ByRef _n12="", ByRef _v12="", ByRef _n13="", ByRef _v13="", ByRef _n14="", ByRef _v14="", ByRef _n15="", ByRef _v15="", ByRef _n16="", ByRef _v16="", ByRef _n17="", ByRef _v17="", ByRef _n18="", ByRef _v18="", ByRef _n19="", ByRef _v19="", ByRef _n20="", ByRef _v20="", ByRef _n21="", ByRef _v21="", ByRef _n22="", ByRef _v22="", ByRef _n23="", ByRef _v23="", ByRef _n24="", ByRef _v24="", ByRef _n25="", ByRef _v25="", ByRef _n26="", ByRef _v26="", ByRef _n27="", ByRef _v27="", ByRef _n28="", ByRef _v28="", ByRef _n29="", ByRef _v29="", ByRef _n30="", ByRef _v30="", ByRef _n31="", ByRef _v31="", ByRef _n32="", ByRef _v32="") { If (_maxcount<1||_maxcount>32) _maxcount:=32 If (_maxcount=32) ; Optimization to avoid Loop. _n1:="",_n2:="",_n3:="",_n4:="",_n5:="",_n6:="",_n7:="",_n8:="",_n9:="",_n10:="",_n11:="",_n12:="",_n13:="",_n14:="",_n15:="",_n16:="",_n17:="",_n18:="",_n19:="",_n20:="",_n21:="",_n22:="",_n23:="",_n24:="",_n25:="",_n26:="",_n27:="",_n28:="",_n29:="",_n30:="",_n31:="",_n32:="",regex := "JSs`a)(?:('(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?" Else If (_maxcount=16) ; Optimization to avoid Loop. _n1:="",_n2:="",_n3:="",_n4:="",_n5:="",_n6:="",_n7:="",_n8:="",_n9:="",_n10:="",_n11:="",_n12:="",_n13:="",_n14:="",_n15:="",_n16:="",regex := "JSs`a)(?:('(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?" Else If (_maxcount=8) ; Optimization to avoid Loop. _n1:="",_n2:="",_n3:="",_n4:="",_n5:="",_n6:="",_n7:="",_n8:="",regex := "JSs`a)(?:('(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?" Else { If (_maxcount>8) VarSetCapacity(regex,4624) regex:="JSs`a)(?:('(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|\s*(?P[^-/\s]*)\s*))?" Loop,%_maxcount% _n%A_Index%:="",regex.="(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?" } RegExMatch(_args,regex,_),ErrorLevel:=_v If (_n%_maxcount%!="") ; Possible shortcut to avoid checking for each variable. Return _maxcount Else { count:=0 Loop,%_maxcount% If (_n%A_Index%!="") count:=A_Index } Return count } /* Func: argp_getopt Check for known keys and get list of them and all values as separate variables. Syntax: > optlist := argp_getopt( source [, keylist, caseSense, value1, ... value32] ) Parameters: args - *Variable* [string] input: Source String variable with options to parse. See above at "Specification", which is a description about the format. keyList - *Optional* [string] input: A space separated list of option names. Every key in options source string args will be in returning optlist. All values are written to output variables from number 1 to 32. The third item in this list relates to third output variable. If the keylist is empty "", then all existing key names are get. case - *Optional* [flag] input: Case sensitivity of names checking; sensitiv at default (true or 1) leads to let "a" as a different option as "A". 1-32 - *Variable Optional* [string] output: Stores the value of option into variable. Variable number 1 would hold value (i.e. "33") of first defined option (i.e. "A"). Returns: Get a space separated list of matching names. This means, all not found option names are filtered out from keyList. Duplicate names are not found and first one is used instead. (In example: "A file A c i", these are the names of 4 options.) If keyList is empty, then all options found in source is returned. Order of corresponding values (specified variables 1-32) reflects the order in source. But if keyList is a non empty list, then all options specified in this list are returned. Remarks: Other than argp_parse(), this function awaits a list of option names in keyList. That keylist is compared against all found option names from source. All matching keys are copied to resulting return list. The returning list have spaces around also (at begin of list and end of). That allows checking for existency of keys with > InStr(keylist, " A ") Any existing value corresponding to the key name is copied to output variable ranging from 1 to 32. In example second options value belongs to second variable, even if there is no value. In that case, the value is an empty string (blank value). ErrorLevel: ErrorLevel is set to the number of matching option names. Duplicates are not counted. If nothing is found, it is set to '0'. It is not the count of resulting keylist, but the count of keys in source string args. Examples: (Code) options = -A='33' -i /f:c:\test -time:5:10 -x /date:11:08:2009 optlist := argp_getopt(options, "s i test a", false, v1, v2, v3, v4) Text = ( Number of options in source (options): %count% List of all matching key names (optlist): %optlist% Value of key 4 (v4): %v4% ) MsgBox %Text% (End) *Output:* (Code) Number of options in source (options): 6 List of all matching key names (optlist): a i Value of key 4 (v4): 33 (End) */ argp_getopt(ByRef _args, _keylist="", _case=true, ByRef _1="", ByRef _2="", ByRef _3="", ByRef _4="", ByRef _5="", ByRef _6="", ByRef _7="", ByRef _8="", ByRef _9="", ByRef _10="", ByRef _11="", ByRef _12="", ByRef _13="", ByRef _14="", ByRef _15="", ByRef _16="", ByRef _17="", ByRef _18="", ByRef _19="", ByRef _20="", ByRef _21="", ByRef _22="", ByRef _23="", ByRef _24="", ByRef _25="", ByRef _26="", ByRef _27="", ByRef _28="", ByRef _29="", ByRef _30="", ByRef _31="", ByRef _32="") { CaseSense:=A_StringCaseSense StringCaseSense,Off _1:="",_2:="",_3:="",_4:="",_5:="",_6:="",_7:="",_8:="",_9:="",_10:="",_11:="",_12:="",_13:="",_14:="",_15:="",_16:="",_17:="",_18:="",_19:="",_20:="",_21:="",_22:="",_23:="",_24:="",_25:="",_26:="",_27:="",_28:="",_29:="",_30:="",_31:="",_32:="",RegExMatch(_args,"JSs`a)(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?(?:(?:.*?\s*)[-/](?P[a-zA-Z0-9_?!@.]+)(?:[:=]\s*)?(\s*'(?:(?P.+?)')(?=.*?)|""(?:(?P.+?)"")(?=.*?)|[\s'""]?\s*(?P[^-/\s]*)\s*))?",_) ; 32 elements. ; At keys, one space is needed for checking. count:=0,keys:=" ",i:=0 Loop,32 ; 32 corresponding to the maximum possible number of matching elements. If (_n%A_Index%!="") count:=A_Index If (_keylist="") { Loop,%count% { n:=_n%A_Index% If (!InStr(keys," " . n . " ",_case)) _%A_Index%:=_v%A_Index%,keys.=_n . A_Space } } Else If (_case) { Loop,%count% { i:=A_Index,n:=_n%A_Index% Loop,Parse,_keylist,%A_Space%,%A_Space% If (n==A_LoopField&&!InStr(keys," " . A_LoopField . " ",true)) { _%A_Index%:=_v%i%,keys.=A_LoopField . A_Space Break } Else If (!InStr(keys," " . A_LoopField . " ",false)) _%A_Index%:="" } } Else ; Uses = instead of == and false instead of true in InStr() and case ; takes the correct case version from source. { Loop,%count% { i:=A_Index,n:=_n%A_Index% Loop,Parse,_keylist,%A_Space%,%A_Space% If (n=A_LoopField&&!InStr(keys," " . A_LoopField . " ",false)) { _%A_Index%:=_v%i%,keys.=n . A_Space ; n is case from source. Break } Else If (!InStr(keys," " . A_LoopField . " ",false)) _%A_Index%:="" } } StringCaseSense,%CaseSense% ErrorLevel:=count ; Number of matching elements. Return keys }