parseopt stdlib module: dont rely on the zero terminator

This commit is contained in:
Andreas Rumpf 2018-04-29 01:31:29 +02:00
commit 203d833688

View file

@ -57,26 +57,26 @@ type
{.deprecated: [TCmdLineKind: CmdLineKind, TOptParser: OptParser].} {.deprecated: [TCmdLineKind: CmdLineKind, TOptParser: OptParser].}
proc parseWord(s: string, i: int, w: var string, proc parseWord(s: string, i: int, w: var string,
delim: set[char] = {'\x09', ' ', '\0'}): int = delim: set[char] = {'\x09', ' '}): int =
result = i result = i
if s[result] == '\"': if result < s.len and s[result] == '\"':
inc(result) inc(result)
while not (s[result] in {'\0', '\"'}): while result < s.len and s[result] != '\"':
add(w, s[result]) add(w, s[result])
inc(result) inc(result)
if s[result] == '\"': inc(result) if result < s.len and s[result] == '\"': inc(result)
else: else:
while not (s[result] in delim): while result < s.len and s[result] notin delim:
add(w, s[result]) add(w, s[result])
inc(result) inc(result)
when declared(os.paramCount): when declared(os.paramCount):
proc quote(s: string): string = proc quote(s: string): string =
if find(s, {' ', '\t'}) >= 0 and s[0] != '"': if find(s, {' ', '\t'}) >= 0 and s.len > 0 and s[0] != '"':
if s[0] == '-': if s[0] == '-':
result = newStringOfCap(s.len) result = newStringOfCap(s.len)
var i = parseWord(s, 0, result, {'\0', ' ', '\x09', ':', '='}) var i = parseWord(s, 0, result, {' ', '\x09', ':', '='})
if s[i] in {':','='}: if i < s.len and s[i] in {':','='}:
result.add s[i] result.add s[i]
inc i inc i
result.add '"' result.add '"'
@ -144,43 +144,45 @@ proc handleShortOption(p: var OptParser) =
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 i < p.cmd.len and p.cmd[i] in {'\x09', ' '}:
inc(i) inc(i)
p.inShortState = false p.inShortState = false
if p.cmd[i] in {':', '='} or card(p.shortNoVal) > 0 and p.key.string[0] notin p.shortNoVal: if i < p.cmd.len and p.cmd[i] in {':', '='} or
if p.cmd[i] in {':', '='}: card(p.shortNoVal) > 0 and p.key.string[0] notin p.shortNoVal:
if i < p.cmd.len and p.cmd[i] in {':', '='}:
inc(i) inc(i)
p.inShortState = false p.inShortState = false
while p.cmd[i] in {'\x09', ' '}: inc(i) while i < p.cmd.len and p.cmd[i] in {'\x09', ' '}: inc(i)
i = parseWord(p.cmd, i, p.val.string) i = parseWord(p.cmd, i, p.val.string)
if p.cmd[i] == '\0': p.inShortState = false if i >= p.cmd.len: 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
while p.cmd[i] in {'\x09', ' '}: inc(i) while i < p.cmd.len and p.cmd[i] in {'\x09', ' '}: inc(i)
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] if i >= p.cmd.len:
of '\0':
p.kind = cmdEnd p.kind = cmdEnd
of '-': return
if p.cmd[i] == '-':
inc(i) inc(i)
if p.cmd[i] == '-': if i < p.cmd.len and 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, {' ', '\x09', ':', '='})
while p.cmd[i] in {'\x09', ' '}: inc(i) while i < p.cmd.len and p.cmd[i] in {'\x09', ' '}: inc(i)
if p.cmd[i] in {':', '='} or len(p.longNoVal) > 0 and p.key.string notin p.longNoVal: if i < p.cmd.len and p.cmd[i] in {':', '='} or
if p.cmd[i] in {':', '='}: len(p.longNoVal) > 0 and p.key.string notin p.longNoVal:
if i < p.cmd.len and p.cmd[i] in {':', '='}:
inc(i) inc(i)
while p.cmd[i] in {'\x09', ' '}: inc(i) while i < p.cmd.len and 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