parseopt2.nim 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2015 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## This module provides the standard Nim command line parser.
  10. ## It supports one convenience iterator over all command line options and some
  11. ## lower-level features.
  12. ##
  13. ## Supported syntax:
  14. ##
  15. ## 1. short options - `-abcd`, where a, b, c, d are names
  16. ## 2. long option - `--foo:bar`, `--foo=bar` or `--foo`
  17. ## 3. argument - everything else
  18. {.deprecated: "Use the 'parseopt' module instead".}
  19. {.push debugger: off.}
  20. include "system/inclrtl"
  21. import
  22. os, strutils
  23. type
  24. CmdLineKind* = enum ## the detected command line token
  25. cmdEnd, ## end of command line reached
  26. cmdArgument, ## argument detected
  27. cmdLongOption, ## a long option `--option` detected
  28. cmdShortOption ## a short option `-c` detected
  29. OptParser* =
  30. object of RootObj ## this object implements the command line parser
  31. cmd: seq[string]
  32. pos: int
  33. remainingShortOptions: string
  34. kind*: CmdLineKind ## the detected command line token
  35. key*, val*: string ## key and value pair; `key` is the option
  36. ## or the argument, `value` is not "" if
  37. ## the option was given a value
  38. proc initOptParser*(cmdline: seq[string]): OptParser {.rtl.} =
  39. ## Initializes option parses with cmdline. cmdline should not contain
  40. ## argument 0 - program name.
  41. ## If cmdline.len == 0 default to current command line arguments.
  42. result.remainingShortOptions = ""
  43. when not defined(createNimRtl):
  44. if cmdline.len == 0:
  45. result.cmd = commandLineParams()
  46. return
  47. else:
  48. assert cmdline != nil, "Cannot determine command line arguments."
  49. result.cmd = @cmdline
  50. when not defined(createNimRtl):
  51. proc initOptParser*(): OptParser =
  52. ## Initializes option parser from current command line arguments.
  53. return initOptParser(commandLineParams())
  54. proc next*(p: var OptParser) {.rtl, extern: "npo2$1".}
  55. proc nextOption(p: var OptParser, token: string, allowEmpty: bool) =
  56. for splitchar in [':', '=']:
  57. if splitchar in token:
  58. let pos = token.find(splitchar)
  59. p.key = token[0..pos-1]
  60. p.val = token[pos+1..token.len-1]
  61. return
  62. p.key = token
  63. if allowEmpty:
  64. p.val = ""
  65. else:
  66. p.remainingShortOptions = token[0..token.len-1]
  67. p.next()
  68. proc next(p: var OptParser) =
  69. if p.remainingShortOptions.len != 0:
  70. p.kind = cmdShortOption
  71. p.key = p.remainingShortOptions[0..0]
  72. p.val = ""
  73. p.remainingShortOptions = p.remainingShortOptions[1..p.remainingShortOptions.len-1]
  74. return
  75. if p.pos >= p.cmd.len:
  76. p.kind = cmdEnd
  77. return
  78. let token = p.cmd[p.pos]
  79. p.pos += 1
  80. if token.startsWith("--"):
  81. p.kind = cmdLongOption
  82. nextOption(p, token[2..token.len-1], allowEmpty=true)
  83. elif token.startsWith("-"):
  84. p.kind = cmdShortOption
  85. nextOption(p, token[1..token.len-1], allowEmpty=true)
  86. else:
  87. p.kind = cmdArgument
  88. p.key = token
  89. p.val = ""
  90. proc cmdLineRest*(p: OptParser): string {.rtl, extern: "npo2$1".} =
  91. ## Returns the part of command line string that has not been parsed yet,
  92. ## properly quoted.
  93. return p.cmd[p.pos..p.cmd.len-1].quoteShellCommand
  94. type
  95. GetoptResult* = tuple[kind: CmdLineKind, key, val: string]
  96. iterator getopt*(p: var OptParser): GetoptResult =
  97. ## This is an convenience iterator for iterating over the given OptParser object.
  98. ## Example:
  99. ##
  100. ## .. code-block:: nim
  101. ## var p = initOptParser("--left --debug:3 -l=4 -r:2")
  102. ## for kind, key, val in p.getopt():
  103. ## case kind
  104. ## of cmdArgument:
  105. ## filename = key
  106. ## of cmdLongOption, cmdShortOption:
  107. ## case key
  108. ## of "help", "h": writeHelp()
  109. ## of "version", "v": writeVersion()
  110. ## of cmdEnd: assert(false) # cannot happen
  111. ## if filename == "":
  112. ## # no filename has been given, so we show the help:
  113. ## writeHelp()
  114. p.pos = 0
  115. while true:
  116. next(p)
  117. if p.kind == cmdEnd: break
  118. yield (p.kind, p.key, p.val)
  119. when declared(paramCount):
  120. iterator getopt*(): GetoptResult =
  121. ## This is an convenience iterator for iterating over the command line arguments.
  122. ## This create a new OptParser object.
  123. ## See above for a more detailed example
  124. ##
  125. ## .. code-block:: nim
  126. ## for kind, key, val in getopt():
  127. ## # this will iterate over all arguments passed to the cmdline.
  128. ## continue
  129. ##
  130. var p = initOptParser()
  131. while true:
  132. next(p)
  133. if p.kind == cmdEnd: break
  134. yield (p.kind, p.key, p.val)
  135. {.pop.}