Check-in [7a39dde24b]
Not logged in
Overview

SHA1 Hash:7a39dde24bbc2436e41d32085410b76f4aa4ed55
Date: 2009-09-26 08:17:33
User: robert
Comment:Clean up and merge updates from trunk
Timelines: ancestors | descendants | both | creole
Other Links: files | ZIP archive | manifest

Tags And Properties
Changes
[hide diffs]

Modified src/configure.c from [d749a9aa69] to [ac12a5f70a].

@@ -76,10 +76,12 @@
   int groupMask;       /* Which config groups is it part of */
 } aConfig[] = {
   { "css",                    CONFIGSET_SKIN },
   { "header",                 CONFIGSET_SKIN },
   { "footer",                 CONFIGSET_SKIN },
+  { "logo-mimetype",          CONFIGSET_SKIN },
+  { "logo-image",             CONFIGSET_SKIN },
   { "project-name",           CONFIGSET_PROJ },
   { "project-description",    CONFIGSET_PROJ },
   { "index-page",             CONFIGSET_SKIN },
   { "timeline-block-markup",  CONFIGSET_SKIN },
   { "timeline-max-comment",   CONFIGSET_SKIN },

Modified src/creoleparser.c from [803615829f] to [f8a37ab2ca].

@@ -28,11 +28,11 @@
 #include <assert.h>
 #include "config.h"
 #include "creoleparser.h"
 
 #if INTERFACE
-#define HAVE_MACRO_EXTENSIONS 1
+#define HAVE_CREOLE_MACRO 1
 #endif
 
 //{{{ LOCAL INTERFACE
 #if LOCAL_INTERFACE
 
@@ -61,59 +61,59 @@
 
 #define KIND_TABLE_ROW       0x0010000
 //}}}
 //{{{ FLAG
 // keep first four bits free
-#define FLAG_CENTER	 0x0000100
+#define FLAG_CENTER   0x0000100
 //}}}
 struct Node {//{{{
 
-	char *start;
-	char *end;
-
-	int kind;
-	int level;
-	int flags;
-
-	Node *parent;
-	Node *next;
-	Node *children;
+  char *start;
+  char *end;
+
+  int kind;
+  int level;
+  int flags;
+
+  Node *parent;
+  Node *next;
+  Node *children;
 
 };
 //}}}
 struct NodePool {//{{{
-	NodePool *next;
-	Node a[POOL_CHUNK_SIZE];
+  NodePool *next;
+  Node a[POOL_CHUNK_SIZE];
 }
 //}}}
 struct Parser {//{{{
 
-	Blob *pOut;                 /* Output appended to this blob */
-	Renderer *r;
-
-	NodePool *pool;
-	int nFree;
+  Blob *pOut;                 /* Output appended to this blob */
+  Renderer *r;
+
+  NodePool *pool;
+  int nFree;
 
   Node *this;
-	Node *previous;
-	Node *list;
-
-	char *cursor;
-
-	int lineWasBlank;
-	int charCount;
-
-	Node *item;
-	Node *istack;
-	char *icursor;
-	char *iend;
-
-	int inLink;
-	int inTable;
-	int iesc;
-
-	Blob *iblob;
+  Node *previous;
+  Node *list;
+
+  char *cursor;
+
+  int lineWasBlank;
+  int charCount;
+
+  Node *item;
+  Node *istack;
+  char *icursor;
+  char *iend;
+
+  int inLink;
+  int inTable;
+  int iesc;
+
+  Blob *iblob;
 
 
 
 
 };
@@ -126,484 +126,485 @@
 //}}}
 
 //{{{ POOL MANAGEMENT
 static Node *pool_new(Parser *p){
 
-	if ( p->pool == NULL || p->nFree == 0){
-
-		NodePool *temp = p->pool;
-
-		p->pool = malloc(sizeof(NodePool));
-		if( p->pool == NULL ) fossil_panic("out of memory");
-
-		p->pool->next = temp;
-		p->nFree = POOL_CHUNK_SIZE;
-	}
-	p->nFree -= 1;
-	Node *node = &(p->pool->a[p->nFree]);
-	memset(node, 0, sizeof(*node));
-
-	return node;
+  if ( p->pool == NULL || p->nFree == 0){
+
+    NodePool *temp = p->pool;
+
+    p->pool = malloc(sizeof(NodePool));
+    if( p->pool == NULL ) fossil_panic("out of memory");
+
+    p->pool->next = temp;
+    p->nFree = POOL_CHUNK_SIZE;
+  }
+  p->nFree -= 1;
+  Node *node = &(p->pool->a[p->nFree]);
+  memset(node, 0, sizeof(*node));
+
+  return node;
 }
 
 
 static void pool_free(Parser *p){
 
-	NodePool *temp;
-
-	while (p->pool != NULL){
-		temp = p->pool;
-		p->pool = temp->next;
-		free(temp);
-	}
+  NodePool *temp;
+
+  while (p->pool != NULL){
+    temp = p->pool;
+    p->pool = temp->next;
+    free(temp);
+  }
 
 }
 //}}}
 
 //{{{ Utility Methods
 
 static char *cr_skipBlanks(Parser *p, char* z){//{{{
-	char *s = z;
-	while (z[0] == ' ' || z[0] == '\t') z++;
-	p->charCount = z - s;
-	return z;
+  char *s = z;
+  while (z[0] == ' ' || z[0] == '\t') z++;
+  p->charCount = z - s;
+  return z;
 }
 //}}}
 static int cr_countBlanks(Parser *p, char* z){//{{{
-	cr_skipBlanks(p, z);
-	return p->charCount;
+  cr_skipBlanks(p, z);
+  return p->charCount;
 }
 //}}}
 static char *cr_skipChars(Parser *p, char *z, char c){//{{{
-	char *s = z;
-	while (z[0] == c) z++;
-	p->charCount = z - s;
-	return z;
+  char *s = z;
+  while (z[0] == c) z++;
+  p->charCount = z - s;
+  return z;
 }
 //}}}
 static int cr_countChars(Parser *p, char *z, char c){//{{{
-	cr_skipChars(p, z, c);
-	return p->charCount;
+  cr_skipChars(p, z, c);
+  return p->charCount;
 }
 //}}}
 static char *cr_nextLine(Parser *p, char *z){//{{{
 
-	p->lineWasBlank = 1;
-
-	while (1){
-
-		switch (z[0]){
-
-			case '\r':
-				if (z[1] == '\n') {
-					z[0] = ' ';
-					return z + 2;
-				}
-				z[0] = '\n';
-				return z + 1;
-
-			case'\n':
-				return z + 1;
-
-			case '\t':
-				z[0] = ' ';
-				z++;
-				break;
-
-			case ' ':
-				z++;
-				break;
-
-			case '\0':
-				return z;
-
-			default:
-				p->lineWasBlank = 0;
-				z++;
-		}
-	}
+  p->lineWasBlank = 1;
+
+  while (1){
+
+    switch (z[0]){
+
+      case '\r':
+        if (z[1] == '\n') {
+          z[0] = ' ';
+          return z + 2;
+        }
+        z[0] = '\n';
+        return z + 1;
+
+      case'\n':
+        return z + 1;
+
+      case '\t':
+        z[0] = ' ';
+        z++;
+        break;
+
+      case ' ':
+        z++;
+        break;
+
+      case '\0':
+        return z;
+
+      default:
+        p->lineWasBlank = 0;
+        z++;
+    }
+  }
 }
 //}}}
 //}}}
 
 //{{{ INLINE PARSER
 
 static int cr_isEsc(Parser *p){//{{{
-	if (p->iesc){
-		blob_append(p->iblob, p->icursor, 1);
-		p->iesc = 0;
-		p->icursor += 1;
-		return 1;
-	}
-	return 0;
+  if (p->iesc){
+    blob_append(p->iblob, p->icursor, 1);
+    p->iesc = 0;
+    p->icursor += 1;
+    return 1;
+  }
+  return 0;
 }
 //}}}
 static int cr_iOpen(Parser *p, int kind){//{{{
 
-	switch (kind){
-
-		case KIND_BOLD:
-			blob_append(p->iblob, "<strong>", 8);
-			return 1;
-
-		case KIND_ITALIC:
-			blob_append(p->iblob, "<em>", 4);
-			return 1;
-
-		case KIND_SUPERSCRIPT:
-			blob_append(p->iblob, "<sup>", 5);
-			return 1;
-
-		case KIND_SUBSCRIPT:
-			blob_append(p->iblob, "<sub>", 5);
-			return 1;
-
-		case KIND_MONOSPACED:
-			blob_append(p->iblob, "<tt>", 4);
-			return 1;
-	}
-	return 0;
+  switch (kind){
+
+    case KIND_BOLD:
+      blob_append(p->iblob, "<strong>", 8);
+      return 1;
+
+    case KIND_ITALIC:
+      blob_append(p->iblob, "<em>", 4);
+      return 1;
+
+    case KIND_SUPERSCRIPT:
+      blob_append(p->iblob, "<sup>", 5);
+      return 1;
+
+    case KIND_SUBSCRIPT:
+      blob_append(p->iblob, "<sub>", 5);
+      return 1;
+
+    case KIND_MONOSPACED:
+      blob_append(p->iblob, "<tt>", 4);
+      return 1;
+  }
+  return 0;
 }
 //}}}
 static int cr_iClose(Parser *p, int kind){//{{{
 
-	switch (kind){
-
-		case KIND_BOLD:
-			blob_append(p->iblob, "</strong>", 9);
-			return 1;
-
-		case KIND_ITALIC:
-			blob_append(p->iblob, "</em>", 5);
-			return 1;
-
-		case KIND_SUPERSCRIPT:
-			blob_append(p->iblob, "</sup>", 6);
-			return 1;
-
-		case KIND_SUBSCRIPT:
-			blob_append(p->iblob, "</sub>", 6);
-			return 1;
-
-		case KIND_MONOSPACED:
-			blob_append(p->iblob, "</tt>", 5);
-			return 1;
-	}
-	return 0;
+  switch (kind){
+
+    case KIND_BOLD:
+      blob_append(p->iblob, "</strong>", 9);
+      return 1;
+
+    case KIND_ITALIC:
+      blob_append(p->iblob, "</em>", 5);
+      return 1;
+
+    case KIND_SUPERSCRIPT:
+      blob_append(p->iblob, "</sup>", 6);
+      return 1;
+
+    case KIND_SUBSCRIPT:
+      blob_append(p->iblob, "</sub>", 6);
+      return 1;
+
+    case KIND_MONOSPACED:
+      blob_append(p->iblob, "</tt>", 5);
+      return 1;
+  }
+  return 0;
 }
 //}}}
 
 
 static void cr_iMarkup(Parser *p, int kind){//{{{
 
-	if (p->iesc) {
-		blob_append(p->iblob, p->icursor, 1);
-		p->icursor +=1;
-		p->iesc =0;
-		return;
-	}
-
-	if (p->icursor[1] != p->icursor[0]) {
-		blob_append(p->iblob, p->icursor, 1);
-		p->icursor +=1;
-		return;
-	}
-
-	p->icursor += 2;
-
-	if (kind & KIND_BREAK) {
-			blob_append(p->iblob, "<br />", 6);
-			return;
-	}
-
-	if (kind & KIND_ITALIC && p->icursor[-3] == ':'){
-				blob_append(p->iblob, "//", 2);
-				return;
-	}
-
-	Node *n = p->istack;
-
-	int found = 0;
-	while (n) {
-		if (n->kind & kind) {
-			found = 1;
-			break;
-		}
-		n = n->next;
-	}
-
-	if (!found) {
-		n = pool_new(p);
-		n->kind = kind;
-		n->next = p->istack;
-		p->istack = n;
-
-		assert(cr_iOpen(p, kind));
-		return;
-	};
-
-	n= p->istack;
-	while (n){
-		p->istack = n->next;
-
-		assert(cr_iClose(p, n->kind));
-
-		if (kind == n->kind) return;
-		n = p->istack;
-	}
+  if (p->iesc) {
+    blob_append(p->iblob, p->icursor, 1);
+    p->icursor +=1;
+    p->iesc =0;
+    return;
+  }
+
+  if (p->icursor[1] != p->icursor[0]) {
+    blob_append(p->iblob, p->icursor, 1);
+    p->icursor +=1;
+    return;
+  }
+
+  p->icursor += 2;
+
+  if (kind & KIND_BREAK) {
+      blob_append(p->iblob, "<br />", 6);
+      return;
+  }
+
+  if (kind & KIND_ITALIC && p->icursor[-3] == ':'){
+        blob_append(p->iblob, "//", 2);
+        return;
+  }
+
+  Node *n = p->istack;
+
+  int found = 0;
+  while (n) {
+    if (n->kind & kind) {
+      found = 1;
+      break;
+    }
+    n = n->next;
+  }
+
+  if (!found) {
+    n = pool_new(p);
+    n->kind = kind;
+    n->next = p->istack;
+    p->istack = n;
+
+    assert(cr_iOpen(p, kind));
+    return;
+  };
+
+  n= p->istack;
+  while (n){
+    p->istack = n->next;
+
+    assert(cr_iClose(p, n->kind));
+
+    if (kind == n->kind) return;
+    n = p->istack;
+  }
 }
 //}}}
 static int cr_iNoWiki(Parser *p){//{{{
 
-	if ((p->iend - p->icursor)<6) return 0;
-
-	if (p->icursor[1]!='{' || p->icursor[2]!='{')
-		return 0;
-
-	char *s = p->icursor + 3;
-
-	int count = p->iend - p->icursor - 6;
-	while (count--){
-		if (s[0]=='}' && s[1]=='}' && s[2]=='}' && s[3]!='}'){
-			blob_appendf(p->iblob, "<tt style='background:oldlace'>%s</tt>", htmlize(p->icursor + 3, s - p->icursor-3));
-			p->icursor = s + 3;
-			return 1;
-		}
-		s++;
-	}
-	return 0;
+  if ((p->iend - p->icursor)<6) return 0;
+
+  if (p->icursor[1]!='{' || p->icursor[2]!='{')
+    return 0;
+
+  char *s = p->icursor + 3;
+
+  int count = p->iend - p->icursor - 6;
+  while (count--){
+    if (s[0]=='}' && s[1]=='}' && s[2]=='}' && s[3]!='}'){
+      blob_appendf(p->iblob, "<tt style='background:oldlace'>%s</tt>", htmlize(p->icursor + 3, s - p->icursor-3));
+      p->icursor = s + 3;
+      return 1;
+    }
+    s++;
+  }
+  return 0;
 }
 
 //}}}
 static int cr_iImage(Parser *p){//{{{
 
-	if (p->inLink) return 0;
-	if ((p->iend - p->icursor)<3) return 0;
-
-	if (p->icursor[1]!='{') return 0;
-
-	char *s = p->icursor + 2;
-	char *bar = NULL;
-
-	int count = p->iend - p->icursor - 4;
-	while (count--){
-		if (s[0]=='}' && s[1]=='}'){
-			if (!bar) bar = p->icursor + 2;
-			blob_appendf(p->iblob, "<span style='color:green;border:1px solid green;'>%s</span>", htmlize(bar, s - bar ));
-			p->icursor = s + 2;
-			return 1;
-		}
-		if (!bar && s[0]=='|') bar=s+1;
-		s++;
-	}
-	return 0;
+  if (p->inLink) return 0;
+  if ((p->iend - p->icursor)<3) return 0;
+
+  if (p->icursor[1]!='{') return 0;
+
+  char *s = p->icursor + 2;
+  char *bar = NULL;
+
+  int count = p->iend - p->icursor - 4;
+  while (count--){
+    if (s[0]=='}' && s[1]=='}'){
+      if (!bar) bar = p->icursor + 2;
+      blob_appendf(p->iblob, "<span style='color:green;border:1px solid green;'>%s</span>", htmlize(bar, s - bar ));
+      p->icursor = s + 2;
+      return 1;
+    }
+    if (!bar && s[0]=='|') bar=s+1;
+    s++;
+  }
+  return 0;
 }
 //}}}
 static int cr_iMacro(Parser *p){//{{{
 
-	if (p->inLink) return 0;
-	if ((p->iend - p->icursor)<3) return 0;
-
-	if (p->icursor[1]!='<') return 0;
-
-	char *s = p->icursor + 2;
-
-	int count = p->iend - p->icursor - 4;
-	while (count--){
-		if (s[0]=='>' && s[1]=='>'){
-			blob_appendf(p->iblob, "<span style='color:red;border:1px solid red;'>%s</span>", htmlize(p->icursor, s - p->icursor + 2));
-			p->icursor = s + 2;
-			return 1;
-		}
-		s++;
-	}
-	return 0;
+  if (p->inLink) return 0;
+  if ((p->iend - p->icursor)<3) return 0;
+
+  if (p->icursor[1]!='<') return 0;
+
+  char *s = p->icursor + 2;
+
+  int count = p->iend - p->icursor - 3;
+  while (count--){
+    blob_appendf(p->iblob, "|~%s|", s,2 );
+    if (s[0]=='>' && s[1]=='>'){
+      blob_appendf(p->iblob, "<span style='color:red;border:1px solid red;'>%s</span>", htmlize(p->icursor, s - p->icursor + 2));
+      p->icursor = s + 2;
+      return 1;
+    }
+    s++;
+  }
+  return 0;
 
 }
 //}}}
 
 static void cr_renderLink(Parser *p, char *s, char *bar, char *e){//{{{
 
-	int tsize = bar-s;
-	int dsize = e - bar-1;
-
-	if (tsize < 1) return;
-	if (dsize < 1) dsize = 0;
-
-	char zTarget[tsize + 1];
-	memcpy(zTarget, s, tsize);
-	zTarget[tsize] = '\0';
-
-	char zClose[20];
-
-	Blob *pOut = p->r->pOut;
-
-	p->r->pOut = p->iblob;
-	wf_openHyperlink(p->r, zTarget, zClose, sizeof(zClose));
-	p->r->pOut = pOut;
-
-	if (dsize)
-		cr_parseInline(p, bar+1, e) ;
-	else
-		blob_append(p->iblob, htmlize(s, tsize), -1);
-	blob_append(p->iblob, zClose, -1);
+  int tsize = bar-s;
+  int dsize = e - bar-1;
+
+  if (tsize < 1) return;
+  if (dsize < 1) dsize = 0;
+
+  char zTarget[tsize + 1];
+  memcpy(zTarget, s, tsize);
+  zTarget[tsize] = '\0';
+
+  char zClose[20];
+
+  Blob *pOut = p->r->pOut;
+
+  p->r->pOut = p->iblob;
+  wf_openHyperlink(p->r, zTarget, zClose, sizeof(zClose));
+  p->r->pOut = pOut;
+
+  if (dsize)
+    cr_parseInline(p, bar+1, e) ;
+  else
+    blob_append(p->iblob, htmlize(s, tsize), -1);
+  blob_append(p->iblob, zClose, -1);
 }
 //}}}
 
 static int cr_iLink(Parser *p){//{{{
 
-	if (p->inLink) return 0;
-	if ((p->iend - p->icursor)<3) return 0;
-
-	if (p->icursor[1]!='[') return 0;
-
-	char *s = p->icursor + 2;
-	char *bar = NULL;
-
-	int count = p->iend - p->icursor -3;
-	while (count--){
-		if (s[0]==']' && s[1]==']'){
-			if (!bar) bar = s;
-			p->inLink = 1;
-			cr_renderLink(p, p->icursor+2, bar, s);
-			p->inLink = 0;
-			p->icursor = s + 2;
-			return 1;
-		}
-		if (!bar && s[0]=='|') bar=s;
-		s++;
-	}
-	return 0;
+  if (p->inLink) return 0;
+  if ((p->iend - p->icursor)<3) return 0;
+
+  if (p->icursor[1]!='[') return 0;
+
+  char *s = p->icursor + 2;
+  char *bar = NULL;
+
+  int count = p->iend - p->icursor -3;
+  while (count--){
+    if (s[0]==']' && s[1]==']'){
+      if (!bar) bar = s;
+      p->inLink = 1;
+      cr_renderLink(p, p->icursor+2, bar, s);
+      p->inLink = 0;
+      p->icursor = s + 2;
+      return 1;
+    }
+    if (!bar && s[0]=='|') bar=s;
+    s++;
+  }
+  return 0;
 }
 //}}}
 
 LOCAL char *cr_parseInline(Parser *p, char *s, char *e){//{{{
 
-	int save_iesc = p->iesc;
-	char *save_iend = p->iend;
-	Node *save_istack = p->istack;
-
-	p->iesc = 0;
-	p->iend = e;
-	p->istack = NULL;
-
-	p->icursor = s;
-
-	char *eof = NULL;
-	while (!eof &&  p->icursor < p->iend ){
-
-		switch (*p->icursor) {//{{{
-
-			case '~':
-				if (p->iesc) {
-					blob_append(p->iblob, "~", 1);
-					p->iesc = 0;
-				}
-				p->iesc = !p->iesc;
-				p->icursor+=1;
-				break;
-
-			case '*':
-				cr_iMarkup(p, KIND_BOLD);
-				break;
-
-			case '/':
-				cr_iMarkup(p, KIND_ITALIC);
-				break;
-
-			case '^':
-				cr_iMarkup(p, KIND_SUPERSCRIPT);
-				break;
-
-			case ',':
-				cr_iMarkup(p, KIND_SUBSCRIPT);
-				break;
-
-			case '#':
-				cr_iMarkup(p, KIND_MONOSPACED);
-				break;
-
-			case '\\':
-				cr_iMarkup(p, KIND_BREAK);
-				break;
-
-			case '{':
-				if (cr_isEsc(p)) break;
-				if (cr_iNoWiki(p)) break;
-				if (cr_iImage(p)) break;
-				blob_append(p->iblob, p->icursor, 1);
-				p->icursor += 1;
-				break;
-
-			case '[':
-				if (cr_isEsc(p)) break;
-				if (cr_iLink(p)) break;
-				blob_append(p->iblob, p->icursor, 1);
-				p->icursor += 1;
-				break;
-
-
-			case '<':
-				if (cr_isEsc(p)) break;
-				if (cr_iMacro(p)) break;
-
-				blob_append(p->iblob, "&lt;", 4);
-				p->icursor += 1;
-				break;
-
-			case '>':
-				if (p->iesc) {
-					blob_append(p->iblob, "~", 1);
-					p->iesc = 0;
-				}
-				blob_append(p->iblob, "&gt;", 4);
-				p->icursor += 1;
-				break;
-
-			case '&':
-				if (p->iesc) {
-					blob_append(p->iblob, "~", 1);
-					p->iesc = 0;
-				}
-				blob_append(p->iblob, "&amp;", 5);
-				p->icursor += 1;
-				break;
-
-			case '|':
-				if (p->inTable){
-					if (p->iesc) {
-						blob_append(p->iblob, p->icursor, 1);
-						p->iesc = 0;
-						p->icursor += 1;
-						break;
-					}
-					eof = p->icursor + 1;
-					break;
-				}
-				// fall through to default
-
-			default:
-				if (p->iesc) {
-					blob_append(p->iblob, "~", 1);
-					p->iesc = 0;
-				}
-				blob_append(p->iblob, p->icursor, 1);
-				p->icursor +=1;
-		}//}}}
-
-	}
-
-	while (p->istack){
-		cr_iClose(p, p->istack->kind);
-		p->istack = p->istack->next;
-	}
-
-	p->iesc = save_iesc;
-	p->iend = save_iend;
-	p->istack = save_istack;
-
-	return eof;
+  int save_iesc = p->iesc;
+  char *save_iend = p->iend;
+  Node *save_istack = p->istack;
+
+  p->iesc = 0;
+  p->iend = e;
+  p->istack = NULL;
+
+  p->icursor = s;
+
+  char *eof = NULL;
+  while (!eof &&  p->icursor < p->iend ){
+
+    switch (*p->icursor) {//{{{
+
+      case '~':
+        if (p->iesc) {
+          blob_append(p->iblob, "~", 1);
+          p->iesc = 0;
+        }
+        p->iesc = !p->iesc;
+        p->icursor+=1;
+        break;
+
+      case '*':
+        cr_iMarkup(p, KIND_BOLD);
+        break;
+
+      case '/':
+        cr_iMarkup(p, KIND_ITALIC);
+        break;
+
+      case '^':
+        cr_iMarkup(p, KIND_SUPERSCRIPT);
+        break;
+
+      case ',':
+        cr_iMarkup(p, KIND_SUBSCRIPT);
+        break;
+
+      case '#':
+        cr_iMarkup(p, KIND_MONOSPACED);
+        break;
+
+      case '\\':
+        cr_iMarkup(p, KIND_BREAK);
+        break;
+
+      case '{':
+        if (cr_isEsc(p)) break;
+        if (cr_iNoWiki(p)) break;
+        if (cr_iImage(p)) break;
+        blob_append(p->iblob, p->icursor, 1);
+        p->icursor += 1;
+        break;
+
+      case '[':
+        if (cr_isEsc(p)) break;
+        if (cr_iLink(p)) break;
+        blob_append(p->iblob, p->icursor, 1);
+        p->icursor += 1;
+        break;
+
+
+      case '<':
+        if (cr_isEsc(p)) break;
+        if (cr_iMacro(p)) break;
+
+        blob_append(p->iblob, "&lt;", 4);
+        p->icursor += 1;
+        break;
+
+      case '>':
+        if (p->iesc) {
+          blob_append(p->iblob, "~", 1);
+          p->iesc = 0;
+        }
+        blob_append(p->iblob, "&gt;", 4);
+        p->icursor += 1;
+        break;
+
+      case '&':
+        if (p->iesc) {
+          blob_append(p->iblob, "~", 1);
+          p->iesc = 0;
+        }
+        blob_append(p->iblob, "&amp;", 5);
+        p->icursor += 1;
+        break;
+
+      case '|':
+        if (p->inTable){
+          if (p->iesc) {
+            blob_append(p->iblob, p->icursor, 1);
+            p->iesc = 0;
+            p->icursor += 1;
+            break;
+          }
+          eof = p->icursor + 1;
+          break;
+        }
+        // fall through to default
+
+      default:
+        if (p->iesc) {
+          blob_append(p->iblob, "~", 1);
+          p->iesc = 0;
+        }
+        blob_append(p->iblob, p->icursor, 1);
+        p->icursor +=1;
+    }//}}}
+
+  }
+
+  while (p->istack){
+    cr_iClose(p, p->istack->kind);
+    p->istack = p->istack->next;
+  }
+
+  p->iesc = save_iesc;
+  p->iend = save_iend;
+  p->istack = save_istack;
+
+  return eof;
 
 }
 //}}}
 //}}}
 
@@ -610,472 +611,455 @@
 //{{{ BLOCK PARSER
 
 static void cr_renderListItem(Parser *p, Node *n){//{{{
 
 
-	blob_append(p->iblob, "<li>", 4);
-	cr_parseInline(p, n->start, n->end);
-
-	if (n->children){
-
-		int ord = (n->children->kind & KIND_ORDERED_LIST);
-
-		if (ord) 	blob_append(p->iblob, "<ol>", 4);
-		else 			blob_append(p->iblob, "<ul>", 4);
-
-		n = n->children;
-		while (n){
-			cr_renderListItem(p, n);
-			n = n->next;
-		}
-
-		if (ord) 	blob_append(p->iblob, "</ol>", 5);
-		else 			blob_append(p->iblob, "</ul>", 5);
-	}
-	blob_append(p->iblob, "</li>", 5);
+  blob_append(p->iblob, "<li>", 4);
+  cr_parseInline(p, n->start, n->end);
+
+  if (n->children){
+
+    int ord = (n->children->kind & KIND_ORDERED_LIST);
+
+    if (ord)   blob_append(p->iblob, "<ol>", 4);
+    else       blob_append(p->iblob, "<ul>", 4);
+
+    n = n->children;
+    while (n){
+      cr_renderListItem(p, n);
+      n = n->next;
+    }
+
+    if (ord)   blob_append(p->iblob, "</ol>", 5);
+    else       blob_append(p->iblob, "</ul>", 5);
+  }
+  blob_append(p->iblob, "</li>", 5);
 }
 //}}}
 static void cr_renderList(Parser *p){//{{{
 
-	Node *n = p->list;
-
-	while (n->parent !=n)  n = n->parent;
-
-	int ord = (n->kind & KIND_ORDERED_LIST);
-
-	if (ord) 	blob_append(p->iblob, "\n\n<ol>", -1);
-	else 			blob_append(p->iblob, "\n\n<ul>", -1);
-
-	while (n) {
-		cr_renderListItem(p, n);
-		n = n->next;
-	}
-
-	if (ord) 	blob_append(p->iblob, "</ol>", 5);
-	else 			blob_append(p->iblob, "</ul>", 5);
+  Node *n = p->list;
+
+  while (n->parent !=n)  n = n->parent;
+
+  int ord = (n->kind & KIND_ORDERED_LIST);
+
+  if (ord)   blob_append(p->iblob, "\n\n<ol>", -1);
+  else       blob_append(p->iblob, "\n\n<ul>", -1);
+
+  while (n) {
+    cr_renderListItem(p, n);
+    n = n->next;
+  }
+
+  if (ord)   blob_append(p->iblob, "</ol>", 5);
+  else       blob_append(p->iblob, "</ul>", 5);
 }
 
 //}}}
 
 static void cr_renderTableRow(Parser *p, Node *row){//{{{
 
-	char *s = row->start;
-	int th;
-
-	blob_append(p->iblob, "\n<tr>", -1);
-
-	while (s && s < row->end){
-
-		if ((th = *s == '=')) {
-			s++;
-			blob_append(p->iblob, "<th>", -1);
-		}
-		else {
-			blob_append(p->iblob, "<td>", -1);
-		}
-
-		s = cr_parseInline(p, s, row->end);
-
-		if (th)
-			blob_append(p->iblob, "</th>\n", -1);
-		else
-			blob_append(p->iblob, "</td>\n", -1);
-
-		if (!s) break;
-	}
-	blob_append(p->iblob, "</tr>", 5);
+  char *s = row->start;
+  int th;
+
+  blob_append(p->iblob, "\n<tr>", -1);
+
+  while (s && s < row->end){
+
+    if ((th = *s == '=')) {
+      s++;
+      blob_append(p->iblob, "<th>", -1);
+    }
+    else {
+      blob_append(p->iblob, "<td>", -1);
+    }
+
+    s = cr_parseInline(p, s, row->end);
+
+    if (th)
+      blob_append(p->iblob, "</th>\n", -1);
+    else
+      blob_append(p->iblob, "</td>\n", -1);
+
+    if (!s) break;
+  }
+  blob_append(p->iblob, "</tr>", 5);
 }
 //}}}
 static void cr_renderTable(Parser *p, Node *n){//{{{
 
-	Node *row = n->children;
-
-	blob_append(p->iblob, "<table class='creoletable'>", -1);
-	p->inTable = 1;
-	while (row){
-
-		cr_renderTableRow(p, row);
-		row = row->next;
-
-	}
-	blob_append(p->iblob, "</table>", -1);
-	p->inTable = 0;
+  Node *row = n->children;
+
+  blob_append(p->iblob, "<table class='creoletable'>", -1);
+  p->inTable = 1;
+  while (row){
+
+    cr_renderTableRow(p, row);
+    row = row->next;
+
+  }
+  blob_append(p->iblob, "</table>", -1);
+  p->inTable = 0;
 
 }
 //}}}
 
 static void cr_render(Parser *p, Node *node){//{{{
 
-	if (node->kind & KIND_PARAGRAPH){
-		blob_append(p->iblob, 	"\n<p>", -1);
-		cr_parseInline(p, node->start, node->end );
-		blob_append(p->iblob, "</p>\n", -1	);
-	}
-
-	if (node->kind & KIND_HEADING){
-		blob_appendf(p->iblob,
-				"\n<h%d %s>",
-				node->level,
-				(node->flags & FLAG_CENTER) ? " style='text-align:center;'" : ""
-		);
-		cr_parseInline(p, node->start, node->end);
-		blob_appendf(p->iblob, "</h%d>\n", node->level	);
-		return;
-	}
-
-	if (node->kind & KIND_HORIZONTAL_RULE){
-		blob_append(p->iblob, "<hr />", -1);
-		return;
-	}
-
-	if (node->kind & KIND_LIST){
-		cr_renderList(p);
-		p->list = NULL;
-		return;
-	}
-
-	if (node->kind & KIND_TABLE){
-		cr_renderTable(p, node);
-		return;
-	}
-
-	if (node->kind & KIND_NO_WIKI_BLOCK){
-		blob_appendf(p->iblob,
-			"\n<blockquote style='background:oldlace'><pre>%s</pre></blockquote>\n",
-				htmlize( node->start, node->end - node->start)
-		);
-	}
+  if (node->kind & KIND_PARAGRAPH){
+    blob_append(p->iblob,   "\n<p>", -1);
+    cr_parseInline(p, node->start, node->end );
+    blob_append(p->iblob, "</p>\n", -1  );
+  }
+
+  if (node->kind & KIND_HEADING){
+    blob_appendf(p->iblob,
+        "\n<h%d %s>",
+        node->level,
+        (node->flags & FLAG_CENTER) ? " style='text-align:center;'" : ""
+    );
+    cr_parseInline(p, node->start, node->end);
+    blob_appendf(p->iblob, "</h%d>\n", node->level  );
+    return;
+  }
+
+  if (node->kind & KIND_HORIZONTAL_RULE){
+    blob_append(p->iblob, "<hr />", -1);
+    return;
+  }
+
+  if (node->kind & KIND_LIST){
+    cr_renderList(p);
+    p->list = NULL;
+    return;
+  }
+
+  if (node->kind & KIND_TABLE){
+    cr_renderTable(p, node);
+    return;
+  }
+
+  if (node->kind & KIND_NO_WIKI_BLOCK){
+    blob_appendf(p->iblob,
+      "\n<blockquote style='background:oldlace'><pre>%s</pre></blockquote>\n",
+        htmlize( node->start, node->end - node->start)
+    );
+  }
 }
 //}}}
 
 static char *cr_findEndOfBlock(Parser *p, char *s, char c){//{{{
 
-	char *end;
-	while (s[0]){
-
-		end = s;
-		if (s[0] == c && s[0] == c && s[0] == c) {
-			s = cr_nextLine(p, s + 3);
-			if (p->lineWasBlank) {
-					p->cursor = s;
-					return end;
-			}
-		}
-		else {
-			s = cr_nextLine(p, s);
-		}
-	}
-	return 0;
+  char *end;
+  while (s[0]){
+
+    end = s;
+    if (s[0] == c && s[0] == c && s[0] == c) {
+      s = cr_nextLine(p, s + 3);
+      if (p->lineWasBlank) {
+          p->cursor = s;
+          return end;
+      }
+    }
+    else {
+      s = cr_nextLine(p, s);
+    }
+  }
+  return 0;
 }
 //}}}
 static int cr_addListItem(Parser *p, Node *n){//{{{
 
-	n->parent = n;
-	n->next = n->children = NULL;
-
-	if (!p->list) {
-		if (n->level != 1) return 0;
-		p->list = n;
-		return 1;
-	}
-
-	Node *list = p->list;
-
-	while (n->level < list->level){
-		list = list->parent;
-	}
-
-	if (n->level == list->level){
-
-		if (n->kind != list->kind){
-			if (n->level>1) return 0;
-			cr_renderList(p);
-			p->list = n;
-			return 1;
-		}
-		n->parent = list->parent;
-		p->list = list->next = n;
-		return 1;
-	}
-
-	if ( (n->level - list->level) > 1 ) return 0;
-	n->parent = p->list;
-	p->list->children = n;
-	p->list = n;
-	return 1;
+  n->parent = n;
+  n->next = n->children = NULL;
+
+  if (!p->list) {
+    if (n->level != 1) return 0;
+    p->list = n;
+    return 1;
+  }
+
+  Node *list = p->list;
+
+  while (n->level < list->level){
+    list = list->parent;
+  }
+
+  if (n->level == list->level){
+
+    if (n->kind != list->kind){
+      if (n->level>1) return 0;
+      cr_renderList(p);
+      p->list = n;
+      return 1;
+    }
+    n->parent = list->parent;
+    p->list = list->next = n;
+    return 1;
+  }
+
+  if ( (n->level - list->level) > 1 ) return 0;
+  n->parent = p->list;
+  p->list->children = n;
+  p->list = n;
+  return 1;
 
 }
 //}}}
 
 static int isEndWikiMarker(Parser *p){//{{{
 
-	char *s = p->cursor;
-	if (memcmp(s, "<<fossil>>", 10)) return 0;
-	p->this->start = s;
-	p->this->kind = KIND_END_WIKI_MARKER;
-	p->cursor += 10;
-	return 1;
+  char *s = p->cursor;
+  if (memcmp(s, "<<fossil>>", 10)) return 0;
+  p->this->start = s;
+  p->this->kind = KIND_END_WIKI_MARKER;
+  p->cursor += 10;
+  return 1;
 }
 ///}}}
 static int isNoWikiBlock(Parser *p){//{{{
 
-	char *s = p->cursor;
-
-	if (s[0] != '{') return 0; s++;
-	if (s[0] != '{') return 0; s++;
-	if (s[0] != '{') return 0; s++;
-
-	s = cr_nextLine(p, s);
-	if (!p->lineWasBlank) return 0;
-
-	p->this->start = s;
-
-	s = cr_findEndOfBlock(p, s, '}');
-
-	if (!s) return 0;
-
-	// p->cursor was set by findEndOfBlock
-	p->this->kind = KIND_NO_WIKI_BLOCK;
-	p->this->end = s;
-	return 1;
+  char *s = p->cursor;
+
+  if (s[0] != '{') return 0; s++;
+  if (s[0] != '{') return 0; s++;
+  if (s[0] != '{') return 0; s++;
+
+  s = cr_nextLine(p, s);
+  if (!p->lineWasBlank) return 0;
+
+  p->this->start = s;
+
+  s = cr_findEndOfBlock(p, s, '}');
+
+  if (!s) return 0;
+
+  // p->cursor was set by findEndOfBlock
+  p->this->kind = KIND_NO_WIKI_BLOCK;
+  p->this->end = s;
+  return 1;
 }
 
 //}}}
 static int isParaBreak(Parser *p){//{{{
 
-	char *s = cr_nextLine(p, p->cursor);
-	if (!p->lineWasBlank) return 0;
-
-	p->cursor = s;
-	p->this->kind = KIND_PARA_BREAK;
-	return 1;
+  char *s = cr_nextLine(p, p->cursor);
+  if (!p->lineWasBlank) return 0;
+
+  p->cursor = s;
+  p->this->kind = KIND_PARA_BREAK;
+  return 1;
 }
 //}}}
 static int isHeading(Parser *p){//{{{
 
-	char *s = cr_skipBlanks(p, p->cursor);
-
-	int flags = 0;
-	int level = cr_countChars(p, s, '=');
-	if (!level) return 0;
-
-	s += level;
-
-	if (s[0] == '<' && s[1] == '>') {
-		flags |= FLAG_CENTER;
-		s += 2;
-	}
-	s = cr_skipBlanks(p, s);
-
-	p->this->start = s;
-
-	s = cr_nextLine(p, s);
-	char *z = s;
-
-	if (s[-1] == '\n') s--;
-	while(s[-1] == ' ' || s[-1]=='\t') s--;
-	while(s[-1] == '=' ) s--;
-	if (p->this->start < s){
-		p->cursor = z;
-		p->this->kind = KIND_HEADING;
-		p->this->end = s;
-		p->this->level = level;
-		p->this->flags |= flags;
-		return 1;
-	}
-	return 0;
+  char *s = cr_skipBlanks(p, p->cursor);
+
+  int flags = 0;
+  int level = cr_countChars(p, s, '=');
+  if (!level) return 0;
+
+  s += level;
+
+  if (s[0] == '<' && s[1] == '>') {
+    flags |= FLAG_CENTER;
+    s += 2;
+  }
+  s = cr_skipBlanks(p, s);
+
+  p->this->start = s;
+
+  s = cr_nextLine(p, s);
+  char *z = s;
+
+  if (s[-1] == '\n') s--;
+  while(s[-1] == ' ' || s[-1]=='\t') s--;
+  while(s[-1] == '=' ) s--;
+  if (p->this->start < s){
+    p->cursor = z;
+    p->this->kind = KIND_HEADING;
+    p->this->end = s;
+    p->this->level = level;
+    p->this->flags |= flags;
+    return 1;
+  }
+  return 0;
 }
 //}}}
 static int isHorizontalRule(Parser *p){//{{{
 
-	char *s = cr_skipBlanks(p, p->cursor);
-
-	int level = cr_countChars(p, s, '-');
-
-	if  (level < 4) return 0;
-	s = cr_nextLine(p, s + level);
-	if (!p->lineWasBlank) return 0;
-
-	p->cursor = s;
-	p->this->kind = KIND_HORIZONTAL_RULE;
-
-	return 1;
+  char *s = cr_skipBlanks(p, p->cursor);
+
+  int level = cr_countChars(p, s, '-');
+
+  if  (level < 4) return 0;
+  s = cr_nextLine(p, s + level);
+  if (!p->lineWasBlank) return 0;
+
+  p->cursor = s;
+  p->this->kind = KIND_HORIZONTAL_RULE;
+
+  return 1;
 }
 //}}}
 static int isListItem(Parser *p){//{{{
 
-	char *s = cr_skipBlanks(p, p->cursor);
-
-	int level = cr_countChars(p, s, '#');
-	if (!level) level = cr_countChars(p, s, '*');
-
-	if ( !level) return 0;
-
-	p->this->kind = (s[0] == '#') ? KIND_ORDERED_LIST : KIND_UNORDERED_LIST;
-	p->this->level = level;
-
-	s = cr_skipBlanks(p, s + level);
-	p->this->start = s;
-
-	s = cr_nextLine(p, s);
-	if (p->lineWasBlank) return 0;
-
-	if (cr_addListItem(p, p->this)){
-		p->cursor = p->this->end = s;
-		return 1;
-	}
-	p->this->kind = 0;
-	return 0;
+  char *s = cr_skipBlanks(p, p->cursor);
+
+  int level = cr_countChars(p, s, '#');
+  if (!level) level = cr_countChars(p, s, '*');
+
+  if ( !level) return 0;
+
+  p->this->kind = (s[0] == '#') ? KIND_ORDERED_LIST : KIND_UNORDERED_LIST;
+  p->this->level = level;
+
+  s = cr_skipBlanks(p, s + level);
+  p->this->start = s;
+
+  s = cr_nextLine(p, s);
+  if (p->lineWasBlank) return 0;
+
+  if (cr_addListItem(p, p->this)){
+    p->cursor = p->this->end = s;
+    return 1;
+  }
+  p->this->kind = 0;
+  return 0;
 }
 //}}}
 static int isTable(Parser *p){//{{{
 
-	p->this->start = p->cursor;
-	char *s = cr_skipBlanks(p, p->cursor);
-	if (s[0] != '|') return 0;
+  p->this->start = p->cursor;
+  char *s = cr_skipBlanks(p, p->cursor);
+  if (s[0] != '|') return 0;
   s +=1;
-	p->this->kind = KIND_TABLE;
-
-
-	//p->cursor = 	p->this->end = cr_nextLine(p, s);
-	Node *row;
-	Node *tail = NULL;
-
-	while (1) {
-
-		row = pool_new(p);
-		row->kind = KIND_TABLE_ROW;
-
-		if (tail) 	tail = tail->next = row;
-		else p->this->children = tail = row;
-
-		row->start = s;
-		p->cursor = s = 	row->end = p->this->end = cr_nextLine(p, s);
-
-		if (row->end[-1] == '\n') row->end -= 1;
-		while(row->end[-1] == ' ' ) row->end -= 1;
-		if (row->end[-1] == '|') row->end -= 1;
-
-		if (!*s) break;
-
-		// blanks *not* normalized
-		s = cr_skipBlanks(p, p->cursor);
-		if (s[0] != '|') break;
-		s++;
-
-	}
-	return 1;
+  p->this->kind = KIND_TABLE;
+
+
+  //p->cursor =   p->this->end = cr_nextLine(p, s);
+  Node *row;
+  Node *tail = NULL;
+
+  while (1) {
+
+    row = pool_new(p);
+    row->kind = KIND_TABLE_ROW;
+
+    if (tail)   tail = tail->next = row;
+    else p->this->children = tail = row;
+
+    row->start = s;
+    p->cursor = s =   row->end = p->this->end = cr_nextLine(p, s);
+
+    if (row->end[-1] == '\n') row->end -= 1;
+    while(row->end[-1] == ' ' ) row->end -= 1;
+    if (row->end[-1] == '|') row->end -= 1;
+
+    if (!*s) break;
+
+    // blanks *not* normalized
+    s = cr_skipBlanks(p, p->cursor);
+    if (s[0] != '|') break;
+    s++;
+
+  }
+  return 1;
 
 };
 //}}}
 static int isParagraph(Parser *p){//{{{
 
-	char *s = p->cursor;
-	p->this->start = s;
-
-	s = cr_nextLine(p, s);
-	p->cursor = p->this->end = s;
-	p->this->kind = KIND_PARAGRAPH;
-	return 1;
+  char *s = p->cursor;
+  p->this->start = s;
+
+  s = cr_nextLine(p, s);
+  p->cursor = p->this->end = s;
+  p->this->kind = KIND_PARAGRAPH;
+  return 1;
 
 }
 //}}}
 static void cr_parse(Parser *p, char* z){//{{{
 
-	p->previous = pool_new(p);
-	p->previous->kind = KIND_PARA_BREAK;
-
-	p->this = pool_new(p);
-	p->this->kind = KIND_PARA_BREAK;
-
-	p->inLink = 0;
-	p->inTable = 0;
-
-	p->cursor = z;
-	p->list = NULL;
-	p->istack = NULL;
-
-	while (p->cursor[0]) {
-
-		while (1){
-
-			// must be first
-			if (isNoWikiBlock(p)) break;
-			if (isParaBreak(p)) 	break;
-
-			// order not important
-			if (isHeading(p)) break;
-			if (isHorizontalRule(p)) break;
-			if (isListItem(p)) break;
-			if (isTable(p)) break;
-
-			// here for efficiency?
-			if (isEndWikiMarker(p)) break;
-
-			// must be last
-			if (isParagraph(p)); break;
+  p->previous = pool_new(p);
+  p->previous->kind = KIND_PARA_BREAK;
+
+  p->this = pool_new(p);
+  p->this->kind = KIND_PARA_BREAK;
+
+  p->inLink = 0;
+  p->inTable = 0;
+
+  p->cursor = z;
+  p->list = NULL;
+  p->istack = NULL;
+
+  while (p->cursor[0]) {
+
+    while (1){
+
+      // must be first
+      if (isNoWikiBlock(p)) break;
+      if (isParaBreak(p))   break;
+
+      // order not important
+      if (isHeading(p)) break;
+      if (isHorizontalRule(p)) break;
+      if (isListItem(p)) break;
+      if (isTable(p)) break;
+
+      // here for efficiency?
+      if (isEndWikiMarker(p)) break;
+
+      // must be last
+      if (isParagraph(p)); break;
+
+      // doh!
+      assert(0);
+    }
+
+    int kind = p->this->kind;
+    int prev = p->previous->kind;
+
+    if (kind & KIND_END_WIKI_MARKER)  return;
+
+    if (kind == KIND_PARAGRAPH && prev & KIND_LIST_OR_PARAGRAPH) {
+        p->previous->end = p->this->end;
+        p->this = pool_new(p);
+        continue;
+    }
+
+    if ( !(kind & KIND_LIST && prev & KIND_LIST) )
+      cr_render(p, p->previous);
+
+    p->previous = p->this;
+    p->this = pool_new(p);
 
-			// doh!
-		  assert(0);
-		}
-
-		int kind = p->this->kind;
-		int prev = p->previous->kind;
-
-		if (kind & KIND_END_WIKI_MARKER)	return;
-
-		if (kind == KIND_PARAGRAPH && prev & KIND_LIST_OR_PARAGRAPH) {
-				p->previous->end = p->this->end;
-				p->this = pool_new(p);
-				continue;
-		}
-
-		if ( !(kind & KIND_LIST && prev & KIND_LIST) )
-			cr_render(p, p->previous);
-
-		p->previous = p->this;
-		p->this = pool_new(p);
-
-	}
+  }
 }
 //}}}
 
 //}}}
 
-char *wiki_render_creole(Renderer *r, char *z){//{{{
+char *wiki_render_creole(Renderer *r, char *z){
 
   Parser parser;
-	Parser *p = &parser;
+  Parser *p = &parser;
+
+  p->r = r;
+  p->iblob = r->pOut;
+
+  p->nFree = 0;
+  p->pool = NULL;
 
-	p->r = r;
-	p->iblob = r->pOut;
+  cr_parse(p, z);
 
-	p->nFree = 0;
-	p->pool = NULL;
+  cr_render(p, p->previous);
 
-	cr_parse(p, z);
+  pool_free(p);
 
-	cr_render(p, p->previous);
-
-	pool_free(p);
-
-	return p->cursor;
+  return p->cursor;
 
 }
-//}}}
-
-
-char *wiki_render_macro(Renderer *p, char *z, int *tokenType){
-	if (!memcmp(z, "<<fossil>>", 9)){
-		*tokenType = 1;
-		return z + 10;
-	}
-	if (memcmp(z, "<<creole>>", 9)) {
-		*tokenType = 0;
-		return z;
-	}
-	*tokenType = 1;
-	return wiki_render_creole(p, z+10);
-
-}
-
-/* :folding=explicit:collapseFolds=1:tabSize=2:indentSize=2:noTabs=false: */
+

Modified src/doc.c from [a9193f6c29] to [cb0906ed17].

@@ -316,10 +316,11 @@
 }
 
 /*
 ** WEBPAGE: doc
 ** URL: /doc?name=BASELINE/PATH
+** URL: /doc/BASELINE/PATH
 **
 ** BASELINE can be either a baseline uuid prefix or magic words "tip"
 ** to me the most recently checked in baseline or "ckout" to mean the
 ** content of the local checkout, if any.  PATH is the relative pathname
 ** of some file.  This method returns the file content.
@@ -438,11 +439,14 @@
   }
 
   /* The file is now contained in the filebody blob.  Deliver the
   ** file to the user
   */
-  zMime = mimetype_from_name(zName);
+  zMime = P("mimetype");
+  if( zMime==0 ){
+    zMime = mimetype_from_name(zName);
+  }
   if( strcmp(zMime, "application/x-fossil-wiki")==0 ){
     Blob title, tail;
     if( wiki_find_title(&filebody, &title, &tail) ){
       style_header(blob_str(&title));
       wiki_convert(&tail, 0, 0);
@@ -468,6 +472,95 @@
   db_end_transaction(0);
   style_header("Document Not Found");
   @ <p>No such document: %h(PD("name","tip/index.wiki"))</p>
   style_footer();
   return;
+}
+
+/*
+** The default logo.
+*/
+static const unsigned char aLogo[] = {
+    71,  73,  70,  56,  55,  97,  62,   0,  71,   0, 244,   0,   0,  85,
+   129, 149,  95, 136, 155,  99, 139, 157, 106, 144, 162, 113, 150, 166,
+   116, 152, 168, 127, 160, 175, 138, 168, 182, 148, 176, 188, 159, 184,
+   195, 170, 192, 202, 180, 199, 208, 184, 202, 210, 191, 207, 215, 201,
+   215, 221, 212, 223, 228, 223, 231, 235, 226, 227, 226, 226, 234, 237,
+   233, 239, 241, 240, 244, 246, 244, 247, 248, 255, 255, 255,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  44,   0,   0,
+     0,   0,  62,   0,  71,   0,   0,   5, 255,  96, 100, 141, 100, 105,
+   158, 168,  37,  41, 132, 192, 164, 112,  44, 207, 102,  99,   0,  56,
+    16,  84, 116, 239, 199, 141,  65, 110, 232, 248,  25, 141, 193, 161,
+    82, 113, 108, 202,  32,  55, 229, 210,  73,  61,  41, 164,  88, 102,
+   181,  10,  41,  96, 179,  91, 106,  35, 240,   5, 135, 143, 137, 242,
+    87, 123, 246,  33, 190,  81, 108, 163, 237, 198,  14,  30, 113, 233,
+   131,  78, 115,  72,  11, 115,  87, 101,  19, 124,  51,  66,  74,   8,
+    19,  16,  67, 100,  74, 133,  50,  15, 101, 135,  56,  11,  74,   6,
+   143,  49, 126, 106,  56,   8, 145,  67,   9, 152,  48, 139, 155,   5,
+    22,  13,  74, 115, 161,  41, 147, 101,  13, 130,  57, 132, 170,  40,
+   167, 155,   0,  94,  57,   3, 178,  48, 183, 181,  57, 160, 186,  40,
+    19, 141, 189,   0,  69, 192,  40,  16, 195, 155, 185, 199,  41, 201,
+   189, 191, 205, 193, 188, 131, 210,  49, 175,  88, 209, 214,  38,  19,
+     3,  11,  19, 111, 127,  60, 219,  39,  55, 204,  19,  11,   6, 100,
+     5,  10, 227, 228,  37, 163,   0, 239, 117,  56, 238, 243,  49, 195,
+   177, 247,  48, 158,  56, 251,  50, 216, 254, 197,  56, 128, 107, 158,
+     2, 125, 171, 114,  92, 218, 246,  96,  66,   3,   4,  50, 134, 176,
+   145,   6,  97,  64, 144,  24,  19, 136, 108,  91, 177, 160,   0, 194,
+    19, 253,   0, 216, 107, 214, 224, 192, 129,   5,  16,  83, 255, 244,
+    43, 213, 195,  24, 159,  27, 169,  64, 230,  88, 208, 227, 129, 182,
+    54,   4,  89, 158,  24, 181, 163, 199,   1, 155,  52, 233,   8, 130,
+   176,  83,  24, 128, 137,  50,  18,  32,  48,  48, 114,  11, 173, 137,
+    19, 110,   4,  64, 105,   1, 194,  30, 140,  68,  15,  24,  24, 224,
+    50,  76,  70,   0,  11, 171,  54,  26, 160, 181, 194, 149, 148,  40,
+   174, 148, 122,  64, 180, 208, 161,  17, 207, 112, 164,   1, 128,  96,
+   148,  78,  18,  21, 194,  33, 229,  51, 247,  65, 133,  97,   5, 250,
+    69, 229, 100,  34, 220, 128, 166, 116, 190,  62,   8, 167, 195, 170,
+    47, 163,   0, 130,  90, 152,  11, 160, 173, 170,  27, 154,  26,  91,
+   232, 151, 171,  18,  14, 162, 253,  98, 170,  18,  70, 171,  64, 219,
+    10,  67, 136, 134, 187, 116,  75, 180,  46, 179, 174, 135,   4, 189,
+   229, 231,  78,  40,  10,  62, 226, 164, 172,  64, 240, 167, 170,  10,
+    18, 124, 188,  10, 107,  65, 193,  94,  11,  93, 171,  28, 248,  17,
+   239,  46, 140,  78,  97,  34,  25, 153,  36,  99,  65, 130,   7, 203,
+   183, 168,  51,  34, 136,  25, 140,  10,   6,  16,  28, 255, 145, 241,
+   230, 140,  10,  66, 178, 167, 112,  48, 192, 128, 129,   9,  31, 141,
+    84, 138,  63, 163, 162,   2, 203, 206, 240,  56,  55,  98, 192, 188,
+    15, 185,  50, 160,   6,   0, 125,  62,  33, 214, 195,  33,   5,  24,
+   184,  25, 231,  14, 201, 245, 144,  23, 126, 104, 228,   0, 145,   2,
+    13, 140, 244, 212,  17,  21,  20, 176, 159,  17,  95, 225, 160, 128,
+    16,   1,  32, 224, 142,  32, 227, 125,  87,  64,   0,  16,  54, 129,
+   205,   2, 141,  76,  53, 130, 103,  37, 166,  64, 144, 107,  78, 196,
+     5, 192,   0,  54,  50, 229,   9, 141,  49,  84, 194,  35,  12, 196,
+   153,  48, 192, 137,  57,  84,  24,   7,  87, 159, 249, 240, 215, 143,
+   105, 241, 118, 149,   9, 139,   4,  64, 203, 141,  35, 140, 129, 131,
+    16, 222, 125, 231, 128,   2, 238,  17, 152,  66,   3,   5,  56, 224,
+   159, 103,  16,  76,  25,  75,   5,  11, 164, 215,  96,   9,  14,  16,
+    36, 225,  15,  11,  40, 144, 192, 156,  41,  10, 178, 199,   3,  66,
+    64,  80, 193,   3, 124,  90,  48, 129, 129, 102, 177,  18, 192, 154,
+    49,  84, 240, 208,  92,  22, 149,  96,  39,   9,  31,  74,  17,  94,
+     3,   8, 177, 199,  72,  59,  85,  76,  25, 216,   8, 139, 194, 197,
+   138, 163,  69,  96, 115,   0, 147,  72,  72,  84,  28,  14,  79,  86,
+   233, 230,  23, 113,  26, 160, 128,   3,  10,  58, 129, 103,  14, 159,
+   214, 163, 146, 117, 238, 213, 154, 128, 151, 109,  84,  64, 217,  13,
+    27,  10, 228,  39,   2, 235, 164, 168,  74,   8,   0,  59,
+};
+
+/*
+** WEBPAGE: logo
+**
+** Return the logo image.  This image is available to anybody who can see
+** the login page.  It is designed for use in the upper left-hand corner
+** of the header.
+*/
+void logo_page(void){
+  Blob logo;
+  char *zMime;
+
+  zMime = db_get("logo-mimetype", "image/gif");
+  blob_zero(&logo);
+  db_blob(&logo, "SELECT value FROM config WHERE name='logo-image'");
+  if( blob_size(&logo)==0 ){
+    blob_init(&logo, (char*)aLogo, sizeof(aLogo));
+  }
+  cgi_set_content_type(zMime);
+  cgi_set_content(&logo);
 }

Modified src/login.c from [24e3ed3b13] to [3b52c138db].

@@ -218,13 +218,13 @@
   }
   @ <table align="left" hspace="10">
   @ <tr>
   @   <td align="right">User ID:</td>
   if( anonFlag ){
-    @   <td><input type="text" name="u" value="anonymous" size=30></td>
+    @   <td><input type="text" id="u" name="u" value="anonymous" size=30></td>
   }else{
-    @   <td><input type="text" name="u" value="" size=30></td>
+    @   <td><input type="text" id="u" name="u" value="" size=30></td>
   }
   @ </tr>
   @ <tr>
   @  <td align="right">Password:</td>
   @   <td><input type="password" name="p" value="" size=30></td>
@@ -237,10 +237,11 @@
   @ <tr>
   @   <td></td>
   @   <td><input type="submit" name="in" value="Login"></td>
   @ </tr>
   @ </table>
+  @ <script>document.getElementById('u').focus()</script>
   if( g.zLogin==0 ){
     @ <p>Enter
   }else{
     @ <p>You are currently logged in as <b>%h(g.zLogin)</b></p>
     @ <p>To change your login to a different user, enter

Modified src/manifest.c from [5e32c12dce] to [daaac5b065].

@@ -952,11 +952,11 @@
       if( strcmp(pManifest->aField[i].zName, zStatusColumn)==0 ){
         zNewStatus = pManifest->aField[i].zValue;
       }
     }
     if( zNewStatus ){
-      blob_appendf(&comment, "%h ticket [%.10s]: <i>%h</i>",
+      blob_appendf(&comment, "%h ticket [%.10s]: <i>%s</i>",
          zNewStatus, pManifest->zTicketUuid, zTitle
       );
       if( pManifest->nField>1 ){
         blob_appendf(&comment, " plus %d other change%s",
           pManifest->nField-1, pManifest->nField==2 ? "" : "s");
@@ -966,11 +966,11 @@
     }else{
       zNewStatus = db_text("unknown",
          "SELECT %s FROM ticket WHERE tkt_uuid='%s'",
          zStatusColumn, pManifest->zTicketUuid
       );
-      blob_appendf(&comment, "Ticket [%.10s] <i>%h</i> status still %h with "
+      blob_appendf(&comment, "Ticket [%.10s] <i>%s</i> status still %h with "
            "%d other change%s",
            pManifest->zTicketUuid, zTitle, zNewStatus, pManifest->nField,
            pManifest->nField==1 ? "" : "s"
       );
       free(zNewStatus);

Modified src/setup.c from [ddfa4b243d] to [95f147ca17].

@@ -76,10 +76,12 @@
     "Edit the Cascading Style Sheet used by all pages of this repository");
   setup_menu_entry("Header", "setup_header",
     "Edit HTML text inserted at the top of every page");
   setup_menu_entry("Footer", "setup_footer",
     "Edit HTML text inserted at the bottom of every page");
+  setup_menu_entry("Logo", "setup_logo",
+    "Change the logo image for the server");
   setup_menu_entry("Shunned", "shun",
     "Show artifacts that are shunned by this repository");
   setup_menu_entry("Log", "rcvfromlist",
     "A record of received artifacts and their sources");
   setup_menu_entry("Stats", "stat",
@@ -1012,8 +1014,64 @@
   @ <hr>
   @ Here is the default page footer:
   @ <blockquote><pre>
   @ %h(zDefaultFooter)
   @ </pre></blockquote>
+  style_footer();
+  db_end_transaction(0);
+}
+
+/*
+** WEBPAGE: setup_logo
+*/
+void setup_logo(void){
+  const char *zMime = "image/gif";
+  const char *aImg = P("im");
+  int szImg = atoi(PD("im:bytes","0"));
+  if( szImg>0 ){
+    zMime = PD("im:mimetype","image/gif");
+  }
+  login_check_credentials();
+  if( !g.okSetup ){
+    login_needed();
+  }
+  db_begin_transaction();
+  if( P("set")!=0 && zMime && zMime[0] && szImg>0 ){
+    Blob img;
+    Stmt ins;
+    blob_init(&img, aImg, szImg);
+    db_prepare(&ins,
+        "REPLACE INTO config(name, value)"
+        " VALUES('logo-image',:bytes)"
+    );
+    db_bind_blob(&ins, ":bytes", &img);
+    db_step(&ins);
+    db_finalize(&ins);
+    db_multi_exec(
+       "REPLACE INTO config(name, value) VALUES('logo-mimetype',%Q)",
+       zMime
+    );
+  }else if( P("clr")!=0 ){
+    db_multi_exec(
+       "DELETE FROM config WHERE name GLOB 'logo-*'"
+    );
+  }
+  style_header("Edit Project Logo");
+  @ <p>The current project logo has a MIME-Type of <b>%h(zMime)</b> and looks
+  @ like this:</p>
+  @ <blockquote><img src="%s(g.zTop)/logo" alt="logo"></blockquote>
+  @
+  @ <form action="%s(g.zBaseURL)/setup_logo" method="POST"
+  @  enctype="multipart/form-data">
+  @ <p>The logo is accessible to all users at this URL:
+  @ <a href="%s(g.zBaseURL)/logo">%s(g.zBaseURL)/logo</a>.
+  @ To set a new logo image, select a file to use as the logo using
+  @ the entry box below and then press the "Change Logo" button.</p>
+  login_insert_csrf_secret();
+  @ Logo Image file:
+  @ <input type="file" name="im" size="60" accepts="image/*"><br>
+  @ <input type="submit" name="set" value="Change Logo">
+  @ <input type="submit" name="clr" value="Revert To Default">
+  @ </form>
   style_footer();
   db_end_transaction(0);
 }

Modified src/style.c from [64c82161ee] to [6ac00aef9b].

@@ -143,11 +143,11 @@
   @ <div class="content">
   cgi_destination(CGI_BODY);
 
   /* Put the footer at the bottom of the page.
   */
-  @ </div>
+  @ </div><br clear="both"></br>
   zFooter = db_get("footer", (char*)zDefaultFooter);
   if( g.thTrace ) Th_Trace("BEGIN_FOOTER<br />\n", -1);
   Th_Render(zFooter);
   if( g.thTrace ) Th_Trace("END_FOOTER<br />\n", -1);
 
@@ -191,12 +191,12 @@
 @       media="screen">
 @ </head>
 @ <body>
 @ <div class="header">
 @   <div class="logo">
-@     <!-- <img src="logo.gif" alt="logo"><br></br> -->
-@     <nobr>$<project_name></nobr>
+@     <img src="/logo" alt="logo">
+@     <br><nobr>$<project_name></nobr>
 @   </div>
 @   <div class="title">$<title></div>
 @   <div class="status"><nobr><th1>
 @      if {[info exists login]} {
 @        puts "Logged in as $login"
@@ -269,11 +269,12 @@
 @ /* The page title centered at the top of each page */
 @ div.title {
 @   display: table-cell;
 @   font-size: 2em;
 @   font-weight: bold;
-@   text-align: center;
+@   text-align: left;
+@   padding: 0 0 0 1em;
 @   color: #558195;
 @   vertical-align: bottom;
 @   width: 100%;
 @ }
 @
@@ -392,32 +393,11 @@
 @
 @ div.miniform {
 @     font-size: smaller;
 @     margin: 8px;
 @ }
-@ table.fossil_db_generic_query_view {
-@   border-spacing: 0px;
-@   border: 1px solid black;
-@ }
-@ table.fossil_db_generic_query_view td {
-@   padding: 2px 1em 2px 1em;
-@ }
-@ table.fossil_db_generic_query_view tr {
-@ }
-@ table.fossil_db_generic_query_view tr.even {
-@   background: #ffffff;
-@ }
-@ table.fossil_db_generic_query_view tr.odd {
-@   background: #e5e5e5;
-@ }
-@ table.fossil_db_generic_query_view tr.header {
-@   background: #558195;
-@   font-size: 1.5em;
-@   color: #ffffff;
-@ }
-@
-@ /* addeitions to support creole parser */
+@ /* additions to support creole parser */
 @
 @ .creoletable {
 @   border: 1px solid #666666;
 @   border-spacing: 0;
 @   margin: 1.5em 2em 1.8em 2em;
@@ -435,10 +415,24 @@
 @   padding: .4em .7em .45em .7em;
 @   border-left: 1px solid #D9D9D9;
 @   border-top: 1px solid #D9D9D9;
 @   vertical-align: center;
 @   empty-cells: show;
+@ }
+@ .creole-nowiki {
+@   background: oldlace;
+@ }
+@ .creole-inline-nowiki {
+@   background: oldlace;
+@ }
+@ .creole-image {
+@   color:green;
+@   border:1px solid green;
+@ }
+@ .creole-nomacro {
+@   color:red;
+@   border:1px solid red;
 @ }
 ;
 
 /*
 ** WEBPAGE: style.css

Modified src/tktsetup.c from [831f07a38a] to [57c97126a8].

@@ -363,11 +363,11 @@
 @ <tr><td align="right">Ticket&nbsp;UUID:</td><td bgcolor="#d0d0d0" colspan="3">
 @ $<tkt_uuid>
 @ </td></tr>
 @ <tr><td align="right">Title:</td>
 @ <td bgcolor="#d0d0d0" colspan="3" valign="top">
-@ $<title>
+@ <th1>wiki $title</th1>
 @ </td></tr>
 @ <tr><td align="right">Status:</td><td bgcolor="#d0d0d0">
 @ $<status>
 @ </td>
 @ <td align="right">Type:</td><td bgcolor="#d0d0d0">

Modified src/url.c from [c5cf8d9b2a] to [118ae7487c].

@@ -65,12 +65,14 @@
     }
     for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!='@'; i++){}
     if( c=='@' ){
       for(j=iStart; j<i && zUrl[j]!=':'; j++){}
       g.urlUser = mprintf("%.*s", j-iStart, &zUrl[iStart]);
+      dehttpize(g.urlUser);
       if( j<i ){
         g.urlPasswd = mprintf("%.*s", i-j-1, &zUrl[j+1]);
+        dehttpize(g.urlPasswd);
       }
       for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){}
       g.urlName = mprintf("%.*s", j-i-1, &zUrl[i+1]);
       i = j;
     }else{

Modified src/wikiformat.c from [3654a443f2] to [c4abfd0c8e].

@@ -1022,11 +1022,10 @@
 static int stackTopType(Renderer *p){
   if( p->nStack<=0 ) return 0;
   return aMarkup[p->aStack[p->nStack-1].iCode].iType;
 }
 
-
 /*
 ** Convert the wiki in z[] into html in the renderer p.  The
 ** renderer has already been initialized.
 **
 ** This routine will probably modify the content of z[].
@@ -1038,24 +1037,22 @@
   int inlineOnly = (p->state & INLINE_MARKUP_ONLY)!=0;
 
   while( z[0] ){
 
      /*
-     ** Additions to support creole parser
+     ** Additions to support macro extensions
      */
 
     if (!p->inVerbatim && z[0]=='<' && z[1] == '<') {
       z = wiki_render_macro(p, z, &tokenType);
       if (tokenType) continue;
     }
-    //
+    /* end additions */
 
     n = nextToken(z, p, &tokenType);
     p->state &= ~(AT_NEWLINE|AT_PARAGRAPH);
-
-    switch( tokenType ){
-
+    switch( tokenType ){
       case TOKEN_PARAGRAPH: {
         if( inlineOnly ){
           /* blob_append(p->pOut, " &para; ", -1); */
           blob_append(p->pOut, " &nbsp;&nbsp; ", -1);
         }else{
@@ -1227,22 +1224,22 @@
         */
         if( (markup.iType&MUTYPE_FONT)==0 && (p->state & FONT_MARKUP_ONLY)!=0 ){
           /* Do nothing */
         }else
 
-        /* Ignore block markup for in-line rendering.
-        */
-        if( inlineOnly && (markup.iType&MUTYPE_INLINE)==0 ){
-          /* Do nothing */
-        }else
-
         if( markup.iCode==MARKUP_NOWIKI ){
           if( markup.endTag ){
             p->state |= ALLOW_WIKI;
           }else{
             p->state &= ~ALLOW_WIKI;
           }
+        }else
+
+        /* Ignore block markup for in-line rendering.
+        */
+        if( inlineOnly && (markup.iType&MUTYPE_INLINE)==0 ){
+          /* Do nothing */
         }else
 
         /* Generate end-tags */
         if( markup.endTag ){
           popStackToTag(p, markup.iCode);
@@ -1355,11 +1352,10 @@
   }
   blob_append(renderer.pOut, "\n", 1);
   free(renderer.aStack);
 }
 
-
 /*
 ** COMMAND: test-wiki-render
 */
 void test_wiki_render(void){
   Blob in, out;
@@ -1394,21 +1390,35 @@
   blob_init(pTitle, &z[iStart], i-iStart);
   blob_init(pTail, &z[i+8], -1);
   return 1;
 }
 
-
 /*
-** Additions to support creole parser
+** Additions to support macro extensions
+**
+** This only allows block level macros, not inline macros
+**
+** All macros must recognize '<<fossil>>' in the input
+** stream and return control to fossil.
 */
 
-#ifndef HAVE_MACRO_EXTENSIONS
-char *wiki_render_macro(Renderer *p, char *z, int *tokenType) {
+char *wiki_render_macro(Renderer *p, char *z, int *tokenType){
+  if (!memcmp(z, "<<fossil>>", 10)){
+    *tokenType = 1;
+    return z + 10;
+  }
+
+#ifdef HAVE_CREOLE_MACRO
+  if (!memcmp(z, "<<creole>>", 10)) {
+    *tokenType = 1;
+    return wiki_render_creole(p, z+10);
+  }
+#endif
+
   *tokenType = 0;
   return z;
 }
-#endif
 
 int wf_linkLength(const char *z){
   return linkLength(z);
 }
 void wf_openHyperlink(
@@ -1417,7 +1427,6 @@
   char *zClose,           /* Write hyperlink closing text here */
   int nClose              /* Bytes available in zClose[] */
 ){
   return openHyperlink(p, zTarget, zClose, nClose);
 }
-
-
+/* end additions */

Modified src/xfer.c from [0008bf7842] to [2973354cfc].

@@ -383,17 +383,19 @@
 ** http_exchange() routine.
 */
 void check_login(Blob *pLogin, Blob *pNonce, Blob *pSig){
   Stmt q;
   int rc = -1;
+  char *zLogin = blob_terminate(pLogin);
+  defossilize(zLogin);
 
   db_prepare(&q,
      "SELECT pw, cap, uid FROM user"
-     " WHERE login=%B"
+     " WHERE login=%Q"
      "   AND login NOT IN ('anonymous','nobody','developer','reader')"
      "   AND length(pw)>0",
-     pLogin
+     zLogin
   );
   if( db_step(&q)==SQLITE_ROW ){
     Blob pw, combined, hash;
     blob_zero(&pw);
     db_ephemeral_blob(&q, 0, &pw);
@@ -521,15 +523,18 @@
 /*
 ** Send a single config card for configuration item zName
 */
 static void send_config_card(Xfer *pXfer, const char *zName){
   if( zName[0]!='@' ){
-    char *zValue = db_get(zName, 0);
-    if( zValue ){
-      blob_appendf(pXfer->pOut, "config %s %d\n%s\n",
-                   zName, strlen(zValue), zValue);
-      free(zValue);
+    Blob val;
+    blob_zero(&val);
+    db_blob(&val, "SELECT value FROM config WHERE name=%Q", zName);
+    if( blob_size(&val)>0 ){
+      blob_appendf(pXfer->pOut, "config %s %d\n", zName, blob_size(&val));
+      blob_append(pXfer->pOut, blob_buffer(&val), blob_size(&val));
+      blob_reset(&val);
+      blob_append(pXfer->pOut, "\n", 1);
     }
   }else{
     Blob content;
     blob_zero(&content);
     configure_render_special_name(zName, &content);
@@ -766,14 +771,25 @@
         @ error not\sauthorized\sto\spush\sconfiguration
         nErr++;
         break;
       }
       if( zName[0]!='@' ){
-        db_multi_exec(
-            "REPLACE INTO config(name,value) VALUES(%Q,%Q)",
-            zName, blob_str(&content)
-        );
+        if( strcmp(zName, "logo-image")==0 ){
+          Stmt ins;
+          db_prepare(&ins,
+            "REPLACE INTO config(name, value) VALUES(:name, :value)"
+          );
+          db_bind_text(&ins, ":name", zName);
+          db_bind_blob(&ins, ":value", &content);
+          db_step(&ins);
+          db_finalize(&ins);
+        }else{
+          db_multi_exec(
+              "REPLACE INTO config(name,value) VALUES(%Q,%Q)",
+              zName, blob_str(&content)
+          );
+        }
       }else{
         /* Notice that we are evaluating arbitrary SQL received from the
         ** client.  But this can only happen if the client has authenticated
         ** as an administrator, so presumably we trust the client at this
         ** point.
@@ -1128,14 +1144,25 @@
         blob_zero(&content);
         blob_extract(xfer.pIn, size, &content);
         g.okAdmin = g.okRdAddr = 1;
         if( configure_is_exportable(zName) & origConfigRcvMask ){
           if( zName[0]!='@' ){
-            db_multi_exec(
-                "REPLACE INTO config(name,value) VALUES(%Q,%Q)",
-                zName, blob_str(&content)
-            );
+            if( strcmp(zName, "logo-image")==0 ){
+              Stmt ins;
+              db_prepare(&ins,
+                "REPLACE INTO config(name, value) VALUES(:name, :value)"
+              );
+              db_bind_text(&ins, ":name", zName);
+              db_bind_blob(&ins, ":value", &content);
+              db_step(&ins);
+              db_finalize(&ins);
+            }else{
+              db_multi_exec(
+                  "REPLACE INTO config(name,value) VALUES(%Q,%Q)",
+                  zName, blob_str(&content)
+              );
+            }
           }else{
             /* Notice that we are evaluating arbitrary SQL received from the
             ** server.  But this can only happen if we have specifically
             ** requested configuration information from the server, so
             ** presumably the operator trusts the server.

Modified www/bugtheory.wiki from [953206fd82] to [b809c20d72].

@@ -113,13 +113,14 @@
 
 Each repository also defines scripts used to generate web pages for
 creating new tickets, viewing existing tickets, and modifying an
 existing ticket.  These scripts consist of HTML with an embedded
 scripts written an a Tcl-like language called "TH1".  Every new fossil
-repository is created with default scripts.  There is currently no
-documentation on the TH1 language.  Administrators wishing to
+repository is created with default scripts.  Paul Ruizendaal has written
+documentation on the TH1 language that is available at
+[http://www.sqliteconcepts.org/THManual.pdf].  Administrators wishing to
 customize their ticket entry, viewing, and editing screens should
 modify the default scripts to suit their needs.  These screen generator
 scripts are part of the local state of a repository and are not shared
 with other repositories during a sync, push, or pull.
 
 <i>To be continued...</i>

Modified www/index.wiki from [5f5f3d2cbf] to [3bb8082d9a].

@@ -21,10 +21,15 @@
 <li> [http://www.fossil-scm.org/download.html | Download]
 <li> [./build.wiki | Install]
 <li> [../COPYRIGHT-GPL2.txt | License]
 <li> [/timeline | Recent changes]
 <li> [./faq.wiki | FAQ]
+<li> Mailing list
+     <ul>
+     <li> [http://lists.fossil-scm.org:8080/cgi-bin/mailman/listinfo/fossil-users | sign-up]
+     <li> [http://www.mail-archive.com/fossil-users@lists.fossil-scm.org | archives]
+     <ul>
 </ul>
 </td></tr>
 <tr><td>
 <center><img src="fossil3.gif"></center>
 </td></tr>
@@ -106,17 +111,21 @@
      to do it using fossil.
   *  The [./selfcheck.wiki | automatic self-check] mechanism
      helps insure project integrity.
   *  Fossil contains a [./wikitheory.wiki | built-in wiki].
   *  There is a
-    [http://lists.fossil-scm.org:8080/cgi-bin/mailman/listinfo/fossil-users | mailing list]
+    [http://lists.fossil-scm.org:8080/cgi-bin/mailman/listinfo/fossil-users | mailing list] (with publically readable
+     [http://www.mail-archive.com/fossil-users@lists.fossil-scm.org | archives]
      available for discussing fossil issues.
   *  [./stats.wiki | Performance statistics] taken from real-world projects
      hosted on fossil.
   *  How to [./shunning.wiki | delete content] from a fossil repository.
   *  Some (unfinished but expanding) extended
       [./reference.wiki | reference documentation] for the fossil command line.
+  *  Documentation on the
+     [http://www.sqliteconcepts.org/THManual.pdf | TH1 Script Language] used
+     to configure the ticketing subsystem.
 
 <h3>Links For Fossil Developer:</h3>
 
   *  [./pop.wiki | Principles Of Operation]
   *  The [./fileformat.wiki | file format] used by every content