Merge branch 'master' of github.com:Araq/Nimrod

This commit is contained in:
dom96 2011-05-14 20:35:17 +01:00
commit 4fd42d5150
43 changed files with 262 additions and 177 deletions

View file

@ -88,7 +88,7 @@ proc matchOrFind(s: string, pattern: TRegEx, matches: var openarray[string],
for i in 1..int(res)-1:
var a = rawMatches[i * 2]
var b = rawMatches[i * 2 + 1]
if a >= 0'i32: matches[i-1] = copy(s, int(a), int(b)-1)
if a >= 0'i32: matches[i-1] = substr(s, int(a), int(b)-1)
else: matches[i-1] = ""
return rawMatches[1] - rawMatches[0]
@ -106,7 +106,7 @@ proc findBounds*(s: string, pattern: TRegEx, matches: var openarray[string],
for i in 1..int(res)-1:
var a = rawMatches[i * 2]
var b = rawMatches[i * 2 + 1]
if a >= 0'i32: matches[i-1] = copy(s, int(a), int(b)-1)
if a >= 0'i32: matches[i-1] = substr(s, int(a), int(b)-1)
else: matches[i-1] = ""
return (rawMatches[0].int, rawMatches[1].int - 1)
@ -186,7 +186,7 @@ proc find*(s: string, pattern: TRegEx, matches: var openarray[string],
for i in 1..int(res)-1:
var a = rawMatches[i * 2]
var b = rawMatches[i * 2 + 1]
if a >= 0'i32: matches[i-1] = copy(s, int(a), int(b)-1)
if a >= 0'i32: matches[i-1] = substr(s, int(a), int(b)-1)
else: matches[i-1] = ""
return rawMatches[0]
@ -277,10 +277,10 @@ proc replace*(s: string, sub: TRegEx, by = ""): string =
while true:
var match = findBounds(s, sub, prev)
if match.first < 0: break
add(result, copy(s, prev, match.first-1))
add(result, substr(s, prev, match.first-1))
add(result, by)
prev = match.last + 1
add(result, copy(s, prev))
add(result, substr(s, prev))
proc replacef*(s: string, sub: TRegEx, by: string): string =
## Replaces `sub` in `s` by the string `by`. Captures can be accessed in `by`
@ -300,10 +300,10 @@ proc replacef*(s: string, sub: TRegEx, by: string): string =
while true:
var match = findBounds(s, sub, caps, prev)
if match.first < 0: break
add(result, copy(s, prev, match.first-1))
add(result, substr(s, prev, match.first-1))
addf(result, by, caps)
prev = match.last + 1
add(result, copy(s, prev))
add(result, substr(s, prev))
when false:
result = ""
var i = 0
@ -316,8 +316,8 @@ proc replacef*(s: string, sub: TRegEx, by: string): string =
else:
addf(result, by, caps)
inc(i, x)
# copy the rest:
add(result, copy(s, i))
# substr the rest:
add(result, substr(s, i))
proc parallelReplace*(s: string, subs: openArray[
tuple[pattern: TRegEx, repl: string]]): string =
@ -337,7 +337,7 @@ proc parallelReplace*(s: string, subs: openArray[
add(result, s[i])
inc(i)
# copy the rest:
add(result, copy(s, i))
add(result, substr(s, i))
proc transformFile*(infile, outfile: string,
subs: openArray[tuple[pattern: TRegEx, repl: string]]) =
@ -385,7 +385,7 @@ iterator split*(s: string, sep: TRegEx): string =
x = matchLen(s, sep, last)
if x > 0: break
if first < last:
yield copy(s, first, last-1)
yield substr(s, first, last-1)
proc split*(s: string, sep: TRegEx): seq[string] =
## Splits the string `s` into substrings.

View file

@ -36,7 +36,7 @@ proc URLencode*(s: string): string =
## ``{'A'..'Z', 'a'..'z', '0'..'9', '_'}`` are carried over to the result,
## a space is converted to ``'+'`` and every other character is encoded as
## ``'%xx'`` where ``xx`` denotes its hexadecimal value.
result = ""
result = newStringOfCap(s.len + s.len shr 2) # assume 12% non-alnum-chars
for i in 0..s.len-1:
case s[i]
of 'a'..'z', 'A'..'Z', '0'..'9', '_': add(result, s[i])
@ -57,8 +57,9 @@ proc URLdecode*(s: string): string =
## is converted to a space, ``'%xx'`` (where ``xx`` denotes a hexadecimal
## value) is converted to the character with ordinal number ``xx``, and
## and every other character is carried over.
result = ""
result = newString(s.len)
var i = 0
var j = 0
while i < s.len:
case s[i]
of '%':
@ -66,10 +67,12 @@ proc URLdecode*(s: string): string =
handleHexChar(s[i+1], x)
handleHexChar(s[i+2], x)
inc(i, 2)
add(result, chr(x))
of '+': add(result, ' ')
else: add(result, s[i])
result[j] = chr(x)
of '+': result[j] = ' '
else: result[j] = s[i]
inc(i)
inc(j)
setLen(result, j)
proc addXmlChar(dest: var string, c: Char) {.inline.} =
case c
@ -86,7 +89,7 @@ proc XMLencode*(s: string): string =
## * ``>`` is replaced by ``&gt;``
## * ``&`` is replaced by ``&amp;``
## * every other character is carried over.
result = ""
result = newStringOfCap(s.len + s.len shr 2)
for i in 0..len(s)-1: addXmlChar(result, s[i])
type
@ -367,4 +370,8 @@ proc existsCookie*(name: string): bool =
if gcookies == nil: gcookies = parseCookies(getHttpCookie())
result = hasKey(gcookies, name)
when isMainModule:
const test1 = "abc\L+def xyz"
assert UrlEncode(test1) == "abc%0A%2Bdef+xyz"
assert UrlDecode(UrlEncode(test1)) == test1

View file

@ -1,7 +1,7 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2010 Andreas Rumpf
# (c) Copyright 2011 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@ -24,7 +24,7 @@ proc parseCookies*(s: string): PStringTable =
inc(i) # skip '='
var valstart = i
while s[i] != ';' and s[i] != '\0': inc(i)
result[copy(s, keystart, keyend)] = copy(s, valstart, i-1)
result[substr(s, keystart, keyend)] = substr(s, valstart, i-1)
if s[i] == '\0': break
inc(i) # skip ';'

View file

@ -109,7 +109,7 @@ proc parseChunks(d: var string, start: int, s: TSocket): string =
if charAt(d, i, s) == '\L': inc(i)
else: httpError("CR-LF after chunksize expected")
var x = copy(d, i, i+chunkSize-1)
var x = substr(d, i, i+chunkSize-1)
var size = x.len
result.add(x)
inc(i, size)
@ -133,7 +133,7 @@ proc parseBody(d: var string, start: int, s: TSocket,
if headers["Transfer-Encoding"] == "chunked":
result = parseChunks(d, start, s)
else:
result = copy(d, start)
result = substr(d, start)
# -REGION- Content-Length
# (http://tools.ietf.org/html/rfc2616#section-4.4) NR.3
var contentLengthHeader = headers["Content-Length"]
@ -236,7 +236,7 @@ proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
## | Extra headers can be specified and must be seperated by ``\c\L``
var r = parseUrl(url)
var headers = copy($httpMethod, len("http"))
var headers = substr($httpMethod, len("http"))
headers.add(" /" & r.path & r.query)
headers.add(" HTTP/1.1\c\L")

View file

@ -121,7 +121,7 @@ proc executeCgi(client: TSocket, path, query: string, meth: TRequestMethod) =
if L.startsWith("content-length:"):
var i = len("content-length:")
while L[i] in Whitespace: inc(i)
contentLength = parseInt(copy(L, i))
contentLength = parseInt(substr(L, i))
if contentLength < 0:
badRequest(client)
@ -165,7 +165,7 @@ proc acceptRequest(client: TSocket) =
# extract path
if q >= 0:
# strip "?..." from path, this may be found in both POST and GET
path = "." & data[1].copy(0, q-1)
path = "." & data[1].substr(0, q-1)
else:
path = "." & data[1]
# path starts with "/", by adding "." in front of it we serve files from cwd
@ -173,7 +173,7 @@ proc acceptRequest(client: TSocket) =
if cmpIgnoreCase(data[0], "GET") == 0:
if q >= 0:
cgi = true
query = data[1].copy(q+1)
query = data[1].substr(q+1)
elif cmpIgnoreCase(data[0], "POST") == 0:
cgi = true
meth = reqPost
@ -250,11 +250,11 @@ proc next*(s: var TServer) =
if data[last] == '?' and query == 0: query = last
inc(last)
if query > 0:
s.query = data.copy(query+1, last-1)
s.path = data.copy(i, query-1)
s.query = data.substr(query+1, last-1)
s.path = data.substr(i, query-1)
else:
s.query = ""
s.path = data.copy(i, last-1)
s.path = data.substr(i, last-1)
proc close*(s: TServer) =
## closes the server (and the socket the server uses).

View file

@ -649,7 +649,8 @@ proc nl(s: var string, ml: bool) =
proc escapeJson*(s: string): string =
## Converts a string `s` to its JSON representation.
result = "\""
result = newStringOfCap(s.len + s.len shr 3)
result.add("\"")
for x in runes(s):
var r = int(x)
if r >= 32 and r <= 127:

View file

@ -330,7 +330,7 @@ proc JoinPath*(head, tail: string): string {.
result = tail
elif head[len(head)-1] in {DirSep, AltSep}:
if tail[0] in {DirSep, AltSep}:
result = head & copy(tail, 1)
result = head & substr(tail, 1)
else:
result = head & tail
else:
@ -362,8 +362,8 @@ proc SplitPath*(path: string, head, tail: var string) {.noSideEffect,
sepPos = i
break
if sepPos >= 0:
head = copy(path, 0, sepPos-1)
tail = copy(path, sepPos+1)
head = substr(path, 0, sepPos-1)
tail = substr(path, sepPos+1)
else:
head = ""
tail = path # make a string copy here
@ -388,8 +388,8 @@ proc SplitPath*(path: string): tuple[head, tail: string] {.
sepPos = i
break
if sepPos >= 0:
result.head = copy(path, 0, sepPos-1)
result.tail = copy(path, sepPos+1)
result.head = substr(path, 0, sepPos-1)
result.tail = substr(path, sepPos+1)
else:
result.head = ""
result.tail = path
@ -412,7 +412,7 @@ proc parentDir*(path: string): string {.
sepPos = i
break
if sepPos >= 0:
result = copy(path, 0, sepPos-1)
result = substr(path, 0, sepPos-1)
else:
result = path
@ -462,9 +462,9 @@ proc splitFile*(path: string): tuple[dir, name, ext: string] {.
elif path[i] in {dirsep, altsep}:
sepPos = i
break
result.dir = copy(path, 0, sepPos-1)
result.name = copy(path, sepPos+1, dotPos-1)
result.ext = copy(path, dotPos)
result.dir = substr(path, 0, sepPos-1)
result.name = substr(path, sepPos+1, dotPos-1)
result.ext = substr(path, dotPos)
proc extractDir*(path: string): string {.noSideEffect, deprecated.} =
## Extracts the directory of a given path. This is almost the
@ -507,8 +507,8 @@ proc SplitFilename*(filename: string, name, extension: var string) {.
## **Deprecated since version 0.8.2**: Use ``splitFile(filename)`` instead.
var extPos = searchExtPos(filename)
if extPos >= 0:
name = copy(filename, 0, extPos-1)
extension = copy(filename, extPos)
name = substr(filename, 0, extPos-1)
extension = substr(filename, extPos)
else:
name = filename # make a string copy here
extension = ""
@ -537,7 +537,7 @@ proc ChangeFileExt*(filename, ext: string): string {.
## of none such beast.)
var extPos = searchExtPos(filename)
if extPos < 0: result = filename & normExt(ext)
else: result = copy(filename, 0, extPos-1) & normExt(ext)
else: result = substr(filename, 0, extPos-1) & normExt(ext)
proc addFileExt*(filename, ext: string): string {.
noSideEffect, rtl, extern: "nos$1".} =
@ -748,7 +748,7 @@ proc getEnv*(key: string): string =
## `existsEnv(key)`.
var i = findEnvVar(key)
if i >= 0:
return copy(environment[i], find(environment[i], '=')+1)
return substr(environment[i], find(environment[i], '=')+1)
else:
var env = cgetenv(key)
if env == nil: return ""
@ -788,7 +788,7 @@ iterator iterOverEnvironment*(): tuple[key, value: string] {.deprecated.} =
getEnvVarsC()
for i in 0..high(environment):
var p = find(environment[i], '=')
yield (copy(environment[i], 0, p-1), copy(environment[i], p+1))
yield (substr(environment[i], 0, p-1), substr(environment[i], p+1))
iterator envPairs*(): tuple[key, value: string] =
## Iterate over all `environments variables`:idx:. In the first component
@ -797,7 +797,7 @@ iterator envPairs*(): tuple[key, value: string] =
getEnvVarsC()
for i in 0..high(environment):
var p = find(environment[i], '=')
yield (copy(environment[i], 0, p-1), copy(environment[i], p+1))
yield (substr(environment[i], 0, p-1), substr(environment[i], p+1))
iterator walkFiles*(pattern: string): string =
## Iterate over all the files that match the `pattern`. On POSIX this uses
@ -944,14 +944,14 @@ proc createDir*(dir: string) {.rtl, extern: "nos$1".} =
## fail if the path already exists because for most usages this does not
## indicate an error.
for i in 1.. dir.len-1:
if dir[i] in {dirsep, altsep}: rawCreateDir(copy(dir, 0, i-1))
if dir[i] in {dirsep, altsep}: rawCreateDir(substr(dir, 0, i-1))
rawCreateDir(dir)
proc copyDir*(source, dest: string) {.rtl, extern: "nos$1".} =
## Copies a directory from `source` to `dest`. If this fails, `EOS` is raised.
createDir(dest)
for kind, path in walkDir(source):
var noSource = path.copy(source.len()+1)
var noSource = path.substr(source.len()+1)
case kind
of pcFile:
copyFile(path, dest / noSource)

View file

@ -126,7 +126,7 @@ proc next*(p: var TOptParser) {.
proc cmdLineRest*(p: TOptParser): string {.
rtl, extern: "npo$1".} =
## retrieves the rest of the command line that has not been parsed yet.
result = strip(copy(p.cmd, p.pos, len(p.cmd) - 1))
result = strip(substr(p.cmd, p.pos, len(p.cmd) - 1))
proc getRestOfCommandLine*(p: TOptParser): string {.deprecated.} =
## **Deprecated since version 0.8.2**: Use `cmdLineRest` instead.

View file

@ -73,7 +73,7 @@ proc parseIdent*(s: string, ident: var string, start = 0): int =
if s[i] in IdentStartChars:
inc(i)
while s[i] in IdentChars: inc(i)
ident = copy(s, start, i-1)
ident = substr(s, start, i-1)
result = i-start
proc parseToken*(s: string, token: var string, validChars: set[char],
@ -86,7 +86,7 @@ proc parseToken*(s: string, token: var string, validChars: set[char],
var i = start
while s[i] in validChars: inc(i)
result = i-start
token = copy(s, start, i-1)
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
@ -120,7 +120,7 @@ proc parseUntil*(s: string, token: var string, until: set[char],
var i = start
while s[i] notin until: inc(i)
result = i-start
token = copy(s, start, i-1)
token = substr(s, start, i-1)
proc parseWhile*(s: string, token: var string, validChars: set[char],
start = 0): int {.inline.} =
@ -130,7 +130,7 @@ proc parseWhile*(s: string, token: var string, validChars: set[char],
var i = start
while s[i] in validChars: inc(i)
result = i-start
token = copy(s, start, i-1)
token = substr(s, start, i-1)
{.push overflowChecks: on.}
# this must be compiled with overflow checking turned on:

View file

@ -736,7 +736,7 @@ proc rawMatch*(s: string, p: TPeg, start: int, c: var TCaptures): int {.
var (a, b) = c.matches[p.index]
var n: TPeg
n.kind = succ(pkTerminal, ord(p.kind)-ord(pkBackRef))
n.term = s.copy(a, b)
n.term = s.substr(a, b)
result = rawMatch(s, n, start, c)
of pkStartAnchor:
if c.origStart == start: result = 0
@ -754,7 +754,7 @@ proc match*(s: string, pattern: TPeg, matches: var openarray[string],
result = rawMatch(s, pattern, start, c) == len(s) - start
if result:
for i in 0..c.ml-1:
matches[i] = copy(s, c.matches[i][0], c.matches[i][1])
matches[i] = substr(s, c.matches[i][0], c.matches[i][1])
proc match*(s: string, pattern: TPeg,
start = 0): bool {.nosideEffect, rtl, extern: "npegs$1".} =
@ -774,7 +774,7 @@ proc matchLen*(s: string, pattern: TPeg, matches: var openarray[string],
result = rawMatch(s, pattern, start, c)
if result >= 0:
for i in 0..c.ml-1:
matches[i] = copy(s, c.matches[i][0], c.matches[i][1])
matches[i] = substr(s, c.matches[i][0], c.matches[i][1])
proc matchLen*(s: string, pattern: TPeg,
start = 0): int {.nosideEffect, rtl, extern: "npegs$1".} =
@ -903,7 +903,7 @@ proc replacef*(s: string, sub: TPeg, by: string): string {.
else:
addf(result, by, caps)
inc(i, x)
add(result, copy(s, i))
add(result, substr(s, i))
proc replace*(s: string, sub: TPeg, by = ""): string {.
nosideEffect, rtl, extern: "npegs$1".} =
@ -920,7 +920,7 @@ proc replace*(s: string, sub: TPeg, by = ""): string {.
else:
addf(result, by, caps)
inc(i, x)
add(result, copy(s, i))
add(result, substr(s, i))
proc parallelReplace*(s: string, subs: openArray[
tuple[pattern: TPeg, repl: string]]): string {.
@ -941,7 +941,7 @@ proc parallelReplace*(s: string, subs: openArray[
add(result, s[i])
inc(i)
# copy the rest:
add(result, copy(s, i))
add(result, substr(s, i))
proc transformFile*(infile, outfile: string,
subs: openArray[tuple[pattern: TPeg, repl: string]]) {.
@ -990,7 +990,7 @@ iterator split*(s: string, sep: TPeg): string =
x = matchLen(s, sep, last)
if x > 0: break
if first < last:
yield copy(s, first, last-1)
yield substr(s, first, last-1)
proc split*(s: string, sep: TPeg): seq[string] {.
nosideEffect, rtl, extern: "npegs$1".} =
@ -1688,7 +1688,7 @@ when isMainModule:
assert rawMatch(s, expr.rule, 0, c) == len(s)
var a = ""
for i in 0..c.ml-1:
a.add(copy(s, c.matches[i][0], c.matches[i][1]))
a.add(substr(s, c.matches[i][0], c.matches[i][1]))
assert a == "abcdef"
#echo expr.rule

View file

@ -84,7 +84,7 @@ proc matchOrFind(s: string, pattern: PPcre, matches: var openarray[string],
var
a = rawMatches[i * 2]
b = rawMatches[i * 2 + 1]
if a >= 0'i32: matches[i] = copy(s, a, int(b)-1)
if a >= 0'i32: matches[i] = substr(s, a, int(b)-1)
else: matches[i] = ""
return res

View file

@ -287,7 +287,7 @@ when false:
if frmt[i] != '$': inc(i)
else: break
if i - 1 >= start:
add(result, copy(frmt, start, i-1))
add(result, substr(frmt, start, i-1))
proc `%`*(frmt: string, args: openarray[PRope]): PRope {.
rtl, extern: "nroFormat".} =
@ -330,7 +330,7 @@ proc `%`*(frmt: string, args: openarray[PRope]): PRope {.
if frmt[i] != '$': inc(i)
else: break
if i - 1 >= start:
add(result, copy(frmt, start, i - 1))
add(result, substr(frmt, start, i - 1))
proc addf*(c: var PRope, frmt: string, args: openarray[PRope]) {.
rtl, extern: "nro$1".} =

View file

@ -181,12 +181,12 @@ proc `%`*(f: string, t: PStringTable, flags: set[TFormatFlag] = {}): string {.
of '{':
var j = i + 1
while j < f.len and f[j] != '}': inc(j)
add(result, getValue(t, flags, copy(f, i+2, j-1)))
add(result, getValue(t, flags, substr(f, i+2, j-1)))
i = j + 1
of 'a'..'z', 'A'..'Z', '\x80'..'\xFF', '_':
var j = i + 1
while j < f.len and f[j] in PatternChars: inc(j)
add(result, getValue(t, flags, copy(f, i+1, j-1)))
add(result, getValue(t, flags, substr(f, i+1, j-1)))
i = j
else:
add(result, f[i])

View file

@ -83,18 +83,22 @@ proc capitalize*(s: string): string {.noSideEffect, procvar,
rtl, extern: "nsuCapitalize".} =
## Converts the first character of `s` into upper case.
## This works only for the letters a-z.
result = toUpper(s[0]) & copy(s, 1)
result = toUpper(s[0]) & substr(s, 1)
proc normalize*(s: string): string {.noSideEffect, procvar,
rtl, extern: "nsuNormalize".} =
## Normalizes the string `s`. That means to convert it to lower case and
## remove any '_'. This is needed for Nimrod identifiers for example.
result = ""
result = newString(s.len)
var j = 0
for i in 0..len(s) - 1:
if s[i] in {'A'..'Z'}:
add result, Chr(Ord(s[i]) + (Ord('a') - Ord('A')))
result[j] = Chr(Ord(s[i]) + (Ord('a') - Ord('A')))
inc j
elif s[i] != '_':
add result, s[i]
result[j] = s[i]
inc j
if j != s.len: setLen(result, j)
proc cmpIgnoreCase*(a, b: string): int {.noSideEffect,
rtl, extern: "nsuCmpIgnoreCase", procvar.} =
@ -171,14 +175,14 @@ proc addf*(s: var string, formatstr: string, a: openarray[string]) {.
of '{':
var j = i+1
while formatstr[j] notin {'\0', '}'}: inc(j)
var x = findNormalized(copy(formatstr, i+2, j-1), a)
var x = findNormalized(substr(formatstr, i+2, j-1), a)
if x >= 0 and x < high(a): add s, a[x+1]
else: raise newException(EInvalidValue, "invalid format string")
i = j+1
of 'a'..'z', 'A'..'Z', '\128'..'\255', '_':
var j = i+1
while formatstr[j] in PatternChars: inc(j)
var x = findNormalized(copy(formatstr, i+1, j-1), a)
var x = findNormalized(substr(formatstr, i+1, j-1), a)
if x >= 0 and x < high(a): add s, a[x+1]
else: raise newException(EInvalidValue, "invalid format string")
i = j
@ -226,13 +230,14 @@ proc `%` *(formatstr: string, a: openarray[string]): string {.noSideEffect,
##
## The variables are compared with `cmpIgnoreStyle`. `EInvalidValue` is
## raised if an ill-formed format string has been passed to the `%` operator.
result = ""
result = newStringOfCap(formatstr.len + a.len shl 4)
addf(result, formatstr, a)
proc `%` *(formatstr, a: string): string {.noSideEffect,
rtl, extern: "nsuFormatSingleElem".} =
## This is the same as ``formatstr % [a]``.
return formatstr % [a]
result = newStringOfCap(formatstr.len + a.len)
addf(result, formatstr, [a])
proc strip*(s: string, leading = true, trailing = true): string {.noSideEffect,
rtl, extern: "nsuStrip".} =
@ -248,7 +253,7 @@ proc strip*(s: string, leading = true, trailing = true): string {.noSideEffect,
while s[first] in chars: inc(first)
if trailing:
while last >= 0 and s[last] in chars: dec(last)
result = copy(s, first, last)
result = substr(s, first, last)
proc toOctal*(c: char): string {.noSideEffect, rtl, extern: "nsuToOctal".} =
## Converts a character `c` to its octal representation. The resulting
@ -288,7 +293,7 @@ iterator split*(s: string, seps: set[char] = Whitespace): string =
var first = last
while last < len(s) and s[last] not_in seps: inc(last) # BUGFIX!
if first <= last-1:
yield copy(s, first, last-1)
yield substr(s, first, last-1)
iterator split*(s: string, sep: char): string =
## Splits the string `s` into substrings.
@ -321,7 +326,7 @@ iterator split*(s: string, sep: char): string =
while last <= len(s):
var first = last
while last < len(s) and s[last] != sep: inc(last)
yield copy(s, first, last-1)
yield substr(s, first, last-1)
inc(last)
iterator splitLines*(s: string): string =
@ -349,7 +354,7 @@ iterator splitLines*(s: string): string =
var last = 0
while true:
while s[last] notin {'\0', '\c', '\l'}: inc(last)
yield copy(s, first, last-1)
yield substr(s, first, last-1)
# skip newlines:
if s[last] == '\l': inc(last)
elif s[last] == '\c':
@ -499,7 +504,7 @@ iterator tokenize*(s: string, seps: set[char] = Whitespace): tuple[
var isSep = s[j] in seps
while j < s.len and (s[j] in seps) == isSep: inc(j)
if j > i:
yield (copy(s, i, j-1), isSep)
yield (substr(s, i, j-1), isSep)
else:
break
i = j
@ -510,19 +515,19 @@ proc wordWrap*(s: string, maxLineWidth = 80,
newLine = "\n"): string {.
noSideEffect, rtl, extern: "nsuWordWrap".} =
## word wraps `s`.
result = ""
result = newStringOfCap(s.len + s.len shr 6)
var SpaceLeft = maxLineWidth
for word, isSep in tokenize(s, seps):
if len(word) > SpaceLeft:
if splitLongWords and len(word) > maxLineWidth:
result.add(copy(word, 0, spaceLeft-1))
result.add(substr(word, 0, spaceLeft-1))
var w = spaceLeft+1
var wordLeft = len(word) - spaceLeft
while wordLeft > 0:
result.add(newLine)
var L = min(maxLineWidth, wordLeft)
SpaceLeft = maxLineWidth - L
result.add(copy(word, w, w+L-1))
result.add(substr(word, w, w+L-1))
inc(w, L)
dec(wordLeft, L)
else:
@ -700,11 +705,11 @@ proc replace*(s, sub: string, by = ""): string {.noSideEffect,
while true:
var j = findAux(s, sub, i, a)
if j < 0: break
add result, copy(s, i, j - 1)
add result, substr(s, i, j - 1)
add result, by
i = j + len(sub)
# copy the rest:
add result, copy(s, i)
add result, substr(s, i)
proc replace*(s: string, sub, by: char): string {.noSideEffect,
rtl, extern: "nsuReplaceChar".} =
@ -804,7 +809,8 @@ proc escape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect,
## The procedure has been designed so that its output is usable for many
## different common syntaxes. The resulting string is prefixed with
## `prefix` and suffixed with `suffix`. Both may be empty strings.
result = prefix
result = newStringOfCap(s.len + s.len shr 2)
result.add(prefix)
for c in items(s):
case c
of '\0'..'\31', '\128'..'\255':
@ -837,7 +843,7 @@ proc validEmailAddress*(s: string): bool {.noSideEffect,
while s[i] in {'0'..'9', 'a'..'z', '-', '.'}: inc(i)
if s[i] != '\0': return false
var x = copy(s, j+1)
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)
of "com", "org", "net", "gov", "mil", "biz", "info", "mobi", "name",

View file

@ -1021,9 +1021,9 @@ proc splitData*(TextNode: PText, offset: int): PText =
if offset > TextNode.data.len():
raise newException(EIndexSizeErr, "Index out of bounds")
var left: string = TextNode.data.copy(0, offset)
var left: string = TextNode.data.substr(0, offset)
TextNode.data = left
var right: string = TextNode.data.copy(offset, TextNode.data.len())
var right: string = TextNode.data.substr(offset, TextNode.data.len())
if TextNode.FParentNode != nil:
for i in low(TextNode.FParentNode.childNodes)..high(TextNode.FParentNode.childNodes):

View file

@ -44,6 +44,10 @@ type
typeDesc* {.magic: TypeDesc.} ## meta type to denote
## a type description (for templates)
const
hasThreadSupport = false # deactivate for now: thread stack walking
# is missing!
proc defined*[T](x: T): bool {.magic: "Defined", noSideEffect.}
## Special compile-time procedure that checks whether `x` is
## defined. `x` has to be an identifier or a qualified identifier.
@ -685,7 +689,13 @@ proc newString*(len: int): string {.
## content. One needs to fill the string character after character
## with the index operator ``s[i]``. This procedure exists only for
## optimization purposes; the same effect can be achieved with the
## ``&`` operator.
## ``&`` operator or with ``add``.
proc newStringOfCap*(cap: int): string {.
magic: "NewStringOfCap", importc: "rawNewString", noSideEffect.}
## returns a new string of length ``0`` but with capacity `cap`.This
## procedure exists only for optimization purposes; the same effect can
## be achieved with the ``&`` operator or with ``add``.
proc `&` * (x: string, y: char): string {.
magic: "ConStrStr", noSideEffect, merge.}
@ -899,8 +909,19 @@ proc addQuitProc*(QuitProc: proc {.noconv.}) {.importc: "atexit", nodecl.}
# not be called explicitly! The user may decide to do this manually though.
proc copy*(s: string, first = 0): string {.
magic: "CopyStr", importc: "copyStr", noSideEffect.}
magic: "CopyStr", importc: "copyStr", noSideEffect, deprecated.}
proc copy*(s: string, first, last: int): string {.
magic: "CopyStrLast", importc: "copyStrLast", noSideEffect,
deprecated.}
## copies a slice of `s` into a new string and returns this new
## string. The bounds `first` and `last` denote the indices of
## the first and last characters that shall be copied. If ``last``
## is omitted, it is treated as ``high(s)``.
## **Deprecated since version 0.8.12**: Use ``substr`` instead.
proc substr*(s: string, first = 0): string {.
magic: "CopyStr", importc: "copyStr", noSideEffect.}
proc substr*(s: string, first, last: int): string {.
magic: "CopyStrLast", importc: "copyStrLast", noSideEffect.}
## copies a slice of `s` into a new string and returns this new
## string. The bounds `first` and `last` denote the indices of
@ -1219,21 +1240,21 @@ proc each*[T](data: var openArray[T], op: proc (x: var T)) =
## `op` to every item in `data`.
for i in 0..data.len-1: op(data[i])
iterator fields*(x: tuple[]): expr {.magic: "Fields", noSideEffect.}
iterator fields*[T: tuple](x: T): expr {.magic: "Fields", noSideEffect.}
## iterates over every field of `x`. Warning: This is really transforms
## the 'for' and unrolls the loop. The current implementation also has a bug
## that affects symbol binding in the loop body.
iterator fields*(x, y: tuple[]): tuple[a, b: expr] {.
iterator fields*[S: tuple, T: tuple](x: S, y: T): tuple[a, b: expr] {.
magic: "Fields", noSideEffect.}
## iterates over every field of `x` and `y`.
## Warning: This is really transforms the 'for' and unrolls the loop.
## The current implementation also has a bug that affects symbol binding
## in the loop body.
iterator fieldPairs*(x: tuple[]): expr {.magic: "FieldPairs", noSideEffect.}
iterator fieldPairs*[T: tuple](x: T): expr {.magic: "FieldPairs", noSideEffect.}
## iterates over every field of `x`. Warning: This is really transforms
## the 'for' and unrolls the loop. The current implementation also has a bug
## that affects symbol binding in the loop body.
iterator fieldPairs*(x, y: tuple[]): tuple[a, b: expr] {.
iterator fieldPairs*[S: tuple, T: tuple](x: S, y: T): tuple[a, b: expr] {.
magic: "FieldPairs", noSideEffect.}
## iterates over every field of `x` and `y`.
## Warning: This is really transforms the 'for' and unrolls the loop.
@ -1773,7 +1794,7 @@ template `-|`(b, s: expr): expr =
proc `[]`*(s: string, x: TSlice[int]): string {.inline.} =
## slice operation for strings. Negative indexes are supported.
result = s.copy(x.a-|s, x.b-|s)
result = s.substr(x.a-|s, x.b-|s)
proc `[]=`*(s: var string, x: TSlice[int], b: string) =
## slice assignment for strings. Negative indexes are supported.

View file

@ -23,39 +23,50 @@ proc nimLoadLibraryError(path: string) {.compilerproc, noinline.}
proc setStackBottom(theStackBottom: pointer) {.compilerRtl, noinline.}
# Support for thread local storage:
when defined(windows):
type
TThreadVarSlot {.compilerproc.} = distinct int32
when false:
# Support for thread local storage:
when defined(windows):
type
TThreadVarSlot {.compilerproc.} = distinct int32
proc TlsAlloc(): TThreadVarSlot {.
importc: "TlsAlloc", stdcall, dynlib: "kernel32".}
proc TlsSetValue(dwTlsIndex: TThreadVarSlot, lpTlsValue: pointer) {.
importc: "TlsSetValue", stdcall, dynlib: "kernel32".}
proc TlsGetValue(dwTlsIndex: TThreadVarSlot): pointer {.
importc: "TlsGetValue", stdcall, dynlib: "kernel32".}
proc ThreadVarAlloc(): TThreadVarSlot {.compilerproc, inline.} =
result = TlsAlloc()
proc ThreadVarSetValue(s: TThreadVarSlot, value: pointer) {.compilerproc.} =
TlsSetValue(s, value)
proc ThreadVarGetValue(s: TThreadVarSlot): pointer {.compilerproc.} =
result = TlsGetValue(s)
else:
type
Tpthread_key {.importc: "pthread_key_t",
header: "<sys/types.h>".} = distinct int
TThreadVarSlot {.compilerproc.} = Tpthread_key
proc TlsAlloc(): TThreadVarSlot {.
importc: "TlsAlloc", stdcall, dynlib: "kernel32".}
proc TlsSetValue(dwTlsIndex: TThreadVarSlot, lpTlsValue: pointer) {.
importc: "TlsSetValue", stdcall, dynlib: "kernel32".}
proc TlsGetValue(dwTlsIndex: TThreadVarSlot): pointer {.
importc: "TlsGetValue", stdcall, dynlib: "kernel32".}
proc ThreadVarAlloc(): TThreadVarSlot {.compilerproc, inline.} =
result = TlsAlloc()
proc ThreadVarSetValue(s: TThreadVarSlot, value: pointer) {.
compilerproc, inline.} =
TlsSetValue(s, value)
proc ThreadVarGetValue(s: TThreadVarSlot): pointer {.
compilerproc, inline.} =
result = TlsGetValue(s)
else:
type
Tpthread_key {.importc: "pthread_key_t",
header: "<sys/types.h>".} = distinct int
TThreadVarSlot {.compilerproc.} = Tpthread_key
proc pthread_getspecific(a1: Tpthread_key): pointer {.
importc: "pthread_getspecific", header: "<pthread.h>".}
proc pthread_key_create(a1: ptr Tpthread_key,
destruct: proc (x: pointer) {.noconv.}): int32 {.
importc: "pthread_key_create", header: "<pthread.h>".}
proc pthread_key_delete(a1: Tpthread_key): int32 {.
importc: "pthread_key_delete", header: "<pthread.h>".}
proc pthread_getspecific(a1: Tpthread_key): pointer {.
importc: "pthread_getspecific", header: "<pthread.h>".}
proc pthread_key_create(a1: ptr Tpthread_key,
destruct: proc (x: pointer) {.noconv.}): int32 {.
importc: "pthread_key_create", header: "<pthread.h>".}
proc pthread_key_delete(a1: Tpthread_key): int32 {.
importc: "pthread_key_delete", header: "<pthread.h>".}
proc pthread_setspecific(a1: Tpthread_key, a2: pointer): int32 {.
importc: "pthread_setspecific", header: "<pthread.h>".}
proc pthread_setspecific(a1: Tpthread_key, a2: pointer): int32 {.
importc: "pthread_setspecific", header: "<pthread.h>".}
proc ThreadVarAlloc(): TThreadVarSlot {.compilerproc, inline.} =
discard pthread_key_create(addr(result), nil)
proc ThreadVarSetValue(s: TThreadVarSlot, value: pointer) {.
compilerproc, inline.} =
discard pthread_setspecific(s, value)
proc ThreadVarGetValue(s: TThreadVarSlot): pointer {.compilerproc, inline.} =
result = pthread_getspecific(s)

View file

@ -39,6 +39,8 @@ type
exc: ref E_Base # XXX only needed for bootstrapping; unused
context: C_JmpBuf
#when hasThreadSupport: nil
var
excHandler {.threadvar, compilerproc.}: PSafePoint = nil
# list of exception handlers

View file

@ -626,10 +626,23 @@ else:
# We use a jmp_buf buffer that is in the C stack.
# Used to traverse the stack and registers assuming
# that 'setjmp' will save registers in the C stack.
type PStackSlice = ptr array [0..7, pointer]
var registers: C_JmpBuf
if c_setjmp(registers) == 0'i32: # To fill the C stack with registers.
var max = cast[TAddress](stackBottom)
var sp = cast[TAddress](addr(registers))
# loop unrolled:
while sp <% max - 8*sizeof(pointer):
gcMark(cast[PStackSlice](sp)[0])
gcMark(cast[PStackSlice](sp)[1])
gcMark(cast[PStackSlice](sp)[2])
gcMark(cast[PStackSlice](sp)[3])
gcMark(cast[PStackSlice](sp)[4])
gcMark(cast[PStackSlice](sp)[5])
gcMark(cast[PStackSlice](sp)[6])
gcMark(cast[PStackSlice](sp)[7])
sp = sp +% sizeof(pointer)*8
# last few entries:
while sp <=% max:
gcMark(cast[ppointer](sp)[])
sp = sp +% sizeof(pointer)

View file

@ -111,7 +111,7 @@ type
TReprClosure {.final.} = object # we cannot use a global variable here
# as this wouldn't be thread-safe
marked: TCellSet
recdepth: int # do not recurse endless
recdepth: int # do not recurse endlessly
indent: int # indentation
when not defined(useNimRtl):

View file

@ -8,8 +8,6 @@
#
const
hasThreadSupport = false # deactivate for now: thread stack walking
# is missing!
maxThreads = 256
when (defined(gcc) or defined(llvm_gcc)) and hasThreadSupport: