Index: src/wikiformat.c
==================================================================
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -7,11 +7,11 @@
 **
 ** This program is distributed in the hope that it will be useful,
 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ** General Public License for more details.
-** 
+**
 ** You should have received a copy of the GNU General Public
 ** License along with this library; if not, write to the
 ** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 ** Boston, MA  02111-1307, USA.
 **
@@ -150,11 +150,11 @@
 /*
 ** Allowed markup.
 **
 ** Except for MARKUP_INVALID, this must all be in alphabetical order
 ** and in numerical sequence.  The first markup type must be zero.
-** The value for MARKUP_XYZ must correspond to the <xyz> entry 
+** The value for MARKUP_XYZ must correspond to the <xyz> entry
 ** in aAllowedMarkup[].
 */
 #define MARKUP_INVALID           0
 #define MARKUP_A                 1
 #define MARKUP_ADDRESS           2
@@ -189,23 +189,24 @@
 #define MARKUP_P                31
 #define MARKUP_PRE              32
 #define MARKUP_S                33
 #define MARKUP_SAMP             34
 #define MARKUP_SMALL            35
-#define MARKUP_STRIKE           36
-#define MARKUP_STRONG           37
-#define MARKUP_SUB              38
-#define MARKUP_SUP              39
-#define MARKUP_TABLE            40
-#define MARKUP_TD               41
-#define MARKUP_TH               42
-#define MARKUP_TR               43
-#define MARKUP_TT               44
-#define MARKUP_U                45
-#define MARKUP_UL               46
-#define MARKUP_VAR              47
-#define MARKUP_VERBATIM         48
+#define MARKUP_SPAN             36
+#define MARKUP_STRIKE           37
+#define MARKUP_STRONG           38
+#define MARKUP_SUB              39
+#define MARKUP_SUP              40
+#define MARKUP_TABLE            41
+#define MARKUP_TD               42
+#define MARKUP_TH               43
+#define MARKUP_TR               44
+#define MARKUP_TT               45
+#define MARKUP_U                46
+#define MARKUP_UL               47
+#define MARKUP_VAR              48
+#define MARKUP_VERBATIM         49
 
 /*
 ** The various markup is divided into the following types:
 */
 #define MUTYPE_SINGLE      0x0001   /* <img>, <br>, or <hr> */
@@ -258,46 +259,47 @@
  { "h2",            MARKUP_H2,           MUTYPE_BLOCK,         AMSK_ALIGN  },
  { "h3",            MARKUP_H3,           MUTYPE_BLOCK,         AMSK_ALIGN  },
  { "h4",            MARKUP_H4,           MUTYPE_BLOCK,         AMSK_ALIGN  },
  { "h5",            MARKUP_H5,           MUTYPE_BLOCK,         AMSK_ALIGN  },
  { "h6",            MARKUP_H6,           MUTYPE_BLOCK,         AMSK_ALIGN  },
