summary refs log tree commit diff stats
diff options
context:
space:
mode:
authordom96 <dominikpicheta@googlemail.com>2011-05-14 20:35:17 +0100
committerdom96 <dominikpicheta@googlemail.com>2011-05-14 20:35:17 +0100
commit4fd42d5150fa97d934d782f43433dd2ca2a49b3f (patch)
tree6bfa52cfc246b79801179b00463f017bb2d4a09b
parentd1cd1cea345e82ff1f8b55803b81d68a86cb9d50 (diff)
parent3e9dcc8be5d1286e3647e8f665f456966aa02437 (diff)
downloadNim-4fd42d5150fa97d934d782f43433dd2ca2a49b3f.tar.gz
Merge branch 'master' of github.com:Araq/Nimrod
-rwxr-xr-xcompiler/ast.nim4
-rwxr-xr-xcompiler/ccgexprs.nim3
-rwxr-xr-xcompiler/cgen.nim10
-rwxr-xr-xcompiler/commands.nim4
-rwxr-xr-xcompiler/docgen.nim6
-rwxr-xr-xcompiler/evals.nim8
-rwxr-xr-xcompiler/filter_tmpl.nim6
-rwxr-xr-xcompiler/llstream.nim2
-rwxr-xr-xcompiler/nimrod.nim4
-rwxr-xr-xcompiler/nstrtabs.nim6
-rwxr-xr-xcompiler/options.nim8
-rwxr-xr-xcompiler/pragmas.nim8
-rwxr-xr-xcompiler/renderer.nim2
-rwxr-xr-xcompiler/ropes.nim2
-rwxr-xr-xcompiler/semfold.nim9
-rwxr-xr-xcompiler/sigmatch.nim11
-rwxr-xr-xcompiler/syntaxes.nim2
-rwxr-xr-xdoc/apis.txt2
-rwxr-xr-xlib/impure/re.nim22
-rwxr-xr-xlib/pure/cgi.nim19
-rwxr-xr-xlib/pure/cookies.nim4
-rwxr-xr-xlib/pure/httpclient.nim6
-rwxr-xr-xlib/pure/httpserver.nim12
-rwxr-xr-xlib/pure/json.nim3
-rwxr-xr-xlib/pure/os.nim34
-rwxr-xr-xlib/pure/parseopt.nim2
-rwxr-xr-xlib/pure/parseutils.nim8
-rwxr-xr-xlib/pure/pegs.nim16
-rwxr-xr-xlib/pure/regexprs.nim2
-rwxr-xr-xlib/pure/ropes.nim4
-rwxr-xr-xlib/pure/strtabs.nim4
-rwxr-xr-xlib/pure/strutils.nim46
-rwxr-xr-xlib/pure/xmldom.nim4
-rwxr-xr-xlib/system.nim35
-rwxr-xr-xlib/system/cgprocs.nim81
-rwxr-xr-xlib/system/excpt.nim2
-rwxr-xr-xlib/system/gc.nim13
-rwxr-xr-xlib/system/repr.nim2
-rwxr-xr-xlib/system/systhread.nim2
-rw-r--r--tests/accept/compile/teval1.nim19
-rwxr-xr-xtests/accept/compile/tlibs.nim2
-rwxr-xr-xtodo.txt2
-rwxr-xr-xweb/news.txt4
43 files changed, 265 insertions, 180 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index fa7880c30..d1c10168a 100755
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -337,7 +337,9 @@ type
     mFields, mFieldPairs,
     mAppendStrCh, mAppendStrStr, mAppendSeqElem, 
     mInRange, mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq, mAssert, 
-    mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast, mNewString, mReset, 
+    mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast, 
+    mNewString, mNewStringOfCap,
+    mReset,
     mArray, mOpenArray, mRange, mSet, mSeq, 
     mOrdinal, mInt, mInt8, mInt16, mInt32, 
     mInt64, mFloat, mFloat32, mFloat64, mBool, mChar, mString, mCstring, 
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 49afc3088..69c06fbb5 100755
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -1457,7 +1457,8 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
   of mIncl, mExcl, mCard, mLtSet, mLeSet, mEqSet, mMulSet, mPlusSet, mMinusSet,
      mInSet:
     genSetOp(p, e, d, op)
