about summary refs log blame commit diff stats
path: root/src/utils/twtstr.nim
blob: ef81edc4c456541bdcd1391ac573bdd0b11f3c89 (plain) (tree)
1
2
3
4
5
6
7
8
9

               
              

             
         
           
            
               


                    
 


                                                         
 


                                                                     
 










                                                                          

                            
                                                

                                           
            
 


                                                      
                            
 
                                   
                                           
 
                                    
                                               

                                    




                                        




                                   
                                       


                                          
                                     






                                     
                                      

                                              

                                       
                                 





                                                           
         
           











                                                           

















                                                                     























                                            
                     

                              
                  



                              
                  


                            






                                                                   
 


                                 
                                   
                                               

                                   
                                          
 



                                                       
 
                                               
                               


                                    



                                                        
 




























                                                                                                   




                                      
                            





                     































                         



















































                                                


                                    



























                                                
                                      











































                                                                                         





















                                             
                                                









                                                
              

                                                
              

                                               
              
 







                                                     
 

                           
 



                                                                             


                                                          
                                                                             
 

                                                                              





                                                                       

                                                                           
 


                                                                            
 

                                                                             
 
 

                                                                              


















































                                                                   
                               
                  
                           










                                                                         




                                                 
                                               


















                                     



                                                                            



                           
                                   
 


                             
 


                                
 














                                                                              
 






















































                                                                  
  



























                                                                               
 
                                   
                                                    
                            

             
                   
 



                                      











                                                                                                                                                           




                                         
















                                       
                                                
























                                                         













                                                                          























                                            
import terminal
import strutils
import unicode
import tables
import json
import os
import math
import sugar
import sequtils

when defined(posix):
  import posix

func ansiStyle*(str: string, style: Style): seq[string] =
  result &= ansiStyleCode(style)
  result &= str

func ansiFgColor*(str: string, color: ForegroundColor): seq[string] =
  result &= ansiForegroundColorCode(color)
  result &= str

func ansiReset*(str: string): seq[string] =
  result &= str
  result &= ansiResetCode

func ansiStyle*(str: seq[string], style: Style): seq[string] =
  return ansiStyleCode(style) & str

func ansiFgColor*(str: seq[string], color: ForegroundColor): seq[string] =
  return ansiForegroundColorCode(color) & str

func ansiReset*(str: seq[string]): seq[string] =
  return str & ansiResetCode

func maxString*(str: string, max: int): string =
  if max < str.runeLen():
    return str.runeSubstr(0, max - 2) & "$"
  return str

func fitValueToSize*(str: string, size: int): string =
  if str.runeLen < size:
    return str & ' '.repeat(size - str.runeLen)
  return str.maxString(size)

func isWhitespace*(c: char): bool =
  return c in {' ', '\n', '\r', '\t', '\f'}

func isControlChar*(c: char): bool =
  return c in {chr(0x00)..chr(0x1F), chr(0x7F)}

func isControlChar*(r: Rune): bool =
  case r
  of Rune(0x00)..Rune(0x1F): return true
  of Rune(0x7F): return true
  else: return false

func genControlCharMap*(): string =
  for c in low(char)..high(char):
    if c == '?':
      result &= char(127)
    else:
      result &= char((int(c) and 0x1f))

const controlCharMap = genControlCharMap()

func getControlChar*(c: char): char =
  return controlCharMap[int(c)]

func genControlLetterMap*(): string =
  for c in low(char)..high(char):
    if c == char(127):
      result &= '?'
    else:
      result &= char((int(c) or 0x40))

const controlLetterMap = genControlLetterMap()

func getControlLetter*(c: char): char =
  return controlLetterMap[int(c)]

func findChar*(str: string, c: char, start: int = 0): int =
  var i = start
  while i < str.len:
    if str[i] == c:
      return i
    inc i
  return -1

func findChar*(str: string, c: Rune, start: int = 0): int =
  var i = start
  var n = i
  while i < str.runeLen():
    var r: Rune
    fastRuneAt(str, n, r)
    if r == c:
      return i
    i = n
  return -1

func getLowerChars*(): string =
  result = ""
  for i in 0..255:
    if chr(i) >= 'A' and chr(i) <= 'Z':
      result &= chr(i + 32)
    else:
      result &= chr(i)

const lowerChars = getLowerChars()

func tolower*(c: char): char =
  return lowerChars[int(c)]

const breakWord = [
  Rune('\n'), Rune('/'), Rune('\\'), Rune(' '), Rune('&'), Rune('='),
  Rune('?'), Rune('.'), Rune(';')
]

func genHexCharMap(): seq[int] =
  for i in 0..255:
    case chr(i)
    of '0'..'9': result &= i - ord('0')
    of 'a'..'f': result &= i - ord('a') + 10
    of 'A'..'F': result &= i - ord('A') + 10
    else: result &= -1

func genDecCharMap(): seq[int] =
  for i in 0..255:
    case chr(i)
    of '0'..'9': result &= i - ord('0')
    else: result &= -1

const hexCharMap = genHexCharMap()
const decCharMap = genDecCharMap()

func hexValue*(c: char): int =
  return hexCharMap[int(c)]

func decValue*(c: char): int =
  return decCharMap[int(c)]

func isAscii*(r: Rune): bool =
  return int(r) < 128

func hexValue*(r: Rune): int =
  if int(r) < 256:
    return hexValue(char(r))
  return -1

func decValue*(r: Rune): int =
  if int(r) < 256:
    return decValue(char(r))
  return -1

func equalsIgnoreCase*(s1: seq[Rune], s2: string): bool =
  var i = 0
  while i < min(s1.len, s2.len):
    if not s1[i].isAscii() or cast[char](s1[i]).tolower() != s2[i]:
      return false
    inc i
  return true

func breaksWord*(r: Rune): bool =
  return r in breakWord

func isAlphaAscii*(r: Rune): bool =
  return int(r) < 256 and isAlphaAscii(char(r))

func isDigitAscii*(r: Rune): bool =
  return int(r) < 256 and isDigit(char(r))

func substr*(s: seq[Rune], i: int, j: int): seq[Rune] =
  if s.len == 0:
    return @[]
  return s[min(high(s), i)..min(high(s), j - 1)]

func substr*(s: seq[Rune], i: int): seq[Rune] =
  if i > high(s) or s.len == 0:
    return @[]
  return s[min(high(s), i)..high(s)]

func skipBlanks*(buf: string, at: int): int =
  result = at
  while result < buf.len and buf[result].isWhitespace():
    inc result

func number_additive*(i: int, range: HSlice[int, int], symbols: openarray[(int, string)]): string =
  if i notin range:
    return $i

  var n = i
  let o = n
  var at = 0
  while n > 0:
    if n >= symbols[at][0]:
      n -= symbols[at][0]
      result &= symbols[at][1]
      continue
    inc at

  return result

const romanNumbers = [
  (1000, "M"), (900, "CM"), (500, "D"), (400, "CD"), (100, "C"), (90, "XC"), (50, "L"),
  (40, "XL"), (10, "X"), (9, "IX"), (5, "V"), (4, "IV"), (1, "I")
]

const romanNumbers_lower = romanNumbers.map((x) => (x[0], x[1].tolower()))

func romanNumber*(i: int): string =
  return number_additive(i, 1..3999, romanNumbers)

func romanNumber_lower*(i: int): string =
  return number_additive(i, 1..3999, romanNumbers_lower)

func japaneseNumber*(i: int): string =
  if i == 0:
    return "〇"
  var n = i
  if i < 0:
    result &= "マイナス"
    n *= -1

  let o = n

  var ss: seq[string]
  var d = 0
  while n > 0:
    let m = n mod 10

    if m != 0:
      case d
      of 1: ss.add("十")
      of 2: ss.add("百")
      of 3: ss.add("千")
      of 4:
        ss.add("万")
        ss.add("一")
      of 5:
        ss.add("万")
        ss.add("十")
      of 6:
        ss.add("万")
        ss.add("百")
      of 7:
        ss.add("万")
        ss.add("千")
        ss.add("一")
      of 8:
        ss.add("億")
        ss.add("一")
      of 9:
        ss.add("億")
        ss.add("十")
      else: discard
    case m
    of 0:
      inc d
      n = n div 10
    of 1:
      if o == n:
        ss.add("一")
    of 2: ss.add("二")
    of 3: ss.add("三")
    of 4: ss.add("四")
    of 5: ss.add("五")
    of 6: ss.add("六")
    of 7: ss.add("七")
    of 8: ss.add("八")
    of 9: ss.add("九")
    else: discard
    n -= m

  n = ss.len - 1
  while n >= 0:
    result &= ss[n]
    dec n

func parseInt32*(s: string): int =
  var sign = 1
  var t = 1
  var integer: int = 0
  var e: int = 0

  var i = 0
  if i < s.len and s[i] == '-':
    sign = -1
    inc i
  elif i < s.len and s[i] == '+':
    inc i

  while i < s.len and isDigit(s[i]):
    integer *= 10
    integer += decValue(s[i])
    inc i

  if i < s.len and (s[i] == 'e' or s[i] == 'E'):
    inc i
    if i < s.len and s[i] == '-':
      t = -1
      inc i
    elif i < s.len and s[i] == '+':
      inc i

    while i < s.len and isDigit(s[i]):
      e *= 10
      e += decValue(s[i])
      inc i

  return sign * integer * 10 ^ (t * e)

func parseInt64*(s: string): int64 =
  var sign = 1
  var t = 1
  var integer: int64 = 0
  var e: int64 = 0

  var i = 0
  if i < s.len and s[i] == '-':
    sign = -1
    inc i
  elif i < s.len and s[i] == '+':
    inc i

  while i < s.len and isDigit(s[i]):
    integer *= 10
    integer += decValue(s[i])
    inc i

  if i < s.len and (s[i] == 'e' or s[i] == 'E'):
    inc i
    if i < s.len and s[i] == '-':
      t = -1
      inc i
    elif i < s.len and s[i] == '+':
      inc i

    while i < s.len and isDigit(s[i]):
      e *= 10
      e += decValue(s[i])
      inc i

  return sign * integer * 10 ^ (t * e)

func parseFloat64*(s: string): float64 =
  var sign = 1
  var t = 1
  var d = 0
  var integer: float64 = 0
  var f: float64 = 0
  var e: float64 = 0

  var i = 0
  if i < s.len and s[i] == '-':
    sign = -1
    inc i
  elif i < s.len and s[i] == '+':
    inc i

  while i < s.len and isDigit(s[i]):
    integer *= 10
    integer += float64(decValue(s[i]))
    inc i

  if i < s.len and s[i] == '.':
    inc i
    while i < s.len and isDigit(s[i]):
      f *= 10
      f += float64(decValue(s[i]))
      inc i
      inc d

  if i < s.len and (s[i] == 'e' or s[i] == 'E'):
    inc i
    if i < s.len and s[i] == '-':
      t = -1
      inc i
    elif i < s.len and s[i] == '+':
      inc i

    while i < s.len and isDigit(s[i]):
      e *= 10
      e += float64(decValue(s[i]))
      inc i

  return float64(sign) * (integer + f * pow(10, float64(-d))) * pow(10, (float64(t) * e))

proc expandPath*(path: string): string =
  if path.len == 0:
    return path
  result = path
  var i = 0
  if path[0] == '~':
    if path.len == 1:
      result = getHomeDir()
    elif path[1] == '/':
      result = getHomeDir() / path.substr(2)
      inc i
    else:
      when defined(posix):
        i = 1
        var usr = ""
        while path[i] != '/':
          usr &= path[i]
          inc i
        let p = getpwnam(usr)
        if p != nil:
          result = $p.pw_dir / path.substr(i)

template CSI*(s: varargs[string, `$`]): string =
  var r = "\e["
  var first = true
  for x in s:
    if not first:
      r &= ";"
    first = false
    r &= x
  r

template SGR*(s: varargs[string, `$`]): string =
  CSI(s) & "m"

template HVP*(s: varargs[string, `$`]): string =
  CSI(s) & "f"

template EL*(s: varargs[string, `$`]): string =
  CSI(s) & "K"

iterator split*(s: seq[Rune], sep: Rune): seq[Rune] =
  var i = 0
  var prev = 0
  while i < s.len:
    if s[i] == sep:
      yield s.substr(prev, i)
      prev = i
    inc i

  if prev < i:
    yield s.substr(prev, i)

# Measure length of runes. From https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
#
# The following two functions define the column width of an ISO 10646
# character as follows:
#
#   - The null character (U+0000) has a column width of 0.
#
#   - Other C0/C1 control characters and DEL will lead to a return value of 0
#
#   - Non-spacing and enclosing combining characters (general category code Mn
#     or Me in the Unicode database) have a column width of 0.
#
#   - SOFT HYPHEN (U+00AD) has a column width of 1.
#
#   - Other format characters (general category code Cf in the Unicode
#     database) and ZERO WIDTH SPACE (U+200B) have a column width of 0.
#
#   - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF) have a
#     column width of 0.
#
#   - Spacing characters in the East Asian Wide (W) or East Asian Full-width
#     (F) category as defined in Unicode Technical Report #11 have a column
#     width of 2.
#
#   - All remaining characters (including all printable ISO 8859-1 and WGL4
#     characters, Unicode control characters, etc.) have a column width of 1.
#

# sorted list of non-overlapping intervals of non-spacing characters generated
# by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c"
const combining = [
  ( 0x0300, 0x036F ), ( 0x0483, 0x0486 ), ( 0x0488, 0x0489 ),
  ( 0x0591, 0x05BD ), ( 0x05BF, 0x05BF ), ( 0x05C1, 0x05C2 ),
  ( 0x05C4, 0x05C5 ), ( 0x05C7, 0x05C7 ), ( 0x0600, 0x0603 ),
  ( 0x0610, 0x0615 ), ( 0x064B, 0x065E ), ( 0x0670, 0x0670 ),
  ( 0x06D6, 0x06E4 ), ( 0x06E7, 0x06E8 ), ( 0x06EA, 0x06ED ),
  ( 0x070F, 0x070F ), ( 0x0711, 0x0711 ), ( 0x0730, 0x074A ),
  ( 0x07A6, 0x07B0 ), ( 0x07EB, 0x07F3 ), ( 0x0901, 0x0902 ),
  ( 0x093C, 0x093C ), ( 0x0941, 0x0948 ), ( 0x094D, 0x094D ),
  ( 0x0951, 0x0954 ), ( 0x0962, 0x0963 ), ( 0x0981, 0x0981 ),
  ( 0x09BC, 0x09BC ), ( 0x09C1, 0x09C4 ), ( 0x09CD, 0x09CD ),
  ( 0x09E2, 0x09E3 ), ( 0x0A01, 0x0A02 ), ( 0x0A3C, 0x0A3C ),
  ( 0x0A41, 0x0A42 ), ( 0x0A47, 0x0A48 ), ( 0x0A4B, 0x0A4D ),
  ( 0x0A70, 0x0A71 ), ( 0x0A81, 0x0A82 ), ( 0x0ABC, 0x0ABC ),
  ( 0x0AC1, 0x0AC5 ), ( 0x0AC7, 0x0AC8 ), ( 0x0ACD, 0x0ACD ),
  ( 0x0AE2, 0x0AE3 ), ( 0x0B01, 0x0B01 ), ( 0x0B3C, 0x0B3C ),
  ( 0x0B3F, 0x0B3F ), ( 0x0B41, 0x0B43 ), ( 0x0B4D, 0x0B4D ),
  ( 0x0B56, 0x0B56 ), ( 0x0B82, 0x0B82 ), ( 0x0BC0, 0x0BC0 ),
  ( 0x0BCD, 0x0BCD ), ( 0x0C3E, 0x0C40 ), ( 0x0C46, 0x0C48 ),
  ( 0x0C4A, 0x0C4D ), ( 0x0C55, 0x0C56 ), ( 0x0CBC, 0x0CBC ),
  ( 0x0CBF, 0x0CBF ), ( 0x0CC6, 0x0CC6 ), ( 0x0CCC, 0x0CCD ),
  ( 0x0CE2, 0x0CE3 ), ( 0x0D41, 0x0D43 ), ( 0x0D4D, 0x0D4D ),
  ( 0x0DCA, 0x0DCA ), ( 0x0DD2, 0x0DD4 ), ( 0x0DD6, 0x0DD6 ),
  ( 0x0E31, 0x0E31 ), ( 0x0E34, 0x0E3A ), ( 0x0E47, 0x0E4E ),
  ( 0x0EB1, 0x0EB1 ), ( 0x0EB4, 0x0EB9 ), ( 0x0EBB, 0x0EBC ),
  ( 0x0EC8, 0x0ECD ), ( 0x0F18, 0x0F19 ), ( 0x0F35, 0x0F35 ),
  ( 0x0F37, 0x0F37 ), ( 0x0F39, 0x0F39 ), ( 0x0F71, 0x0F7E ),
  ( 0x0F80, 0x0F84 ), ( 0x0F86, 0x0F87 ), ( 0x0F90, 0x0F97 ),
  ( 0x0F99, 0x0FBC ), ( 0x0FC6, 0x0FC6 ), ( 0x102D, 0x1030 ),
  ( 0x1032, 0x1032 ), ( 0x1036, 0x1037 ), ( 0x1039, 0x1039 ),
  ( 0x1058, 0x1059 ), ( 0x1160, 0x11FF ), ( 0x135F, 0x135F ),
  ( 0x1712, 0x1714 ), ( 0x1732, 0x1734 ), ( 0x1752, 0x1753 ),
  ( 0x1772, 0x1773 ), ( 0x17B4, 0x17B5 ), ( 0x17B7, 0x17BD ),
  ( 0x17C6, 0x17C6 ), ( 0x17C9, 0x17D3 ), ( 0x17DD, 0x17DD ),
  ( 0x180B, 0x180D ), ( 0x18A9, 0x18A9 ), ( 0x1920, 0x1922 ),
  ( 0x1927, 0x1928 ), ( 0x1932, 0x1932 ), ( 0x1939, 0x193B ),
  ( 0x1A17, 0x1A18 ), ( 0x1B00, 0x1B03 ), ( 0x1B34, 0x1B34 ),
  ( 0x1B36, 0x1B3A ), ( 0x1B3C, 0x1B3C ), ( 0x1B42, 0x1B42 ),
  ( 0x1B6B, 0x1B73 ), ( 0x1DC0, 0x1DCA ), ( 0x1DFE, 0x1DFF ),
  ( 0x200B, 0x200F ), ( 0x202A, 0x202E ), ( 0x2060, 0x2063 ),
  ( 0x206A, 0x206F ), ( 0x20D0, 0x20EF ), ( 0x302A, 0x302F ),
  ( 0x3099, 0x309A ), ( 0xA806, 0xA806 ), ( 0xA80B, 0xA80B ),
  ( 0xA825, 0xA826 ), ( 0xFB1E, 0xFB1E ), ( 0xFE00, 0xFE0F ),
  ( 0xFE20, 0xFE23 ), ( 0xFEFF, 0xFEFF ), ( 0xFFF9, 0xFFFB ),
  ( 0x10A01, 0x10A03 ), ( 0x10A05, 0x10A06 ), ( 0x10A0C, 0x10A0F ),
  ( 0x10A38, 0x10A3A ), ( 0x10A3F, 0x10A3F ), ( 0x1D167, 0x1D169 ),
  ( 0x1D173, 0x1D182 ), ( 0x1D185, 0x1D18B ), ( 0x1D1AA, 0x1D1AD ),
  ( 0x1D242, 0x1D244 ), ( 0xE0001, 0xE0001 ), ( 0xE0020, 0xE007F ),
  ( 0xE0100, 0xE01EF )
]

func is_dwidth(r: Rune): bool =
  let ucs = int(r)
  return (ucs >= 0x1100 and
     (ucs <= 0x115f or                    # Hangul Jamo init. consonants
      ucs == 0x2329 or ucs == 0x232a or
      (ucs >= 0x2e80 and ucs <= 0xa4cf and
       ucs != 0x303f) or                  # CJK ... Yi
      (ucs >= 0xac00 and ucs <= 0xd7a3) or # Hangul Syllables
      (ucs >= 0xf900 and ucs <= 0xfaff) or # CJK Compatibility Ideographs
      (ucs >= 0xfe10 and ucs <= 0xfe19) or # Vertical forms
      (ucs >= 0xfe30 and ucs <= 0xfe6f) or # CJK Compatibility Forms
      (ucs >= 0xff00 and ucs <= 0xff60) or # Fullwidth Forms
      (ucs >= 0xffe0 and ucs <= 0xffe6) or
      (ucs >= 0x20000 and ucs <= 0x2fffd) or
      (ucs >= 0x30000 and ucs <= 0x3fffd)))

func makewidthtable(): array[0..0x10FFFF, byte] =
  for r in low(char)..high(char):
    if r.isControlChar():
      result[int(r)] = 2 #TODO this should be 0
    else:
      result[int(r)] = 1

  var i = 0
  var next_combining = combining[i]
  for ucs in 256..0x10FFFF:
    if ucs >= next_combining[0]:
      if ucs <= next_combining[1]:
        result[ucs] = 0
        continue
      elif i + 1 < combining.len:
        inc i
        next_combining = combining[i]

    if Rune(ucs).is_dwidth():
      result[ucs] = 2
    else:
      result[ucs] = 1

# compute lookup table on startup
# TODO: we could have an option to store it in the executable but honestly I
# don't see the need to
let width_table = makewidthtable()

{.push boundChecks:off.}
func width*(r: Rune): int =
  {.cast(noSideEffect).}:
    return int(width_table[int(r)])

func width*(s: string): int =
  for r in s.runes():
    result += width(r)

func width*(s: seq[Rune]): int =
  for r in s:
    result += width(r)

func width*(s: seq[Rune], min: int, max: int): int =
  var i = min
  var mi = min(max, s.len)
  while i < mi:
    result += width(s[i])
    inc i

func width*(s: seq[Rune], min: int): int =
  var i = min
  while i < s.len:
    result += width(s[i])
    inc i

# sorted list of non-overlapping intervals of East Asian Ambiguous characters,
# generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c"

const ambiguous = [
  ( 0x00A1, 0x00A1 ), ( 0x00A4, 0x00A4 ), ( 0x00A7, 0x00A8 ),
  ( 0x00AA, 0x00AA ), ( 0x00AE, 0x00AE ), ( 0x00B0, 0x00B4 ),
  ( 0x00B6, 0x00BA ), ( 0x00BC, 0x00BF ), ( 0x00C6, 0x00C6 ),
  ( 0x00D0, 0x00D0 ), ( 0x00D7, 0x00D8 ), ( 0x00DE, 0x00E1 ),
  ( 0x00E6, 0x00E6 ), ( 0x00E8, 0x00EA ), ( 0x00EC, 0x00ED ),
  ( 0x00F0, 0x00F0 ), ( 0x00F2, 0x00F3 ), ( 0x00F7, 0x00FA ),
  ( 0x00FC, 0x00FC ), ( 0x00FE, 0x00FE ), ( 0x0101, 0x0101 ),
  ( 0x0111, 0x0111 ), ( 0x0113, 0x0113 ), ( 0x011B, 0x011B ),
  ( 0x0126, 0x0127 ), ( 0x012B, 0x012B ), ( 0x0131, 0x0133 ),
  ( 0x0138, 0x0138 ), ( 0x013F, 0x0142 ), ( 0x0144, 0x0144 ),
  ( 0x0148, 0x014B ), ( 0x014D, 0x014D ), ( 0x0152, 0x0153 ),
  ( 0x0166, 0x0167 ), ( 0x016B, 0x016B ), ( 0x01CE, 0x01CE ),
  ( 0x01D0, 0x01D0 ), ( 0x01D2, 0x01D2 ), ( 0x01D4, 0x01D4 ),
  ( 0x01D6, 0x01D6 ), ( 0x01D8, 0x01D8 ), ( 0x01DA, 0x01DA ),
  ( 0x01DC, 0x01DC ), ( 0x0251, 0x0251 ), ( 0x0261, 0x0261 ),
  ( 0x02C4, 0x02C4 ), ( 0x02C7, 0x02C7 ), ( 0x02C9, 0x02CB ),
  ( 0x02CD, 0x02CD ), ( 0x02D0, 0x02D0 ), ( 0x02D8, 0x02DB ),
  ( 0x02DD, 0x02DD ), ( 0x02DF, 0x02DF ), ( 0x0391, 0x03A1 ),
  ( 0x03A3, 0x03A9 ), ( 0x03B1, 0x03C1 ), ( 0x03C3, 0x03C9 ),
  ( 0x0401, 0x0401 ), ( 0x0410, 0x044F ), ( 0x0451, 0x0451 ),
  ( 0x2010, 0x2010 ), ( 0x2013, 0x2016 ), ( 0x2018, 0x2019 ),
  ( 0x201C, 0x201D ), ( 0x2020, 0x2022 ), ( 0x2024, 0x2027 ),
  ( 0x2030, 0x2030 ), ( 0x2032, 0x2033 ), ( 0x2035, 0x2035 ),
  ( 0x203B, 0x203B ), ( 0x203E, 0x203E ), ( 0x2074, 0x2074 ),
  ( 0x207F, 0x207F ), ( 0x2081, 0x2084 ), ( 0x20AC, 0x20AC ),
  ( 0x2103, 0x2103 ), ( 0x2105, 0x2105 ), ( 0x2109, 0x2109 ),
  ( 0x2113, 0x2113 ), ( 0x2116, 0x2116 ), ( 0x2121, 0x2122 ),
  ( 0x2126, 0x2126 ), ( 0x212B, 0x212B ), ( 0x2153, 0x2154 ),
  ( 0x215B, 0x215E ), ( 0x2160, 0x216B ), ( 0x2170, 0x2179 ),
  ( 0x2190, 0x2199 ), ( 0x21B8, 0x21B9 ), ( 0x21D2, 0x21D2 ),
  ( 0x21D4, 0x21D4 ), ( 0x21E7, 0x21E7 ), ( 0x2200, 0x2200 ),
  ( 0x2202, 0x2203 ), ( 0x2207, 0x2208 ), ( 0x220B, 0x220B ),
  ( 0x220F, 0x220F ), ( 0x2211, 0x2211 ), ( 0x2215, 0x2215 ),
  ( 0x221A, 0x221A ), ( 0x221D, 0x2220 ), ( 0x2223, 0x2223 ),
  ( 0x2225, 0x2225 ), ( 0x2227, 0x222C ), ( 0x222E, 0x222E ),
  ( 0x2234, 0x2237 ), ( 0x223C, 0x223D ), ( 0x2248, 0x2248 ),
  ( 0x224C, 0x224C ), ( 0x2252, 0x2252 ), ( 0x2260, 0x2261 ),
  ( 0x2264, 0x2267 ), ( 0x226A, 0x226B ), ( 0x226E, 0x226F ),
  ( 0x2282, 0x2283 ), ( 0x2286, 0x2287 ), ( 0x2295, 0x2295 ),
  ( 0x2299, 0x2299 ), ( 0x22A5, 0x22A5 ), ( 0x22BF, 0x22BF ),
  ( 0x2312, 0x2312 ), ( 0x2460, 0x24E9 ), ( 0x24EB, 0x254B ),
  ( 0x2550, 0x2573 ), ( 0x2580, 0x258F ), ( 0x2592, 0x2595 ),
  ( 0x25A0, 0x25A1 ), ( 0x25A3, 0x25A9 ), ( 0x25B2, 0x25B3 ),
  ( 0x25B6, 0x25B7 ), ( 0x25BC, 0x25BD ), ( 0x25C0, 0x25C1 ),
  ( 0x25C6, 0x25C8 ), ( 0x25CB, 0x25CB ), ( 0x25CE, 0x25D1 ),
  ( 0x25E2, 0x25E5 ), ( 0x25EF, 0x25EF ), ( 0x2605, 0x2606 ),
  ( 0x2609, 0x2609 ), ( 0x260E, 0x260F ), ( 0x2614, 0x2615 ),
  ( 0x261C, 0x261C ), ( 0x261E, 0x261E ), ( 0x2640, 0x2640 ),
  ( 0x2642, 0x2642 ), ( 0x2660, 0x2661 ), ( 0x2663, 0x2665 ),
  ( 0x2667, 0x266A ), ( 0x266C, 0x266D ), ( 0x266F, 0x266F ),
  ( 0x273D, 0x273D ), ( 0x2776, 0x277F ), ( 0xE000, 0xF8FF ),
  ( 0xFFFD, 0xFFFD ), ( 0xF0000, 0xFFFFD ), ( 0x100000, 0x10FFFD )
]

# 
# The following functions are the same as mk_wcwidth() and mk_wcswidth(),
# except that spacing characters in the East Asian Ambiguous (A) category as
# defined in Unicode Technical Report #11 have a column width of 2. This
# variant might be useful for users of CJK legacy encodings who want to migrate
# to UCS without changing the traditional terminal character-width behaviour.
# It is not otherwise recommended for general use.
#
# TODO: currently these are unused, the user should be able to toggle them

# auxiliary function for binary search in interval table
func bisearch(ucs: Rune, table: openarray[(int, int)]): bool =
  var max = table.high
  var min = 0
  var mid: int

  if int(ucs) < table[0][0] or int(ucs) > table[max][1]:
    return false

  while max >= min:
    mid = (min + max) div 2
    if int(ucs) > table[mid][1]:
      min = mid + 1
    elif int(ucs) < table[mid][0]:
      max = mid - 1
    else:
      return true
  return false


func mk_wcwidth_cjk(r: Rune): int =
  # binary search in table of non-spacing characters
  if bisearch(r, ambiguous):
    return 2;

  return r.width();

func mk_wcswidth_cjk(s: string): int =
  for r in s.runes:
    result += mk_wcwidth_cjk(r)
  return result

const CanHaveDakuten = "かきくけこさしすせそたちつてとはひふへほカキクケコサシスセソタチツテトハヒフヘホ".toRunes()

const CanHaveHandakuten = "はひふへほハヒフヘホ".toRunes()

const HasDakuten = "がぎぐげござじずぜぞだぢづでどばびぶべぼガギグゲゴザジゼゾダヂヅデドバビブベボ".toRunes()

const HasHanDakuten = "ぱぴぷぺぽパピプペポ".toRunes()

#in unicode, char + 1 is dakuten and char + 2 handakuten
#゙゚

const HalfDakuten = "゙".toRunes()[0]
const HalfHanDakuten = "゚".toRunes()[0]

const Dakuten = Rune(0x3099)
const HanDakuten = Rune(0x309A)

func dakuten*(r: Rune): Rune =
  if r in CanHaveDakuten:
    return cast[Rune](cast[int](r) + 1)
  return r

func handakuten*(r: Rune): Rune =
  if r in CanHaveHandakuten:
    return cast[Rune](cast[int](r) + 2)

func nodakuten*(r: Rune): Rune =
  return cast[Rune](cast[int](r) - 1)

func nohandakuten*(r: Rune): Rune =
  return cast[Rune](cast[int](r) - 2)

# Halfwidth to fullwidth & vice versa
const widthconv = staticRead"res/widthconv.json"
proc genHalfWidthTable(): Table[Rune, Rune] =
  let widthconvjson = parseJson(widthconv)
  for k, v in widthconvjson:
    if v.kind == JString:
      result[v.getStr().toRunes()[0]] = k.toRunes()[0]
    else:
      for s in v:
        result[s.getStr().toRunes()[0]] = k.toRunes()[0]

proc genFullWidthTable(): Table[Rune, Rune] =
  let widthconvjson = parseJson(widthconv)
  for k, v in widthconvjson:
    if v.kind == JString:
      result[k.toRunes()[0]] = v.getStr().toRunes()[0]
    else:
      result[k.toRunes()[0]] = v[0].getStr().toRunes()[0]

const halfwidthtable = genHalfWidthTable()
const fullwidthtable = genFullWidthTable()

func halfwidth*(r: Rune): Rune =
  return halfwidthtable.getOrDefault(r, r)

func halfwidth*(s: seq[Rune]): seq[Rune] =
  for r in s:
    #TODO combining dakuten don't always work with half width chars
    #a proper solution would be something like:
    #* try to detect if they work, if not fallback to halfwidth handakuten
    #* add a config option for overriding this
    #* also add an option to completely ignore dakuten
    #* and one to disable half width ruby of course
    if r in HasDakuten:
      result.add(halfwidth(r.nodakuten()))
      result.add(Dakuten)
    elif r in HasHanDakuten:
      result.add(halfwidth(r.nohandakuten()))
      result.add(HanDakuten)
    else:
      result.add(halfwidth(r))

func halfwidth*(s: string): string =
  return $halfwidth(s.toRunes())

func fullwidth*(r: Rune): Rune =
  return fullwidthtable.getOrDefault(r, r)

proc fullwidth*(s: seq[Rune]): seq[Rune] =
  for r in s:
    if r == Rune(0xFF9E): #dakuten
      if result.len > 0:
        result[^1] = result[^1].dakuten()
      else:
        result.add(r)
    elif r == Rune(0xFF9F): #handakuten
      if result.len > 0:
        result[^1] = result[^1].handakuten()
      else:
        result.add(r)
    else:
      result.add(fullwidth(r))

proc fullwidth*(s: string): string =
  return $fullwidth(s.toRunes())
/a>
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767

 
                            
                                         






                                                            


                                                                         
                                             



                                                                               
                                                                     


                                                                          
                                              

                                                
      
                                                                      
                                                                            
 

                                                  




                                                          

                      

                                                                 
                                                                    
 
     
                                                      
                          
                                                                   
 
     
                                                      






                                                                          
 

                                                                              
                                                                      
                                
 
                                      
                      
                                                 
              
 
                                             
                      

                                                                   
                                                                            
                                               
                           
              
 



                                                                   
                                                                            
                                                       


                           
                                           
                      

                                                                   
                                                                           
                           
 

                                                           
                                                     
 
                                                      
                                                          

                                                                                      
              
 
                                                    
                     
                                                 

                      



                                            







                                                                                                 
 
                                                                                           
                                   
          
           

                                                 
                        

                                                                  
               
          
                               
                                                                
                                                      
 
                                                                                       
                                          


                                    
                                                                 
 
                                                                                             

                                                      


                                    

                                                                     
 
                                                                                              
                                           


                                                
                                                                 
 


                                                                                                 
 


                                                                                                
 
                                                                               
                                                                          


                                  
                                         

                   
                                             
                                                    
                                                    
                                                    
                    
                                                 
                                              
                                                       
       
                                                    
                                              
                                                          

                               


                                  
           







                                                                 
                                  





                                                                                            
 
                                                                                         
                       
          
                      



                                                             
                                                             
                                                   
                                                     
                                                            
                                                                         
           



                                                                            
                                                                           
                                             







                                                                          
                                                                           
                      

                                                          
 
                                                                                 












                                                                           
                                                             
                                                                      
                   
                                                                                
                                                          
                                                          
                                                          




                                                                    
                                                            

                                                              
                                                          
                                                       

                                                                 
                                                                 
                                                                       
                                                                     
                                                         
                                                                                     
                                                          
 
                                                                
                                                     
                                                
                

                                  
               
                                   
      
                                                                 
                    
                                                
              
 
                                                                             






                                                                  
                                       
                    
                                                

              



                                                                
                        

                                                                              

                                          
                                                   
                                            
                                                   
 
                                                
                                 


                                                         
 
                                                           
                        
                                                                    

                                          
                                                   
                                            

                                                   
 
                                                                                                
                                

                                            
 

                                                                             
     

                    
                    
                       
                 

                                                                                                              


                                                                

                                                                     

                                                                        
                                  
                                   

                                              
                   

                                            
 

                                                      
 

                                                           

                                                                
                
                                            
                                                         
                
                                            
                      
                    
                                            
                           
                       
                                                                      
                   
                                            
                         

                                                  
         
                                     
                  

                                            
              
                                            
                            
               

                                                            
            

                                                                   
                 
                                              
                                   
                
                                              
                                         
                        
                                              
                                        
                 
                                              
                                      
              
                                              
                                   
                       
                                              
                                          
               
                                              
                        
          
                                            
                      
               
                           
                                           



                          

                                  
                                                  

                                  
                                                  

                        
                                        

                          
                                        

                            

                                                                         
                     


                                                                                      
             




                                                                                                



                           
                                        

                           
                                       
                       

                                                    

                                                                                             
         
                                                                  
                


                                                                      
                  


                                                                          
                        


                                                                                      


                      
                             
                                                  
             
                              
                                                 
         


                                                                             
                   











                                                                                    
                                                                   
               



                                                                                  
                      
                                                                  
                
                                                            
           
                                            
                      
               

                                      
              

                                      
              

                                      
                                                                           
           
                                            
                      
             
                                        

                                              
                 
                                        

                                              
             

                                        

                                           


                                           


                                                                           
                  

                                                                          
                  

                                                                       
                 

                                                                             
               

                                                                         
            

                                                                               
              
                                         

                                     
                                                             
              
                                            
                                                               
               
                                            
                                                                
               
                                              
                                    
                  
                                              
                                       
          
                                            
                                  
                                    
                                                                          
                                    
                                   
           
                                            
                                  
                                   
                                                                          
                                   
                                
                
                                              
                                
                 
                                            
                              



                                           
                     
                                            
                                       
                    
                                              
                          
                
                                              
                            
                
                                              
                       
                 
                                              
                     
                   




                                              
                                
                                                                            
               
                                              
                                           
                   
                                              
                                               
                   
                                              
                                               
                     
                                              
                                                  
                            
                                              
                                      
                                        
                                                                         
           
                                            
                                                                       
              

                                                
                       
          

                                            
             

                                            
                  

                                            
               
                                              
                        
           
                                              
                        
            
                                            
                   
               
                                              
                        
              
                                              
                        
              
                                              
                                   
                     
                                              
                         
                      
                                                 
                         
                                              
                             
          
                                                     
                                            
                    
                    
                                                

          
                                                  
                        
                                                              
                       
                                              
                                            
                                                 
                 


                                            
                  



                                               
                             
                                              
                          
                                                       
       



                                                                               
 
                                                                             
                      
                                                           
                                                     

 
                                                                          


                                                               
                    

                                                        
                                                       
       
                                                           
 
                                                       
                                                                    
                    

                                                              

                                                  
                                       

                          
                            
       
                                                     
                      
                                                                           
                                                  
                                       

                   
#
#
#           The Nim Compiler
#        (c) Copyright 2015 Andreas Rumpf
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#