- { "hr",            MARKUP_HR,           MUTYPE_SINGLE,        
+ { "hr",            MARKUP_HR,           MUTYPE_SINGLE,
                     AMSK_ALIGN|AMSK_COLOR|AMSK_SIZE|AMSK_WIDTH  },
  { "i",             MARKUP_I,            MUTYPE_FONT,          0  },
- { "img",           MARKUP_IMG,          MUTYPE_SINGLE,        
+ { "img",           MARKUP_IMG,          MUTYPE_SINGLE,
                     AMSK_ALIGN|AMSK_ALT|AMSK_BORDER|AMSK_HEIGHT|
                     AMSK_HSPACE|AMSK_SRC|AMSK_VSPACE|AMSK_WIDTH  },
  { "kbd",           MARKUP_KBD,          MUTYPE_FONT,          0  },
- { "li",            MARKUP_LI,           MUTYPE_LI,            
+ { "li",            MARKUP_LI,           MUTYPE_LI,
                     AMSK_TYPE|AMSK_VALUE  },
  { "nobr",          MARKUP_NOBR,         MUTYPE_FONT,          0  },
  { "nowiki",        MARKUP_NOWIKI,       MUTYPE_SPECIAL,       0  },
- { "ol",            MARKUP_OL,           MUTYPE_LIST,          
+ { "ol",            MARKUP_OL,           MUTYPE_LIST,
                     AMSK_START|AMSK_TYPE|AMSK_COMPACT  },
  { "p",             MARKUP_P,            MUTYPE_BLOCK,         AMSK_ALIGN  },
  { "pre",           MARKUP_PRE,          MUTYPE_BLOCK,         0  },
  { "s",             MARKUP_S,            MUTYPE_FONT,          0  },
  { "samp",          MARKUP_SAMP,         MUTYPE_FONT,          0  },
  { "small",         MARKUP_SMALL,        MUTYPE_FONT,          0  },
+ { "span",          MARKUP_SPAN,         MUTYPE_FONT,          0  },
  { "strike",        MARKUP_STRIKE,       MUTYPE_FONT,          0  },
  { "strong",        MARKUP_STRONG,       MUTYPE_FONT,          0  },
  { "sub",           MARKUP_SUB,          MUTYPE_FONT,          0  },
  { "sup",           MARKUP_SUP,          MUTYPE_FONT,          0  },
- { "table",         MARKUP_TABLE,        MUTYPE_TABLE,         
+ { "table",         MARKUP_TABLE,        MUTYPE_TABLE,
                     AMSK_ALIGN|AMSK_BGCOLOR|AMSK_BORDER|AMSK_CELLPADDING|
                     AMSK_CELLSPACING|AMSK_HSPACE|AMSK_VSPACE  },
- { "td",            MARKUP_TD,           MUTYPE_TD,            
+ { "td",            MARKUP_TD,           MUTYPE_TD,
                     AMSK_ALIGN|AMSK_BGCOLOR|AMSK_COLSPAN|
                     AMSK_ROWSPAN|AMSK_VALIGN  },
  { "th",            MARKUP_TH,           MUTYPE_TD,
                     AMSK_ALIGN|AMSK_BGCOLOR|AMSK_COLSPAN|
                     AMSK_ROWSPAN|AMSK_VALIGN  },
- { "tr",            MARKUP_TR,           MUTYPE_TR, 
+ { "tr",            MARKUP_TR,           MUTYPE_TR,
                     AMSK_ALIGN|AMSK_BGCOLOR||AMSK_VALIGN  },
  { "tt",            MARKUP_TT,           MUTYPE_FONT,          0  },
  { "u",             MARKUP_U,            MUTYPE_FONT,          0  },
- { "ul",            MARKUP_UL,           MUTYPE_LIST,          
+ { "ul",            MARKUP_UL,           MUTYPE_LIST,
                     AMSK_TYPE|AMSK_COMPACT  },
  { "var",           MARKUP_VAR,          MUTYPE_FONT,          0  },
  { "verbatim",      MARKUP_VERBATIM,     MUTYPE_SPECIAL,       AMSK_ID },
 };
 
@@ -332,11 +334,12 @@
 #define TOKEN_PARAGRAPH     4    /* blank lines */
 #define TOKEN_NEWLINE       5    /* A single "\n" */
 #define TOKEN_BULLET        6    /*  "  *  " */
 #define TOKEN_ENUM          7    /*  "  \(?\d+[.)]?  " */
 #define TOKEN_INDENT        8    /*  "   " */
-#define TOKEN_TEXT          9    /* None of the above */
+#define TOKEN_COMMENT       9    /* <!-- --> */
+#define TOKEN_TEXT         10    /* None of the above */
 
 /*
 ** State flags
 */
 #define AT_NEWLINE          0x001  /* At start of a line */
@@ -376,10 +379,28 @@
 ** it is not well-formed markup, return 0.
 */
 static int markupLength(const char *z){
   int n = 1;
   int inparen = 0;
+
+  // is a comment - if valid return n else return 0
+  if( z[n]=='!' ){
+    n++;
+    if (z[n]!='-') return 0;
+    n++;
+    if (z[n]!='-') return 0;
+    n++;
+    while (z[n]){
+      while (z[n] && z[n]!='>') n++;
+      if (!z[n]) return 0;
+      n++;
+      if(n>3 && z[n-3]=='-' && z[n-2]=='-')
+        return (n>7) ? n : 0;
+    }
+    return 0;
+  }
+
   if( z[n]=='/' ){ n++; }
   if( !isalpha(z[n]) ) return 0;
   while( isalnum(z[n]) ){ n++; }
   if( z[n]!='>' && !isspace(z[n]) ) return 0;
   while( z[n] && (z[n]!='>' || inparen) ){
@@ -433,11 +454,11 @@
   while( (c = z[0])!=0 && c!='<' && c!='&' &&
                (useWiki==0 || (c!='[' && c!='\n')) ){
     n++;
     z++;
   }
-  return n; 
+  return n;
 }
 
 /*
 ** Return true if z[] begins with an HTML character element.
 */
@@ -554,13 +575,19 @@
 */
 static int nextToken(const char *z, Renderer *p, int *pTokenType){
   int n;
   if( z[0]=='<' ){
     n = markupLength(z);
-    if( n>0 ){
-      *pTokenType = TOKEN_MARKUP;
-      return n;
+
+    if( n>1 ){
+      if (z[1]=='!'){
+        *pTokenType = TOKEN_COMMENT;
+        return n;
+      } else {
+        *pTokenType = TOKEN_MARKUP;
+        return n;
+      }
     }else{
       *pTokenType = TOKEN_CHARACTER;
       return 1;
     }
   }
@@ -626,11 +653,11 @@
 
 /*
 ** z[] is an HTML markup element - something that begins with '<'.
 ** Parse this element into the p structure.
 **
-** The content of z[] might be modified by converting characters 
+** The content of z[] might be modified by converting characters
 ** to lowercase and by inserting some "\000" characters.
 */
 static void parseMarkup(ParsedMarkup *p, char *z){
   int i, j, c;
   int iACode;
@@ -644,11 +671,11 @@
   }else{
     p->endTag = 0;
     i = 1;
   }
   j = 0;
-  while( isalnum(z[i]) ){ 
+  while( isalnum(z[i]) ){
     if( j<sizeof(zTag)-1 ) zTag[j++] = tolower(z[i]);
     i++;
   }
   zTag[j] = 0;
   p->iCode = findTag(zTag);
@@ -656,11 +683,11 @@
   p->nAttr = 0;
   while( isspace(z[i]) ){ i++; }
   while( p->nAttr<8 && isalpha(z[i]) ){
     int attrOk;    /* True to preserver attribute.  False to ignore it */
     j = 0;
-    while( isalnum(z[i]) ){ 
+    while( isalnum(z[i]) ){
       if( j<sizeof(zTag)-1 ) zTag[j++] = tolower(z[i]);
       i++;
     }
     zTag[j] = 0;
     p->aAttr[p->nAttr].iACode = iACode = findAttr(zTag);
@@ -799,11 +826,11 @@
   }
 }
 
 /*
 ** Attempt to find a find a tag of type iTag with id zId.  Return -1
-** if not found.  If found, return its stack level.  
+** if not found.  If found, return its stack level.
 */
 static int findTagWithId(Renderer *p, int iTag, const char *zId){
   int i;
   assert( zId!=0 );
   for(i=p->nStack-1; i>=0; i--){
@@ -889,11 +916,11 @@
   canonical16(zLower, n+1);
   memcpy(zUpper, zLower, n+1);
   zUpper[n-1]++;
   if( once ){
     const char *zClosedExpr = db_get("ticket-closed-expr", "status='Closed'");
-    db_static_prepare(&q, 
+    db_static_prepare(&q,
       "SELECT %s FROM ticket "
       " WHERE tkt_uuid>=:lwr AND tkt_uuid<:upr",
       zClosedExpr
     );
     once = 0;
@@ -927,13 +954,13 @@
   int nClose              /* Bytes available in zClose[] */
 ){
   const char *zTerm = "</a>";
   assert( nClose>10 );
 
-  if( strncmp(zTarget, "http:", 5)==0 
+  if( strncmp(zTarget, "http:", 5)==0
    || strncmp(zTarget, "https:", 6)==0
-   || strncmp(zTarget, "ftp:", 4)==0 
+   || strncmp(zTarget, "ftp:", 4)==0
    || strncmp(zTarget, "mailto:", 7)==0
   ){
     blob_appendf(p->pOut, "<a href=\"%s\">", zTarget);
   }else if( zTarget[0]=='/' ){
     if( 1 /* g.okHistory */ ){
@@ -1022,10 +1049,19 @@
 
   while( z[0] ){
     n = nextToken(z, p, &tokenType);
     p->state &= ~(AT_NEWLINE|AT_PARAGRAPH);
     switch( tokenType ){
+
+      case TOKEN_COMMENT: {
+        if (p->inVerbatim){
+          blob_append(p->pOut, htmlize(z, n), -1);
+        } else {
+          blob_append(p->pOut, z, n);
+        }
+        break;
+      }
       case TOKEN_PARAGRAPH: {
         if( inlineOnly ){
           /* blob_append(p->pOut, " &para; ", -1); */
           blob_append(p->pOut, " &nbsp;&nbsp; ", -1);
         }else{
@@ -1143,11 +1179,11 @@
         int iDiv;
         parseMarkup(&markup, z);
 
         /* Markup of the form </div id=ID> where there is a matching
         ** ID somewhere on the stack.  Exit the verbatim if were are in
-        ** it.  Pop the stack up to the matching <div>.  Discard the 
+        ** it.  Pop the stack up to the matching <div>.  Discard the
         ** </div>
         */
         if( markup.iCode==MARKUP_DIV && markup.endTag &&
              (zId = markupId(&markup))!=0 &&
              (iDiv = findTagWithId(p, MARKUP_DIV, zId))>=0
@@ -1167,11 +1203,11 @@
           p->nStack--;
         }else
 
         /* If within <verbatim id=ID> ignore everything other than
         ** </verbatim id=ID> and the </dev id=ID2> above.
-        */           
+        */
         if( p->inVerbatim ){
           if( endVerbatim(p, &markup) ){
             p->inVerbatim = 0;
             p->state = p->preVerbState;
             blob_append(p->pOut, "</pre>", 6);
@@ -1225,11 +1261,11 @@
                           (p->state & ALLOW_WIKI)!=0);
         }else
 
         /* Enter <verbatim> processing.  With verbatim enabled, all other
         ** markup other than the corresponding end-tag with the same ID is
-        ** ignored. 
+        ** ignored.
         */
         if( markup.iCode==MARKUP_VERBATIM ){
           if( markup.nAttr==1 ){
             p->zVerbatimId = markup.aAttr[0].zValue;
           }else{
@@ -1298,11 +1334,11 @@
 ** reply.
 */
 void wiki_convert(Blob *pIn, Blob *pOut, int flags){
   char *z;
   Renderer renderer;
-  
+
   memset(&renderer, 0, sizeof(renderer));
   renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH;
   if( flags & WIKI_NOBLOCK ){
     renderer.state |= INLINE_MARKUP_ONLY;
   }