-  of mNewString, mCopyStr, mCopyStrLast, mExit: genCall(p, e, d)
+  of mNewString, mNewStringOfCap, mCopyStr, mCopyStrLast, mExit: 
+    genCall(p, e, d)
   of mReset: genReset(p, e)
   of mEcho: genEcho(p, e)
   of mArrToSeq: genArrToSeq(p, e, d)
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 619caf250..61cd36c42 100755
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -210,7 +210,7 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: openarray[PRope]): PRope =
       inc(i)
       var j = i
       while frmt[j] in IdentChars: inc(j)
-      var ident = copy(frmt, i, j-1)
+      var ident = substr(frmt, i, j-1)
       i = j
       app(result, cgsym(m, ident))
     elif frmt[i] == '#' and frmt[i+1] == '$':
@@ -225,7 +225,7 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: openarray[PRope]): PRope =
       if frmt[i] != '$' and frmt[i] != '#': inc(i)
       else: break 
     if i - 1 >= start: 
-      app(result, copy(frmt, start, i - 1))
+      app(result, substr(frmt, start, i - 1))
 
 proc appcg(m: BModule, c: var PRope, frmt: TFormatStr, 
            args: openarray[PRope]) = 
@@ -489,9 +489,9 @@ proc libCandidates(s: string, dest: var TStringSeq) =
   var le = strutils.find(s, '(')
   var ri = strutils.find(s, ')', le+1)
   if le >= 0 and ri > le: 
-    var prefix = copy(s, 0, le - 1)
-    var suffix = copy(s, ri + 1)
-    for middle in split(copy(s, le + 1, ri - 1), '|'):
+    var prefix = substr(s, 0, le - 1)
+    var suffix = substr(s, ri + 1)
+    for middle in split(substr(s, le + 1, ri - 1), '|'):
       libCandidates(prefix & middle & suffix, dest)
   else: 
     add(dest, s)
