This commit is contained in:
Araq 2015-07-01 16:44:16 +02:00
commit 30829ffec4

View file

@ -21,17 +21,17 @@
include "system/inclrtl" include "system/inclrtl"
import import
os, strutils os, strutils
type type
CmdLineKind* = enum ## the detected command line token CmdLineKind* = enum ## the detected command line token
cmdEnd, ## end of command line reached cmdEnd, ## end of command line reached
cmdArgument, ## argument detected cmdArgument, ## argument detected
cmdLongOption, ## a long option ``--option`` detected cmdLongOption, ## a long option ``--option`` detected
cmdShortOption ## a short option ``-c`` detected cmdShortOption ## a short option ``-c`` detected
OptParser* = OptParser* =
object of RootObj ## this object implements the command line parser object of RootObj ## this object implements the command line parser
cmd: string cmd: string
pos: int pos: int
inShortState: bool inShortState: bool
@ -42,8 +42,40 @@ type
{.deprecated: [TCmdLineKind: CmdLineKind, TOptParser: OptParser].} {.deprecated: [TCmdLineKind: CmdLineKind, TOptParser: OptParser].}
proc parseWord(s: string, i: int, w: var string,
delim: set[char] = {'\x09', ' ', '\0'}): int =
result = i
if s[result] == '\"':
inc(result)
while not (s[result] in {'\0', '\"'}):
add(w, s[result])
inc(result)
if s[result] == '\"': inc(result)
else:
while not (s[result] in delim):
add(w, s[result])
inc(result)
when declared(os.paramCount): when declared(os.paramCount):
# we cannot provide this for NimRtl creation on Posix, because we can't proc quote(s: string): string =
if find(s, {' ', '\t'}) >= 0 and s[0] != '"':
if s[0] == '-':
result = newStringOfCap(s.len)
var i = parseWord(s, 0, result, {'\0', ' ', '\x09', ':', '='})
if s[i] in {':','='}:
result.add s[i]
inc i
result.add '"'
while i < s.len:
result.add s[i]
inc i
result.add '"'
else:
result = '"' & s & '"'
else:
result = s
# we cannot provide this for NimRtl creation on Posix, because we can't
# access the command line arguments then! # access the command line arguments then!
proc initOptParser*(cmdline = ""): OptParser = proc initOptParser*(cmdline = ""): OptParser =
@ -51,40 +83,27 @@ when declared(os.paramCount):
## (as provided by the ``OS`` module) is taken. ## (as provided by the ``OS`` module) is taken.
result.pos = 0 result.pos = 0
result.inShortState = false result.inShortState = false
if cmdline != "": if cmdline != "":
result.cmd = cmdline result.cmd = cmdline
else: else:
result.cmd = "" result.cmd = ""
for i in countup(1, paramCount()): for i in countup(1, paramCount()):
result.cmd = result.cmd & quoteIfContainsWhite(paramStr(i).string) & ' ' result.cmd.add quote(paramStr(i).string)
result.cmd.add ' '
result.kind = cmdEnd result.kind = cmdEnd
result.key = TaintedString"" result.key = TaintedString""
result.val = TaintedString"" result.val = TaintedString""
proc parseWord(s: string, i: int, w: var string, proc handleShortOption(p: var OptParser) =
delim: set[char] = {'\x09', ' ', '\0'}): int =
result = i
if s[result] == '\"':
inc(result)
while not (s[result] in {'\0', '\"'}):
add(w, s[result])
inc(result)
if s[result] == '\"': inc(result)
else:
while not (s[result] in delim):
add(w, s[result])
inc(result)
proc handleShortOption(p: var OptParser) =
var i = p.pos var i = p.pos
p.kind = cmdShortOption p.kind = cmdShortOption
add(p.key.string, p.cmd[i]) add(p.key.string, p.cmd[i])
inc(i) inc(i)
p.inShortState = true p.inShortState = true
while p.cmd[i] in {'\x09', ' '}: while p.cmd[i] in {'\x09', ' '}:
inc(i) inc(i)
p.inShortState = false p.inShortState = false
if p.cmd[i] in {':', '='}: if p.cmd[i] in {':', '='}:
inc(i) inc(i)
p.inShortState = false p.inShortState = false
while p.cmd[i] in {'\x09', ' '}: inc(i) while p.cmd[i] in {'\x09', ' '}: inc(i)
@ -92,7 +111,7 @@ proc handleShortOption(p: var OptParser) =
if p.cmd[i] == '\0': p.inShortState = false if p.cmd[i] == '\0': p.inShortState = false
p.pos = i p.pos = i
proc next*(p: var OptParser) {.rtl, extern: "npo$1".} = proc next*(p: var OptParser) {.rtl, extern: "npo$1".} =
## parses the first or next option; ``p.kind`` describes what token has been ## parses the first or next option; ``p.kind`` describes what token has been
## parsed. ``p.key`` and ``p.val`` are set accordingly. ## parsed. ``p.key`` and ``p.val`` are set accordingly.
var i = p.pos var i = p.pos
@ -100,33 +119,33 @@ proc next*(p: var OptParser) {.rtl, extern: "npo$1".} =
p.pos = i p.pos = i
setLen(p.key.string, 0) setLen(p.key.string, 0)
setLen(p.val.string, 0) setLen(p.val.string, 0)
if p.inShortState: if p.inShortState:
handleShortOption(p) handleShortOption(p)
return return
case p.cmd[i] case p.cmd[i]
of '\0': of '\0':
p.kind = cmdEnd p.kind = cmdEnd
of '-': of '-':
inc(i) inc(i)
if p.cmd[i] == '-': if p.cmd[i] == '-':
p.kind = cmdLongoption p.kind = cmdLongoption
inc(i) inc(i)
i = parseWord(p.cmd, i, p.key.string, {'\0', ' ', '\x09', ':', '='}) i = parseWord(p.cmd, i, p.key.string, {'\0', ' ', '\x09', ':', '='})
while p.cmd[i] in {'\x09', ' '}: inc(i) while p.cmd[i] in {'\x09', ' '}: inc(i)
if p.cmd[i] in {':', '='}: if p.cmd[i] in {':', '='}:
inc(i) inc(i)
while p.cmd[i] in {'\x09', ' '}: inc(i) while p.cmd[i] in {'\x09', ' '}: inc(i)
p.pos = parseWord(p.cmd, i, p.val.string) p.pos = parseWord(p.cmd, i, p.val.string)
else: else:
p.pos = i p.pos = i
else: else:
p.pos = i p.pos = i
handleShortOption(p) handleShortOption(p)
else: else:
p.kind = cmdArgument p.kind = cmdArgument
p.pos = parseWord(p.cmd, i, p.key.string) p.pos = parseWord(p.cmd, i, p.key.string)
proc cmdLineRest*(p: OptParser): TaintedString {.rtl, extern: "npo$1".} = proc cmdLineRest*(p: OptParser): TaintedString {.rtl, extern: "npo$1".} =
## retrieves the rest of the command line that has not been parsed yet. ## retrieves the rest of the command line that has not been parsed yet.
result = strip(substr(p.cmd, p.pos, len(p.cmd) - 1)).TaintedString result = strip(substr(p.cmd, p.pos, len(p.cmd) - 1)).TaintedString
@ -140,7 +159,7 @@ when declared(initOptParser):
## filename = "" ## filename = ""
## for kind, key, val in getopt(): ## for kind, key, val in getopt():
## case kind ## case kind
## of cmdArgument: ## of cmdArgument:
## filename = key ## filename = key
## of cmdLongOption, cmdShortOption: ## of cmdLongOption, cmdShortOption:
## case key ## case key