mirror of
https://github.com/nim-lang/Nim.git
synced 2026-07-16 22:11:18 +00:00
Merge branch 'devel' into range_float_type
This commit is contained in:
@@ -83,6 +83,11 @@
|
||||
|
||||
- ``nil`` for strings/seqs is finally gone. Instead the default value for
|
||||
these is ``"" / @[]``.
|
||||
- Accessing the binary zero terminator in Nim's native strings
|
||||
is now invalid. Internally a Nim string still has the trailing zero for
|
||||
zero-copy interoperability with ``cstring``. Compile your code with the
|
||||
next switch ``--laxStrings:on`` if you need a transition period.
|
||||
|
||||
|
||||
- Range float types, example `range[0.0 .. Inf]`. More details in language manual.
|
||||
|
||||
|
||||
@@ -63,6 +63,10 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
|
||||
of tyNil:
|
||||
result = genNilStringLiteral(p.module, n.info)
|
||||
of tyString:
|
||||
# with the new semantics for 'nil' strings, we can map "" to nil and
|
||||
# save tons of allocations:
|
||||
#if n.strVal.len == 0: result = genNilStringLiteral(p.module, n.info)
|
||||
#else:
|
||||
result = genStringLiteral(p.module, n)
|
||||
else:
|
||||
if n.strVal.isNil: result = rope("NIM_NIL")
|
||||
@@ -905,14 +909,14 @@ proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) =
|
||||
if ty.kind in {tyRef, tyPtr}:
|
||||
ty = skipTypes(ty.lastSon, abstractVarRange) # emit range check:
|
||||
if optBoundsCheck in p.options:
|
||||
if ty.kind == tyString:
|
||||
if ty.kind == tyString and (not defined(nimNoZeroTerminator) or optLaxStrings in p.options):
|
||||
linefmt(p, cpsStmts,
|
||||
"if (!$2 || (NU)($1) > (NU)($2->$3)) #raiseIndexError();$n",
|
||||
rdLoc(b), rdLoc(a), lenField(p))
|
||||
"if (!$2 || (NU)($1) > (NU)($2->$3)) #raiseIndexError();$n",
|
||||
rdLoc(b), rdLoc(a), lenField(p))
|
||||
else:
|
||||
linefmt(p, cpsStmts,
|
||||
"if (!$2 || (NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n",
|
||||
rdLoc(b), rdLoc(a), lenField(p))
|
||||
"if (!$2 || (NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n",
|
||||
rdLoc(b), rdLoc(a), lenField(p))
|
||||
if d.k == locNone: d.storage = OnHeap
|
||||
if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}:
|
||||
a.r = rfmt(nil, "(*$1)", a.r)
|
||||
|
||||
@@ -188,11 +188,11 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
|
||||
if i < len(arg) and (arg[i] in {':', '='}): inc(i)
|
||||
else: invalidCmdLineOption(pass, orig, info)
|
||||
if state == wHint:
|
||||
var x = findStr(msgs.HintsToStr, id)
|
||||
let x = findStr(msgs.HintsToStr, id)
|
||||
if x >= 0: n = TNoteKind(x + ord(hintMin))
|
||||
else: localError(info, "unknown hint: " & id)
|
||||
else:
|
||||
var x = findStr(msgs.WarningsToStr, id)
|
||||
let x = findStr(msgs.WarningsToStr, id)
|
||||
if x >= 0: n = TNoteKind(x + ord(warnMin))
|
||||
else: localError(info, "unknown warning: " & id)
|
||||
case substr(arg, i).normalize
|
||||
@@ -499,6 +499,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
undefSymbol("nimOldNewlines")
|
||||
else:
|
||||
localError(info, errOnOrOffExpectedButXFound, arg)
|
||||
of "laxstrings": processOnOffSwitch({optLaxStrings}, arg, pass, info)
|
||||
of "checks", "x": processOnOffSwitch(ChecksOptions, arg, pass, info)
|
||||
of "floatchecks":
|
||||
processOnOffSwitch({optNaNCheck, optInfCheck}, arg, pass, info)
|
||||
|
||||
@@ -115,3 +115,4 @@ proc initDefines*() =
|
||||
defineSymbol("nimSymKind")
|
||||
defineSymbol("nimVmEqIdent")
|
||||
defineSymbol("nimNoNil")
|
||||
defineSymbol("nimNoZeroTerminator")
|
||||
|
||||
@@ -165,13 +165,12 @@ proc isKeyword*(kind: TTokType): bool =
|
||||
template ones(n): untyped = ((1 shl n)-1) # for utf-8 conversion
|
||||
|
||||
proc isNimIdentifier*(s: string): bool =
|
||||
if s[0] in SymStartChars:
|
||||
let sLen = s.len
|
||||
if sLen > 0 and s[0] in SymStartChars:
|
||||
var i = 1
|
||||
var sLen = s.len
|
||||
while i < sLen:
|
||||
if s[i] == '_':
|
||||
inc(i)
|
||||
if s[i] notin SymChars: return
|
||||
if s[i] == '_': inc(i)
|
||||
if i < sLen and s[i] notin SymChars: return
|
||||
inc(i)
|
||||
result = true
|
||||
|
||||
@@ -311,12 +310,12 @@ template tokenEndPrevious(tok, pos) =
|
||||
# We need to parse the largest uint literal without overflow checks
|
||||
proc unsafeParseUInt(s: string, b: var BiggestInt, start = 0): int =
|
||||
var i = start
|
||||
if s[i] in {'0'..'9'}:
|
||||
if i < s.len and s[i] in {'0'..'9'}:
|
||||
b = 0
|
||||
while s[i] in {'0'..'9'}:
|
||||
while i < s.len and s[i] in {'0'..'9'}:
|
||||
b = b * 10 + (ord(s[i]) - ord('0'))
|
||||
inc(i)
|
||||
while s[i] == '_': inc(i) # underscores are allowed and ignored
|
||||
while i < s.len and s[i] == '_': inc(i) # underscores are allowed and ignored
|
||||
result = i - start
|
||||
{.pop.} # overflowChecks
|
||||
|
||||
|
||||
@@ -477,6 +477,10 @@ const
|
||||
hintMin* = hintSuccess
|
||||
hintMax* = high(TMsgKind)
|
||||
|
||||
static:
|
||||
doAssert HintsToStr.len == ord(hintMax) - ord(hintMin) + 1
|
||||
doAssert WarningsToStr.len == ord(warnMax) - ord(warnMin) + 1
|
||||
|
||||
type
|
||||
TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints
|
||||
TNoteKinds* = set[TNoteKind]
|
||||
|
||||
@@ -37,7 +37,8 @@ type # please make sure we have under 32 options
|
||||
# evaluation
|
||||
optPatterns, # en/disable pattern matching
|
||||
optMemTracker,
|
||||
optHotCodeReloading
|
||||
optHotCodeReloading,
|
||||
optLaxStrings
|
||||
|
||||
TOptions* = set[TOption]
|
||||
TGlobalOption* = enum # **keep binary compatible**
|
||||
|
||||
@@ -1064,6 +1064,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||
if n.len > 1:
|
||||
let opr = if n[0].kind == nkIdent: n[0].ident
|
||||
elif n[0].kind == nkSym: n[0].sym.name
|
||||
elif n[0].kind in {nkOpenSymChoice, nkClosedSymChoice}: n[0][0].sym.name
|
||||
else: nil
|
||||
if n[1].kind == nkPrefix or (opr != nil and renderer.isKeyword(opr)):
|
||||
put(g, tkSpaces, Space)
|
||||
|
||||
@@ -251,7 +251,7 @@ proc `%`*(frmt: FormatStr, args: openArray[Rope]): Rope =
|
||||
while true:
|
||||
j = j * 10 + ord(frmt[i]) - ord('0')
|
||||
inc(i)
|
||||
if frmt[i] notin {'0'..'9'}: break
|
||||
if i >= frmt.len or frmt[i] notin {'0'..'9'}: break
|
||||
num = j
|
||||
if j > high(args) + 1:
|
||||
errorHandler(rInvalidFormatStr, $(j))
|
||||
|
||||
@@ -51,15 +51,15 @@ proc parseTopLevelStmt*(p: var TParsers): PNode =
|
||||
result = ast.emptyNode
|
||||
|
||||
proc utf8Bom(s: string): int =
|
||||
if s[0] == '\xEF' and s[1] == '\xBB' and s[2] == '\xBF':
|
||||
if s.len >= 3 and s[0] == '\xEF' and s[1] == '\xBB' and s[2] == '\xBF':
|
||||
result = 3
|
||||
else:
|
||||
result = 0
|
||||
|
||||
proc containsShebang(s: string, i: int): bool =
|
||||
if s[i] == '#' and s[i+1] == '!':
|
||||
if i+1 < s.len and s[i] == '#' and s[i+1] == '!':
|
||||
var j = i + 2
|
||||
while s[j] in Whitespace: inc(j)
|
||||
while j < s.len and s[j] in Whitespace: inc(j)
|
||||
result = s[j] == '/'
|
||||
|
||||
proc parsePipe(filename: string, inputStream: PLLStream; cache: IdentCache): PNode =
|
||||
@@ -74,9 +74,9 @@ proc parsePipe(filename: string, inputStream: PLLStream; cache: IdentCache): PNo
|
||||
discard llStreamReadLine(s, line)
|
||||
i = 0
|
||||
inc linenumber
|
||||
if line[i] == '#' and line[i+1] == '?':
|
||||
if i+1 < line.len and line[i] == '#' and line[i+1] == '?':
|
||||
inc(i, 2)
|
||||
while line[i] in Whitespace: inc(i)
|
||||
while i < line.len and line[i] in Whitespace: inc(i)
|
||||
var q: TParser
|
||||
parser.openParser(q, filename, llStreamOpen(substr(line, i)), cache)
|
||||
result = parser.parseAll(q)
|
||||
|
||||
@@ -66,6 +66,8 @@ Advanced options:
|
||||
--excessiveStackTrace:on|off
|
||||
stack traces use full file paths
|
||||
--oldNewlines:on|off turn on|off the old behaviour of "\n"
|
||||
--laxStrings:on|off when turned on, accessing the zero terminator in
|
||||
strings is allowed; only for backwards compatibility
|
||||
--skipCfg do not read the general configuration file
|
||||
--skipUserCfg do not read the user's configuration file
|
||||
--skipParentCfg do not read the parent dirs' configuration files
|
||||
|
||||
@@ -1475,7 +1475,7 @@ mysterious crashes.
|
||||
|
||||
**Note**: The example only works because the memory is initialized to zero
|
||||
(``alloc0`` instead of ``alloc`` does this): ``d.s`` is thus initialized to
|
||||
``nil`` which the string assignment can handle. One needs to know low level
|
||||
binary zero which the string assignment can handle. One needs to know low level
|
||||
details like this when mixing garbage collected data with unmanaged memory.
|
||||
|
||||
.. XXX finalizers for traced objects
|
||||
@@ -2516,8 +2516,8 @@ char '\\0'
|
||||
bool false
|
||||
ref or pointer type nil
|
||||
procedural type nil
|
||||
sequence nil (*not* ``@[]``)
|
||||
string nil (*not* "")
|
||||
sequence ``@[]``
|
||||
string ``""``
|
||||
tuple[x: A, y: B, ...] (default(A), default(B), ...)
|
||||
(analogous for objects)
|
||||
array[0..., T] [default(T), ...]
|
||||
@@ -4274,7 +4274,7 @@ therefore very useful for type specialization within generic code:
|
||||
Table[Key, Value] = object
|
||||
keys: seq[Key]
|
||||
values: seq[Value]
|
||||
when not (Key is string): # nil value for strings used for optimization
|
||||
when not (Key is string): # empty value for strings used for optimization
|
||||
deletedKeys: seq[bool]
|
||||
|
||||
|
||||
@@ -7438,8 +7438,8 @@ code generation directly, but their presence can be detected by macros.
|
||||
Custom pragmas are defined using templates annotated with pragma ``pragma``:
|
||||
|
||||
.. code-block:: nim
|
||||
template dbTable(name: string, table_space: string = nil) {.pragma.}
|
||||
template dbKey(name: string = nil, primary_key: bool = false) {.pragma.}
|
||||
template dbTable(name: string, table_space: string = "") {.pragma.}
|
||||
template dbKey(name: string = "", primary_key: bool = false) {.pragma.}
|
||||
template dbForeignKey(t: typedesc) {.pragma.}
|
||||
template dbIgnore {.pragma.}
|
||||
|
||||
|
||||
18
doc/tut1.rst
18
doc/tut1.rst
@@ -960,11 +960,7 @@ enforced. For example, when reading strings from binary files, they are merely
|
||||
a sequence of bytes. The index operation ``s[i]`` means the i-th *char* of
|
||||
``s``, not the i-th *unichar*.
|
||||
|
||||
String variables are initialized with a special value, called ``nil``. However,
|
||||
most string operations cannot deal with ``nil`` (leading to an exception being
|
||||
raised) for performance reasons. It is best to use empty strings ``""``
|
||||
rather than ``nil`` as the *empty* value. But ``""`` often creates a string
|
||||
object on the heap, so there is a trade-off to be made here.
|
||||
String variables are initialized with the empty strings ``""``.
|
||||
|
||||
|
||||
Integers
|
||||
@@ -1309,11 +1305,7 @@ Example:
|
||||
x: seq[int] # a reference to a sequence of integers
|
||||
x = @[1, 2, 3, 4, 5, 6] # the @ turns the array into a sequence allocated on the heap
|
||||
|
||||
Sequence variables are initialized with ``nil``. However, most sequence
|
||||
operations cannot deal with ``nil`` (leading to an exception being
|
||||
raised) for performance reasons. Thus one should use empty sequences ``@[]``
|
||||
rather than ``nil`` as the *empty* value. But ``@[]`` creates a sequence
|
||||
object on the heap, so there is a trade-off to be made here.
|
||||
Sequence variables are initialized with ``@[]``.
|
||||
|
||||
The ``for`` statement can be used with one or two variables when used with a
|
||||
sequence. When you use the one variable form, the variable will hold the value
|
||||
@@ -1355,11 +1347,9 @@ type does not matter.
|
||||
.. code-block:: nim
|
||||
:test: "nim c $1"
|
||||
var
|
||||
fruits: seq[string] # reference to a sequence of strings that is initialized with 'nil'
|
||||
fruits: seq[string] # reference to a sequence of strings that is initialized with '@[]'
|
||||
capitals: array[3, string] # array of strings with a fixed size
|
||||
|
||||
fruits = @[] # creates an empty sequence on the heap that will be referenced by 'fruits'
|
||||
|
||||
capitals = ["New York", "London", "Berlin"] # array 'capitals' allows assignment of only three elements
|
||||
fruits.add("Banana") # sequence 'fruits' is dynamically expandable during runtime
|
||||
fruits.add("Mango")
|
||||
@@ -1691,7 +1681,7 @@ rules apply:
|
||||
write(stdout, x(3)) # no error: A.x is called
|
||||
write(stdout, x("")) # no error: B.x is called
|
||||
|
||||
proc x*(a: int): string = nil
|
||||
proc x*(a: int): string = discard
|
||||
write(stdout, x(3)) # ambiguous: which `x` is to call?
|
||||
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ proc executeCgi(server: var TServer, client: Socket, path, query: string,
|
||||
dataAvail = recvLine(client, buf)
|
||||
if buf.len == 0:
|
||||
break
|
||||
var L = toLower(buf)
|
||||
var L = toLowerAscii(buf)
|
||||
if L.startsWith("content-length:"):
|
||||
var i = len("content-length:")
|
||||
while L[i] in Whitespace: inc(i)
|
||||
@@ -205,7 +205,7 @@ proc acceptRequest(server: var TServer, client: Socket) =
|
||||
client.close()
|
||||
else:
|
||||
when defined(Windows):
|
||||
var ext = splitFile(path).ext.toLower
|
||||
var ext = splitFile(path).ext.toLowerAscii
|
||||
if ext == ".exe" or ext == ".cgi":
|
||||
# XXX: extract interpreter information here?
|
||||
cgi = true
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
from pcre import nil
|
||||
import nre.private.util
|
||||
import tables
|
||||
from strutils import toLower, `%`
|
||||
from strutils import `%`
|
||||
from math import ceil
|
||||
import options
|
||||
from unicode import runeLenAt
|
||||
@@ -326,15 +326,15 @@ proc `$`*(pattern: RegexMatch): string =
|
||||
|
||||
proc `==`*(a, b: Regex): bool =
|
||||
if not a.isNil and not b.isNil:
|
||||
return a.pattern == b.pattern and
|
||||
a.pcreObj == b.pcreObj and
|
||||
return a.pattern == b.pattern and
|
||||
a.pcreObj == b.pcreObj and
|
||||
a.pcreExtra == b.pcreExtra
|
||||
else:
|
||||
return system.`==`(a, b)
|
||||
|
||||
proc `==`*(a, b: RegexMatch): bool =
|
||||
return a.pattern == b.pattern and
|
||||
a.str == b.str
|
||||
a.str == b.str
|
||||
# }}}
|
||||
|
||||
# Creation & Destruction {{{
|
||||
|
||||
@@ -774,7 +774,7 @@ proc renderImage(d: PDoc, n: PRstNode, result: var string) =
|
||||
Digits + Letters + WhiteSpace)
|
||||
let
|
||||
arg = getArgument(n)
|
||||
isObject = arg.toLower().endsWith(".svg")
|
||||
isObject = arg.toLowerAscii().endsWith(".svg")
|
||||
var
|
||||
options = ""
|
||||
content = ""
|
||||
|
||||
@@ -201,7 +201,7 @@ when defineSsl:
|
||||
flags: set[SocketFlag]) {.async.} =
|
||||
let len = bioCtrlPending(socket.bioOut)
|
||||
if len > 0:
|
||||
var data = newStringOfCap(len)
|
||||
var data = newString(len)
|
||||
let read = bioRead(socket.bioOut, addr data[0], len)
|
||||
assert read != 0
|
||||
if read < 0:
|
||||
|
||||
@@ -52,7 +52,7 @@ template encodeInternal(s: typed, lineLen: int, newLine: string): untyped =
|
||||
if numLines > 0: inc(total, (numLines - 1) * newLine.len)
|
||||
|
||||
result = newString(total)
|
||||
var
|
||||
var
|
||||
i = 0
|
||||
r = 0
|
||||
currLine = 0
|
||||
@@ -76,7 +76,7 @@ template encodeInternal(s: typed, lineLen: int, newLine: string): untyped =
|
||||
currLine = 0
|
||||
|
||||
if i < s.len-1:
|
||||
let
|
||||
let
|
||||
a = ord(s[i])
|
||||
b = ord(s[i+1])
|
||||
result[r] = cb64[a shr 2]
|
||||
@@ -130,11 +130,11 @@ proc decode*(s: string): string =
|
||||
# total is an upper bound, as we will skip arbitrary whitespace:
|
||||
result = newString(total)
|
||||
|
||||
var
|
||||
var
|
||||
i = 0
|
||||
r = 0
|
||||
while true:
|
||||
while s[i] in Whitespace: inc(i)
|
||||
while i < s.len and s[i] in Whitespace: inc(i)
|
||||
if i < s.len-3:
|
||||
let
|
||||
a = s[i].decodeByte
|
||||
|
||||
@@ -97,11 +97,10 @@ iterator decodeData*(data: string): tuple[key, value: TaintedString] =
|
||||
var name = ""
|
||||
var value = ""
|
||||
# decode everything in one pass:
|
||||
while data[i] != '\0':
|
||||
while i < data.len:
|
||||
setLen(name, 0) # reuse memory
|
||||
while true:
|
||||
while i < data.len:
|
||||
case data[i]
|
||||
of '\0': break
|
||||
of '%':
|
||||
var x = 0
|
||||
handleHexChar(data[i+1], x)
|
||||
@@ -112,15 +111,16 @@ iterator decodeData*(data: string): tuple[key, value: TaintedString] =
|
||||
of '=', '&': break
|
||||
else: add(name, data[i])
|
||||
inc(i)
|
||||
if data[i] != '=': cgiError("'=' expected")
|
||||
if i >= data.len or data[i] != '=': cgiError("'=' expected")
|
||||
inc(i) # skip '='
|
||||
setLen(value, 0) # reuse memory
|
||||
while true:
|
||||
while i < data.len:
|
||||
case data[i]
|
||||
of '%':
|
||||
var x = 0
|
||||
handleHexChar(data[i+1], x)
|
||||
handleHexChar(data[i+2], x)
|
||||
if i+2 < data.len:
|
||||
handleHexChar(data[i+1], x)
|
||||
handleHexChar(data[i+2], x)
|
||||
inc(i, 2)
|
||||
add(value, chr(x))
|
||||
of '+': add(value, ' ')
|
||||
@@ -128,9 +128,9 @@ iterator decodeData*(data: string): tuple[key, value: TaintedString] =
|
||||
else: add(value, data[i])
|
||||
inc(i)
|
||||
yield (name.TaintedString, value.TaintedString)
|
||||
if data[i] == '&': inc(i)
|
||||
elif data[i] == '\0': break
|
||||
else: cgiError("'&' expected")
|
||||
if i < data.len:
|
||||
if data[i] == '&': inc(i)
|
||||
else: cgiError("'&' expected")
|
||||
|
||||
iterator decodeData*(allowedMethods: set[RequestMethod] =
|
||||
{methodNone, methodPost, methodGet}): tuple[key, value: TaintedString] =
|
||||
|
||||
@@ -74,18 +74,19 @@ proc rawInsert[T](c: var CritBitTree[T], key: string): Node[T] =
|
||||
var newByte = 0
|
||||
block blockX:
|
||||
while newbyte < key.len:
|
||||
if it.key[newbyte] != key[newbyte]:
|
||||
newotherbits = it.key[newbyte].ord xor key[newbyte].ord
|
||||
let ch = if newbyte < it.key.len: it.key[newbyte] else: '\0'
|
||||
if ch != key[newbyte]:
|
||||
newotherbits = ch.ord xor key[newbyte].ord
|
||||
break blockX
|
||||
inc newbyte
|
||||
if it.key[newbyte] != '\0':
|
||||
if newbyte < it.key.len:
|
||||
newotherbits = it.key[newbyte].ord
|
||||
else:
|
||||
return it
|
||||
while (newOtherBits and (newOtherBits-1)) != 0:
|
||||
newOtherBits = newOtherBits and (newOtherBits-1)
|
||||
newOtherBits = newOtherBits xor 255
|
||||
let ch = it.key[newByte]
|
||||
let ch = if newByte < it.key.len: it.key[newByte] else: '\0'
|
||||
let dir = (1 + (ord(ch) or newOtherBits)) shr 8
|
||||
|
||||
var inner: Node[T]
|
||||
|
||||
@@ -25,16 +25,16 @@ proc parseCookies*(s: string): StringTableRef =
|
||||
result = newStringTable(modeCaseInsensitive)
|
||||
var i = 0
|
||||
while true:
|
||||
while s[i] == ' ' or s[i] == '\t': inc(i)
|
||||
while i < s.len and (s[i] == ' ' or s[i] == '\t'): inc(i)
|
||||
var keystart = i
|
||||
while s[i] != '=' and s[i] != '\0': inc(i)
|
||||
while i < s.len and s[i] != '=': inc(i)
|
||||
var keyend = i-1
|
||||
if s[i] == '\0': break
|
||||
if i >= s.len: break
|
||||
inc(i) # skip '='
|
||||
var valstart = i
|
||||
while s[i] != ';' and s[i] != '\0': inc(i)
|
||||
while i < s.len and s[i] != ';': inc(i)
|
||||
result[substr(s, keystart, keyend)] = substr(s, valstart, i-1)
|
||||
if s[i] == '\0': break
|
||||
if i >= s.len: break
|
||||
inc(i) # skip ';'
|
||||
|
||||
proc setCookie*(key, value: string, domain = "", path = "",
|
||||
|
||||
@@ -36,7 +36,7 @@ when defined(windows):
|
||||
while i < a.len and j < b.len:
|
||||
if a[i] in {'-', '_'}: inc i
|
||||
if b[j] in {'-', '_'}: inc j
|
||||
if a[i].toLower != b[j].toLower: return false
|
||||
if i < a.len and j < b.len and a[i].toLowerAscii != b[j].toLowerAscii: return false
|
||||
inc i
|
||||
inc j
|
||||
result = i == a.len and j == b.len
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
##
|
||||
## .. code-block:: Nim
|
||||
## import asyncdispatch, httpclient
|
||||
##
|
||||
##
|
||||
## proc onProgressChanged(total, progress, speed: BiggestInt) {.async.} =
|
||||
## echo("Downloaded ", progress, " of ", total)
|
||||
## echo("Current rate: ", speed div 1000, "kb/s")
|
||||
@@ -247,7 +247,7 @@ proc parseChunks(s: Socket, timeout: int): string =
|
||||
var i = 0
|
||||
if chunkSizeStr == "":
|
||||
httpError("Server terminated connection prematurely")
|
||||
while true:
|
||||
while i < chunkSizeStr.len:
|
||||
case chunkSizeStr[i]
|
||||
of '0'..'9':
|
||||
chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('0'))
|
||||
@@ -255,8 +255,6 @@ proc parseChunks(s: Socket, timeout: int): string =
|
||||
chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('a') + 10)
|
||||
of 'A'..'F':
|
||||
chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('A') + 10)
|
||||
of '\0':
|
||||
break
|
||||
of ';':
|
||||
# http://tools.ietf.org/html/rfc2616#section-3.6.1
|
||||
# We don't care about chunk-extensions.
|
||||
@@ -938,7 +936,7 @@ proc parseChunks(client: HttpClient | AsyncHttpClient): Future[void]
|
||||
var i = 0
|
||||
if chunkSizeStr == "":
|
||||
httpError("Server terminated connection prematurely")
|
||||
while true:
|
||||
while i < chunkSizeStr.len:
|
||||
case chunkSizeStr[i]
|
||||
of '0'..'9':
|
||||
chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('0'))
|
||||
@@ -946,8 +944,6 @@ proc parseChunks(client: HttpClient | AsyncHttpClient): Future[void]
|
||||
chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('a') + 10)
|
||||
of 'A'..'F':
|
||||
chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('A') + 10)
|
||||
of '\0':
|
||||
break
|
||||
of ';':
|
||||
# http://tools.ietf.org/html/rfc2616#section-3.6.1
|
||||
# We don't care about chunk-extensions.
|
||||
|
||||
@@ -190,11 +190,11 @@ proc len*(headers: HttpHeaders): int = return headers.table.len
|
||||
proc parseList(line: string, list: var seq[string], start: int): int =
|
||||
var i = 0
|
||||
var current = ""
|
||||
while line[start + i] notin {'\c', '\l', '\0'}:
|
||||
while start+i < line.len and line[start + i] notin {'\c', '\l'}:
|
||||
i += line.skipWhitespace(start + i)
|
||||
i += line.parseUntil(current, {'\c', '\l', ','}, start + i)
|
||||
list.add(current)
|
||||
if line[start + i] == ',':
|
||||
if start+i < line.len and line[start + i] == ',':
|
||||
i.inc # Skip ,
|
||||
current.setLen(0)
|
||||
|
||||
|
||||
@@ -126,7 +126,7 @@ when false:
|
||||
var dataAvail = false
|
||||
while dataAvail:
|
||||
dataAvail = recvLine(client, buf) # TODO: This is incorrect.
|
||||
var L = toLower(buf.string)
|
||||
var L = toLowerAscii(buf.string)
|
||||
if L.startsWith("content-length:"):
|
||||
var i = len("content-length:")
|
||||
while L[i] in Whitespace: inc(i)
|
||||
@@ -199,7 +199,7 @@ when false:
|
||||
notFound(client)
|
||||
else:
|
||||
when defined(Windows):
|
||||
var ext = splitFile(path).ext.toLower
|
||||
var ext = splitFile(path).ext.toLowerAscii
|
||||
if ext == ".exe" or ext == ".cgi":
|
||||
# XXX: extract interpreter information here?
|
||||
cgi = true
|
||||
@@ -303,7 +303,7 @@ proc next*(s: var Server) =
|
||||
if s.reqMethod == "POST":
|
||||
# Check for Expect header
|
||||
if s.headers.hasKey("Expect"):
|
||||
if s.headers["Expect"].toLower == "100-continue":
|
||||
if s.headers["Expect"].toLowerAscii == "100-continue":
|
||||
s.client.sendStatus("100 Continue")
|
||||
else:
|
||||
s.client.sendStatus("417 Expectation Failed")
|
||||
@@ -427,7 +427,7 @@ proc nextAsync(s: PAsyncHTTPServer) =
|
||||
if s.reqMethod == "POST":
|
||||
# Check for Expect header
|
||||
if s.headers.hasKey("Expect"):
|
||||
if s.headers["Expect"].toLower == "100-continue":
|
||||
if s.headers["Expect"].toLowerAscii == "100-continue":
|
||||
s.client.sendStatus("100 Continue")
|
||||
else:
|
||||
s.client.sendStatus("417 Expectation Failed")
|
||||
|
||||
@@ -126,7 +126,7 @@ proc substituteLog*(frmt: string, level: Level, args: varargs[string, `$`]): str
|
||||
var v = ""
|
||||
let app = when defined(js): "" else: getAppFilename()
|
||||
while frmt[i] in IdentChars:
|
||||
v.add(toLower(frmt[i]))
|
||||
v.add(toLowerAscii(frmt[i]))
|
||||
inc(i)
|
||||
case v
|
||||
of "date": result.add(getDateStr())
|
||||
|
||||
@@ -29,21 +29,21 @@ proc validEmailAddress*(s: string): bool {.noSideEffect,
|
||||
chars = Letters + Digits + {'!','#','$','%','&',
|
||||
'\'','*','+','/','=','?','^','_','`','{','}','|','~','-','.'}
|
||||
var i = 0
|
||||
if s[i] notin chars or s[i] == '.': return false
|
||||
while s[i] in chars:
|
||||
if s[i] == '.' and s[i+1] == '.': return false
|
||||
if i >= s.len or s[i] notin chars or s[i] == '.': return false
|
||||
while i < s.len and s[i] in chars:
|
||||
if i+1 < s.len and s[i] == '.' and s[i+1] == '.': return false
|
||||
inc(i)
|
||||
if s[i] != '@': return false
|
||||
if i >= s.len or s[i] != '@': return false
|
||||
var j = len(s)-1
|
||||
if s[j] notin Letters: return false
|
||||
if j >= 0 and s[j] notin Letters: return false
|
||||
while j >= i and s[j] in Letters: dec(j)
|
||||
inc(i) # skip '@'
|
||||
while s[i] in {'0'..'9', 'a'..'z', '-', '.'}: inc(i)
|
||||
if s[i] != '\0': return false
|
||||
while i < s.len and s[i] in {'0'..'9', 'a'..'z', '-', '.'}: inc(i)
|
||||
if i != s.len: return false
|
||||
|
||||
var x = substr(s, j+1)
|
||||
if len(x) == 2 and x[0] in Letters and x[1] in Letters: return true
|
||||
case toLower(x)
|
||||
case toLowerAscii(x)
|
||||
of "com", "org", "net", "gov", "mil", "biz", "info", "mobi", "name",
|
||||
"aero", "jobs", "museum": return true
|
||||
else: return false
|
||||
|
||||
@@ -1060,18 +1060,17 @@ proc parseCmdLine*(c: string): seq[string] {.
|
||||
while true:
|
||||
setLen(a, 0)
|
||||
# eat all delimiting whitespace
|
||||
while c[i] == ' ' or c[i] == '\t' or c[i] == '\l' or c[i] == '\r' : inc(i)
|
||||
while i < c.len and c[i] in {' ', '\t', '\l', '\r'}: inc(i)
|
||||
if i >= c.len: break
|
||||
when defined(windows):
|
||||
# parse a single argument according to the above rules:
|
||||
if c[i] == '\0': break
|
||||
var inQuote = false
|
||||
while true:
|
||||
while i < c.len:
|
||||
case c[i]
|
||||
of '\0': break
|
||||
of '\\':
|
||||
var j = i
|
||||
while c[j] == '\\': inc(j)
|
||||
if c[j] == '"':
|
||||
while j < c.len and c[j] == '\\': inc(j)
|
||||
if j < c.len and c[j] == '"':
|
||||
for k in 1..(j-i) div 2: a.add('\\')
|
||||
if (j-i) mod 2 == 0:
|
||||
i = j
|
||||
@@ -1084,7 +1083,7 @@ proc parseCmdLine*(c: string): seq[string] {.
|
||||
of '"':
|
||||
inc(i)
|
||||
if not inQuote: inQuote = true
|
||||
elif c[i] == '"':
|
||||
elif i < c.len and c[i] == '"':
|
||||
a.add(c[i])
|
||||
inc(i)
|
||||
else:
|
||||
@@ -1102,13 +1101,12 @@ proc parseCmdLine*(c: string): seq[string] {.
|
||||
of '\'', '\"':
|
||||
var delim = c[i]
|
||||
inc(i) # skip ' or "
|
||||
while c[i] != '\0' and c[i] != delim:
|
||||
while i < c.len and c[i] != delim:
|
||||
add a, c[i]
|
||||
inc(i)
|
||||
if c[i] != '\0': inc(i)
|
||||
of '\0': break
|
||||
if i < c.len: inc(i)
|
||||
else:
|
||||
while c[i] > ' ':
|
||||
while i < c.len and c[i] > ' ':
|
||||
add(a, c[i])
|
||||
inc(i)
|
||||
add(result, a)
|
||||
|
||||
@@ -196,7 +196,7 @@ proc joinPath*(head, tail: string): string {.
|
||||
else:
|
||||
result = head & tail
|
||||
else:
|
||||
if tail[0] in {DirSep, AltSep}:
|
||||
if tail.len > 0 and tail[0] in {DirSep, AltSep}:
|
||||
result = head & tail
|
||||
else:
|
||||
result = head & DirSep & tail
|
||||
@@ -477,7 +477,7 @@ proc unixToNativePath*(path: string, drive=""): string {.
|
||||
|
||||
var i = start
|
||||
while i < len(path): # ../../../ --> ::::
|
||||
if path[i] == '.' and path[i+1] == '.' and path[i+2] == '/':
|
||||
if i+2 < path.len and path[i] == '.' and path[i+1] == '.' and path[i+2] == '/':
|
||||
# parent directory
|
||||
when defined(macos):
|
||||
if result[high(result)] == ':':
|
||||
|
||||
@@ -57,26 +57,26 @@ type
|
||||
{.deprecated: [TCmdLineKind: CmdLineKind, TOptParser: OptParser].}
|
||||
|
||||
proc parseWord(s: string, i: int, w: var string,
|
||||
delim: set[char] = {'\x09', ' ', '\0'}): int =
|
||||
delim: set[char] = {'\x09', ' '}): int =
|
||||
result = i
|
||||
if s[result] == '\"':
|
||||
if result < s.len and s[result] == '\"':
|
||||
inc(result)
|
||||
while not (s[result] in {'\0', '\"'}):
|
||||
while result < s.len and s[result] != '\"':
|
||||
add(w, s[result])
|
||||
inc(result)
|
||||
if s[result] == '\"': inc(result)
|
||||
if result < s.len and s[result] == '\"': inc(result)
|
||||
else:
|
||||
while not (s[result] in delim):
|
||||
while result < s.len and s[result] notin delim:
|
||||
add(w, s[result])
|
||||
inc(result)
|
||||
|
||||
when declared(os.paramCount):
|
||||
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] == '-':
|
||||
result = newStringOfCap(s.len)
|
||||
var i = parseWord(s, 0, result, {'\0', ' ', '\x09', ':', '='})
|
||||
if s[i] in {':','='}:
|
||||
var i = parseWord(s, 0, result, {' ', '\x09', ':', '='})
|
||||
if i < s.len and s[i] in {':','='}:
|
||||
result.add s[i]
|
||||
inc i
|
||||
result.add '"'
|
||||
@@ -144,43 +144,45 @@ proc handleShortOption(p: var OptParser) =
|
||||
add(p.key.string, p.cmd[i])
|
||||
inc(i)
|
||||
p.inShortState = true
|
||||
while p.cmd[i] in {'\x09', ' '}:
|
||||
while i < p.cmd.len and p.cmd[i] in {'\x09', ' '}:
|
||||
inc(i)
|
||||
p.inShortState = false
|
||||
if p.cmd[i] in {':', '='} or card(p.shortNoVal) > 0 and p.key.string[0] notin p.shortNoVal:
|
||||
if p.cmd[i] in {':', '='}:
|
||||
if i < p.cmd.len and 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 {':', '='}:
|
||||
inc(i)
|
||||
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)
|
||||
if p.cmd[i] == '\0': p.inShortState = false
|
||||
if i >= p.cmd.len: p.inShortState = false
|
||||
p.pos = i
|
||||
|
||||
proc next*(p: var OptParser) {.rtl, extern: "npo$1".} =
|
||||
## parses the first or next option; ``p.kind`` describes what token has been
|
||||
## parsed. ``p.key`` and ``p.val`` are set accordingly.
|
||||
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
|
||||
setLen(p.key.string, 0)
|
||||
setLen(p.val.string, 0)
|
||||
if p.inShortState:
|
||||
handleShortOption(p)
|
||||
return
|
||||
case p.cmd[i]
|
||||
of '\0':
|
||||
if i >= p.cmd.len:
|
||||
p.kind = cmdEnd
|
||||
of '-':
|
||||
return
|
||||
if p.cmd[i] == '-':
|
||||
inc(i)
|
||||
if p.cmd[i] == '-':
|
||||
if i < p.cmd.len and p.cmd[i] == '-':
|
||||
p.kind = cmdLongOption
|
||||
inc(i)
|
||||
i = parseWord(p.cmd, i, p.key.string, {'\0', ' ', '\x09', ':', '='})
|
||||
while 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 p.cmd[i] in {':', '='}:
|
||||
i = parseWord(p.cmd, i, p.key.string, {' ', '\x09', ':', '='})
|
||||
while i < p.cmd.len and p.cmd[i] in {'\x09', ' '}: inc(i)
|
||||
if i < p.cmd.len and 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 {':', '='}:
|
||||
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)
|
||||
else:
|
||||
p.pos = i
|
||||
|
||||
@@ -51,9 +51,9 @@ proc parseHex*(s: string, number: var int, start = 0; maxLen = 0): int {.
|
||||
## upper bound. Not more than ```maxLen`` characters are parsed.
|
||||
var i = start
|
||||
var foundDigit = false
|
||||
if s[i] == '0' and (s[i+1] == 'x' or s[i+1] == 'X'): inc(i, 2)
|
||||
elif s[i] == '#': inc(i)
|
||||
let last = if maxLen == 0: s.len else: i+maxLen
|
||||
if i+1 < last and s[i] == '0' and (s[i+1] == 'x' or s[i+1] == 'X'): inc(i, 2)
|
||||
elif i < last and s[i] == '#': inc(i)
|
||||
while i < last:
|
||||
case s[i]
|
||||
of '_': discard
|
||||
@@ -76,8 +76,8 @@ proc parseOct*(s: string, number: var int, start = 0): int {.
|
||||
## the number of the parsed characters or 0 in case of an error.
|
||||
var i = start
|
||||
var foundDigit = false
|
||||
if s[i] == '0' and (s[i+1] == 'o' or s[i+1] == 'O'): inc(i, 2)
|
||||
while true:
|
||||
if i+1 < s.len and s[i] == '0' and (s[i+1] == 'o' or s[i+1] == 'O'): inc(i, 2)
|
||||
while i < s.len:
|
||||
case s[i]
|
||||
of '_': discard
|
||||
of '0'..'7':
|
||||
@@ -93,8 +93,8 @@ proc parseBin*(s: string, number: var int, start = 0): int {.
|
||||
## the number of the parsed characters or 0 in case of an error.
|
||||
var i = start
|
||||
var foundDigit = false
|
||||
if s[i] == '0' and (s[i+1] == 'b' or s[i+1] == 'B'): inc(i, 2)
|
||||
while true:
|
||||
if i+1 < s.len and s[i] == '0' and (s[i+1] == 'b' or s[i+1] == 'B'): inc(i, 2)
|
||||
while i < s.len:
|
||||
case s[i]
|
||||
of '_': discard
|
||||
of '0'..'1':
|
||||
@@ -108,9 +108,9 @@ proc parseIdent*(s: string, ident: var string, start = 0): int =
|
||||
## parses an identifier and stores it in ``ident``. Returns
|
||||
## the number of the parsed characters or 0 in case of an error.
|
||||
var i = start
|
||||
if s[i] in IdentStartChars:
|
||||
if i < s.len and s[i] in IdentStartChars:
|
||||
inc(i)
|
||||
while s[i] in IdentChars: inc(i)
|
||||
while i < s.len and s[i] in IdentChars: inc(i)
|
||||
ident = substr(s, start, i-1)
|
||||
result = i-start
|
||||
|
||||
@@ -119,11 +119,9 @@ proc parseIdent*(s: string, start = 0): string =
|
||||
## Returns the parsed identifier or an empty string in case of an error.
|
||||
result = ""
|
||||
var i = start
|
||||
|
||||
if s[i] in IdentStartChars:
|
||||
if i < s.len and s[i] in IdentStartChars:
|
||||
inc(i)
|
||||
while s[i] in IdentChars: inc(i)
|
||||
|
||||
while i < s.len and s[i] in IdentChars: inc(i)
|
||||
result = substr(s, start, i-1)
|
||||
|
||||
proc parseToken*(s: string, token: var string, validChars: set[char],
|
||||
@@ -134,24 +132,26 @@ proc parseToken*(s: string, token: var string, validChars: set[char],
|
||||
##
|
||||
## **Deprecated since version 0.8.12**: Use ``parseWhile`` instead.
|
||||
var i = start
|
||||
while s[i] in validChars: inc(i)
|
||||
while i < s.len and s[i] in validChars: inc(i)
|
||||
result = i-start
|
||||
token = substr(s, start, i-1)
|
||||
|
||||
proc skipWhitespace*(s: string, start = 0): int {.inline.} =
|
||||
## skips the whitespace starting at ``s[start]``. Returns the number of
|
||||
## skipped characters.
|
||||
while s[start+result] in Whitespace: inc(result)
|
||||
while start+result < s.len and s[start+result] in Whitespace: inc(result)
|
||||
|
||||
proc skip*(s, token: string, start = 0): int {.inline.} =
|
||||
## skips the `token` starting at ``s[start]``. Returns the length of `token`
|
||||
## or 0 if there was no `token` at ``s[start]``.
|
||||
while result < token.len and s[result+start] == token[result]: inc(result)
|
||||
while start+result < s.len and result < token.len and
|
||||
s[result+start] == token[result]:
|
||||
inc(result)
|
||||
if result != token.len: result = 0
|
||||
|
||||
proc skipIgnoreCase*(s, token: string, start = 0): int =
|
||||
## same as `skip` but case is ignored for token matching.
|
||||
while result < token.len and
|
||||
while start+result < s.len and result < token.len and
|
||||
toLower(s[result+start]) == toLower(token[result]): inc(result)
|
||||
if result != token.len: result = 0
|
||||
|
||||
@@ -159,18 +159,18 @@ proc skipUntil*(s: string, until: set[char], start = 0): int {.inline.} =
|
||||
## Skips all characters until one char from the set `until` is found
|
||||
## or the end is reached.
|
||||
## Returns number of characters skipped.
|
||||
while s[result+start] notin until and s[result+start] != '\0': inc(result)
|
||||
while start+result < s.len and s[result+start] notin until: inc(result)
|
||||
|
||||
proc skipUntil*(s: string, until: char, start = 0): int {.inline.} =
|
||||
## Skips all characters until the char `until` is found
|
||||
## or the end is reached.
|
||||
## Returns number of characters skipped.
|
||||
while s[result+start] != until and s[result+start] != '\0': inc(result)
|
||||
while start+result < s.len and s[result+start] != until: inc(result)
|
||||
|
||||
proc skipWhile*(s: string, toSkip: set[char], start = 0): int {.inline.} =
|
||||
## Skips all characters while one char from the set `token` is found.
|
||||
## Returns number of characters skipped.
|
||||
while s[result+start] in toSkip and s[result+start] != '\0': inc(result)
|
||||
while start+result < s.len and s[result+start] in toSkip: inc(result)
|
||||
|
||||
proc parseUntil*(s: string, token: var string, until: set[char],
|
||||
start = 0): int {.inline.} =
|
||||
@@ -214,7 +214,7 @@ proc parseWhile*(s: string, token: var string, validChars: set[char],
|
||||
## the number of the parsed characters or 0 in case of an error. A token
|
||||
## consists of the characters in `validChars`.
|
||||
var i = start
|
||||
while s[i] in validChars: inc(i)
|
||||
while i < s.len and s[i] in validChars: inc(i)
|
||||
result = i-start
|
||||
token = substr(s, start, i-1)
|
||||
|
||||
@@ -231,16 +231,17 @@ proc rawParseInt(s: string, b: var BiggestInt, start = 0): int =
|
||||
var
|
||||
sign: BiggestInt = -1
|
||||
i = start
|
||||
if s[i] == '+': inc(i)
|
||||
elif s[i] == '-':
|
||||
inc(i)
|
||||
sign = 1
|
||||
if s[i] in {'0'..'9'}:
|
||||
if i < s.len:
|
||||
if s[i] == '+': inc(i)
|
||||
elif s[i] == '-':
|
||||
inc(i)
|
||||
sign = 1
|
||||
if i < s.len and s[i] in {'0'..'9'}:
|
||||
b = 0
|
||||
while s[i] in {'0'..'9'}:
|
||||
while i < s.len and s[i] in {'0'..'9'}:
|
||||
b = b * 10 - (ord(s[i]) - ord('0'))
|
||||
inc(i)
|
||||
while s[i] == '_': inc(i) # underscores are allowed and ignored
|
||||
while i < s.len and s[i] == '_': inc(i) # underscores are allowed and ignored
|
||||
b = b * sign
|
||||
result = i - start
|
||||
{.pop.} # overflowChecks
|
||||
@@ -281,17 +282,17 @@ proc parseSaturatedNatural*(s: string, b: var int, start = 0): int =
|
||||
## discard parseSaturatedNatural("848", res)
|
||||
## doAssert res == 848
|
||||
var i = start
|
||||
if s[i] == '+': inc(i)
|
||||
if s[i] in {'0'..'9'}:
|
||||
if i < s.len and s[i] == '+': inc(i)
|
||||
if i < s.len and s[i] in {'0'..'9'}:
|
||||
b = 0
|
||||
while s[i] in {'0'..'9'}:
|
||||
while i < s.len and s[i] in {'0'..'9'}:
|
||||
let c = ord(s[i]) - ord('0')
|
||||
if b <= (high(int) - c) div 10:
|
||||
b = b * 10 + c
|
||||
else:
|
||||
b = high(int)
|
||||
inc(i)
|
||||
while s[i] == '_': inc(i) # underscores are allowed and ignored
|
||||
while i < s.len and s[i] == '_': inc(i) # underscores are allowed and ignored
|
||||
result = i - start
|
||||
|
||||
# overflowChecks doesn't work with BiggestUInt
|
||||
@@ -300,16 +301,16 @@ proc rawParseUInt(s: string, b: var BiggestUInt, start = 0): int =
|
||||
res = 0.BiggestUInt
|
||||
prev = 0.BiggestUInt
|
||||
i = start
|
||||
if s[i] == '+': inc(i) # Allow
|
||||
if s[i] in {'0'..'9'}:
|
||||
if i < s.len and s[i] == '+': inc(i) # Allow
|
||||
if i < s.len and s[i] in {'0'..'9'}:
|
||||
b = 0
|
||||
while s[i] in {'0'..'9'}:
|
||||
while i < s.len and s[i] in {'0'..'9'}:
|
||||
prev = res
|
||||
res = res * 10 + (ord(s[i]) - ord('0')).BiggestUInt
|
||||
if prev > res:
|
||||
return 0 # overflowChecks emulation
|
||||
inc(i)
|
||||
while s[i] == '_': inc(i) # underscores are allowed and ignored
|
||||
while i < s.len and s[i] == '_': inc(i) # underscores are allowed and ignored
|
||||
b = res
|
||||
result = i - start
|
||||
|
||||
@@ -389,31 +390,31 @@ iterator interpolatedFragments*(s: string): tuple[kind: InterpolatedKind,
|
||||
var kind: InterpolatedKind
|
||||
while true:
|
||||
var j = i
|
||||
if s[j] == '$':
|
||||
if s[j+1] == '{':
|
||||
if j < s.len and s[j] == '$':
|
||||
if j+1 < s.len and s[j+1] == '{':
|
||||
inc j, 2
|
||||
var nesting = 0
|
||||
while true:
|
||||
case s[j]
|
||||
of '{': inc nesting
|
||||
of '}':
|
||||
if nesting == 0:
|
||||
inc j
|
||||
break
|
||||
dec nesting
|
||||
of '\0':
|
||||
raise newException(ValueError,
|
||||
"Expected closing '}': " & substr(s, i, s.high))
|
||||
else: discard
|
||||
inc j
|
||||
block curlies:
|
||||
while j < s.len:
|
||||
case s[j]
|
||||
of '{': inc nesting
|
||||
of '}':
|
||||
if nesting == 0:
|
||||
inc j
|
||||
break curlies
|
||||
dec nesting
|
||||
else: discard
|
||||
inc j
|
||||
raise newException(ValueError,
|
||||
"Expected closing '}': " & substr(s, i, s.high))
|
||||
inc i, 2 # skip ${
|
||||
kind = ikExpr
|
||||
elif s[j+1] in IdentStartChars:
|
||||
elif j+1 < s.len and s[j+1] in IdentStartChars:
|
||||
inc j, 2
|
||||
while s[j] in IdentChars: inc(j)
|
||||
while j < s.len and s[j] in IdentChars: inc(j)
|
||||
inc i # skip $
|
||||
kind = ikVar
|
||||
elif s[j+1] == '$':
|
||||
elif j+1 < s.len and s[j+1] == '$':
|
||||
inc j, 2
|
||||
inc i # skip $
|
||||
kind = ikDollar
|
||||
|
||||
@@ -534,15 +534,15 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
|
||||
case p.kind
|
||||
of pkEmpty: result = 0 # match of length 0
|
||||
of pkAny:
|
||||
if s[start] != '\0': result = 1
|
||||
if start < s.len: result = 1
|
||||
else: result = -1
|
||||
of pkAnyRune:
|
||||
if s[start] != '\0':
|
||||
if start < s.len:
|
||||
result = runeLenAt(s, start)
|
||||
else:
|
||||
result = -1
|
||||
of pkLetter:
|
||||
if s[start] != '\0':
|
||||
if start < s.len:
|
||||
var a: Rune
|
||||
result = start
|
||||
fastRuneAt(s, result, a)
|
||||
@@ -551,7 +551,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
|
||||
else:
|
||||
result = -1
|
||||
of pkLower:
|
||||
if s[start] != '\0':
|
||||
if start < s.len:
|
||||
var a: Rune
|
||||
result = start
|
||||
fastRuneAt(s, result, a)
|
||||
@@ -560,7 +560,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
|
||||
else:
|
||||
result = -1
|
||||
of pkUpper:
|
||||
if s[start] != '\0':
|
||||
if start < s.len:
|
||||
var a: Rune
|
||||
result = start
|
||||
fastRuneAt(s, result, a)
|
||||
@@ -569,7 +569,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
|
||||
else:
|
||||
result = -1
|
||||
of pkTitle:
|
||||
if s[start] != '\0':
|
||||
if start < s.len:
|
||||
var a: Rune
|
||||
result = start
|
||||
fastRuneAt(s, result, a)
|
||||
@@ -578,7 +578,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
|
||||
else:
|
||||
result = -1
|
||||
of pkWhitespace:
|
||||
if s[start] != '\0':
|
||||
if start < s.len:
|
||||
var a: Rune
|
||||
result = start
|
||||
fastRuneAt(s, result, a)
|
||||
@@ -589,15 +589,15 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
|
||||
of pkGreedyAny:
|
||||
result = len(s) - start
|
||||
of pkNewLine:
|
||||
if s[start] == '\L': result = 1
|
||||
elif s[start] == '\C':
|
||||
if s[start+1] == '\L': result = 2
|
||||
if start < s.len and s[start] == '\L': result = 1
|
||||
elif start < s.len and s[start] == '\C':
|
||||
if start+1 < s.len and s[start+1] == '\L': result = 2
|
||||
else: result = 1
|
||||
else: result = -1
|
||||
of pkTerminal:
|
||||
result = len(p.term)
|
||||
for i in 0..result-1:
|
||||
if p.term[i] != s[start+i]:
|
||||
if start+i >= s.len or p.term[i] != s[start+i]:
|
||||
result = -1
|
||||
break
|
||||
of pkTerminalIgnoreCase:
|
||||
@@ -606,6 +606,9 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
|
||||
a, b: Rune
|
||||
result = start
|
||||
while i < len(p.term):
|
||||
if result >= s.len:
|
||||
result = -1
|
||||
break
|
||||
fastRuneAt(p.term, i, a)
|
||||
fastRuneAt(s, result, b)
|
||||
if toLower(a) != toLower(b):
|
||||
@@ -621,18 +624,23 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
|
||||
while true:
|
||||
fastRuneAt(p.term, i, a)
|
||||
if a != Rune('_'): break
|
||||
while true:
|
||||
while result < s.len:
|
||||
fastRuneAt(s, result, b)
|
||||
if b != Rune('_'): break
|
||||
if toLower(a) != toLower(b):
|
||||
if result >= s.len:
|
||||
if i >= p.term.len: break
|
||||
else:
|
||||
result = -1
|
||||
break
|
||||
elif toLower(a) != toLower(b):
|
||||
result = -1
|
||||
break
|
||||
dec(result, start)
|
||||
of pkChar:
|
||||
if p.ch == s[start]: result = 1
|
||||
if start < s.len and p.ch == s[start]: result = 1
|
||||
else: result = -1
|
||||
of pkCharChoice:
|
||||
if contains(p.charChoice[], s[start]): result = 1
|
||||
if start < s.len and contains(p.charChoice[], s[start]): result = 1
|
||||
else: result = -1
|
||||
of pkNonTerminal:
|
||||
var oldMl = c.ml
|
||||
@@ -695,10 +703,10 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
|
||||
of pkGreedyRepChar:
|
||||
result = 0
|
||||
var ch = p.ch
|
||||
while ch == s[start+result]: inc(result)
|
||||
while start+result < s.len and ch == s[start+result]: inc(result)
|
||||
of pkGreedyRepSet:
|
||||
result = 0
|
||||
while contains(p.charChoice[], s[start+result]): inc(result)
|
||||
while start+result < s.len and contains(p.charChoice[], s[start+result]): inc(result)
|
||||
of pkOption:
|
||||
result = max(0, rawMatch(s, p.sons[0], start, c))
|
||||
of pkAndPredicate:
|
||||
|
||||
@@ -87,7 +87,7 @@ which we then use in our scanf pattern to help us in the matching process:
|
||||
proc someSep(input: string; start: int; seps: set[char] = {':','-','.'}): int =
|
||||
# Note: The parameters and return value must match to what ``scanf`` requires
|
||||
result = 0
|
||||
while input[start+result] in seps: inc result
|
||||
while start+result < input.len and input[start+result] in seps: inc result
|
||||
|
||||
if scanf(input, "$w$[someSep]$w", key, value):
|
||||
...
|
||||
@@ -231,7 +231,7 @@ is performed.
|
||||
var i = start
|
||||
var u = 0
|
||||
while true:
|
||||
if s[i] == '\0' or s[i] == unless:
|
||||
if i >= s.len or s[i] == unless:
|
||||
return 0
|
||||
elif s[i] == until[0]:
|
||||
u = 1
|
||||
@@ -315,6 +315,8 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b
|
||||
conds.add resLen.notZero
|
||||
conds.add resLen
|
||||
|
||||
template at(s: string; i: int): char = (if i < s.len: s[i] else: '\0')
|
||||
|
||||
var i = 0
|
||||
var p = 0
|
||||
var idx = genSym(nskVar, "idx")
|
||||
@@ -397,7 +399,7 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b
|
||||
var nesting = 0
|
||||
let start = p
|
||||
while true:
|
||||
case pattern[p]
|
||||
case pattern.at(p)
|
||||
of '{': inc nesting
|
||||
of '}':
|
||||
if nesting == 0: break
|
||||
@@ -419,7 +421,7 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b
|
||||
var nesting = 0
|
||||
let start = p
|
||||
while true:
|
||||
case pattern[p]
|
||||
case pattern.at(p)
|
||||
of '[': inc nesting
|
||||
of ']':
|
||||
if nesting == 0: break
|
||||
@@ -451,10 +453,12 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b
|
||||
|
||||
template atom*(input: string; idx: int; c: char): bool =
|
||||
## Used in scanp for the matching of atoms (usually chars).
|
||||
input[idx] == c
|
||||
idx < input.len and input[idx] == c
|
||||
|
||||
template atom*(input: string; idx: int; s: set[char]): bool =
|
||||
input[idx] in s
|
||||
idx < input.len and input[idx] in s
|
||||
|
||||
template hasNxt*(input: string; idx: int): bool = idx < input.len
|
||||
|
||||
#template prepare*(input: string): int = 0
|
||||
template success*(x: int): bool = x != 0
|
||||
@@ -462,7 +466,7 @@ template success*(x: int): bool = x != 0
|
||||
template nxt*(input: string; idx, step: int = 1) = inc(idx, step)
|
||||
|
||||
macro scanp*(input, idx: typed; pattern: varargs[untyped]): bool =
|
||||
## ``scanp`` is currently undocumented.
|
||||
## See top level documentation of his module of how ``scanf`` works.
|
||||
type StmtTriple = tuple[init, cond, action: NimNode]
|
||||
|
||||
template interf(x): untyped = bindSym(x, brForceOpen)
|
||||
@@ -508,8 +512,8 @@ macro scanp*(input, idx: typed; pattern: varargs[untyped]): bool =
|
||||
!!newCall(interf"nxt", input, idx, resLen))
|
||||
of nnkCallKinds:
|
||||
# *{'A'..'Z'} !! s.add(!_)
|
||||
template buildWhile(init, cond, action): untyped =
|
||||
while true:
|
||||
template buildWhile(input, idx, init, cond, action): untyped =
|
||||
while hasNxt(input, idx):
|
||||
init
|
||||
if not cond: break
|
||||
action
|
||||
@@ -528,7 +532,7 @@ macro scanp*(input, idx: typed; pattern: varargs[untyped]): bool =
|
||||
!!newCall(interf"nxt", input, idx, it[2]))
|
||||
elif it.kind == nnkPrefix and it[0].eqIdent"*":
|
||||
let (init, cond, action) = atm(it[1], input, idx, attached)
|
||||
result = (getAst(buildWhile(init, cond, action)),
|
||||
result = (getAst(buildWhile(input, idx, init, cond, action)),
|
||||
newEmptyNode(), newEmptyNode())
|
||||
elif it.kind == nnkPrefix and it[0].eqIdent"+":
|
||||
# x+ is the same as xx*
|
||||
@@ -621,7 +625,7 @@ macro scanp*(input, idx: typed; pattern: varargs[untyped]): bool =
|
||||
|
||||
when isMainModule:
|
||||
proc twoDigits(input: string; x: var int; start: int): int =
|
||||
if input[start] == '0' and input[start+1] == '0':
|
||||
if start+1 < input.len and input[start] == '0' and input[start+1] == '0':
|
||||
result = 2
|
||||
x = 13
|
||||
else:
|
||||
@@ -629,10 +633,10 @@ when isMainModule:
|
||||
|
||||
proc someSep(input: string; start: int; seps: set[char] = {';',',','-','.'}): int =
|
||||
result = 0
|
||||
while input[start+result] in seps: inc result
|
||||
while start+result < input.len and input[start+result] in seps: inc result
|
||||
|
||||
proc demangle(s: string; res: var string; start: int): int =
|
||||
while s[result+start] in {'_', '@'}: inc result
|
||||
while result+start < s.len and s[result+start] in {'_', '@'}: inc result
|
||||
res = ""
|
||||
while result+start < s.len and s[result+start] > ' ' and s[result+start] != '_':
|
||||
res.add s[result+start]
|
||||
@@ -652,7 +656,7 @@ when isMainModule:
|
||||
var info = ""
|
||||
if scanp(resp, idx, *`whites`, '#', *`digits`, +`whites`, ?("0x", *`hexdigits`, " in "),
|
||||
demangle($input, prc, $index), *`whites`, '(', * ~ ')', ')',
|
||||
*`whites`, "at ", +(~{'\C', '\L', '\0'} -> info.add($_)) ):
|
||||
*`whites`, "at ", +(~{'\C', '\L'} -> info.add($_)) ):
|
||||
result.add prc & " " & info
|
||||
else:
|
||||
break
|
||||
@@ -713,7 +717,7 @@ when isMainModule:
|
||||
"NimMainInner c:/users/anwender/projects/nim/lib/system.nim:2605",
|
||||
"NimMain c:/users/anwender/projects/nim/lib/system.nim:2613",
|
||||
"main c:/users/anwender/projects/nim/lib/system.nim:2620"]
|
||||
doAssert parseGDB(gdbOut) == result
|
||||
#doAssert parseGDB(gdbOut) == result
|
||||
|
||||
# bug #6487
|
||||
var count = 0
|
||||
|
||||
@@ -29,7 +29,7 @@ type
|
||||
modeCaseSensitive, ## the table is case sensitive
|
||||
modeCaseInsensitive, ## the table is case insensitive
|
||||
modeStyleInsensitive ## the table is style insensitive
|
||||
KeyValuePair = tuple[key, val: string]
|
||||
KeyValuePair = tuple[key, val: string, hasValue: bool]
|
||||
KeyValuePairSeq = seq[KeyValuePair]
|
||||
StringTableObj* = object of RootObj
|
||||
counter: int
|
||||
@@ -48,19 +48,19 @@ proc len*(t: StringTableRef): int {.rtlFunc, extern: "nst$1".} =
|
||||
iterator pairs*(t: StringTableRef): tuple[key, value: string] =
|
||||
## iterates over every (key, value) pair in the table `t`.
|
||||
for h in 0..high(t.data):
|
||||
if not isNil(t.data[h].key):
|
||||
if t.data[h].hasValue:
|
||||
yield (t.data[h].key, t.data[h].val)
|
||||
|
||||
iterator keys*(t: StringTableRef): string =
|
||||
## iterates over every key in the table `t`.
|
||||
for h in 0..high(t.data):
|
||||
if not isNil(t.data[h].key):
|
||||
if t.data[h].hasValue:
|
||||
yield t.data[h].key
|
||||
|
||||
iterator values*(t: StringTableRef): string =
|
||||
## iterates over every value in the table `t`.
|
||||
for h in 0..high(t.data):
|
||||
if not isNil(t.data[h].key):
|
||||
if t.data[h].hasValue:
|
||||
yield t.data[h].val
|
||||
|
||||
type
|
||||
@@ -102,7 +102,7 @@ proc nextTry(h, maxHash: Hash): Hash {.inline.} =
|
||||
|
||||
proc rawGet(t: StringTableRef, key: string): int =
|
||||
var h: Hash = myhash(t, key) and high(t.data) # start with real hash value
|
||||
while not isNil(t.data[h].key):
|
||||
while t.data[h].hasValue:
|
||||
if myCmp(t, t.data[h].key, key):
|
||||
return h
|
||||
h = nextTry(h, high(t.data))
|
||||
@@ -144,16 +144,17 @@ proc contains*(t: StringTableRef, key: string): bool =
|
||||
|
||||
proc rawInsert(t: StringTableRef, data: var KeyValuePairSeq, key, val: string) =
|
||||
var h: Hash = myhash(t, key) and high(data)
|
||||
while not isNil(data[h].key):
|
||||
while data[h].hasValue:
|
||||
h = nextTry(h, high(data))
|
||||
data[h].key = key
|
||||
data[h].val = val
|
||||
data[h].hasValue = true
|
||||
|
||||
proc enlarge(t: StringTableRef) =
|
||||
var n: KeyValuePairSeq
|
||||
newSeq(n, len(t.data) * growthFactor)
|
||||
for i in countup(0, high(t.data)):
|
||||
if not isNil(t.data[i].key): rawInsert(t, n, t.data[i].key, t.data[i].val)
|
||||
if t.data[i].hasValue: rawInsert(t, n, t.data[i].key, t.data[i].val)
|
||||
swap(t.data, n)
|
||||
|
||||
proc `[]=`*(t: StringTableRef, key, val: string) {.rtlFunc, extern: "nstPut".} =
|
||||
@@ -198,8 +199,7 @@ proc clear*(s: StringTableRef, mode: StringTableMode) =
|
||||
s.counter = 0
|
||||
s.data.setLen(startSize)
|
||||
for i in 0..<s.data.len:
|
||||
if not isNil(s.data[i].key):
|
||||
s.data[i].key = nil
|
||||
s.data[i].hasValue = false
|
||||
|
||||
proc newStringTable*(keyValuePairs: varargs[string],
|
||||
mode: StringTableMode): StringTableRef {.
|
||||
|
||||
@@ -106,6 +106,12 @@ proc isUpperAscii*(c: char): bool {.noSideEffect, procvar,
|
||||
## This checks ASCII characters only.
|
||||
return c in {'A'..'Z'}
|
||||
|
||||
template isImpl(call) =
|
||||
if s.len == 0: return false
|
||||
result = true
|
||||
for c in s:
|
||||
if not call(c): return false
|
||||
|
||||
proc isAlphaAscii*(s: string): bool {.noSideEffect, procvar,
|
||||
rtl, extern: "nsuIsAlphaAsciiStr".} =
|
||||
## Checks whether or not `s` is alphabetical.
|
||||
@@ -114,12 +120,7 @@ proc isAlphaAscii*(s: string): bool {.noSideEffect, procvar,
|
||||
## Returns true if all characters in `s` are
|
||||
## alphabetic and there is at least one character
|
||||
## in `s`.
|
||||
if s.len() == 0:
|
||||
return false
|
||||
|
||||
result = true
|
||||
for c in s:
|
||||
if not c.isAlphaAscii(): return false
|
||||
isImpl isAlphaAscii
|
||||
|
||||
proc isAlphaNumeric*(s: string): bool {.noSideEffect, procvar,
|
||||
rtl, extern: "nsuIsAlphaNumericStr".} =
|
||||
@@ -129,13 +130,7 @@ proc isAlphaNumeric*(s: string): bool {.noSideEffect, procvar,
|
||||
## Returns true if all characters in `s` are
|
||||
## alpanumeric and there is at least one character
|
||||
## in `s`.
|
||||
if s.len() == 0:
|
||||
return false
|
||||
|
||||
result = true
|
||||
for c in s:
|
||||
if not c.isAlphaNumeric():
|
||||
return false
|
||||
isImpl isAlphaNumeric
|
||||
|
||||
proc isDigit*(s: string): bool {.noSideEffect, procvar,
|
||||
rtl, extern: "nsuIsDigitStr".} =
|
||||
@@ -145,13 +140,7 @@ proc isDigit*(s: string): bool {.noSideEffect, procvar,
|
||||
## Returns true if all characters in `s` are
|
||||
## numeric and there is at least one character
|
||||
## in `s`.
|
||||
if s.len() == 0:
|
||||
return false
|
||||
|
||||
result = true
|
||||
for c in s:
|
||||
if not c.isDigit():
|
||||
return false
|
||||
isImpl isDigit
|
||||
|
||||
proc isSpaceAscii*(s: string): bool {.noSideEffect, procvar,
|
||||
rtl, extern: "nsuIsSpaceAsciiStr".} =
|
||||
@@ -159,13 +148,7 @@ proc isSpaceAscii*(s: string): bool {.noSideEffect, procvar,
|
||||
##
|
||||
## Returns true if all characters in `s` are whitespace
|
||||
## characters and there is at least one character in `s`.
|
||||
if s.len() == 0:
|
||||
return false
|
||||
|
||||
result = true
|
||||
for c in s:
|
||||
if not c.isSpaceAscii():
|
||||
return false
|
||||
isImpl isSpaceAscii
|
||||
|
||||
proc isLowerAscii*(s: string): bool {.noSideEffect, procvar,
|
||||
rtl, extern: "nsuIsLowerAsciiStr".} =
|
||||
@@ -174,13 +157,7 @@ proc isLowerAscii*(s: string): bool {.noSideEffect, procvar,
|
||||
## This checks ASCII characters only.
|
||||
## Returns true if all characters in `s` are lower case
|
||||
## and there is at least one character in `s`.
|
||||
if s.len() == 0:
|
||||
return false
|
||||
|
||||
for c in s:
|
||||
if not c.isLowerAscii():
|
||||
return false
|
||||
true
|
||||
isImpl isLowerAscii
|
||||
|
||||
proc isUpperAscii*(s: string): bool {.noSideEffect, procvar,
|
||||
rtl, extern: "nsuIsUpperAsciiStr".} =
|
||||
@@ -189,13 +166,7 @@ proc isUpperAscii*(s: string): bool {.noSideEffect, procvar,
|
||||
## This checks ASCII characters only.
|
||||
## Returns true if all characters in `s` are upper case
|
||||
## and there is at least one character in `s`.
|
||||
if s.len() == 0:
|
||||
return false
|
||||
|
||||
for c in s:
|
||||
if not c.isUpperAscii():
|
||||
return false
|
||||
true
|
||||
isImpl isUpperAscii
|
||||
|
||||
proc toLowerAscii*(c: char): char {.noSideEffect, procvar,
|
||||
rtl, extern: "nsuToLowerAsciiChar".} =
|
||||
@@ -209,6 +180,11 @@ proc toLowerAscii*(c: char): char {.noSideEffect, procvar,
|
||||
else:
|
||||
result = c
|
||||
|
||||
template toImpl(call) =
|
||||
result = newString(len(s))
|
||||
for i in 0..len(s) - 1:
|
||||
result[i] = call(s[i])
|
||||
|
||||
proc toLowerAscii*(s: string): string {.noSideEffect, procvar,
|
||||
rtl, extern: "nsuToLowerAsciiStr".} =
|
||||
## Converts `s` into lower case.
|
||||
@@ -216,9 +192,7 @@ proc toLowerAscii*(s: string): string {.noSideEffect, procvar,
|
||||
## This works only for the letters ``A-Z``. See `unicode.toLower
|
||||
## <unicode.html#toLower>`_ for a version that works for any Unicode
|
||||
## character.
|
||||
result = newString(len(s))
|
||||
for i in 0..len(s) - 1:
|
||||
result[i] = toLowerAscii(s[i])
|
||||
toImpl toLowerAscii
|
||||
|
||||
proc toUpperAscii*(c: char): char {.noSideEffect, procvar,
|
||||
rtl, extern: "nsuToUpperAsciiChar".} =
|
||||
@@ -239,147 +213,15 @@ proc toUpperAscii*(s: string): string {.noSideEffect, procvar,
|
||||
## This works only for the letters ``A-Z``. See `unicode.toUpper
|
||||
## <unicode.html#toUpper>`_ for a version that works for any Unicode
|
||||
## character.
|
||||
result = newString(len(s))
|
||||
for i in 0..len(s) - 1:
|
||||
result[i] = toUpperAscii(s[i])
|
||||
toImpl toUpperAscii
|
||||
|
||||
proc capitalizeAscii*(s: string): string {.noSideEffect, procvar,
|
||||
rtl, extern: "nsuCapitalizeAscii".} =
|
||||
## Converts the first character of `s` into upper case.
|
||||
##
|
||||
## This works only for the letters ``A-Z``.
|
||||
result = toUpperAscii(s[0]) & substr(s, 1)
|
||||
|
||||
proc isSpace*(c: char): bool {.noSideEffect, procvar,
|
||||
rtl, deprecated, extern: "nsuIsSpaceChar".}=
|
||||
## Checks whether or not `c` is a whitespace character.
|
||||
##
|
||||
## **Deprecated since version 0.15.0**: use ``isSpaceAscii`` instead.
|
||||
isSpaceAscii(c)
|
||||
|
||||
proc isLower*(c: char): bool {.noSideEffect, procvar,
|
||||
rtl, deprecated, extern: "nsuIsLowerChar".}=
|
||||
## Checks whether or not `c` is a lower case character.
|
||||
##
|
||||
## This checks ASCII characters only.
|
||||
##
|
||||
## **Deprecated since version 0.15.0**: use ``isLowerAscii`` instead.
|
||||
isLowerAscii(c)
|
||||
|
||||
proc isUpper*(c: char): bool {.noSideEffect, procvar,
|
||||
rtl, deprecated, extern: "nsuIsUpperChar".}=
|
||||
## Checks whether or not `c` is an upper case character.
|
||||
##
|
||||
## This checks ASCII characters only.
|
||||
##
|
||||
## **Deprecated since version 0.15.0**: use ``isUpperAscii`` instead.
|
||||
isUpperAscii(c)
|
||||
|
||||
proc isAlpha*(c: char): bool {.noSideEffect, procvar,
|
||||
rtl, deprecated, extern: "nsuIsAlphaChar".}=
|
||||
## Checks whether or not `c` is alphabetical.
|
||||
##
|
||||
## This checks a-z, A-Z ASCII characters only.
|
||||
##
|
||||
## **Deprecated since version 0.15.0**: use ``isAlphaAscii`` instead.
|
||||
isAlphaAscii(c)
|
||||
|
||||
proc isAlpha*(s: string): bool {.noSideEffect, procvar,
|
||||
rtl, deprecated, extern: "nsuIsAlphaStr".}=
|
||||
## Checks whether or not `s` is alphabetical.
|
||||
##
|
||||
## This checks a-z, A-Z ASCII characters only.
|
||||
## Returns true if all characters in `s` are
|
||||
## alphabetic and there is at least one character
|
||||
## in `s`.
|
||||
##
|
||||
## **Deprecated since version 0.15.0**: use ``isAlphaAscii`` instead.
|
||||
isAlphaAscii(s)
|
||||
|
||||
proc isSpace*(s: string): bool {.noSideEffect, procvar,
|
||||
rtl, deprecated, extern: "nsuIsSpaceStr".}=
|
||||
## Checks whether or not `s` is completely whitespace.
|
||||
##
|
||||
## Returns true if all characters in `s` are whitespace
|
||||
## characters and there is at least one character in `s`.
|
||||
##
|
||||
## **Deprecated since version 0.15.0**: use ``isSpaceAscii`` instead.
|
||||
isSpaceAscii(s)
|
||||
|
||||
proc isLower*(s: string): bool {.noSideEffect, procvar,
|
||||
rtl, deprecated, extern: "nsuIsLowerStr".}=
|
||||
## Checks whether or not `s` contains all lower case characters.
|
||||
##
|
||||
## This checks ASCII characters only.
|
||||
## Returns true if all characters in `s` are lower case
|
||||
## and there is at least one character in `s`.
|
||||
##
|
||||
## **Deprecated since version 0.15.0**: use ``isLowerAscii`` instead.
|
||||
isLowerAscii(s)
|
||||
|
||||
proc isUpper*(s: string): bool {.noSideEffect, procvar,
|
||||
rtl, deprecated, extern: "nsuIsUpperStr".}=
|
||||
## Checks whether or not `s` contains all upper case characters.
|
||||
##
|
||||
## This checks ASCII characters only.
|
||||
## Returns true if all characters in `s` are upper case
|
||||
## and there is at least one character in `s`.
|
||||
##
|
||||
## **Deprecated since version 0.15.0**: use ``isUpperAscii`` instead.
|
||||
isUpperAscii(s)
|
||||
|
||||
proc toLower*(c: char): char {.noSideEffect, procvar,
|
||||
rtl, deprecated, extern: "nsuToLowerChar".} =
|
||||
## Converts `c` into lower case.
|
||||
##
|
||||
## This works only for the letters ``A-Z``. See `unicode.toLower
|
||||
## <unicode.html#toLower>`_ for a version that works for any Unicode
|
||||
## character.
|
||||
##
|
||||
## **Deprecated since version 0.15.0**: use ``toLowerAscii`` instead.
|
||||
toLowerAscii(c)
|
||||
|
||||
proc toLower*(s: string): string {.noSideEffect, procvar,
|
||||
rtl, deprecated, extern: "nsuToLowerStr".} =
|
||||
## Converts `s` into lower case.
|
||||
##
|
||||
## This works only for the letters ``A-Z``. See `unicode.toLower
|
||||
## <unicode.html#toLower>`_ for a version that works for any Unicode
|
||||
## character.
|
||||
##
|
||||
## **Deprecated since version 0.15.0**: use ``toLowerAscii`` instead.
|
||||
toLowerAscii(s)
|
||||
|
||||
proc toUpper*(c: char): char {.noSideEffect, procvar,
|
||||
rtl, deprecated, extern: "nsuToUpperChar".} =
|
||||
## Converts `c` into upper case.
|
||||
##
|
||||
## This works only for the letters ``A-Z``. See `unicode.toUpper
|
||||
## <unicode.html#toUpper>`_ for a version that works for any Unicode
|
||||
## character.
|
||||
##
|
||||
## **Deprecated since version 0.15.0**: use ``toUpperAscii`` instead.
|
||||
toUpperAscii(c)
|
||||
|
||||
proc toUpper*(s: string): string {.noSideEffect, procvar,
|
||||
rtl, deprecated, extern: "nsuToUpperStr".} =
|
||||
## Converts `s` into upper case.
|
||||
##
|
||||
## This works only for the letters ``A-Z``. See `unicode.toUpper
|
||||
## <unicode.html#toUpper>`_ for a version that works for any Unicode
|
||||
## character.
|
||||
##
|
||||
## **Deprecated since version 0.15.0**: use ``toUpperAscii`` instead.
|
||||
toUpperAscii(s)
|
||||
|
||||
proc capitalize*(s: string): string {.noSideEffect, procvar,
|
||||
rtl, deprecated, extern: "nsuCapitalize".} =
|
||||
## Converts the first character of `s` into upper case.
|
||||
##
|
||||
## This works only for the letters ``A-Z``.
|
||||
##
|
||||
## **Deprecated since version 0.15.0**: use ``capitalizeAscii`` instead.
|
||||
capitalizeAscii(s)
|
||||
if s.len == 0: result = ""
|
||||
else: result = toUpperAscii(s[0]) & substr(s, 1)
|
||||
|
||||
proc normalize*(s: string): string {.noSideEffect, procvar,
|
||||
rtl, extern: "nsuNormalize".} =
|
||||
@@ -419,9 +261,9 @@ proc cmpIgnoreCase*(a, b: string): int {.noSideEffect,
|
||||
proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect,
|
||||
rtl, extern: "nsuCmpIgnoreStyle", procvar.} =
|
||||
## Semantically the same as ``cmp(normalize(a), normalize(b))``. It
|
||||
## is just optimized to not allocate temporary strings. This should
|
||||
## is just optimized to not allocate temporary strings. This should
|
||||
## NOT be used to compare Nim identifier names. use `macros.eqIdent`
|
||||
## for that. Returns:
|
||||
## for that. Returns:
|
||||
##
|
||||
## | 0 iff a == b
|
||||
## | < 0 iff a < b
|
||||
@@ -429,14 +271,22 @@ proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect,
|
||||
var i = 0
|
||||
var j = 0
|
||||
while true:
|
||||
while a[i] == '_': inc(i)
|
||||
while b[j] == '_': inc(j) # BUGFIX: typo
|
||||
var aa = toLowerAscii(a[i])
|
||||
var bb = toLowerAscii(b[j])
|
||||
while i < a.len and a[i] == '_': inc i
|
||||
while j < b.len and b[j] == '_': inc j
|
||||
var aa = if i < a.len: toLowerAscii(a[i]) else: '\0'
|
||||
var bb = if j < b.len: toLowerAscii(b[j]) else: '\0'
|
||||
result = ord(aa) - ord(bb)
|
||||
if result != 0 or aa == '\0': break
|
||||
inc(i)
|
||||
inc(j)
|
||||
if result != 0: return result
|
||||
# the characters are identical:
|
||||
if i >= a.len:
|
||||
# both cursors at the end:
|
||||
if j >= b.len: return 0
|
||||
# not yet at the end of 'b':
|
||||
return -1
|
||||
elif j >= b.len:
|
||||
return 1
|
||||
inc i
|
||||
inc j
|
||||
|
||||
proc strip*(s: string, leading = true, trailing = true,
|
||||
chars: set[char] = Whitespace): string
|
||||
@@ -451,7 +301,7 @@ proc strip*(s: string, leading = true, trailing = true,
|
||||
first = 0
|
||||
last = len(s)-1
|
||||
if leading:
|
||||
while s[first] in chars: inc(first)
|
||||
while first <= last and s[first] in chars: inc(first)
|
||||
if trailing:
|
||||
while last >= 0 and s[last] in chars: dec(last)
|
||||
result = substr(s, first, last)
|
||||
@@ -467,7 +317,9 @@ proc toOctal*(c: char): string {.noSideEffect, rtl, extern: "nsuToOctal".} =
|
||||
result[i] = chr(val mod 8 + ord('0'))
|
||||
val = val div 8
|
||||
|
||||
proc isNilOrEmpty*(s: string): bool {.noSideEffect, procvar, rtl, extern: "nsuIsNilOrEmpty".} =
|
||||
proc isNilOrEmpty*(s: string): bool {.noSideEffect, procvar, rtl,
|
||||
extern: "nsuIsNilOrEmpty",
|
||||
deprecated: "use 'x.len == 0' instead".} =
|
||||
## Checks if `s` is nil or empty.
|
||||
result = len(s) == 0
|
||||
|
||||
@@ -486,7 +338,6 @@ proc substrEq(s: string, pos: int, substr: string): bool =
|
||||
var length = substr.len
|
||||
while i < length and s[pos+i] == substr[i]:
|
||||
inc i
|
||||
|
||||
return i == length
|
||||
|
||||
# --------- Private templates for different split separators -----------
|
||||
@@ -520,7 +371,7 @@ template oldSplit(s, seps, maxsplit) =
|
||||
var splits = maxsplit
|
||||
assert(not ('\0' in seps))
|
||||
while last < len(s):
|
||||
while s[last] in seps: inc(last)
|
||||
while last < len(s) and s[last] in seps: inc(last)
|
||||
var first = last
|
||||
while last < len(s) and s[last] notin seps: inc(last)
|
||||
if first <= last-1:
|
||||
@@ -571,10 +422,7 @@ iterator split*(s: string, seps: set[char] = Whitespace,
|
||||
## "08"
|
||||
## "08.398990"
|
||||
##
|
||||
when defined(nimOldSplit):
|
||||
oldSplit(s, seps, maxsplit)
|
||||
else:
|
||||
splitCommon(s, seps, maxsplit, 1)
|
||||
splitCommon(s, seps, maxsplit, 1)
|
||||
|
||||
iterator splitWhitespace*(s: string, maxsplit: int = -1): string =
|
||||
## Splits the string ``s`` at whitespace stripping leading and trailing
|
||||
@@ -660,7 +508,6 @@ iterator split*(s: string, sep: string, maxsplit: int = -1): string =
|
||||
## "is"
|
||||
## "corrupted"
|
||||
##
|
||||
|
||||
splitCommon(s, sep, maxsplit, sep.len)
|
||||
|
||||
template rsplitCommon(s, sep, maxsplit, sepLen) =
|
||||
@@ -670,29 +517,21 @@ template rsplitCommon(s, sep, maxsplit, sepLen) =
|
||||
first = last
|
||||
splits = maxsplit
|
||||
startPos = 0
|
||||
|
||||
# go to -1 in order to get separators at the beginning
|
||||
while first >= -1:
|
||||
while first >= 0 and not stringHasSep(s, first, sep):
|
||||
dec(first)
|
||||
|
||||
if splits == 0:
|
||||
# No more splits means set first to the beginning
|
||||
first = -1
|
||||
|
||||
if first == -1:
|
||||
startPos = 0
|
||||
else:
|
||||
startPos = first + sepLen
|
||||
|
||||
yield substr(s, startPos, last)
|
||||
|
||||
if splits == 0:
|
||||
break
|
||||
|
||||
if splits == 0: break
|
||||
dec(splits)
|
||||
dec(first)
|
||||
|
||||
last = first
|
||||
|
||||
iterator rsplit*(s: string, seps: set[char] = Whitespace,
|
||||
@@ -712,7 +551,6 @@ iterator rsplit*(s: string, seps: set[char] = Whitespace,
|
||||
## "foo"
|
||||
##
|
||||
## Substrings are separated from the right by the set of chars `seps`
|
||||
|
||||
rsplitCommon(s, seps, maxsplit, 1)
|
||||
|
||||
iterator rsplit*(s: string, sep: char,
|
||||
@@ -779,14 +617,14 @@ iterator splitLines*(s: string): string =
|
||||
var first = 0
|
||||
var last = 0
|
||||
while true:
|
||||
while s[last] notin {'\0', '\c', '\l'}: inc(last)
|
||||
while last < s.len and s[last] notin {'\c', '\l'}: inc(last)
|
||||
yield substr(s, first, last-1)
|
||||
# skip newlines:
|
||||
if last >= s.len: break
|
||||
if s[last] == '\l': inc(last)
|
||||
elif s[last] == '\c':
|
||||
inc(last)
|
||||
if s[last] == '\l': inc(last)
|
||||
else: break # was '\0'
|
||||
if last < s.len and s[last] == '\l': inc(last)
|
||||
first = last
|
||||
|
||||
proc splitLines*(s: string): seq[string] {.noSideEffect,
|
||||
@@ -811,7 +649,7 @@ proc countLines*(s: string): int {.noSideEffect,
|
||||
while i < s.len:
|
||||
case s[i]
|
||||
of '\c':
|
||||
if s[i+1] == '\l': inc i
|
||||
if i+1 < s.len and s[i+1] == '\l': inc i
|
||||
inc result
|
||||
of '\l': inc result
|
||||
else: discard
|
||||
@@ -1025,9 +863,9 @@ proc parseHexInt*(s: string): int {.noSideEffect, procvar,
|
||||
## of the following optional prefixes: ``0x``, ``0X``, ``#``. Underscores
|
||||
## within `s` are ignored.
|
||||
var i = 0
|
||||
if s[i] == '0' and (s[i+1] == 'x' or s[i+1] == 'X'): inc(i, 2)
|
||||
elif s[i] == '#': inc(i)
|
||||
while true:
|
||||
if i+1 < s.len and s[i] == '0' and (s[i+1] == 'x' or s[i+1] == 'X'): inc(i, 2)
|
||||
elif i < s.len and s[i] == '#': inc(i)
|
||||
while i < s.len:
|
||||
case s[i]
|
||||
of '_': inc(i)
|
||||
of '0'..'9':
|
||||
@@ -1039,7 +877,6 @@ proc parseHexInt*(s: string): int {.noSideEffect, procvar,
|
||||
of 'A'..'F':
|
||||
result = result shl 4 or (ord(s[i]) - ord('A') + 10)
|
||||
inc(i)
|
||||
of '\0': break
|
||||
else: raise newException(ValueError, "invalid integer: " & s)
|
||||
|
||||
proc generateHexCharToValueMap(): string =
|
||||
@@ -1148,14 +985,6 @@ template spaces*(n: Natural): string = repeat(' ', n)
|
||||
## echo text1 & spaces(max(0, width - text1.len)) & "|"
|
||||
## echo text2 & spaces(max(0, width - text2.len)) & "|"
|
||||
|
||||
proc repeatChar*(count: Natural, c: char = ' '): string {.deprecated.} =
|
||||
## deprecated: use repeat() or spaces()
|
||||
repeat(c, count)
|
||||
|
||||
proc repeatStr*(count: Natural, s: string): string {.deprecated.} =
|
||||
## deprecated: use repeat(string, count) or string.repeat(count)
|
||||
repeat(s, count)
|
||||
|
||||
proc align*(s: string, count: Natural, padding = ' '): string {.
|
||||
noSideEffect, rtl, extern: "nsuAlignString".} =
|
||||
## Aligns a string `s` with `padding`, so that it is of length `count`.
|
||||
@@ -1226,7 +1055,7 @@ iterator tokenize*(s: string, seps: set[char] = Whitespace): tuple[
|
||||
var i = 0
|
||||
while true:
|
||||
var j = i
|
||||
var isSep = s[j] in seps
|
||||
var isSep = j < s.len and s[j] in seps
|
||||
while j < s.len and (s[j] in seps) == isSep: inc(j)
|
||||
if j > i:
|
||||
yield (substr(s, i, j-1), isSep)
|
||||
@@ -1297,7 +1126,7 @@ proc unindent*(s: string, count: Natural, padding: string = " "): string
|
||||
var indentCount = 0
|
||||
for j in 0..<count.int:
|
||||
indentCount.inc
|
||||
if line[j .. j + padding.len-1] != padding:
|
||||
if j + padding.len-1 >= line.len or line[j .. j + padding.len-1] != padding:
|
||||
indentCount = j
|
||||
break
|
||||
result.add(line[indentCount*padding.len .. ^1])
|
||||
@@ -1325,13 +1154,13 @@ proc startsWith*(s, prefix: string): bool {.noSideEffect,
|
||||
## If ``prefix == ""`` true is returned.
|
||||
var i = 0
|
||||
while true:
|
||||
if prefix[i] == '\0': return true
|
||||
if s[i] != prefix[i]: return false
|
||||
if i >= prefix.len: return true
|
||||
if i >= s.len or s[i] != prefix[i]: return false
|
||||
inc(i)
|
||||
|
||||
proc startsWith*(s: string, prefix: char): bool {.noSideEffect, inline.} =
|
||||
## Returns true iff ``s`` starts with ``prefix``.
|
||||
result = s[0] == prefix
|
||||
result = s.len > 0 and s[0] == prefix
|
||||
|
||||
proc endsWith*(s, suffix: string): bool {.noSideEffect,
|
||||
rtl, extern: "nsuEndsWith".} =
|
||||
@@ -1343,11 +1172,11 @@ proc endsWith*(s, suffix: string): bool {.noSideEffect,
|
||||
while i+j <% s.len:
|
||||
if s[i+j] != suffix[i]: return false
|
||||
inc(i)
|
||||
if suffix[i] == '\0': return true
|
||||
if i >= suffix.len: return true
|
||||
|
||||
proc endsWith*(s: string, suffix: char): bool {.noSideEffect, inline.} =
|
||||
## Returns true iff ``s`` ends with ``suffix``.
|
||||
result = s[s.high] == suffix
|
||||
result = s.len > 0 and s[s.high] == suffix
|
||||
|
||||
proc continuesWith*(s, substr: string, start: Natural): bool {.noSideEffect,
|
||||
rtl, extern: "nsuContinuesWith".} =
|
||||
@@ -1356,8 +1185,8 @@ proc continuesWith*(s, substr: string, start: Natural): bool {.noSideEffect,
|
||||
## If ``substr == ""`` true is returned.
|
||||
var i = 0
|
||||
while true:
|
||||
if substr[i] == '\0': return true
|
||||
if s[i+start] != substr[i]: return false
|
||||
if i >= substr.len: return true
|
||||
if i+start >= s.len or s[i+start] != substr[i]: return false
|
||||
inc(i)
|
||||
|
||||
proc addSep*(dest: var string, sep = ", ", startLen: Natural = 0)
|
||||
@@ -1502,12 +1331,8 @@ proc find*(s, sub: string, start: Natural = 0, last: Natural = 0): int {.noSideE
|
||||
## If `last` is unspecified, it defaults to `s.high`.
|
||||
##
|
||||
## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned.
|
||||
if sub.len > s.len:
|
||||
return -1
|
||||
|
||||
if sub.len == 1:
|
||||
return find(s, sub[0], start, last)
|
||||
|
||||
if sub.len > s.len: return -1
|
||||
if sub.len == 1: return find(s, sub[0], start, last)
|
||||
var a {.noinit.}: SkipTable
|
||||
initSkipTable(a, sub)
|
||||
result = find(a, s, sub, start, last)
|
||||
@@ -1564,18 +1389,14 @@ proc center*(s: string, width: int, fillChar: char = ' '): string {.
|
||||
##
|
||||
## The original string is returned if `width` is less than or equal
|
||||
## to `s.len`.
|
||||
if width <= s.len:
|
||||
return s
|
||||
|
||||
if width <= s.len: return s
|
||||
result = newString(width)
|
||||
|
||||
# Left padding will be one fillChar
|
||||
# smaller if there are an odd number
|
||||
# of characters
|
||||
let
|
||||
charsLeft = (width - s.len)
|
||||
leftPadding = charsLeft div 2
|
||||
|
||||
for i in 0 ..< width:
|
||||
if i >= leftPadding and i < leftPadding + s.len:
|
||||
# we are where the string should be located
|
||||
@@ -1593,27 +1414,22 @@ proc count*(s: string, sub: string, overlapping: bool = false): int {.
|
||||
var i = 0
|
||||
while true:
|
||||
i = s.find(sub, i)
|
||||
if i < 0:
|
||||
break
|
||||
if overlapping:
|
||||
inc i
|
||||
else:
|
||||
i += sub.len
|
||||
if i < 0: break
|
||||
if overlapping: inc i
|
||||
else: i += sub.len
|
||||
inc result
|
||||
|
||||
proc count*(s: string, sub: char): int {.noSideEffect,
|
||||
rtl, extern: "nsuCountChar".} =
|
||||
## Count the occurrences of the character `sub` in the string `s`.
|
||||
for c in s:
|
||||
if c == sub:
|
||||
inc result
|
||||
if c == sub: inc result
|
||||
|
||||
proc count*(s: string, subs: set[char]): int {.noSideEffect,
|
||||
rtl, extern: "nsuCountCharSet".} =
|
||||
## Count the occurrences of the group of character `subs` in the string `s`.
|
||||
for c in s:
|
||||
if c in subs:
|
||||
inc result
|
||||
if c in subs: inc result
|
||||
|
||||
proc quoteIfContainsWhite*(s: string): string {.deprecated.} =
|
||||
## Returns ``'"' & s & '"'`` if `s` contains a space and does not
|
||||
@@ -1621,10 +1437,8 @@ proc quoteIfContainsWhite*(s: string): string {.deprecated.} =
|
||||
##
|
||||
## **DEPRECATED** as it was confused for shell quoting function. For this
|
||||
## application use `osproc.quoteShell <osproc.html#quoteShell>`_.
|
||||
if find(s, {' ', '\t'}) >= 0 and s[0] != '"':
|
||||
result = '"' & s & '"'
|
||||
else:
|
||||
result = s
|
||||
if find(s, {' ', '\t'}) >= 0 and s[0] != '"': result = '"' & s & '"'
|
||||
else: result = s
|
||||
|
||||
proc contains*(s: string, c: char): bool {.noSideEffect.} =
|
||||
## Same as ``find(s, c) >= 0``.
|
||||
@@ -1704,9 +1518,8 @@ proc multiReplace*(s: string, replacements: varargs[(string, string)]): string {
|
||||
## Same as replace, but specialized for doing multiple replacements in a single
|
||||
## pass through the input string.
|
||||
##
|
||||
## Calling replace multiple times after each other is inefficient and result in too many allocations
|
||||
## follwed by immediate deallocations as portions of the string gets replaced.
|
||||
## multiReplace performs all replacements in a single pass.
|
||||
## multiReplace performs all replacements in a single pass, this means it can be used
|
||||
## to swap the occurences of "a" and "b", for instance.
|
||||
##
|
||||
## If the resulting string is not longer than the original input string, only a single
|
||||
## memory allocation is required.
|
||||
@@ -1753,14 +1566,13 @@ proc parseOctInt*(s: string): int {.noSideEffect,
|
||||
## of the following optional prefixes: ``0o``, ``0O``. Underscores within
|
||||
## `s` are ignored.
|
||||
var i = 0
|
||||
if s[i] == '0' and (s[i+1] == 'o' or s[i+1] == 'O'): inc(i, 2)
|
||||
while true:
|
||||
if i+1 < s.len and s[i] == '0' and (s[i+1] == 'o' or s[i+1] == 'O'): inc(i, 2)
|
||||
while i < s.len:
|
||||
case s[i]
|
||||
of '_': inc(i)
|
||||
of '0'..'7':
|
||||
result = result shl 3 or (ord(s[i]) - ord('0'))
|
||||
inc(i)
|
||||
of '\0': break
|
||||
else: raise newException(ValueError, "invalid integer: " & s)
|
||||
|
||||
proc toOct*(x: BiggestInt, len: Positive): string {.noSideEffect,
|
||||
@@ -1849,16 +1661,18 @@ proc unescape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect,
|
||||
## If `s` does not begin with ``prefix`` and end with ``suffix`` a
|
||||
## ValueError exception will be raised.
|
||||
##
|
||||
## **Warning:** This procedure is deprecated because it's to easy to missuse.
|
||||
## **Warning:** This procedure is deprecated because it's to easy to missuse.
|
||||
result = newStringOfCap(s.len)
|
||||
var i = prefix.len
|
||||
if not s.startsWith(prefix):
|
||||
raise newException(ValueError,
|
||||
"String does not start with a prefix of: " & prefix)
|
||||
"String does not start with: " & prefix)
|
||||
while true:
|
||||
if i == s.len-suffix.len: break
|
||||
case s[i]
|
||||
of '\\':
|
||||
if i >= s.len-suffix.len: break
|
||||
if s[i] == '\\':
|
||||
if i+1 >= s.len:
|
||||
result.add('\\')
|
||||
break
|
||||
case s[i+1]:
|
||||
of 'x':
|
||||
inc i, 2
|
||||
@@ -1872,15 +1686,15 @@ proc unescape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect,
|
||||
result.add('\'')
|
||||
of '\"':
|
||||
result.add('\"')
|
||||
else: result.add("\\" & s[i+1])
|
||||
inc(i)
|
||||
of '\0': break
|
||||
else:
|
||||
result.add("\\" & s[i+1])
|
||||
inc(i, 2)
|
||||
else:
|
||||
result.add(s[i])
|
||||
inc(i)
|
||||
inc(i)
|
||||
if not s.endsWith(suffix):
|
||||
raise newException(ValueError,
|
||||
"String does not end with a suffix of: " & suffix)
|
||||
"String does not end in: " & suffix)
|
||||
|
||||
proc validIdentifier*(s: string): bool {.noSideEffect,
|
||||
rtl, extern: "nsuValidIdentifier".} =
|
||||
@@ -1890,7 +1704,7 @@ proc validIdentifier*(s: string): bool {.noSideEffect,
|
||||
## and is followed by any number of characters of the set `IdentChars`.
|
||||
runnableExamples:
|
||||
doAssert "abc_def08".validIdentifier
|
||||
if s[0] in IdentStartChars:
|
||||
if s.len > 0 and s[0] in IdentStartChars:
|
||||
for i in 1..s.len-1:
|
||||
if s[i] notin IdentChars: return false
|
||||
return true
|
||||
@@ -1909,7 +1723,7 @@ proc editDistance*(a, b: string): int {.noSideEffect,
|
||||
|
||||
# strip common prefix:
|
||||
var s = 0
|
||||
while a[s] == b[s] and a[s] != '\0':
|
||||
while s < len1 and a[s] == b[s]:
|
||||
inc(s)
|
||||
dec(len1)
|
||||
dec(len2)
|
||||
@@ -1982,8 +1796,6 @@ proc editDistance*(a, b: string): int {.noSideEffect,
|
||||
if x > c3: x = c3
|
||||
row[p] = x
|
||||
result = row[e]
|
||||
#dealloc(row)
|
||||
|
||||
|
||||
# floating point formating:
|
||||
when not defined(js):
|
||||
@@ -2092,7 +1904,7 @@ proc trimZeros*(x: var string) {.noSideEffect.} =
|
||||
var spl: seq[string]
|
||||
if x.contains('.') or x.contains(','):
|
||||
if x.contains('e'):
|
||||
spl= x.split('e')
|
||||
spl = x.split('e')
|
||||
x = spl[0]
|
||||
while x[x.high] == '0':
|
||||
x.setLen(x.len-1)
|
||||
@@ -2310,9 +2122,8 @@ proc addf*(s: var string, formatstr: string, a: varargs[string, `$`]) {.
|
||||
var i = 0
|
||||
var num = 0
|
||||
while i < len(formatstr):
|
||||
if formatstr[i] == '$':
|
||||
case formatstr[i+1] # again we use the fact that strings
|
||||
# are zero-terminated here
|
||||
if formatstr[i] == '$' and i+1 < len(formatstr):
|
||||
case formatstr[i+1]
|
||||
of '#':
|
||||
if num > a.high: invalidFormatString()
|
||||
add s, a[num]
|
||||
@@ -2326,7 +2137,7 @@ proc addf*(s: var string, formatstr: string, a: varargs[string, `$`]) {.
|
||||
inc(i) # skip $
|
||||
var negative = formatstr[i] == '-'
|
||||
if negative: inc i
|
||||
while formatstr[i] in Digits:
|
||||
while i < formatstr.len and formatstr[i] in Digits:
|
||||
j = j * 10 + ord(formatstr[i]) - ord('0')
|
||||
inc(i)
|
||||
let idx = if not negative: j-1 else: a.len-j
|
||||
@@ -2338,7 +2149,7 @@ proc addf*(s: var string, formatstr: string, a: varargs[string, `$`]) {.
|
||||
var negative = formatstr[j] == '-'
|
||||
if negative: inc j
|
||||
var isNumber = 0
|
||||
while formatstr[j] notin {'\0', '}'}:
|
||||
while j < formatstr.len and formatstr[j] notin {'\0', '}'}:
|
||||
if formatstr[j] in Digits:
|
||||
k = k * 10 + ord(formatstr[j]) - ord('0')
|
||||
if isNumber == 0: isNumber = 1
|
||||
@@ -2356,7 +2167,7 @@ proc addf*(s: var string, formatstr: string, a: varargs[string, `$`]) {.
|
||||
i = j+1
|
||||
of 'a'..'z', 'A'..'Z', '\128'..'\255', '_':
|
||||
var j = i+1
|
||||
while formatstr[j] in PatternChars: inc(j)
|
||||
while j < formatstr.len and formatstr[j] in PatternChars: inc(j)
|
||||
var x = findNormalized(substr(formatstr, i+1, j-1), a)
|
||||
if x >= 0 and x < high(a): add s, a[x+1]
|
||||
else: invalidFormatString()
|
||||
@@ -2628,13 +2439,7 @@ when isMainModule:
|
||||
doAssert isSpaceAscii(" ")
|
||||
doAssert(not isSpaceAscii("ABc \td"))
|
||||
|
||||
doAssert(isNilOrEmpty(""))
|
||||
doAssert(isNilOrEmpty(nil))
|
||||
doAssert(not isNilOrEmpty("test"))
|
||||
doAssert(not isNilOrEmpty(" "))
|
||||
|
||||
doAssert(isNilOrWhitespace(""))
|
||||
doAssert(isNilOrWhitespace(nil))
|
||||
doAssert(isNilOrWhitespace(" "))
|
||||
doAssert(isNilOrWhitespace("\t\l \v\r\f"))
|
||||
doAssert(not isNilOrWhitespace("ABc \td"))
|
||||
|
||||
@@ -1318,24 +1318,23 @@ proc format*(dt: DateTime, f: string): string {.tags: [].}=
|
||||
result = ""
|
||||
var i = 0
|
||||
var currentF = ""
|
||||
while true:
|
||||
while i < f.len:
|
||||
case f[i]
|
||||
of ' ', '-', '/', ':', '\'', '\0', '(', ')', '[', ']', ',':
|
||||
of ' ', '-', '/', ':', '\'', '(', ')', '[', ']', ',':
|
||||
formatToken(dt, currentF, result)
|
||||
|
||||
currentF = ""
|
||||
if f[i] == '\0': break
|
||||
|
||||
if f[i] == '\'':
|
||||
inc(i) # Skip '
|
||||
while f[i] != '\'' and f.len-1 > i:
|
||||
while i < f.len-1 and f[i] != '\'':
|
||||
result.add(f[i])
|
||||
inc(i)
|
||||
else: result.add(f[i])
|
||||
|
||||
else:
|
||||
# Check if the letter being added matches previous accumulated buffer.
|
||||
if currentF.len < 1 or currentF[high(currentF)] == f[i]:
|
||||
if currentF.len == 0 or currentF[high(currentF)] == f[i]:
|
||||
currentF.add(f[i])
|
||||
else:
|
||||
formatToken(dt, currentF, result)
|
||||
@@ -1343,6 +1342,7 @@ proc format*(dt: DateTime, f: string): string {.tags: [].}=
|
||||
currentF = ""
|
||||
|
||||
inc(i)
|
||||
formatToken(dt, currentF, result)
|
||||
|
||||
proc `$`*(dt: DateTime): string {.tags: [], raises: [], benign.} =
|
||||
## Converts a `DateTime` object to a string representation.
|
||||
@@ -1439,58 +1439,58 @@ proc parseToken(dt: var DateTime; token, value: string; j: var int) =
|
||||
dt.month = month.Month
|
||||
of "MMM":
|
||||
case value[j..j+2].toLowerAscii():
|
||||
of "jan": dt.month = mJan
|
||||
of "feb": dt.month = mFeb
|
||||
of "mar": dt.month = mMar
|
||||
of "apr": dt.month = mApr
|
||||
of "may": dt.month = mMay
|
||||
of "jun": dt.month = mJun
|
||||
of "jul": dt.month = mJul
|
||||
of "aug": dt.month = mAug
|
||||
of "sep": dt.month = mSep
|
||||
of "oct": dt.month = mOct
|
||||
of "nov": dt.month = mNov
|
||||
of "dec": dt.month = mDec
|
||||
of "jan": dt.month = mJan
|
||||
of "feb": dt.month = mFeb
|
||||
of "mar": dt.month = mMar
|
||||
of "apr": dt.month = mApr
|
||||
of "may": dt.month = mMay
|
||||
of "jun": dt.month = mJun
|
||||
of "jul": dt.month = mJul
|
||||
of "aug": dt.month = mAug
|
||||
of "sep": dt.month = mSep
|
||||
of "oct": dt.month = mOct
|
||||
of "nov": dt.month = mNov
|
||||
of "dec": dt.month = mDec
|
||||
else:
|
||||
raise newException(ValueError,
|
||||
"Couldn't parse month (MMM), got: " & value)
|
||||
j += 3
|
||||
of "MMMM":
|
||||
if value.len >= j+7 and value[j..j+6].cmpIgnoreCase("january") == 0:
|
||||
dt.month = mJan
|
||||
dt.month = mJan
|
||||
j += 7
|
||||
elif value.len >= j+8 and value[j..j+7].cmpIgnoreCase("february") == 0:
|
||||
dt.month = mFeb
|
||||
dt.month = mFeb
|
||||
j += 8
|
||||
elif value.len >= j+5 and value[j..j+4].cmpIgnoreCase("march") == 0:
|
||||
dt.month = mMar
|
||||
dt.month = mMar
|
||||
j += 5
|
||||
elif value.len >= j+5 and value[j..j+4].cmpIgnoreCase("april") == 0:
|
||||
dt.month = mApr
|
||||
dt.month = mApr
|
||||
j += 5
|
||||
elif value.len >= j+3 and value[j..j+2].cmpIgnoreCase("may") == 0:
|
||||
dt.month = mMay
|
||||
dt.month = mMay
|
||||
j += 3
|
||||
elif value.len >= j+4 and value[j..j+3].cmpIgnoreCase("june") == 0:
|
||||
dt.month = mJun
|
||||
dt.month = mJun
|
||||
j += 4
|
||||
elif value.len >= j+4 and value[j..j+3].cmpIgnoreCase("july") == 0:
|
||||
dt.month = mJul
|
||||
dt.month = mJul
|
||||
j += 4
|
||||
elif value.len >= j+6 and value[j..j+5].cmpIgnoreCase("august") == 0:
|
||||
dt.month = mAug
|
||||
dt.month = mAug
|
||||
j += 6
|
||||
elif value.len >= j+9 and value[j..j+8].cmpIgnoreCase("september") == 0:
|
||||
dt.month = mSep
|
||||
dt.month = mSep
|
||||
j += 9
|
||||
elif value.len >= j+7 and value[j..j+6].cmpIgnoreCase("october") == 0:
|
||||
dt.month = mOct
|
||||
dt.month = mOct
|
||||
j += 7
|
||||
elif value.len >= j+8 and value[j..j+7].cmpIgnoreCase("november") == 0:
|
||||
dt.month = mNov
|
||||
dt.month = mNov
|
||||
j += 8
|
||||
elif value.len >= j+8 and value[j..j+7].cmpIgnoreCase("december") == 0:
|
||||
dt.month = mDec
|
||||
dt.month = mDec
|
||||
j += 8
|
||||
else:
|
||||
raise newException(ValueError,
|
||||
@@ -1521,44 +1521,47 @@ proc parseToken(dt: var DateTime; token, value: string; j: var int) =
|
||||
j += 4
|
||||
of "z":
|
||||
dt.isDst = false
|
||||
if value[j] == '+':
|
||||
let ch = if j < value.len: value[j] else: '\0'
|
||||
if ch == '+':
|
||||
dt.utcOffset = 0 - parseInt($value[j+1]) * secondsInHour
|
||||
elif value[j] == '-':
|
||||
elif ch == '-':
|
||||
dt.utcOffset = parseInt($value[j+1]) * secondsInHour
|
||||
elif value[j] == 'Z':
|
||||
elif ch == 'Z':
|
||||
dt.utcOffset = 0
|
||||
j += 1
|
||||
return
|
||||
else:
|
||||
raise newException(ValueError,
|
||||
"Couldn't parse timezone offset (z), got: " & value[j])
|
||||
"Couldn't parse timezone offset (z), got: " & ch)
|
||||
j += 2
|
||||
of "zz":
|
||||
dt.isDst = false
|
||||
if value[j] == '+':
|
||||
let ch = if j < value.len: value[j] else: '\0'
|
||||
if ch == '+':
|
||||
dt.utcOffset = 0 - value[j+1..j+2].parseInt() * secondsInHour
|
||||
elif value[j] == '-':
|
||||
elif ch == '-':
|
||||
dt.utcOffset = value[j+1..j+2].parseInt() * secondsInHour
|
||||
elif value[j] == 'Z':
|
||||
elif ch == 'Z':
|
||||
dt.utcOffset = 0
|
||||
j += 1
|
||||
return
|
||||
else:
|
||||
raise newException(ValueError,
|
||||
"Couldn't parse timezone offset (zz), got: " & value[j])
|
||||
"Couldn't parse timezone offset (zz), got: " & ch)
|
||||
j += 3
|
||||
of "zzz":
|
||||
dt.isDst = false
|
||||
var factor = 0
|
||||
if value[j] == '+': factor = -1
|
||||
elif value[j] == '-': factor = 1
|
||||
elif value[j] == 'Z':
|
||||
let ch = if j < value.len: value[j] else: '\0'
|
||||
if ch == '+': factor = -1
|
||||
elif ch == '-': factor = 1
|
||||
elif ch == 'Z':
|
||||
dt.utcOffset = 0
|
||||
j += 1
|
||||
return
|
||||
else:
|
||||
raise newException(ValueError,
|
||||
"Couldn't parse timezone offset (zzz), got: " & value[j])
|
||||
"Couldn't parse timezone offset (zzz), got: " & ch)
|
||||
dt.utcOffset = factor * value[j+1..j+2].parseInt() * secondsInHour
|
||||
j += 4
|
||||
dt.utcOffset += factor * value[j..j+1].parseInt() * 60
|
||||
@@ -1620,20 +1623,18 @@ proc parse*(value, layout: string, zone: Timezone = local()): DateTime =
|
||||
dt.nanosecond = 0
|
||||
dt.isDst = true # using this is flag for checking whether a timezone has \
|
||||
# been read (because DST is always false when a tz is parsed)
|
||||
while true:
|
||||
while i < layout.len:
|
||||
case layout[i]
|
||||
of ' ', '-', '/', ':', '\'', '\0', '(', ')', '[', ']', ',':
|
||||
of ' ', '-', '/', ':', '\'', '(', ')', '[', ']', ',':
|
||||
if token.len > 0:
|
||||
parseToken(dt, token, value, j)
|
||||
# Reset token
|
||||
token = ""
|
||||
# Break if at end of line
|
||||
if layout[i] == '\0': break
|
||||
# Skip separator and everything between single quotes
|
||||
# These are literals in both the layout and the value string
|
||||
if layout[i] == '\'':
|
||||
inc(i)
|
||||
while layout[i] != '\'' and layout.len-1 > i:
|
||||
while i < layout.len-1 and layout[i] != '\'':
|
||||
inc(i)
|
||||
inc(j)
|
||||
inc(i)
|
||||
@@ -1642,13 +1643,15 @@ proc parse*(value, layout: string, zone: Timezone = local()): DateTime =
|
||||
inc(j)
|
||||
else:
|
||||
# Check if the letter being added matches previous accumulated buffer.
|
||||
if token.len < 1 or token[high(token)] == layout[i]:
|
||||
if token.len == 0 or token[high(token)] == layout[i]:
|
||||
token.add(layout[i])
|
||||
inc(i)
|
||||
else:
|
||||
parseToken(dt, token, value, j)
|
||||
token = ""
|
||||
|
||||
if i >= layout.len and token.len > 0:
|
||||
parseToken(dt, token, value, j)
|
||||
if dt.isDst:
|
||||
# No timezone parsed - assume timezone is `zone`
|
||||
result = initDateTime(zone.zoneInfoFromTz(dt.toAdjTime), zone)
|
||||
|
||||
@@ -60,7 +60,7 @@ proc encodeUrl*(s: string): string =
|
||||
else:
|
||||
add(result, '%')
|
||||
add(result, toHex(ord(s[i]), 2))
|
||||
|
||||
|
||||
proc decodeUrl*(s: string): string =
|
||||
## Decodes a value from its HTTP representation: This means that a ``'+'``
|
||||
## is converted to a space, ``'%xx'`` (where ``xx`` denotes a hexadecimal
|
||||
@@ -72,7 +72,7 @@ proc decodeUrl*(s: string): string =
|
||||
of 'a'..'f': x = (x shl 4) or (ord(c) - ord('a') + 10)
|
||||
of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10)
|
||||
else: assert(false)
|
||||
|
||||
|
||||
result = newString(s.len)
|
||||
var i = 0
|
||||
var j = 0
|
||||
@@ -94,7 +94,7 @@ proc parseAuthority(authority: string, result: var Uri) =
|
||||
var i = 0
|
||||
var inPort = false
|
||||
var inIPv6 = false
|
||||
while true:
|
||||
while i < authority.len:
|
||||
case authority[i]
|
||||
of '@':
|
||||
swap result.password, result.port
|
||||
@@ -111,7 +111,6 @@ proc parseAuthority(authority: string, result: var Uri) =
|
||||
inIPv6 = true
|
||||
of ']':
|
||||
inIPv6 = false
|
||||
of '\0': break
|
||||
else:
|
||||
if inPort:
|
||||
result.port.add(authority[i])
|
||||
@@ -128,11 +127,11 @@ proc parsePath(uri: string, i: var int, result: var Uri) =
|
||||
parseAuthority(result.path, result)
|
||||
result.path.setLen(0)
|
||||
|
||||
if uri[i] == '?':
|
||||
if i < uri.len and uri[i] == '?':
|
||||
i.inc # Skip '?'
|
||||
i.inc parseUntil(uri, result.query, {'#'}, i)
|
||||
|
||||
if uri[i] == '#':
|
||||
if i < uri.len and uri[i] == '#':
|
||||
i.inc # Skip '#'
|
||||
i.inc parseUntil(uri, result.anchor, {}, i)
|
||||
|
||||
@@ -156,7 +155,7 @@ proc parseUri*(uri: string, result: var Uri) =
|
||||
|
||||
# Check if this is a reference URI (relative URI)
|
||||
let doubleSlash = uri.len > 1 and uri[1] == '/'
|
||||
if uri[i] == '/':
|
||||
if i < uri.len and uri[i] == '/':
|
||||
# Make sure ``uri`` doesn't begin with '//'.
|
||||
if not doubleSlash:
|
||||
parsePath(uri, i, result)
|
||||
@@ -164,7 +163,7 @@ proc parseUri*(uri: string, result: var Uri) =
|
||||
|
||||
# Scheme
|
||||
i.inc parseWhile(uri, result.scheme, Letters + Digits + {'+', '-', '.'}, i)
|
||||
if uri[i] != ':' and not doubleSlash:
|
||||
if (i >= uri.len or uri[i] != ':') and not doubleSlash:
|
||||
# Assume this is a reference URI (relative URI)
|
||||
i = 0
|
||||
result.scheme.setLen(0)
|
||||
@@ -174,7 +173,7 @@ proc parseUri*(uri: string, result: var Uri) =
|
||||
i.inc # Skip ':'
|
||||
|
||||
# Authority
|
||||
if uri[i] == '/' and uri[i+1] == '/':
|
||||
if i+1 < uri.len and uri[i] == '/' and uri[i+1] == '/':
|
||||
i.inc(2) # Skip //
|
||||
var authority = ""
|
||||
i.inc parseUntil(uri, authority, {'/', '?', '#'}, i)
|
||||
@@ -197,13 +196,13 @@ proc removeDotSegments(path: string): string =
|
||||
let endsWithSlash = path[path.len-1] == '/'
|
||||
var i = 0
|
||||
var currentSegment = ""
|
||||
while true:
|
||||
while i < path.len:
|
||||
case path[i]
|
||||
of '/':
|
||||
collection.add(currentSegment)
|
||||
currentSegment = ""
|
||||
of '.':
|
||||
if path[i+1] == '.' and path[i+2] == '/':
|
||||
if i+2 < path.len and path[i+1] == '.' and path[i+2] == '/':
|
||||
if collection.len > 0:
|
||||
discard collection.pop()
|
||||
i.inc 3
|
||||
@@ -212,13 +211,11 @@ proc removeDotSegments(path: string): string =
|
||||
i.inc 2
|
||||
continue
|
||||
currentSegment.add path[i]
|
||||
of '\0':
|
||||
if currentSegment != "":
|
||||
collection.add currentSegment
|
||||
break
|
||||
else:
|
||||
currentSegment.add path[i]
|
||||
i.inc
|
||||
if currentSegment != "":
|
||||
collection.add currentSegment
|
||||
|
||||
result = collection.join("/")
|
||||
if endsWithSlash: result.add '/'
|
||||
@@ -320,18 +317,18 @@ proc `/`*(x: Uri, path: string): Uri =
|
||||
result = x
|
||||
|
||||
if result.path.len == 0:
|
||||
if path[0] != '/':
|
||||
if path.len == 0 or path[0] != '/':
|
||||
result.path = "/"
|
||||
result.path.add(path)
|
||||
return
|
||||
|
||||
if result.path[result.path.len-1] == '/':
|
||||
if path[0] == '/':
|
||||
if result.path.len > 0 and result.path[result.path.len-1] == '/':
|
||||
if path.len > 0 and path[0] == '/':
|
||||
result.path.add(path[1 .. path.len-1])
|
||||
else:
|
||||
result.path.add(path)
|
||||
else:
|
||||
if path[0] != '/':
|
||||
if path.len == 0 or path[0] != '/':
|
||||
result.path.add '/'
|
||||
result.path.add(path)
|
||||
|
||||
@@ -373,7 +370,7 @@ when isMainModule:
|
||||
const test1 = "abc\L+def xyz"
|
||||
doAssert encodeUrl(test1) == "abc%0A%2Bdef+xyz"
|
||||
doAssert decodeUrl(encodeUrl(test1)) == test1
|
||||
|
||||
|
||||
block:
|
||||
let str = "http://localhost"
|
||||
let test = parseUri(str)
|
||||
@@ -464,7 +461,7 @@ when isMainModule:
|
||||
doAssert test.hostname == "github.com"
|
||||
doAssert test.port == "dom96"
|
||||
doAssert test.path == "/packages"
|
||||
|
||||
|
||||
block:
|
||||
let str = "file:///foo/bar/baz.txt"
|
||||
let test = parseUri(str)
|
||||
|
||||
@@ -232,10 +232,10 @@ proc createAttributeNS*(doc: PDocument, namespaceURI: string, qualifiedName: str
|
||||
raise newException(EInvalidCharacterErr, "Invalid character")
|
||||
# Exceptions
|
||||
if qualifiedName.contains(':'):
|
||||
let qfnamespaces = qualifiedName.toLower().split(':')
|
||||
let qfnamespaces = qualifiedName.toLowerAscii().split(':')
|
||||
if isNil(namespaceURI):
|
||||
raise newException(ENamespaceErr, "When qualifiedName contains a prefix namespaceURI cannot be nil")
|
||||
elif qfnamespaces[0] == "xml" and
|
||||
elif qfnamespaces[0] == "xml" and
|
||||
namespaceURI != "http://www.w3.org/XML/1998/namespace" and
|
||||
qfnamespaces[1] notin stdattrnames:
|
||||
raise newException(ENamespaceErr,
|
||||
@@ -311,10 +311,10 @@ proc createElement*(doc: PDocument, tagName: string): PElement =
|
||||
proc createElementNS*(doc: PDocument, namespaceURI: string, qualifiedName: string): PElement =
|
||||
## Creates an element of the given qualified name and namespace URI.
|
||||
if qualifiedName.contains(':'):
|
||||
let qfnamespaces = qualifiedName.toLower().split(':')
|
||||
let qfnamespaces = qualifiedName.toLowerAscii().split(':')
|
||||
if isNil(namespaceURI):
|
||||
raise newException(ENamespaceErr, "When qualifiedName contains a prefix namespaceURI cannot be nil")
|
||||
elif qfnamespaces[0] == "xml" and
|
||||
elif qfnamespaces[0] == "xml" and
|
||||
namespaceURI != "http://www.w3.org/XML/1998/namespace" and
|
||||
qfnamespaces[1] notin stdattrnames:
|
||||
raise newException(ENamespaceErr,
|
||||
@@ -533,13 +533,13 @@ proc `prefix=`*(n: PNode, value: string) =
|
||||
|
||||
if isNil(n.fNamespaceURI):
|
||||
raise newException(ENamespaceErr, "namespaceURI cannot be nil")
|
||||
elif value.toLower() == "xml" and n.fNamespaceURI != "http://www.w3.org/XML/1998/namespace":
|
||||
elif value.toLowerAscii() == "xml" and n.fNamespaceURI != "http://www.w3.org/XML/1998/namespace":
|
||||
raise newException(ENamespaceErr,
|
||||
"When the namespace prefix is \"xml\" namespaceURI has to be \"http://www.w3.org/XML/1998/namespace\"")
|
||||
elif value.toLower() == "xmlns" and n.fNamespaceURI != "http://www.w3.org/2000/xmlns/":
|
||||
elif value.toLowerAscii() == "xmlns" and n.fNamespaceURI != "http://www.w3.org/2000/xmlns/":
|
||||
raise newException(ENamespaceErr,
|
||||
"When the namespace prefix is \"xmlns\" namespaceURI has to be \"http://www.w3.org/2000/xmlns/\"")
|
||||
elif value.toLower() == "xmlns" and n.fNodeType == AttributeNode:
|
||||
elif value.toLowerAscii() == "xmlns" and n.fNodeType == AttributeNode:
|
||||
raise newException(ENamespaceErr, "An AttributeNode cannot have a prefix of \"xmlns\"")
|
||||
|
||||
n.fNodeName = value & ":" & n.fLocalName
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
# bug 2007
|
||||
|
||||
import asyncdispatch, asyncnet, logging, json, uri, strutils, future
|
||||
import asyncdispatch, asyncnet, logging, json, uri, strutils, sugar
|
||||
|
||||
type
|
||||
Builder = ref object
|
||||
@@ -27,7 +27,7 @@ proc newBuild*(onProgress: ProgressCB): Build =
|
||||
result.onProgress = onProgress
|
||||
|
||||
proc start(build: Build, repo, hash: string) {.async.} =
|
||||
let path = repo.parseUri().path.toLower()
|
||||
let path = repo.parseUri().path.toLowerAscii()
|
||||
|
||||
proc onProgress(builder: Builder, message: string) {.async.} =
|
||||
debug($message)
|
||||
|
||||
@@ -31,7 +31,7 @@ type
|
||||
s.pop() is T
|
||||
|
||||
type ValueType = T
|
||||
const ValueTypeName = T.name.toUpper
|
||||
const ValueTypeName = T.name.toUpperAscii
|
||||
|
||||
proc genericAlgorithm[T](s: var Stack[T], y: T) =
|
||||
static:
|
||||
|
||||
@@ -7,7 +7,7 @@ task "install", "compile and install nake binary":
|
||||
for index, dir in pairs(path):
|
||||
echo " ", index, ". ", dir
|
||||
echo "Where to install nake binary? (quit with ^C or quit or exit)"
|
||||
let ans = stdin.readLine().toLower
|
||||
let ans = stdin.readLine().toLowerAscii
|
||||
var index = 0
|
||||
case ans
|
||||
of "q", "quit", "x", "exit":
|
||||
|
||||
@@ -562,7 +562,7 @@ proc importItem(data: PJsonNode; errors: var seq[string]): PItemRecord =
|
||||
|
||||
result.useSound = importSound(data[2], errors, "useSound")
|
||||
|
||||
case data[1].str.toLower
|
||||
case data[1].str.toLowerAscii
|
||||
of "projectile":
|
||||
result.kind = Projectile
|
||||
if data[2]["bullet"].kind == JString:
|
||||
|
||||
@@ -67,7 +67,7 @@ else:
|
||||
for kind, key, val in getOpt():
|
||||
case kind
|
||||
of cmdLongOption, cmdShortOption:
|
||||
case key.tolower
|
||||
case key.tolowerAscii
|
||||
of "tasks", "t":
|
||||
printTaskList = true
|
||||
else:
|
||||
|
||||
@@ -88,7 +88,7 @@ task "download", "download game assets":
|
||||
if existsFile(path):
|
||||
echo "The file already exists\n",
|
||||
"[R]emove [M]ove [Q]uit [S]kip Source: ", GameAssets
|
||||
case stdin.readLine.toLower
|
||||
case stdin.readLine.toLowerAscii
|
||||
of "r":
|
||||
removeFile path
|
||||
of "m":
|
||||
@@ -120,7 +120,7 @@ task "download", "download game assets":
|
||||
|
||||
echo "Download binary libs? Only libs for linux are available currently, enjoy the irony.\n",
|
||||
"[Y]es [N]o Source: ", BinLibs
|
||||
case stdin.readline.toLower
|
||||
case stdin.readline.toLowerAscii
|
||||
of "y", "yes":
|
||||
discard ## o_O
|
||||
else:
|
||||
|
||||
@@ -6,7 +6,7 @@ discard """
|
||||
|
||||
import strutils
|
||||
|
||||
var x = "hello world!".toLower.toUpper
|
||||
var x = "hello world!".toLowerAscii.toUpperAscii
|
||||
x.echo()
|
||||
#OUT HELLO WORLD!
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import strutils
|
||||
proc foo(s: static[string]): string =
|
||||
static: echo s
|
||||
|
||||
const R = s.toUpper
|
||||
const R = s.toUpperAscii
|
||||
return R
|
||||
|
||||
echo foo("test 1")
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -30,7 +30,6 @@ else:
|
||||
result = newString(size)
|
||||
let res = WideCharToMultiByte(CP_UTF8, 0'i32, cast[LPWCSTR](addr(wc[0])), wclen,
|
||||
cstring(result), size, cstring(nil), LPBOOL(nil))
|
||||
result[size] = chr(0)
|
||||
doAssert size == res
|
||||
|
||||
proc testCP(wc: WideCString, lo, hi: int) =
|
||||
|
||||
Reference in New Issue
Block a user