diff --git a/compiler/commands.nim b/compiler/commands.nim
index d3eaf94a9..a4763d6b2 100755
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -172,7 +172,7 @@ proc splitSwitch(switch: string, cmd, arg: var string, pass: TCmdLinePass,
     else: break 
     inc(i)
   if i >= len(switch): arg = ""
-  elif switch[i] in {':', '=', '['}: arg = copy(switch, i + 1)
+  elif switch[i] in {':', '=', '['}: arg = substr(switch, i + 1)
   else: InvalidCmdLineOption(pass, switch, info)
   
 proc ProcessOnOffSwitch(op: TOptions, arg: string, pass: TCmdlinePass, 
@@ -215,7 +215,7 @@ proc ProcessSpecificNote(arg: string, state: TSpecialWord, pass: TCmdlinePass,
     var x = findStr(msgs.WarningsToStr, id)
     if x >= 0: n = TNoteKind(x + ord(warnMin))
     else: InvalidCmdLineOption(pass, arg, info)
-  case whichKeyword(copy(arg, i))
+  case whichKeyword(substr(arg, i))
   of wOn: incl(gNotes, n)
   of wOff: excl(gNotes, n)
   else: LocalError(info, errOnOrOffExpectedButXFound, arg)
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index eeb40f256..64973cddd 100755
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -156,7 +156,7 @@ proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openarray[string],
     while i < L: 
       if (frmt[i] != '$'): inc(i)
       else: break 
-    if i - 1 >= start: app(result, copy(frmt, start, i - 1))
+    if i - 1 >= start: app(result, substr(frmt, start, i - 1))
   
 proc addXmlChar(dest: var string, c: Char) = 
   case c
@@ -581,10 +581,10 @@ proc renderCodeBlock(d: PDoc, n: PRstNode): PRope =
       case g.kind
       of gtEof: break 
       of gtNone, gtWhitespace: 
-        app(result, copy(m.text, g.start + 0, g.length + g.start - 1 + 0))
+        app(result, substr(m.text, g.start + 0, g.length + g.start - 1))
       else: 
         dispA(result, "<span class=\"$2\">$1</span>", "\\span$2{$1}", [
-            toRope(esc(copy(m.text, g.start + 0, g.length + g.start - 1 + 0))), 
+            toRope(esc(substr(m.text, g.start + 0, g.length + g.start - 1))), 
             toRope(tokenClassToStr[g.kind])])
     deinitGeneralTokenizer(g)
   if result != nil: 
diff --git a/compiler/evals.nim b/compiler/evals.nim
index 20d2a68be..6fcbd911a 100755
--- a/compiler/evals.nim
+++ b/compiler/evals.nim
@@ -990,7 +990,13 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
     var a = result
     result = newNodeIT(nkStrLit, n.info, n.typ)
     result.strVal = newString(int(getOrdValue(a)))
-  else: 
+  of mNewStringOfCap:
+    result = evalAux(c, n.sons[1], {})
+    if isSpecial(result): return 
+    var a = result
+    result = newNodeIT(nkStrLit, n.info, n.typ)
+    result.strVal = newString(0)
+  else:
     result = evalAux(c, n.sons[1], {})
     if isSpecial(result): return 
     var a = result
diff --git a/compiler/filter_tmpl.nim b/compiler/filter_tmpl.nim
index 0bb402874..e56a08552 100755
--- a/compiler/filter_tmpl.nim
+++ b/compiler/filter_tmpl.nim
@@ -93,14 +93,14 @@ proc parseLine(p: var TTmplParser) =
     of wIf, wWhen, wTry, wWhile, wFor, wBlock, wCase, wProc, wIterator, 
        wConverter, wMacro, wTemplate, wMethod: 
       LLStreamWrite(p.outp, repeatChar(p.indent))
-      LLStreamWrite(p.outp, copy(p.x, d))
+      LLStreamWrite(p.outp, substr(p.x, d))
       inc(p.indent, 2)
     of wElif, wOf, wElse, wExcept, wFinally: 
       LLStreamWrite(p.outp, repeatChar(p.indent - 2))
-      LLStreamWrite(p.outp, copy(p.x, d))
+      LLStreamWrite(p.outp, substr(p.x, d))
     else: 
       LLStreamWrite(p.outp, repeatChar(p.indent))
-      LLStreamWrite(p.outp, copy(p.x, d))
+      LLStreamWrite(p.outp, substr(p.x, d))
     p.state = psDirective
   else: 
     # data line
diff --git a/compiler/llstream.nim b/compiler/llstream.nim
index 8dfa1e78e..2da56bccd 100755
--- a/compiler/llstream.nim
+++ b/compiler/llstream.nim
@@ -216,7 +216,7 @@ proc LLStreamReadAll(s: PLLStream): string =
     result = ""
   of llsString: 
     if s.rd == 0: result = s.s
-    else: result = copy(s.s, s.rd + 0)
+    else: result = substr(s.s, s.rd)
     s.rd = len(s.s)
   of llsFile: 
     result = newString(bufSize)
diff --git a/compiler/nimrod.nim b/compiler/nimrod.nim
index d9580d955..e4a9d8827 100755
--- a/compiler/nimrod.nim
+++ b/compiler/nimrod.nim
@@ -33,8 +33,8 @@ proc ProcessCmdLine(pass: TCmdLinePass, command, filename: var string) =
       # we fix this here
       var bracketLe = strutils.find(p.key, '[')
       if bracketLe >= 0: 
-        var key = copy(p.key, 0, bracketLe - 1)
-        var val = copy(p.key, bracketLe + 1) & ':' & p.val
+        var key = substr(p.key, 0, bracketLe - 1)
+        var val = substr(p.key, bracketLe + 1) & ':' & p.val
         ProcessSwitch(key, val, pass, cmdLineInfo)
       else: 
         ProcessSwitch(p.key, p.val, pass, cmdLineInfo)
diff --git a/compiler/nstrtabs.nim b/compiler/nstrtabs.nim
index 811e461cc..cd30887c5 100755
--- a/compiler/nstrtabs.nim
+++ b/compiler/nstrtabs.nim
@@ -153,13 +153,13 @@ proc `%`(f: string, t: PStringTable, flags: TFormatFlags = {}): string =
       of '{': 
         var j = i + 1
         while (j <= len(f) + 0 - 1) and (f[j] != '}'): inc(j)
-        var key = copy(f, i + 2 + 0 - 1, j - 1 + 0 - 1)
+        var key = substr(f, i + 2 + 0 - 1, j - 1 + 0 - 1)
         add(result, getValue(t, flags, key))
         i = j + 1
       of 'a'..'z', 'A'..'Z', '\x80'..'\xFF', '_': 
         var j = i + 1
         while (j <= len(f) + 0 - 1) and (f[j] in PatternChars): inc(j)
-        var key = copy(f, i + 1 + 0 - 1, j - 1 + 0 - 1)
+        var key = substr(f, i + 1 + 0 - 1, j - 1 + 0 - 1)
         add(result, getValue(t, flags, key))
         i = j
       else: 
@@ -168,4 +168,4 @@ proc `%`(f: string, t: PStringTable, flags: TFormatFlags = {}): string =
     else: 
       add(result, f[i])
       inc(i)
-  
\ No newline at end of file
+  
diff --git a/compiler/options.nim b/compiler/options.nim
index 9dec04475..b4ee8cf67 100755
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -138,19 +138,19 @@ proc shortenDir(dir: string): string =
   # returns the interesting part of a dir
   var prefix = getPrefixDir() & dirSep
   if startsWith(dir, prefix): 
-    return copy(dir, len(prefix))
+    return substr(dir, len(prefix))
   prefix = getCurrentDir() & dirSep
   if startsWith(dir, prefix): 
-    return copy(dir, len(prefix))
+    return substr(dir, len(prefix))
   prefix = projectPath & dirSep #writeln(output, prefix);
                                 #writeln(output, dir);
   if startsWith(dir, prefix): 
-    return copy(dir, len(prefix))
+    return substr(dir, len(prefix))
   result = dir
 
 proc removeTrailingDirSep*(path: string): string = 
   if (len(path) > 0) and (path[len(path) - 1] == dirSep): 
-    result = copy(path, 0, len(path) - 2)
+    result = substr(path, 0, len(path) - 2)
   else: 
     result = path
   
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index c94b8b68b..7c78570e2 100755
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -119,7 +119,7 @@ proc processMagic(c: PContext, n: PNode, s: PSym) =
   # treat them as imported, instead of modifing a lot of working code
   # BUGFIX: magic does not imply ``lfNoDecl`` anymore!
   for m in countup(low(TMagic), high(TMagic)): 
-    if copy($m, 1) == v: 
+    if substr($m, 1) == v: 
       s.magic = m
       return 
   Message(n.info, warnUnknownMagic, v)
@@ -333,12 +333,12 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
     var a = 0
     while true: 
       var b = strutils.find(str, marker, a)
-      var sub = if b < 0: copy(str, a) else: copy(str, a, b - 1)
+      var sub = if b < 0: substr(str, a) else: substr(str, a, b - 1)
       if sub != "": addSon(result, newStrNode(nkStrLit, sub))
       if b < 0: break 
       var c = strutils.find(str, marker, b + 1)
-      if c < 0: sub = copy(str, b + 1)
-      else: sub = copy(str, b + 1, c - 1)
+      if c < 0: sub = substr(str, b + 1)
+      else: sub = substr(str, b + 1, c - 1)
       if sub != "": 
         var e = SymtabGet(con.tab, getIdent(sub))
         if e != nil: 
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index 2167c8e5d..3ee8450b2 100755
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -1106,7 +1106,7 @@ proc getNextTok(r: var TSrcGen, kind: var TTokType, literal: var string) =
   if r.idx < len(r.tokens): 
     kind = r.tokens[r.idx].kind
     var length = r.tokens[r.idx].length
-    literal = copy(r.buf, r.pos + 0, r.pos + 0 + length - 1)
+    literal = substr(r.buf, r.pos + 0, r.pos + 0 + length - 1)
     inc(r.pos, length)
     inc(r.idx)
   else: 
diff --git a/compiler/ropes.nim b/compiler/ropes.nim
index 9c4c5e700..01ca5c81e 100755
--- a/compiler/ropes.nim
+++ b/compiler/ropes.nim
@@ -328,7 +328,7 @@ proc ropef(frmt: TFormatStr, args: openarray[PRope]): PRope =
       if (frmt[i] != '$'): inc(i)
       else: break 
     if i - 1 >= start: 
-      app(result, copy(frmt, start, i - 1))
+      app(result, substr(frmt, start, i - 1))
   assert(RopeInvariant(result))
 
 proc appf(c: var PRope, frmt: TFormatStr, args: openarray[PRope]) = 
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index 878c0a1a6..dbd5d34e5 100755
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nimrod Compiler
-#        (c) Copyright 2010 Andreas Rumpf
+#        (c) Copyright 2011 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -189,9 +189,9 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
   of mBoolToStr: 
     if getOrdValue(a) == 0: result = newStrNodeT("false", n)
     else: result = newStrNodeT("true", n)
-  of mCopyStr: result = newStrNodeT(copy(getStr(a), int(getOrdValue(b))), n)
+  of mCopyStr: result = newStrNodeT(substr(getStr(a), int(getOrdValue(b))), n)
   of mCopyStrLast: 
-    result = newStrNodeT(copy(getStr(a), int(getOrdValue(b)), 
+    result = newStrNodeT(substr(getStr(a), int(getOrdValue(b)), 
                                          int(getOrdValue(c))), n)
   of mFloatToStr: result = newStrNodeT($(getFloat(a)), n)
   of mCStrToStr, mCharToStr: result = newStrNodeT(getStrOrChar(a), n)
@@ -205,7 +205,8 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
   of mCompileOptionArg:
     result = newIntNodeT(Ord(
       testCompileOptionArg(getStr(a), getStr(b), n.info)), n)
-  of mNewString, mExit, mInc, ast.mDec, mEcho, mAssert, mSwap, mAppendStrCh, 
+  of mNewString, mNewStringOfCap, 
+     mExit, mInc, ast.mDec, mEcho, mAssert, mSwap, mAppendStrCh, 
      mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq, 
      mNLen..mNError, mEqRef: 
     nil
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index d5b8f3204..5b397167a 100755
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -14,7 +14,7 @@ import
   ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst, 
   magicsys
 
-type 
+type
   TCandidateState* = enum 
     csEmpty, csMatch, csNoMatch
   TCandidate* {.final.} = object 
@@ -33,7 +33,6 @@ type
   
   TTypeRelation* = enum      # order is important!
     isNone, isConvertible, isIntConv, isSubtype, 
-    isLifted, # match, but do not change argument type to formal's type!
     isGeneric, 
     isEqual
 
@@ -185,9 +184,6 @@ proc tupleRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
         var x = f.n.sons[i].sym
         var y = a.n.sons[i].sym
         if x.name.id != y.name.id: return isNone
-  elif sonsLen(f) == 0:
-    idTablePut(mapping, f, a)
-    result = isLifted
 
 proc constraintRel(mapping: var TIdTable, f, a: PType): TTypeRelation = 
   result = isNone
@@ -226,7 +222,7 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
   of tyFloat64:  result = handleFloatRange(f, a)
   of tyFloat128: result = handleFloatRange(f, a)
   of tyVar: 
-    if (a.kind == f.kind): result = typeRel(mapping, base(f), base(a))
+    if a.kind == f.kind: result = typeRel(mapping, base(f), base(a))
     else: result = typeRel(mapping, base(f), a)
   of tyArray, tyArrayConstr: 
     # tyArrayConstr cannot happen really, but
@@ -493,9 +489,6 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
   of isSubtype: 
     inc(m.subtypeMatches)
     result = implicitConv(nkHiddenSubConv, f, copyTree(arg), m, c)
-  of isLifted:
-    inc(m.genericMatches)
-    result = copyTree(arg)
   of isGeneric: 
     inc(m.genericMatches)
     result = copyTree(arg)
diff --git a/compiler/syntaxes.nim b/compiler/syntaxes.nim
index b098e4817..14f7d7f03 100755
--- a/compiler/syntaxes.nim
+++ b/compiler/syntaxes.nim
@@ -98,7 +98,7 @@ proc parsePipe(filename: string, inputStream: PLLStream): PNode =
       inc(i, 2)
       while line[i] in WhiteSpace: inc(i)
       var q: TParser
-      OpenParser(q, filename, LLStreamOpen(copy(line, i)))
+      OpenParser(q, filename, LLStreamOpen(substr(line, i)))
       result = parser.parseAll(q)
       CloseParser(q)
     LLStreamClose(s)
diff --git a/doc/apis.txt b/doc/apis.txt
index 2932c05a9..260ce159b 100755
--- a/doc/apis.txt
+++ b/doc/apis.txt
@@ -32,6 +32,7 @@ get                     get, ``[]``    consider overloading ``[]`` for get;
                                        prefix: ``len`` instead of ``getLen``
 length                  len            also used for *number of elements*
 size                    size, len      size should refer to a byte size
+capacity                cap
 memory                  mem            implies a low-level operation
 items                   items          default iterator over a collection
 pairs                   pairs          iterator over (key, value) pairs
@@ -69,6 +70,7 @@ coordinate              coord
 rectangle               rect
 point                   point
 symbol                  sym
+string                  str
 identifier              ident
 indentation             indent
 -------------------     ------------   --------------------------------------
diff --git a/lib/impure/re.nim b/lib/impure/re.nim
index 36adf5d1f..ccc13248a 100755
--- a/lib/impure/re.nim
+++ b/lib/impure/re.nim
@@ -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.
diff --git a/lib/pure/cgi.nim b/lib/pure/cgi.nim
index af222caba..ae05d5734 100755
--- a/lib/pure/cgi.nim
+++ b/lib/pure/cgi.nim
@@ -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
 
diff --git a/lib/pure/cookies.nim b/lib/pure/cookies.nim
index eed6c7512..8e5de008c 100755
--- a/lib/pure/cookies.nim
+++ b/lib/pure/cookies.nim
@@ -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 ';'
 
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
index 39ceb5f68..73a8cb853 100755
--- a/lib/pure/httpclient.nim
+++ b/lib/pure/httpclient.nim
@@ -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")
   
diff --git a/lib/pure/httpserver.nim b/lib/pure/httpserver.nim
index f8368a631..eb5dd7d73 100755
--- a/lib/pure/httpserver.nim
+++ b/lib/pure/httpserver.nim
@@ -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).
diff --git a/lib/pure/json.nim b/lib/pure/json.nim
index adb7e5e8b..7b2707784 100755
--- a/lib/pure/json.nim
+++ b/lib/pure/json.nim
@@ -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:
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index 7847fa332..2b2cb1ba7 100755
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -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)
diff --git a/lib/pure/parseopt.nim b/lib/pure/parseopt.nim
index 1b09934f2..c4625c161 100755
--- a/lib/pure/parseopt.nim
+++ b/lib/pure/parseopt.nim
@@ -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.
diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim
index 90bb5d79f..a7776bd5f 100755
--- a/lib/pure/parseutils.nim
+++ b/lib/pure/parseutils.nim
@@ -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:
diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim
index 9b2606b33..988e510e3 100755
--- a/lib/pure/pegs.nim
+++ b/lib/pure/pegs.nim
@@ -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
 
diff --git a/lib/pure/regexprs.nim b/lib/pure/regexprs.nim
index fb9601c18..3524aac0a 100755
--- a/lib/pure/regexprs.nim
+++ b/lib/pure/regexprs.nim
@@ -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
 
diff --git a/lib/pure/ropes.nim b/lib/pure/ropes.nim
index 52406d4d1..69737576f 100755
--- a/lib/pure/ropes.nim
+++ b/lib/pure/ropes.nim
@@ -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".} =
diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim
index 78f489615..2028daa50 100755
--- a/lib/pure/strtabs.nim
+++ b/lib/pure/strtabs.nim
@@ -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])
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index 382eece7b..7ed224b67 100755
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -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",

diff --git a/lib/pure/xmldom.nim b/lib/pure/xmldom.nim
index bf031fb88..923fc9e18 100755
--- a/lib/pure/xmldom.nim
+++ b/lib/pure/xmldom.nim
@@ -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):
diff --git a/lib/system.nim b/lib/system.nim
index bacb4325a..21da9d6ff 100755
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -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.
diff --git a/lib/system/cgprocs.nim b/lib/system/cgprocs.nim
index f77768a7a..8509fe3a3 100755
--- a/lib/system/cgprocs.nim
+++ b/lib/system/cgprocs.nim
@@ -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
-
-  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 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>".}
+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, 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_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)
 
diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim
index 073013113..ed2ec7ff0 100755
--- a/lib/system/excpt.nim
+++ b/lib/system/excpt.nim
@@ -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
diff --git a/lib/system/gc.nim b/lib/system/gc.nim
index 1edc33375..7c70ccf85 100755
--- a/lib/system/gc.nim
+++ b/lib/system/gc.nim
@@ -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)
diff --git a/lib/system/repr.nim b/lib/system/repr.nim
index 87588421f..9464ff3d8 100755
--- a/lib/system/repr.nim
+++ b/lib/system/repr.nim
@@ -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):
diff --git a/lib/system/systhread.nim b/lib/system/systhread.nim
index 0ffc9605c..fa2d75704 100755
--- a/lib/system/systhread.nim
+++ b/lib/system/systhread.nim
@@ -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:
diff --git a/tests/accept/compile/teval1.nim b/tests/accept/compile/teval1.nim
new file mode 100644
index 000000000..8172ebe28
--- /dev/null
+++ b/tests/accept/compile/teval1.nim
@@ -0,0 +1,19 @@
+import macros
+
+proc testProc: string {.compileTime.} =
+  result = ""
+  result = result & ""
+
+when true:
+  macro test(n: stmt): stmt =
+    result = newNimNode(nnkStmtList)
+    echo "#", testProc(), "#"
+  test:
+    "hi"
+
+const
+  x = testProc()
+  
+echo "##", x, "##"
+
+
diff --git a/tests/accept/compile/tlibs.nim b/tests/accept/compile/tlibs.nim
index 1f81a5ede..d4080eafd 100755
--- a/tests/accept/compile/tlibs.nim
+++ b/tests/accept/compile/tlibs.nim
@@ -15,7 +15,7 @@ import
   lua, lualib, lauxlib, mysql, sqlite3, python, tcl,
   db_postgres, db_mysql, db_sqlite, ropes, sockets, browsers, httpserver,
   httpclient, parseutils, unidecode, xmldom, xmldomparser, xmltree, xmlparser,