# This module handles the parsing of command line arguments.


# We do this here before the 'import' statement so 'defined' does not get
# confused with 'TGCMode.gcGenerational' etc.
template bootSwitch(name, expr, userString) =
  # Helper to build boot constants, for debugging you can 'echo' the else part.
  const name = if expr: " " & userString else: ""

bootSwitch(usedRelease, defined(release), "-d:release")
bootSwitch(usedGnuReadline, defined(useLinenoise), "-d:useLinenoise")
bootSwitch(usedBoehm, defined(boehmgc), "--gc:boehm")
bootSwitch(usedMarkAndSweep, defined(gcmarkandsweep), "--gc:markAndSweep")
bootSwitch(usedGenerational, defined(gcgenerational), "--gc:generational")
bootSwitch(usedGoGC, defined(gogc), "--gc:go")
bootSwitch(usedNoGC, defined(nogc), "--gc:none")

import
  os, msgs, options, nversion, condsyms, strutils, extccomp, platform,
  wordrecg, parseutils, nimblecmd, idents, parseopt, sequtils, configuration

# but some have deps to imported modules. Yay.
bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc")
bootSwitch(usedNativeStacktrace,
  defined(nativeStackTrace) and nativeStackTraceSupported,
  "-d:nativeStackTrace")
bootSwitch(usedFFI, hasFFI, "-d:useFFI")

type
  TCmdLinePass* = enum
    passCmd1,                 # first pass over the command line
    passCmd2,                 # second pass over the command line
    passPP                    # preprocessor called processCommand()

const
  HelpMessage = "Nim Compiler Version $1 [$2: $3]\n" &
      "Compiled at $4\n" &
      "Copyright (c) 2006-" & copyrightYear & " by Andreas Rumpf\n"

const
  Usage = slurp"../doc/basicopt.txt".replace("//", "")
  FeatureDesc = block:
    var x = ""
    for f in low(Feature)..high(Feature):
      if x.len > 0: x.add "|"
      x.add $f
    x
  AdvancedUsage = slurp"../doc/advopt.txt".replace("//", "") % FeatureDesc

proc getCommandLineDesc(): string =
  result = (HelpMessage % [VersionAsString, platform.OS[platform.hostOS].name,
                           CPU[platform.hostCPU].name, CompileDate]) &
                           Usage

proc helpOnError(pass: TCmdLinePass) =
  if pass == passCmd1:
    msgWriteln(getCommandLineDesc(), {msgStdout})
    msgQuit(0)

proc writeAdvancedUsage(pass: TCmdLinePass) =
  if pass == passCmd1:
    msgWriteln(`%`(HelpMessage, [VersionAsString,
                                 platform.OS[platform.hostOS].name,
                                 CPU[platform.hostCPU].name, CompileDate]) &
                                 AdvancedUsage,
               {msgStdout})
    msgQuit(0)

proc writeFullhelp(pass: TCmdLinePass) =
  if pass == passCmd1:
    msgWriteln(`%`(HelpMessage, [VersionAsString,
                                 platform.OS[platform.hostOS].name,
                                 CPU[platform.hostCPU].name, CompileDate]) &
                                 Usage & AdvancedUsage,
               {msgStdout})
    msgQuit(0)

proc writeVersionInfo(pass: TCmdLinePass) =
  if pass == passCmd1:
    msgWriteln(`%`(HelpMessage, [VersionAsString,
                                 platform.OS[platform.hostOS].name,
                                 CPU[platform.hostCPU].name, CompileDate]),
               {msgStdout})

    const gitHash = gorge("git log -n 1 --format=%H").strip
    when gitHash.len == 40:
      msgWriteln("git hash: " & gitHash, {msgStdout})

    msgWriteln("active boot switches:" & usedRelease &
      usedTinyC & usedGnuReadline & usedNativeStacktrace &
      usedFFI & usedBoehm & usedMarkAndSweep & usedGenerational & usedGoGC & usedNoGC,
               {msgStdout})
    msgQuit(0)

proc writeCommandLineUsage*(helpWritten: var bool) =
  if not helpWritten:
    msgWriteln(getCommandLineDesc(), {msgStdout})
    helpWritten = true

proc addPrefix(switch: string): string =
  if len(switch) == 1: result = "-" & switch
  else: result = "--" & switch

const
  errInvalidCmdLineOption = "invalid command line option: '$1'"
  errOnOrOffExpectedButXFound = "'on' or 'off' expected, but '$1' found"
  errOnOffOrListExpectedButXFound = "'on', 'off' or 'list' expected, but '$1' found"

proc invalidCmdLineOption(conf: ConfigRef; pass: TCmdLinePass, switch: string, info: TLineInfo) =
  if switch == " ": localError(conf, info, errInvalidCmdLineOption % "-")
  else: localError(conf, info, errInvalidCmdLineOption % addPrefix(switch))

proc splitSwitch(conf: ConfigRef; switch: string, cmd, arg: var string, pass: TCmdLinePass,
                 info: TLineInfo) =
  cmd = ""
  var i = 0
  if i < len(switch) and switch[i] == '-': inc(i)
  if i < len(switch) and switch[i] == '-': inc(i)
  while i < len(switch):
    case switch[i]
    of 'a'..'z', 'A'..'Z', '0'..'9', '_', '.': add(cmd, switch[i])
    else: break
    inc(i)
  if i >= len(switch): arg = ""
  elif switch[i] in {':', '=', '['}: arg = substr(switch, i + 1)
  else: invalidCmdLineOption(conf, pass, switch, info)

proc processOnOffSwitch(conf: ConfigRef; op: TOptions, arg: string, pass: TCmdLinePass,
                        info: TLineInfo) =
  case arg.normalize
  of "on": gOptions = gOptions + op
  of "off": gOptions = gOptions - op
  else: localError(conf, info, errOnOrOffExpectedButXFound % arg)

proc processOnOffSwitchOrList(conf: ConfigRef; op: TOptions, arg: string, pass: TCmdLinePass,
                              info: TLineInfo): bool =
  result = false
  case arg.normalize
  of "on": gOptions = gOptions + op
  of "off": gOptions = gOptions - op
  of "list": result = true
  else: localError(conf, info, errOnOffOrListExpectedButXFound % arg)

proc processOnOffSwitchG(conf: ConfigRef; op: TGlobalOptions, arg: string, pass: TCmdLinePass,
                         info: TLineInfo) =
  case arg.normalize
  of "on": gGlobalOptions = gGlobalOptions + op
  of "off": gGlobalOptions = gGlobalOptions - op
  else: localError(conf, info, errOnOrOffExpectedButXFound % arg)

