summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rwxr-xr-xcompiler/docgen.nim45
-rwxr-xr-xcompiler/highlite.nim8
-rwxr-xr-xcompiler/rst.nim234
-rwxr-xr-xlib/impure/db_mysql.nim2
-rwxr-xr-xlib/impure/db_postgres.nim2
-rwxr-xr-xlib/impure/db_sqlite.nim2
-rwxr-xr-xlib/pure/htmlgen.nim2
-rwxr-xr-xlib/pure/strutils.nim10
-rwxr-xr-xtodo.txt1
-rwxr-xr-xtools/nimweb.nim6
-rwxr-xr-xweb/news.txt1
11 files changed, 229 insertions, 84 deletions
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index d70f92ac4..c17884f21 100755
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -28,7 +28,8 @@ type
   TSections = array[TSymKind, PRope]
   TMetaEnum = enum 
     metaNone, metaTitle, metaSubtitle, metaAuthor, metaVersion
-  TDocumentor{.final.} = object # contains a module's documentation
+  TDocumentor {.final.} = object # contains a module's documentation
+    options: TRstParseOptions
     filename*: string         # filename of the source file; without extension
     basedir*: string          # base directory (where to put the documentation)
     modDesc*: PRope           # module description
@@ -70,8 +71,8 @@ proc initIndexFile(d: PDoc) =
   gIndexFile = addFileExt(gIndexFile, "txt")
   d.indexValFilename = changeFileExt(extractFilename(d.filename), HtmlExt)
   if ExistsFile(gIndexFile): 
-    d.indexFile = rstParse(readFile(gIndexFile), false, gIndexFile, 0, 1, 
-                           dummyHasToc)
+    d.indexFile = rstParse(readFile(gIndexFile), gIndexFile, 0, 1, 
+                           dummyHasToc, {})
     d.theIndex = findIndexNode(d.indexFile)
     if (d.theIndex == nil) or (d.theIndex.kind != rnDefList): 
       rawMessage(errXisNoValidIndexFile, gIndexFile)
@@ -264,10 +265,11 @@ proc renderIndexTerm(d: PDoc, n: PRstNode): PRope =
 
 proc genComment(d: PDoc, n: PNode): PRope = 
   var dummyHasToc: bool
-  if n.comment != nil and startsWith(n.comment, "##"): 
-    result = renderRstToOut(d, rstParse(n.comment, true, toFilename(n.info), 
+  if n.comment != nil and startsWith(n.comment, "##"):
+    result = renderRstToOut(d, rstParse(n.comment, toFilename(n.info),
                                         toLineNumber(n.info), toColumn(n.info), 
-                                        dummyHasToc))
+                                        dummyHasToc, 
+                                        d.options + {roSkipPounds}))
   
 proc genRecComment(d: PDoc, n: PNode): PRope = 
   if n == nil: return nil
@@ -357,15 +359,15 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
     of tkSymbol: 
       dispA(result, "<span class=\"Identifier\">$1</span>", 
             "\\spanIdentifier{$1}", [toRope(esc(literal))])
-    of tkInd, tkSad, tkDed, tkSpaces: 
+    of tkInd, tkSad, tkDed, tkSpaces, tkInvalid: 
       app(result, literal)
     of tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi, 
        tkBracketDotLe, tkBracketDotRi, tkCurlyDotLe, tkCurlyDotRi, tkParDotLe, 
        tkParDotRi, tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot, 
-       tkAccent: 
+       tkAccent, tkColonColon, 
+       tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr: 
       dispA(result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}", 
             [toRope(esc(literal))])
-    else: InternalError(n.info, "docgen.genThing(" & toktypeToStr[kind] & ')')
   inc(d.id)
   app(d.section[k], ropeFormatNamedVars(getConfigVar("doc.item"), 
                                         ["name", "header", "desc", "itemID"], 
@@ -498,6 +500,9 @@ proc renderRstToRst(d: PDoc, n: PRstNode): PRope =
   of rnStrongEmphasis: 
     result = renderRstSons(d, n)
     result = ropef("**$1**", [result])
+  of rnTripleEmphasis:
+    result = renderRstSons(d, n)
+    result = ropef("***$1***", [result])
   of rnInterpretedText: 
     result = renderRstSons(d, n)
     result = ropef("`$1`", [result])
@@ -506,6 +511,8 @@ proc renderRstToRst(d: PDoc, n: PRstNode): PRope =
     result = renderRstSons(d, n)
     result = ropef("``$1``", [result])
     dec(d.verbatim)
+  of rnSmiley:
+    result = toRope(n.text)
   of rnLeaf: 
     if (d.verbatim == 0) and (n.text == "\\"): 
       result = toRope("\\\\") # XXX: escape more special characters!
@@ -560,6 +567,12 @@ proc renderImage(d: PDoc, n: PRstNode): PRope =
                  [toRope(getArgument(n)), options])
   if rsonsLen(n) >= 3: app(result, renderRstToOut(d, n.sons[2]))
   
+proc renderSmiley(d: PDoc, n: PRstNode): PRope =
+  result = dispF(
+    """<img src="images/smilies/$1.gif" width="15" 
+        height="17" hspace="2" vspace="2" />""",
+    "\\includegraphics{$1}", [toRope(n.text)])
+  
 proc renderCodeBlock(d: PDoc, n: PRstNode): PRope = 
   result = nil
   if n.sons[2] == nil: return 
@@ -741,7 +754,10 @@ proc renderRstToOut(d: PDoc, n: PRstNode): PRope =
   of rnEmphasis: result = renderAux(d, n, disp("<em>$1</em>", "\\emph{$1}"))
   of rnStrongEmphasis:
     result = renderAux(d, n, disp("<strong>$1</strong>", "\\textbf{$1}"))
-  of rnInterpretedText: 
+  of rnTripleEmphasis:
+    result = renderAux(d, n, disp("<strong><em>$1</em></strong>", 
+                                  "\\textbf{emph{$1}}"))
+  of rnInterpretedText:
     result = renderAux(d, n, disp("<cite>$1</cite>", "\\emph{$1}"))
   of rnIdx: 
     if d.theIndex == nil: 
@@ -752,10 +768,10 @@ proc renderRstToOut(d: PDoc, n: PRstNode): PRope =
     result = renderAux(d, n, disp(
       "<tt class=\"docutils literal\"><span class=\"pre\">$1</span></tt>", 
       "\\texttt{$1}"))
+  of rnSmiley: result = renderSmiley(d, n)
   of rnLeaf: result = toRope(esc(n.text))
   of rnContents: d.hasToc = true
   of rnTitle: d.meta[metaTitle] = renderRstToOut(d, n.sons[0])
-  else: InternalError("renderRstToOut")
   
 proc checkForFalse(n: PNode): bool = 
   result = n.kind == nkIdent and IdentEq(n.ident, "false")
@@ -869,7 +885,7 @@ proc CommandRstAux(filename, outExt: string) =
   var filen = addFileExt(filename, "txt")
   var d = newDocumentor(filen)
   initIndexFile(d)
-  var rst = rstParse(readFile(filen), false, filen, 0, 1, d.hasToc)
+  var rst = rstParse(readFile(filen), filen, 0, 1, d.hasToc, {})
   d.modDesc = renderRstToOut(d, rst)
   writeOutput(d, filename, outExt)
   generateIndex(d)
@@ -926,12 +942,13 @@ $content
   setConfigVar("doc.body_no_toc", "$moduledesc $content")
   setConfigVar("doc.file", "$content")
 
-proc rstToHtml*(s: string): string =
+proc rstToHtml*(s: string, options: TRstParseOptions): string =
   ## exported for *nimforum*.
   const filen = "input"
   var d = newDocumentor(filen)
+  d.options = options
   var dummyHasToc = false
-  var rst = rstParse(s, false, filen, 0, 1, dummyHasToc)
+  var rst = rstParse(s, filen, 0, 1, dummyHasToc, options)
   d.modDesc = renderRstToOut(d, rst)
   let res = genOutFile(d)
   result = res.ropeToStr
diff --git a/compiler/highlite.nim b/compiler/highlite.nim
index b0177a01e..ff4b27086 100755
--- a/compiler/highlite.nim
+++ b/compiler/highlite.nim
@@ -25,10 +25,10 @@ type
     gtReference, gtOther
   TGeneralTokenizer* = object of TObject
     kind*: TTokenClass
-    start*, length*: int      # private:
-    buf*: cstring
-    pos*: int
-    state*: TTokenClass
+    start*, length*: int
+    buf: cstring
+    pos: int
+    state: TTokenClass
 
   TSourceLanguage* = enum 
     langNone, langNimrod, langCpp, langCsharp, langC, langJava
diff --git a/compiler/rst.nim b/compiler/rst.nim
index 395c27119..1efcd9930 100755
--- a/compiler/rst.nim
+++ b/compiler/rst.nim
@@ -11,7 +11,7 @@
 # subset is provided.
 
 import 
-  os, msgs, strutils, platform, hashes, ropes, options
+  os, msgs, strutils, hashes, options
 
 type 
   TRstNodeKind* = enum 
@@ -52,15 +52,25 @@ type
                               #     * `file#id <file#id>'_
     rnSubstitutionDef,        # a definition of a substitution
     rnGeneralRole,            # Inline markup:
-    rnSub, rnSup, rnIdx, rnEmphasis, # "*"
+    rnSub, rnSup, rnIdx, 
+    rnEmphasis,               # "*"
     rnStrongEmphasis,         # "**"
+    rnTripleEmphasis,         # "***"
     rnInterpretedText,        # "`"
     rnInlineLiteral,          # "``"
     rnSubstitutionReferences, # "|"
+    rnSmiley,                 # some smiley
     rnLeaf                    # a leaf; the node's text field contains the
                               # leaf val
 
-type                          # the syntax tree of RST:
+type
+  TRstParseOption* = enum     ## options for the RST parser 
+    roSkipPounds,             ## skip ``#`` at line beginning (documentation
+                              ## embedded in Nimrod comments)
+    roSupportSmilies,         ## make the RST parser support smilies like ``:)``
+  
+  TRstParseOptions* = set[TRstParseOption]
+  
   PRSTNode* = ref TRstNode
   TRstNodeSeq* = seq[PRstNode]
   TRSTNode*{.acyclic, final.} = object 
@@ -71,9 +81,9 @@ type                          # the syntax tree of RST:
     sons*: TRstNodeSeq        # the node's sons
   
 
-proc rstParse*(text: string,  # the text to be parsed
-               skipPounds: bool, filename: string, # for error messages
-               line, column: int, hasToc: var bool): PRstNode
+proc rstParse*(text, filename: string,
+               line, column: int, hasToc: var bool,
+               options: TRstParseOptions): PRstNode
 proc rsonsLen*(n: PRstNode): int
 proc newRstNode*(kind: TRstNodeKind): PRstNode
 proc newRstNode*(kind: TRstNodeKind, s: string): PRstNode
@@ -91,8 +101,46 @@ proc clearIndex*(index: PRstNode, filename: string)
 
 const 
   SymChars: TCharSet = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'}
+  SmileyStartChars: TCharSet = {':', ';', '8'}
+  Smilies = {
+    ":D": "icon_e_biggrin",
+    ":-D": "icon_e_biggrin",
+    ":)": "icon_e_smile",
+    ":-)": "icon_e_smile",
+    ";)": "icon_e_wink",
+    ";-)": "icon_e_wink",
+    ":(": "icon_e_sad",
+    ":-(": "icon_e_sad",
+    ":o": "icon_e_surprised",
+    ":-o": "icon_e_surprised",
+    ":shock:": "icon_eek",
+    ":?": "icon_e_confused",
+    ":-?": "icon_e_confused",
+    "8-)": "icon_cool",
+
+    ":lol:": "icon_lol",
+    ":x": "icon_mad",
+    ":-x": "icon_mad",
+    ":P": "icon_razz",
+    ":-P": "icon_razz",
+    ":oops:": "icon_redface",
+    ":cry:": "icon_cry",
+    ":evil:": "icon_evil",
+    ":twisted:": "icon_twisted",
+    ":roll:": "icon_rolleyes",
+    ":!:": "icon_exclaim",
+
+    ":?:": "icon_question",
+    ":idea:": "icon_idea",
+    ":arrow:": "icon_arrow",
+    ":|": "icon_neutral",
+    ":-|": "icon_neutral",
+    ":mrgreen:": "icon_mrgreen",
+    ":geek:": "icon_e_geek",
+    ":ugeek:": "icon_e_ugeek"
+  }
 
-type 
+type
   TTokType = enum 
     tkEof, tkIndent, tkWhite, tkWord, tkAdornment, tkPunct, tkOther
   TToken{.final.} = object    # a RST token
@@ -117,7 +165,7 @@ proc getThing(L: var TLexer, tok: var TToken, s: TCharSet) =
   while True: 
     add(tok.symbol, L.buf[pos])
     inc(pos)
-    if not (L.buf[pos] in s): break 
+    if L.buf[pos] notin s: break 
   inc(L.col, pos - L.bufpos)
   L.bufpos = pos
 
@@ -256,7 +304,8 @@ type
     key*: string
     value*: PRstNode
 
-  TSharedState{.final.} = object 
+  TSharedState {.final.} = object 
+    options: TRstParseOptions    # parsing options
     uLevel*, oLevel*: int        # counters for the section levels
     subs*: seq[TSubstitution]    # substitutions
     refs*: seq[TSubstitution]    # references
@@ -280,10 +329,11 @@ type
     hasToc*: bool
 
 
-proc newSharedState(): PSharedState = 
+proc newSharedState(options: TRstParseOptions): PSharedState = 
   new(result)
   result.subs = @[]
   result.refs = @[]
+  result.options = options
 
 proc tokInfo(p: TRstParser, tok: TToken): TLineInfo = 
   result = newLineInfo(p.filename, p.line + tok.line, p.col + tok.col)
@@ -325,7 +375,7 @@ proc addNodes(n: PRstNode): string =
 
 proc rstnodeToRefnameAux(n: PRstNode, r: var string, b: var bool) = 
   if n.kind == rnLeaf: 
-    for i in countup(0, len(n.text) + 0 - 1): 
+    for i in countup(0, len(n.text) - 1): 
       case n.text[i]
       of '0'..'9': 
         if b: 
@@ -440,15 +490,14 @@ proc matchesHyperlink(h: PRstNode, filename: string): bool =
   
 proc clearIndex(index: PRstNode, filename: string) = 
   var 
-    k, items, lastItem: int
-    val: PRstNode
+    lastItem: int
   assert(index.kind == rnDefList)
   for i in countup(0, rsonsLen(index) - 1): 
     assert(index.sons[i].sons[1].kind == rnDefBody)
-    val = index.sons[i].sons[1].sons[0]
+    var val = index.sons[i].sons[1].sons[0]
     if val.kind == rnInner: val = val.sons[0]
     if val.kind == rnBulletList: 
-      items = rsonsLen(val)
+      var items = rsonsLen(val)
       lastItem = - 1          # save the last valid item index
       for j in countup(0, rsonsLen(val) - 1): 
         if val.sons[j] == nil: 
@@ -464,7 +513,7 @@ proc clearIndex(index: PRstNode, filename: string) =
         index.sons[i] = nil
     elif matchesHyperlink(val, filename): 
       index.sons[i] = nil
-  k = 0
+  var k = 0
   for i in countup(0, rsonsLen(index) - 1): 
     if index.sons[i] != nil: 
       if k != i: index.sons[k] = index.sons[i]
@@ -573,20 +622,6 @@ proc isInlineMarkupStart(p: TRstParser, markup: string): bool =
       of '<': d = '>'
       else: d = '\0'
       if d != '\0': result = p.tok[p.idx + 1].symbol[0] != d
-  
-proc parseBackslash(p: var TRstParser, father: PRstNode) = 
-  assert(p.tok[p.idx].kind == tkPunct)
-  if p.tok[p.idx].symbol == "\\\\": 
-    addSon(father, newRstNode(rnLeaf, "\\"))
-    inc(p.idx)
-  elif p.tok[p.idx].symbol == "\\": 
-    # XXX: Unicode?
-    inc(p.idx)
-    if p.tok[p.idx].kind != tkWhite: addSon(father, newLeaf(p))
-    inc(p.idx)
-  else: 
-    addSon(father, newLeaf(p))
-    inc(p.idx)
 
 proc match(p: TRstParser, start: int, expr: string): bool = 
   # regular expressions are:
@@ -601,7 +636,7 @@ proc match(p: TRstParser, start: int, expr: string): bool =
   # 'e'              tkWord or '#' (for enumeration lists)
   var i = 0
   var j = start
-  var last = len(expr) + 0 - 1
+  var last = len(expr) - 1
   while i <= last: 
     case expr[i]
     of 'w': result = p.tok[j].kind == tkWord
@@ -632,7 +667,7 @@ proc match(p: TRstParser, start: int, expr: string): bool =
     inc(j)
     inc(i)
   result = true
-
+  
 proc fixupEmbeddedRef(n, a, b: PRstNode) = 
   var sep = - 1
   for i in countdown(rsonsLen(n) - 2, 0): 
@@ -687,31 +722,85 @@ proc parsePostfix(p: var TRstParser, n: PRstNode): PRstNode =
       addSon(result, newRstNode(rnLeaf, p.tok[p.idx + 1].symbol))
     inc(p.idx, 3)
 
-proc isURL(p: TRstParser, i: int): bool = 
-  result = (p.tok[i + 1].symbol == ":") and (p.tok[i + 2].symbol == "//") and
-      (p.tok[i + 3].kind == tkWord) and (p.tok[i + 4].symbol == ".")
+proc matchVerbatim(p: TRstParser, start: int, expr: string): int =
+  result = start
+  var j = 0
+  while j < expr.len and continuesWith(expr, p.tok[result].symbol, j):
+    inc j, p.tok[result].symbol.len
+    inc result
+  if j < expr.len: result = 0
+  
+proc parseSmiley(p: var TRstParser): PRstNode =
+  if p.tok[p.idx].symbol[0] notin SmileyStartChars: return
+  for key, val in items(smilies):
+    let m = matchVerbatim(p, p.idx, key)
+    if m > 0:
+      p.idx = m
+      result = newRstNode(rnSmiley)
+      result.text = val
+      return
+
+proc isURL(p: TRstParser, i: int): bool =
+  result = (p.tok[i+1].symbol == ":") and (p.tok[i+2].symbol == "//") and
+          (p.tok[i+3].kind == tkWord) and (p.tok[i+4].symbol == ".")
 
 proc parseURL(p: var TRstParser, father: PRstNode) = 
-  #if p.tok[p.idx].symbol[strStart] = '<' then begin
-  if isURL(p, p.idx): 
+  #if p.tok[p.idx].symbol[strStart] == '<':
+  if isURL(p, p.idx):
     var n = newRstNode(rnStandaloneHyperlink)
     while true: 
       case p.tok[p.idx].kind
-      of tkWord, tkAdornment, tkOther: 
-        nil
+      of tkWord, tkAdornment, tkOther: nil
       of tkPunct: 
-        if not (p.tok[p.idx + 1].kind in
-            {tkWord, tkAdornment, tkOther, tkPunct}): 
-          break 
+        if p.tok[p.idx+1].kind notin {tkWord, tkAdornment, tkOther, tkPunct}:
+          break
       else: break 
       addSon(n, newLeaf(p))
       inc(p.idx)
     addSon(father, n)
-  else: 
+  else:
     var n = newLeaf(p)
     inc(p.idx)
     if p.tok[p.idx].symbol == "_": n = parsePostfix(p, n)
     addSon(father, n)
+  
+proc parseBackslash(p: var TRstParser, father: PRstNode) = 
+  assert(p.tok[p.idx].kind == tkPunct)
+  if p.tok[p.idx].symbol == "\\\\": 
+    addSon(father, newRstNode(rnLeaf, "\\"))
+    inc(p.idx)
+  elif p.tok[p.idx].symbol == "\\": 
+    # XXX: Unicode?
+    inc(p.idx)
+    if p.tok[p.idx].kind != tkWhite: addSon(father, newLeaf(p))
+    inc(p.idx)
+  else: 
+    addSon(father, newLeaf(p))
+    inc(p.idx)
+
+when false:
+  proc parseAdhoc(p: var TRstParser, father: PRstNode, verbatim: bool) =
+    if not verbatim and isURL(p, p.idx):
+      var n = newRstNode(rnStandaloneHyperlink)
+      while true: 
+        case p.tok[p.idx].kind
+        of tkWord, tkAdornment, tkOther: nil
+        of tkPunct: 
+          if p.tok[p.idx+1].kind notin {tkWord, tkAdornment, tkOther, tkPunct}:
+            break
+        else: break 
+        addSon(n, newLeaf(p))
+        inc(p.idx)
+      addSon(father, n)
+    elif not verbatim and roSupportSmilies in p.shared.options:
+      let n = parseSmiley(p)
+      if s != nil:
+        addSon(father, n)
+    else:
+      var n = newLeaf(p)
+      inc(p.idx)
+      if p.tok[p.idx].symbol == "_": n = parsePostfix(p, n)
+      addSon(father, n)
 
 proc parseUntil(p: var TRstParser, father: PRstNode, postfix: string, 
                 interpretBackslash: bool) = 
@@ -743,7 +832,12 @@ proc parseUntil(p: var TRstParser, father: PRstNode, postfix: string,
 proc parseInline(p: var TRstParser, father: PRstNode) = 
   case p.tok[p.idx].kind
   of tkPunct: 
-    if isInlineMarkupStart(p, "**"): 
+    if isInlineMarkupStart(p, "***"):
+      inc(p.idx)
+      var n = newRstNode(rnTripleEmphasis)
+      parseUntil(p, n, "***", true)
+      addSon(father, n)
+    elif isInlineMarkupStart(p, "**"): 
       inc(p.idx)
       var n = newRstNode(rnStrongEmphasis)
       parseUntil(p, n, "**", true)
@@ -769,11 +863,26 @@ proc parseInline(p: var TRstParser, father: PRstNode) =
       var n = newRstNode(rnSubstitutionReferences)
       parseUntil(p, n, "|", false)
       addSon(father, n)
-    else: 
+    else:
+      if roSupportSmilies in p.s.options:
+        let n = parseSmiley(p)
+        if n != nil:
+          addSon(father, n)
+          return
       parseBackslash(p, father)
-  of tkWord: 
+  of tkWord:
+    if roSupportSmilies in p.s.options:
+      let n = parseSmiley(p)
+      if n != nil:
+        addSon(father, n)
+        return
     parseURL(p, father)
   of tkAdornment, tkOther, tkWhite: 
+    if roSupportSmilies in p.s.options:
+      let n = parseSmiley(p)
+      if n != nil:
+        addSon(father, n)
+        return
     addSon(father, newLeaf(p))
     inc(p.idx)
   else: nil
@@ -878,7 +987,9 @@ proc getFieldValue(n: PRstNode, fieldname: string): string =
   result = ""
   if n.sons[1] == nil: return 
   if (n.sons[1].kind != rnFieldList): 
-    InternalError("getFieldValue (2): " & $n.sons[1].kind)
+    #InternalError("getFieldValue (2): " & $n.sons[1].kind)
+    # We don't like internal errors here anymore as that would break the forum!
+    return
   for i in countup(0, rsonsLen(n.sons[1]) - 1): 
     var f = n.sons[1].sons[i]
     if cmpIgnoreStyle(addNodes(f.sons[0]), fieldname) == 0: 
@@ -975,7 +1086,8 @@ proc whichSection(p: TRstParser): TRstNodeKind =
       result = rnLineBlock
     elif (p.tok[p.idx].symbol == "..") and predNL(p): 
       result = rnDirective
-    elif (p.tok[p.idx].symbol == ":") and predNL(p): 
+    elif match(p, p.idx, ":w:") and predNL(p):
+      # (p.tok[p.idx].symbol == ":")
       result = rnFieldList
     elif match(p, p.idx, "(e) "): 
       result = rnEnumList
@@ -1317,13 +1429,14 @@ proc parseSection(p: var TRstParser, result: PRstNode) =
     of rnOverline: a = parseOverline(p)
     of rnTable: a = parseSimpleTable(p)
     of rnOptionList: a = parseOptionList(p)
-    else: InternalError("rst.parseSection()")
-    if (a == nil) and (k != rnDirective): 
+    else:
+      #InternalError("rst.parseSection()")
+      nil
+    if a == nil and k != rnDirective: 
       a = newRstNode(rnParagraph)
       parseParagraph(p, a)
     addSonIfNotNil(result, a)
-  if (sonKind(result, 0) == rnParagraph) and
-      (sonKind(result, 1) != rnParagraph): 
+  if sonKind(result, 0) == rnParagraph and sonKind(result, 1) != rnParagraph: 
     result.sons[0].kind = rnInner
   
 proc parseSectionWrapper(p: var TRstParser): PRstNode = 
@@ -1423,9 +1536,10 @@ proc dirInclude(p: var TRstParser): PRstNode =
       var q: TRstParser
       initParser(q, p.s)
       q.filename = filename
-      getTokens(readFile(path), false, q.tok) # workaround a GCC bug: 
-      if find(q.tok[high(q.tok)].symbol, "\0\x01\x02") > 0: 
-        InternalError("Too many binary zeros in include file")
+      getTokens(readFile(path), false, q.tok) 
+      # workaround a GCC bug; more like the interior pointer bug?
+      #if find(q.tok[high(q.tok)].symbol, "\0\x01\x02") > 0:
+      #  InternalError("Too many binary zeros in include file")
       result = parseDoc(q)
 
 proc dirCodeBlock(p: var TRstParser): PRstNode = 
@@ -1580,15 +1694,15 @@ proc resolveSubs(p: var TRstParser, n: PRstNode): PRstNode =
   else: 
     for i in countup(0, rsonsLen(n) - 1): n.sons[i] = resolveSubs(p, n.sons[i])
   
-proc rstParse(text: string,   # the text to be parsed
-              skipPounds: bool, filename: string, # for error messages
-              line, column: int, hasToc: var bool): PRstNode = 
+proc rstParse(text, filename: string,
+              line, column: int, hasToc: var bool,
+              options: TRstParseOptions): PRstNode =
   var p: TRstParser
   if isNil(text): rawMessage(errCannotOpenFile, filename)
-  initParser(p, newSharedState())
+  initParser(p, newSharedState(options))
   p.filename = filename
   p.line = line
   p.col = column
-  getTokens(text, skipPounds, p.tok)
+  getTokens(text, roSkipPounds in options, p.tok)
   result = resolveSubs(p, parseDoc(p))
   hasToc = p.hasToc
diff --git a/lib/impure/db_mysql.nim b/lib/impure/db_mysql.nim
index 4c77c707f..2b94ab614 100755
--- a/lib/impure/db_mysql.nim
+++ b/lib/impure/db_mysql.nim
@@ -106,7 +106,7 @@ proc getRow*(db: TDbConn, query: TSqlQuery,
   var sqlres = mysql.UseResult(db)
   if sqlres != nil:
     var L = int(mysql.NumFields(sqlres))
-    var result = newRow(L)
+    result = newRow(L)
     var row = mysql.FetchRow(sqlres)
     if row != nil: 
       for i in 0..L-1: 
diff --git a/lib/impure/db_postgres.nim b/lib/impure/db_postgres.nim
index dff607081..506da9c84 100755
--- a/lib/impure/db_postgres.nim
+++ b/lib/impure/db_postgres.nim
@@ -108,7 +108,7 @@ proc getRow*(db: TDbConn, query: TSqlQuery,
   ## retrieves a single row.
   var res = setupQuery(db, query, args)
   var L = int(PQnfields(res))
-  var result = newRow(L)
+  result = newRow(L)
   setRow(res, result, 0, L)
   PQclear(res)
 
diff --git a/lib/impure/db_sqlite.nim b/lib/impure/db_sqlite.nim
index 3f5be772c..b6c8003b9 100755
--- a/lib/impure/db_sqlite.nim
+++ b/lib/impure/db_sqlite.nim
@@ -106,7 +106,7 @@ proc getRow*(db: TDbConn, query: TSqlQuery,
   ## retrieves a single row.
   var stmt = setupQuery(db, query, args)
   var L = int(columnCount(stmt))
-  var result = newRow(L)
+  result = newRow(L)
   if step(stmt) == SQLITE_ROW: 
     setRow(stmt, result, L)
   if finalize(stmt) != SQLITE_OK: dbError(db)
diff --git a/lib/pure/htmlgen.nim b/lib/pure/htmlgen.nim
index b61aa2925..86ee4159b 100755
--- a/lib/pure/htmlgen.nim
+++ b/lib/pure/htmlgen.nim
@@ -222,7 +222,7 @@ macro head*(e: expr): expr =
 
 macro html*(e: expr): expr = 
   ## generates the HTML ``html`` element.
-  result = xmlCheckedTag(e, "html", "", "xmlns")
+  result = xmlCheckedTag(e, "html", "xmlns", "")
 
 macro hr*(e: expr): expr = 
   ## generates the HTML ``hr`` element.
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index 8e3816904..368ef2564 100755
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -531,6 +531,16 @@ proc endsWith*(s, suffix: string): bool {.noSideEffect,
     if s[i+j] != suffix[i]: return false

     inc(i)

   if suffix[i] == '\0': return true

+
+proc continuesWith*(s, substr: string, start: int): bool {.noSideEffect,
+  rtl, extern: "nsuContinuesWith".} =
+  ## Returns true iff ``s`` continues with ``substr`` at position ``start``.

+  ## If ``substr == ""`` true is returned.

+  var i = 0

+  while true:

+    if substr[i] == '\0': return true

+    if s[i+start] != substr[i]: return false

+    inc(i)

 

 proc addSep*(dest: var string, sep = ", ", startLen = 0) {.noSideEffect,

                                                            inline.} =

diff --git a/todo.txt b/todo.txt
index 761c6d419..3f7f2e2df 100755
--- a/todo.txt
+++ b/todo.txt
@@ -2,6 +2,7 @@ version 0.9.0
 =============
 
 - make templates hygienic by default
+- ``bind`` for overloaded symbols does not work apparently
 - ``=`` should be overloadable; requires specialization for ``=``
 - fix remaining generics bugs
 - fix remaining closure bugs:
diff --git a/tools/nimweb.nim b/tools/nimweb.nim
index cc5ea97a6..61f23ab8c 100755
--- a/tools/nimweb.nim
+++ b/tools/nimweb.nim
@@ -203,8 +203,10 @@ proc main(c: var TConfigData) =
   if c.ticker.len > 0:
     Exec(cmd % [c.nimrodArgs, c.ticker])
     var temp = "web" / changeFileExt(c.ticker, "temp")
-    c.ticker = readFile(temp)
-    if isNil(c.ticker): quit("[Error] cannot open:" & temp)
+    try:
+      c.ticker = readFile(temp)
+    except EIO:
+      quit("[Error] cannot open: " & temp)
     RemoveFile(temp)
   for i in 0..c.tabs.len-1:
     var file = c.tabs[i].val
diff --git a/web/news.txt b/web/news.txt
index 8504be619..64d0ce928 100755
--- a/web/news.txt
+++ b/web/news.txt
@@ -43,6 +43,7 @@ Library Additions
 - Added ``system.TInteger`` and ``system.TNumber`` type classes matching
   any of the corresponding type available in nimrod.
 - Added ``system.clamp`` to limit a value within an interval ``[a, b]``.
+- Added ``strutils.continuesWith``.
 - The GC supports (soft) realtime systems via ``GC_setMaxPause`` 
   and ``GC_step`` procs.