-  htmlparser, re, graphics, colors
+  htmlparser, re, graphics, colors, pegs
   
 when defined(linux):
   import
diff --git a/todo.txt b/todo.txt
index 1f1c31301..907fb790a 100755
--- a/todo.txt
+++ b/todo.txt
@@ -1,6 +1,6 @@
 * thread support: threadvar on Windows seems broken; 
   add --deadlock_prevention:on|off switch
-- implicit ref/ptr->var conversion
+* implicit ref/ptr->var conversion
 
 
 High priority (version 0.9.0)
diff --git a/web/news.txt b/web/news.txt
index f8bcef3db..dcfa6e363 100755
--- a/web/news.txt
+++ b/web/news.txt
@@ -31,6 +31,7 @@ Changes affecting backwards compatibility
   priority.
 - Deprecated ``os.getApplicationFilename``: Use ``os.getAppFilename`` instead.
 - Deprecated ``os.getApplicationDir``: Use ``os.getAppDir`` instead.
+- Deprecated ``system.copy``: Use ``substr`` or string slicing instead.
 - Changed and documented how generalized string literals work: The syntax
   ``module.re"abc"`` is now supported.
 - Changed the behaviour of ``strutils.%``, ``ropes.%`` 
@@ -74,10 +75,11 @@ Additions
 - Added the ``linearScanEnd``, ``unroll``, ``shallow`` pragmas.
 - Added ``system.reset`` and a version of ``system.open`` that 
   returns a ``TFile`` and raises an exception in case of an error.
-- The compiler now might use a hashing for string case statements depending
+- The compiler now might use hashing for string case statements depending
   on the number of string literals in the case statement.
 - Added a wrapper for ``redis``.
 - The compiler now supports array, sequence and string slicing.
+- Added ``system.newStringOfCap``.
 
 
 2010-10-20 Version 0.8.10 released