proc expectArg(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
  if arg == "":
    localError(conf, info, "argument for command line option expected: '$1'" % addPrefix(switch))

proc expectNoArg(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
  if arg != "":
    localError(conf, info, "invalid argument for command line option: '$1'" % addPrefix(switch))

proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
                         info: TLineInfo; orig: string; conf: ConfigRef) =
  var id = ""  # arg = "X]:on|off"
  var i = 0
  var n = hintMin
  while i < len(arg) and (arg[i] != ']'):
    add(id, arg[i])
    inc(i)
  if i < len(arg) and (arg[i] == ']'): inc(i)
  else: invalidCmdLineOption(conf, pass, orig, info)
  if i < len(arg) and (arg[i] in {':', '='}): inc(i)
  else: invalidCmdLineOption(conf, pass, orig, info)
  if state == wHint:
    let x = findStr(configuration.HintsToStr, id)
    if x >= 0: n = TNoteKind(x + ord(hintMin))
    else: localError(conf, info, "unknown hint: " & id)
  else:
    let x = findStr(configuration.WarningsToStr, id)
    if x >= 0: n = TNoteKind(x + ord(warnMin))
    else: localError(conf, info, "unknown warning: " & id)
  case substr(arg, i).normalize
  of "on":
    incl(conf.notes, n)
    incl(conf.mainPackageNotes, n)
    incl(conf.enableNotes, n)
  of "off":
    excl(conf.notes, n)
    excl(conf.mainPackageNotes, n)
    incl(conf.disableNotes, n)
    excl(conf.foreignPackageNotes, n)
  else: localError(conf, info, errOnOrOffExpectedButXFound % arg)

proc processCompile(conf: ConfigRef; filename: string) =
  var found = findFile(conf, filename)
  if found == "": found = filename
  extccomp.addExternalFileToCompile(conf, found)

const
  errNoneBoehmRefcExpectedButXFound = "'none', 'boehm' or 'refc' expected, but '$1' found"
  errNoneSpeedOrSizeExpectedButXFound = "'none', 'speed' or 'size' expected, but '$1' found"
  errGuiConsoleOrLibExpectedButXFound = "'gui', 'console' or 'lib' expected, but '$1' found"

proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo): bool =
  case switch.normalize
  of "gc":
    case arg.normalize
    of "boehm":        result = gSelectedGC == gcBoehm
    of "refc":         result = gSelectedGC == gcRefc
    of "v2":           result = gSelectedGC == gcV2
    of "markandsweep": result = gSelectedGC == gcMarkAndSweep
    of "generational": result = gSelectedGC == gcGenerational
    of "go":           result = gSelectedGC == gcGo
    of "none":         result = gSelectedGC == gcNone
    of "stack", "regions": result = gSelectedGC == gcRegions
    else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg)
  of "opt":
    case arg.normalize
    of "speed": result = contains(gOptions, optOptimizeSpeed)
    of "size": result = contains(gOptions, optOptimizeSize)
    of "none": result = gOptions * {optOptimizeSpeed, optOptimizeSize} == {}
    else: localError(conf, info, errNoneSpeedOrSizeExpectedButXFound % arg)
  of "verbosity": result = $gVerbosity == arg
  of "app":
    case arg.normalize
    of "gui":       result = contains(gGlobalOptions, optGenGuiApp)
    of "console":   result = not contains(gGlobalOptions, optGenGuiApp)
    of "lib":       result = contains(gGlobalOptions, optGenDynLib) and
                      not contains(gGlobalOptions, optGenGuiApp)
    of "staticlib": result = contains(gGlobalOptions, optGenStaticLib) and
                      not contains(gGlobalOptions, optGenGuiApp)
    else: localError(conf, info, errGuiConsoleOrLibExpectedButXFound % arg)
  of "dynliboverride":
    result = isDynlibOverride(conf, arg)
  else: invalidCmdLineOption(conf, passCmd1, switch, info)

proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool =
  case switch.normalize
  of "debuginfo": result = contains(gGlobalOptions, optCDebug)
  of "compileonly", "c": result = contains(gGlobalOptions, optCompileOnly)
  of "nolinking": result = contains(gGlobalOptions, optNoLinking)
  of "nomain": result = contains(gGlobalOptions, optNoMain)
  of "forcebuild", "f": result = contains(gGlobalOptions, optForceFullMake)
  of "warnings", "w": result = contains(gOptions, optWarns)
  of "hints": result = contains(gOptions, optHints)
  of "threadanalysis": result = contains(gGlobalOptions, optThreadAnalysis)
  of "stacktrace": result = contains(gOptions, optStackTrace)
  of "linetrace": result = contains(gOptions, optLineTrace)
  of "debugger": result = contains(gOptions, optEndb)
  of "profiler": result = contains(gOptions, optProfiler)
  of "memtracker": result = contains(gOptions, optMemTracker)
  of "checks", "x": result = gOptions * ChecksOptions == ChecksOptions
  of "floatchecks":
    result = gOptions * {optNaNCheck, optInfCheck} == {optNaNCheck, optInfCheck}
  of "infchecks": result = contains(gOptions, optInfCheck)
  of "nanchecks": result = contains(gOptions, optNaNCheck)
  of "nilchecks": result = contains(gOptions, optNilCheck)
  of "objchecks": result = contains(gOptions, optObjCheck)
  of "fieldchecks": result = contains(gOptions, optFieldCheck)
  of "rangechecks": result = contains(gOptions, optRangeCheck)
  of "boundchecks": result = contains(gOptions, optBoundsCheck)
  of "overflowchecks": result = contains(gOptions, optOverflowCheck)
  of "movechecks": result = contains(gOptions, optMoveCheck)
  of "linedir": result = contains(gOptions, optLineDir)
  of "assertions", "a": result = contains(gOptions, optAssert)
  of "run", "r": result = contains(gGlobalOptions, optRun)
  of "symbolfiles": result = gSymbolFiles != disabledSf
  of "genscript": result = contains(gGlobalOptions, optGenScript)
  of "threads": result = contains(gGlobalOptions, optThreads)
  of "taintmode": result = contains(gGlobalOptions, optTaintMode)
  of "tlsemulation": result = contains(gGlobalOptions, optTlsEmulation)
  of "implicitstatic": result = contains(gOptions, optImplicitStatic)
  of "patterns": result = contains(gOptions, optPatterns)
  of "excessivestacktrace": result = contains(gGlobalOptions, optExcessiveStackTrace)
  else: invalidCmdLineOption(conf, passCmd1, switch, info)

proc processPath(conf: ConfigRef; path: string, info: TLineInfo,
                 notRelativeToProj = false): string =
  let p = if os.isAbsolute(path) or '$' in path:
            path
          elif notRelativeToProj:
            getCurrentDir() / path
          else:
            conf.projectPath / path
  try:
    result = pathSubs(conf, p, info.toFullPath().splitFile().dir)
  except ValueError:
    localError(conf, info, "invalid path: " & p)
    result = p

proc processCfgPath(conf: ConfigRef; path: string, info: TLineInfo): string =
  let path = if path[0] == '"': strutils.unescape(path) else: path
  let basedir = info.toFullPath().splitFile().dir
  let p = if os.isAbsolute(path) or '$' in path:
            path
          else:
            basedir / path
  try:
    result = pathSubs(conf, p, basedir)
  except ValueError:
    localError(conf, info, "invalid path: " & p)
    result = p

const
  errInvalidNumber = "$1 is not a valid number"

proc trackDirty(conf: ConfigRef; arg: string, info: TLineInfo) =
  var a = arg.split(',')
  if a.len != 4: localError(conf, info,
                            "DIRTY_BUFFER,ORIGINAL_FILE,LINE,COLUMN expected")
  var line, column: int
  if parseUtils.parseInt(a[2], line) <= 0:
    localError(conf, info, errInvalidNumber % a[1])
  if parseUtils.parseInt(a[3], column) <= 0:
    localError(conf, info, errInvalidNumber % a[2])

  let dirtyOriginalIdx = fileInfoIdx(conf, a[1])
  if dirtyOriginalIdx.int32 >= 0:
    msgs.setDirtyFile(dirtyOriginalIdx, a[0])

  gTrackPos = newLineInfo(dirtyOriginalIdx, line, column)

proc track(conf: ConfigRef; arg: string, info: TLineInfo) =
  var a = arg.split(',')
  if a.len != 3: localError(conf, info, "FILE,LINE,COLUMN expected")
  var line, column: int
  if parseUtils.parseInt(a[1], line) <= 0:
    localError(conf, info, errInvalidNumber % a[1])
  if parseUtils.parseInt(a[2], column) <= 0:
    localError(conf, info, errInvalidNumber % a[2])
  gTrackPos = newLineInfo(conf, a[0], line, column)

proc dynlibOverride(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
  if pass in {passCmd2, passPP}:
    expectArg(conf, switch, arg, pass, info)
    options.inclDynlibOverride(conf, arg)

proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
                    conf: ConfigRef) =
  var
    theOS: TSystemOS
    cpu: TSystemCPU
    key, val: string
  case switch.normalize
  of "path", "p":
    expectArg(conf, switch, arg, pass, info)
    addPath(conf, if pass == passPP: processCfgPath(conf, arg, info) else: processPath(conf, arg, info), info)
  of "nimblepath", "babelpath":
    # keep the old name for compat
    if pass in {passCmd2, passPP} and not options.gNoNimblePath:
      expectArg(conf, switch, arg, pass, info)
      var path = processPath(conf, arg, info, notRelativeToProj=true)
      let nimbleDir = getEnv("NIMBLE_DIR")
      if nimbleDir.len > 0 and pass == passPP: path = nimbleDir / "pkgs"
      nimblePath(conf, path, info)
  of "nonimblepath", "nobabelpath":
    expectNoArg(conf, switch, arg, pass, info)
    disableNimblePath(conf)
  of "excludepath":
    expectArg(conf, switch, arg, pass, info)
    let path = processPath(conf, arg, info)

    conf.searchPaths.keepItIf(cmpPaths(it, path) != 0)
    conf.lazyPaths.keepItIf(cmpPaths(it, path) != 0)

    if (len(path) > 0) and (path[len(path) - 1] == DirSep):
      let strippedPath = path[0 .. (len(path) - 2)]
      conf.searchPaths.keepItIf(cmpPaths(it, strippedPath) != 0)
      conf.lazyPaths.keepItIf(cmpPaths(it, strippedPath) != 0)
  of "nimcache":
    expectArg(conf, switch, arg, pass, info)
    conf.nimcacheDir = processPath(conf, arg, info, true)
  of "out", "o":
    expectArg(conf, switch, arg, pass, info)
    conf.outFile = arg
  of "docseesrcurl":
    expectArg(conf, switch, arg, pass, info)
    conf.docSeeSrcUrl = arg
  of "mainmodule", "m":
    discard "allow for backwards compatibility, but don't do anything"
  of "define", "d":
    expectArg(conf, switch, arg, pass, info)
    if {':', '='} in arg:
      splitSwitch(conf, arg, key, val, pass, info)
      defineSymbol(conf.symbols, key, val)
    else:
      defineSymbol(conf.symbols, arg)
  of "undef", "u":
    expectArg(conf, switch, arg, pass, info)
    undefSymbol(conf.symbols, arg)
  of "symbol":
    expectArg(conf, switch, arg, pass, info)
    # deprecated, do nothing
  of "compile":
    expectArg(conf, switch, arg, pass, info)
    if pass in {passCmd2, passPP}: processCompile(conf, arg)
  of "link":
    expectArg(conf, switch, arg, pass, info)
    if pass in {passCmd2, passPP}: addExternalFileToLink(conf, arg)
  of "debuginfo":
    expectNoArg(conf, switch, arg, pass, info)
    incl(gGlobalOptions, optCDebug)
  of "embedsrc":
    expectNoArg(conf, switch, arg, pass, info)
    incl(gGlobalOptions, optEmbedOrigSrc)
  of "compileonly", "c":
    expectNoArg(conf, switch, arg, pass, info)
    incl(gGlobalOptions, optCompileOnly)
  of "nolinking":
    expectNoArg(conf, switch, arg, pass, info)
    incl(gGlobalOptions, optNoLinking)
  of "nomain":
    expectNoArg(conf, switch, arg, pass, info)
    incl(gGlobalOptions, optNoMain)
  of "forcebuild", "f":
    expectNoArg(conf, switch, arg, pass, info)
    incl(gGlobalOptions, optForceFullMake)
  of "project":
    expectNoArg(conf, switch, arg, pass, info)
    gWholeProject = true
  of "gc":
    expectArg(conf, switch, arg, pass, info)
    case arg.normalize
    of "boehm":
      gSelectedGC = gcBoehm
      defineSymbol(conf.symbols, "boehmgc")
    of "refc":
      gSelectedGC = gcRefc
    of "v2":
      gSelectedGC = gcV2
    of "markandsweep":
      gSelectedGC = gcMarkAndSweep
      defineSymbol(conf.symbols, "gcmarkandsweep")
    of "generational":
      gSelectedGC = gcGenerational
      defineSymbol(conf.symbols, "gcgenerational")
    of "go":
      gSelectedGC = gcGo
      defineSymbol(conf.symbols, "gogc")
    of "none":
      gSelectedGC = gcNone
      defineSymbol(conf.symbols, "nogc")
    of "stack", "regions":
      gSelectedGC= gcRegions
      defineSymbol(conf.symbols, "gcregions")
    else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg)
  of "warnings", "w":
    if processOnOffSwitchOrList(conf, {optWarns}, arg, pass, info): listWarnings(conf)
  of "warning": processSpecificNote(arg, wWarning, pass, info, switch, conf)
  of "hint": processSpecificNote(arg, wHint, pass, info, switch, conf)
  of "hints":
    if processOnOffSwitchOrList(conf, {optHints}, arg, pass, info): listHints(conf)
  of "threadanalysis": processOnOffSwitchG(conf, {optThreadAnalysis}, arg, pass, info)
  of "stacktrace": processOnOffSwitch(conf, {optStackTrace}, arg, pass, info)
  of "excessivestacktrace": processOnOffSwitchG(conf, {optExcessiveStackTrace}, arg, pass, info)
  of "linetrace": processOnOffSwitch(conf, {optLineTrace}, arg, pass, info)
  of "debugger":
    case arg.normalize
    of "on", "endb":
      gOptions.incl optEndb
      defineSymbol(conf.symbols, "endb")
    of "off":
      gOptions.excl optEndb
      undefSymbol(conf.symbols, "endb")
    of "native", "gdb":
      incl(gGlobalOptions, optCDebug)
      gOptions = gOptions + {optLineDir} - {optEndb}
      defineSymbol(conf.symbols, "nimTypeNames") # type names are used in gdb pretty printing
      undefSymbol(conf.symbols, "endb")
    else:
      localError(conf, info, "expected endb|gdb but found " & arg)
  of "profiler":
    processOnOffSwitch(conf, {optProfiler}, arg, pass, info)
    if optProfiler in gOptions: defineSymbol(conf.symbols, "profiler")
    else: undefSymbol(conf.symbols, "profiler")
  of "memtracker":
    processOnOffSwitch(conf, {optMemTracker}, arg, pass, info)
    if optMemTracker in gOptions: defineSymbol(conf.symbols, "memtracker")
    else: undefSymbol(conf.symbols, "memtracker")
  of "hotcodereloading":
    processOnOffSwitch(conf, {optHotCodeReloading}, arg, pass, info)
    if optHotCodeReloading in gOptions: defineSymbol(conf.symbols, "hotcodereloading")
    else: undefSymbol(conf.symbols, "hotcodereloading")
  of "oldnewlines":
    case arg.normalize
    of "on":
      conf.oldNewlines = true
      defineSymbol(conf.symbols, "nimOldNewlines")
    of "off":
      conf.oldNewlines = false
      undefSymbol(conf.symbols, "nimOldNewlines")
    else:
      localError(conf, info, errOnOrOffExpectedButXFound % arg)
  of "laxstrings": processOnOffSwitch(conf, {optLaxStrings}, arg, pass, info)
  of "checks", "x": processOnOffSwitch(conf, ChecksOptions, arg, pass, info)
  of "floatchecks":
    processOnOffSwitch(conf, {optNaNCheck, optInfCheck}, arg, pass, info)
  of "infchecks": processOnOffSwitch(conf, {optInfCheck}, arg, pass, info)
  of "nanchecks": processOnOffSwitch(conf, {optNaNCheck}, arg, pass, info)
  of "nilchecks": processOnOffSwitch(conf, {optNilCheck}, arg, pass, info)
  of "objchecks": processOnOffSwitch(conf, {optObjCheck}, arg, pass, info)
  of "fieldchecks": processOnOffSwitch(conf, {optFieldCheck}, arg, pass, info)
  of "rangechecks": processOnOffSwitch(conf, {optRangeCheck}, arg, pass, info)
  of "boundchecks": processOnOffSwitch(conf, {optBoundsCheck}, arg, pass, info)
  of "overflowchecks": processOnOffSwitch(conf, {optOverflowCheck}, arg, pass, info)
  of "movechecks": processOnOffSwitch(conf, {optMoveCheck}, arg, pass, info)
  of "linedir": processOnOffSwitch(conf, {optLineDir}, arg, pass, info)
  of "assertions", "a": processOnOffSwitch(conf, {optAssert}, arg, pass, info)
  of "deadcodeelim": discard # deprecated, dead code elim always on
  of "threads":
    processOnOffSwitchG(conf, {optThreads}, arg, pass, info)
    #if optThreads in gGlobalOptions: incl(conf.notes, warnGcUnsafe)
  of "tlsemulation": processOnOffSwitchG(conf, {optTlsEmulation}, arg, pass, info)
  of "taintmode": processOnOffSwitchG(conf, {optTaintMode}, arg, pass, info)
  of "implicitstatic":
    processOnOffSwitch(conf, {optImplicitStatic}, arg, pass, info)
  of "patterns":
    processOnOffSwitch(conf, {optPatterns}, arg, pass, info)
  of "opt":
    expectArg(conf, switch, arg, pass, info)
    case arg.normalize
    of "speed":
      incl(gOptions, optOptimizeSpeed)
      excl(gOptions, optOptimizeSize)
    of "size":
      excl(gOptions, optOptimizeSpeed)
      incl(gOptions, optOptimizeSize)
    of "none":
      excl(gOptions, optOptimizeSpeed)
      excl(gOptions, optOptimizeSize)
    else: localError(conf, info, errNoneSpeedOrSizeExpectedButXFound % arg)
  of "app":
    expectArg(conf, switch, arg, pass, info)
    case arg.normalize
    of "gui":
      incl(gGlobalOptions, optGenGuiApp)
      defineSymbol(conf.symbols, "executable")
      defineSymbol(conf.symbols, "guiapp")
    of "console":
      excl(gGlobalOptions, optGenGuiApp)
      defineSymbol(conf.symbols, "executable")
      defineSymbol(conf.symbols, "consoleapp")
    of "lib":
      incl(gGlobalOptions, optGenDynLib)
      excl(gGlobalOptions, optGenGuiApp)
      defineSymbol(conf.symbols, "library")
      defineSymbol(conf.symbols, "dll")
    of "staticlib":
      incl(gGlobalOptions, optGenStaticLib)
      excl(gGlobalOptions, optGenGuiApp)
      defineSymbol(conf.symbols, "library")
      defineSymbol(conf.symbols, "staticlib")
    else: localError(conf, info, errGuiConsoleOrLibExpectedButXFound % arg)
  of "passc", "t":
    expectArg(conf, switch, arg, pass, info)
    if pass in {passCmd2, passPP}: extccomp.addCompileOptionCmd(conf, arg)
  of "passl", "l":
    expectArg(conf, switch, arg, pass, info)
    if pass in {passCmd2, passPP}: extccomp.addLinkOptionCmd(conf, arg)
  of "cincludes":
    expectArg(conf, switch, arg, pass, info)
    if pass in {passCmd2, passPP}: cIncludes.add processPath(conf, arg, info)
  of "clibdir":
    expectArg(conf, switch, arg, pass, info)
    if pass in {passCmd2, passPP}: cLibs.add processPath(conf, arg, info)
  of "clib":
    expectArg(conf, switch, arg, pass, info)
    if pass in {passCmd2, passPP}: cLinkedLibs.add processPath(conf, arg, info)
  of "header":
    if conf != nil: conf.headerFile = arg
    incl(gGlobalOptions, optGenIndex)
  of "index":
    processOnOffSwitchG(conf, {optGenIndex}, arg, pass, info)
  of "import":
    expectArg(conf, switch, arg, pass, info)
    if pass in {passCmd2, passPP}: conf.implicitImports.add arg
  of "include":
    expectArg(conf, switch, arg, pass, info)
    if pass in {passCmd2, passPP}: conf.implicitIncludes.add arg
  of "listcmd":
    expectNoArg(conf, switch, arg, pass, info)
    incl(gGlobalOptions, optListCmd)
  of "genmapping":
    expectNoArg(conf, switch, arg, pass, info)
    incl(gGlobalOptions, optGenMapping)
  of "os":
    expectArg(conf, switch, arg, pass, info)
    if pass in {passCmd1, passPP}:
      theOS = platform.nameToOS(arg)
      if theOS == osNone: localError(conf, info, "unknown OS: '$1'" % arg)
      elif theOS != platform.hostOS:
        setTarget(theOS, targetCPU)
  of "cpu":
    expectArg(conf, switch, arg, pass, info)
    if pass in {passCmd1, passPP}:
      cpu = platform.nameToCPU(arg)
      if cpu == cpuNone: localError(conf, info, "unknown CPU: '$1'" % arg)
      elif cpu != platform.hostCPU:
        setTarget(targetOS, cpu)
  of "run", "r":
    expectNoArg(conf, switch, arg, pass, info)
    incl(gGlobalOptions, optRun)
  of "verbosity":
    expectArg(conf, switch, arg, pass, info)
    gVerbosity = parseInt(arg)
    conf.notes = NotesVerbosity[gVerbosity]
    incl(conf.notes, conf.enableNotes)
    excl(conf.notes, conf.disableNotes)
    conf.mainPackageNotes = conf.notes
  of "parallelbuild":
    expectArg(conf, switch, arg, pass, info)
    gNumberOfProcessors = parseInt(arg)
  of "version", "v":
    expectNoArg(conf, switch, arg, pass, info)
    writeVersionInfo(pass)
  of "advanced":
    expectNoArg(conf, switch, arg, pass, info)
    writeAdvancedUsage(pass)
  of "fullhelp":
    expectNoArg(conf, switch, arg, pass, info)
    writeFullhelp(pass)
  of "help", "h":
    expectNoArg(conf, switch, arg, pass, info)
    helpOnError(pass)
  of "symbolfiles":
    case arg.normalize
    of "on": gSymbolFiles = enabledSf
    of "off": gSymbolFiles = disabledSf
    of "writeonly": gSymbolFiles = writeOnlySf
    of "readonly": gSymbolFiles = readOnlySf
    of "v2": gSymbolFiles = v2Sf
    else: localError(conf, info, "invalid option for --symbolFiles: " & arg)
  of "skipcfg":
    expectNoArg(conf, switch, arg, pass, info)
    incl(gGlobalOptions, optSkipConfigFile)
  of "skipprojcfg":
    expectNoArg(conf, switch, arg, pass, info)
    incl(gGlobalOptions, optSkipProjConfigFile)
  of "skipusercfg":
    expectNoArg(conf, switch, arg, pass, info)
    incl(gGlobalOptions, optSkipUserConfigFile)
  of "skipparentcfg":
    expectNoArg(conf, switch, arg, pass, info)
    incl(gGlobalOptions, optSkipParentConfigFiles)
  of "genscript", "gendeps":
    expectNoArg(conf, switch, arg, pass, info)
    incl(gGlobalOptions, optGenScript)
    incl(gGlobalOptions, optCompileOnly)
  of "colors": processOnOffSwitchG(conf, {optUseColors}, arg, pass, info)
  of "lib":
    expectArg(conf, switch, arg, pass, info)
    conf.libpath = processPath(conf, arg, info, notRelativeToProj=true)
  of "putenv":
    expectArg(conf, switch, arg, pass, info)
    splitSwitch(conf, arg, key, val, pass, info)
    os.putEnv(key, val)
  of "cc":
    expectArg(conf, switch, arg, pass, info)
    setCC(conf, arg, info)
  of "track":
    expectArg(conf, switch, arg, pass, info)
    track(conf, arg, info)
  of "trackdirty":
    expectArg(conf, switch, arg, pass, info)
    trackDirty(conf, arg, info)
  of "suggest":
    expectNoArg(conf, switch, arg, pass, info)
    conf.ideCmd = ideSug
  of "def":
    expectNoArg(conf, switch, arg, pass, info)
    conf.ideCmd = ideDef
  of "eval":
    expectArg(conf, switch, arg, pass, info)
    gEvalExpr = arg
  of "context":
    expectNoArg(conf, switch, arg, pass, info)
    conf.ideCmd = ideCon
  of "usages":
    expectNoArg(conf, switch, arg, pass, info)
    conf.ideCmd = ideUse
  of "stdout":
    expectNoArg(conf, switch, arg, pass, info)
    incl(gGlobalOptions, optStdout)
  of "listfullpaths":
    expectNoArg(conf, switch, arg, pass, info)
    gListFullPaths = true
  of "dynliboverride":
    dynlibOverride(conf, switch, arg, pass, info)
  of "dynliboverrideall":
    expectNoArg(conf, switch, arg, pass, info)
    gDynlibOverrideAll = true
  of "cs":
    # only supported for compatibility. Does nothing.
    expectArg(conf, switch, arg, pass, info)
  of "experimental":
    if arg.len == 0:
      conf.features.incl oldExperimentalFeatures
    else:
      try:
        conf.features.incl parseEnum[Feature](arg)
      except ValueError:
        localError(conf, info, "unknown experimental feature")
  of "nocppexceptions":
    expectNoArg(conf, switch, arg, pass, info)
    incl(gGlobalOptions, optNoCppExceptions)
    defineSymbol(conf.symbols, "noCppExceptions")
  of "cppdefine":
    expectArg(conf, switch, arg, pass, info)
    if conf != nil:
      conf.cppDefine(arg)
  of "newruntime":
    expectNoArg(conf, switch, arg, pass, info)
    doAssert(conf != nil)
    incl(conf.features, destructor)
    defineSymbol(conf.symbols, "nimNewRuntime")
  of "cppcompiletonamespace":
    expectNoArg(conf, switch, arg, pass, info)
    useNimNamespace = true
    defineSymbol(conf.symbols, "cppCompileToNamespace")
  else:
    if strutils.find(switch, '.') >= 0: options.setConfigVar(conf, switch, arg)
    else: invalidCmdLineOption(conf, pass, switch, info)

template gCmdLineInfo*(): untyped = newLineInfo(FileIndex(0), 1, 1)

proc processCommand*(switch: string, pass: TCmdLinePass; config: ConfigRef) =
  var cmd, arg: string
  splitSwitch(config, switch, cmd, arg, pass, gCmdLineInfo)
  processSwitch(cmd, arg, pass, gCmdLineInfo, config)


proc processSwitch*(pass: TCmdLinePass; p: OptParser; config: ConfigRef) =
  # hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off")
  # we fix this here
  var bracketLe = strutils.find(p.key, '[')
  if bracketLe >= 0:
    var key = substr(p.key, 0, bracketLe - 1)
    var val = substr(p.key, bracketLe + 1) & ':' & p.val
    processSwitch(key, val, pass, gCmdLineInfo, config)
  else:
    processSwitch(p.key, p.val, pass, gCmdLineInfo, config)

proc processArgument*(pass: TCmdLinePass; p: OptParser;
                      argsCount: var int; config: ConfigRef): bool =
  if argsCount == 0:
    # nim filename.nims  is the same as "nim e filename.nims":
    if p.key.endswith(".nims"):
      config.command = "e"
      config.projectName = unixToNativePath(p.key)
      config.arguments = cmdLineRest(p)
      result = true
    elif pass != passCmd2:
      config.command = p.key
  else:
    if pass == passCmd1: config.commandArgs.add p.key
    if argsCount == 1:
      # support UNIX style filenames everywhere for portable build scripts:
      config.projectName = unixToNativePath(p.key)
      config.arguments = cmdLineRest(p)
      result = true
  inc argsCount