Changes On Branch robert-exp
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Changes In Branch robert-exp Excluding Merge-Ins

This is equivalent to a diff from 767ae79c3d to 47cc9dfec8

2009-05-08
09:52
Initial commit of Creole Wiki Parser extension. check-in: ecd1f09632 user: robert tags: creole
2009-05-07
00:47
Update the built-in SQLite to version 3.6.14. check-in: b4ec5750c6 user: drh tags: trunk
2009-04-27
08:43
Experimental - Pass < !-- --> comments through the wiki unchanged unless inside a < verbatim > block in which case it is htmlized. Also pass < span > tags, treating them as font markup. These changes make it easier to convert existing html pages and specifically allow the inclusion of license text in pages derived from copyright material. Leaf check-in: 47cc9dfec8 user: robert tags: robert-exp, pass-comments
2009-04-24
18:40
There is some bug in the new HTTP transport layer. The easiest solution is to close the TCP connection after each round trip, which is what this check-in does. check-in: 767ae79c3d user: drh tags: trunk
2009-04-13
09:50
Update to version SQLite 3.6.13 check-in: 879e8c5f32 user: drh tags: trunk

Changes to src/wikiformat.c.

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
...
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
...
187
188
189
190
191
192
193

194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
...
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280

281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
...
330
331
332
333
334
335
336

337
338
339
340
341
342
343
344
...
374
375
376
377
378
379
380


















381
382
383
384
385
386
387
...
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
...
552
553
554
555
556
557
558

559




560
561

562
563
564
565
566
567
568
...
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
...
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
...
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
...
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
...
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
....
1020
1021
1022
1023
1024
1025
1026









1027
1028
1029
1030
1031
1032
1033
....
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
....
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
....
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
....
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
** modify it under the terms of the GNU General Public
** License version 2 as published by the Free Software Foundation.
**
** 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.
**
** Author contact information:
**   drh@hwaci.com
................................................................................


/*
** 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 
** in aAllowedMarkup[].
*/
#define MARKUP_INVALID           0
#define MARKUP_A                 1
#define MARKUP_ADDRESS           2
#define MARKUP_B                 3
#define MARKUP_BIG               4
................................................................................
#define MARKUP_NOWIKI           29
#define MARKUP_OL               30
#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

/*
** The various markup is divided into the following types:
*/
#define MUTYPE_SINGLE      0x0001   /* <img>, <br>, or <hr> */
#define MUTYPE_BLOCK       0x0002   /* Forms a new paragraph. ex: <p>, <h2> */
#define MUTYPE_FONT        0x0004   /* Font changes. ex: <b>, <font>, <sub> */
................................................................................
                    AMSK_COLOR|AMSK_FACE|AMSK_SIZE   },
 { "h1",            MARKUP_H1,           MUTYPE_BLOCK,         AMSK_ALIGN  },
 { "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,        
                    AMSK_ALIGN|AMSK_COLOR|AMSK_SIZE|AMSK_WIDTH  },
 { "i",             MARKUP_I,            MUTYPE_FONT,          0  },
 { "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,            
                    AMSK_TYPE|AMSK_VALUE  },
 { "nobr",          MARKUP_NOBR,         MUTYPE_FONT,          0  },
 { "nowiki",        MARKUP_NOWIKI,       MUTYPE_SPECIAL,       0  },
 { "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  },

 { "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,         
                    AMSK_ALIGN|AMSK_BGCOLOR|AMSK_BORDER|AMSK_CELLPADDING|
                    AMSK_CELLSPACING|AMSK_HSPACE|AMSK_VSPACE  },
 { "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, 
                    AMSK_ALIGN|AMSK_BGCOLOR||AMSK_VALIGN  },
 { "tt",            MARKUP_TT,           MUTYPE_FONT,          0  },
 { "u",             MARKUP_U,            MUTYPE_FONT,          0  },
 { "ul",            MARKUP_UL,           MUTYPE_LIST,          
                    AMSK_TYPE|AMSK_COMPACT  },
 { "var",           MARKUP_VAR,          MUTYPE_FONT,          0  },
 { "verbatim",      MARKUP_VERBATIM,     MUTYPE_SPECIAL,       AMSK_ID },
};

/*
** Use binary search to locate a tag in the aMarkup[] table.
................................................................................
#define TOKEN_CHARACTER     2    /* "&" or "<" not part of markup */
#define TOKEN_LINK          3    /* [...] */
#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 */

/*
** State flags
*/
#define AT_NEWLINE          0x001  /* At start of a line */
#define AT_PARAGRAPH        0x002  /* At start of a paragraph */
#define ALLOW_WIKI          0x004  /* Allow wiki markup */
................................................................................
** a valid markup.  If it is, return the total number of characters in
** the markup including the initial "<" and the terminating ">".  If
** it is not well-formed markup, return 0.
*/
static int markupLength(const char *z){
  int n = 1;
  int inparen = 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) ){
    if( z[n]=='"' ){
      inparen = !inparen;
................................................................................
  int n = 0;
  int c;
  while( (c = z[0])!=0 && c!='<' && c!='&' &&
               (useWiki==0 || (c!='[' && c!='\n')) ){
    n++;
    z++;
  }
  return n; 
}

/*
** Return true if z[] begins with an HTML character element.
*/
static int isElement(const char *z){
  int i;
................................................................................
** z points to the start of a token.  Return the number of
** characters in that token.  Write the token type into *pTokenType.
*/
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;

    }else{
      *pTokenType = TOKEN_CHARACTER;
      return 1;
    }
  }
  if( z[0]=='&' && (p->inVerbatim || !isElement(z)) ){
    *pTokenType = TOKEN_CHARACTER;
................................................................................
  } aAttr[10];
};

/*
** 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 
** to lowercase and by inserting some "\000" characters.
*/
static void parseMarkup(ParsedMarkup *p, char *z){
  int i, j, c;
  int iACode;
  char *zValue;
  int seen = 0;
................................................................................
    p->endTag = 1;
    i = 2;
  }else{
    p->endTag = 0;
    i = 1;
  }
  j = 0;
  while( isalnum(z[i]) ){ 
    if( j<sizeof(zTag)-1 ) zTag[j++] = tolower(z[i]);
    i++;
  }
  zTag[j] = 0;
  p->iCode = findTag(zTag);
  p->iType = aMarkup[p->iCode].iType;
  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]) ){ 
      if( j<sizeof(zTag)-1 ) zTag[j++] = tolower(z[i]);
      i++;
    }
    zTag[j] = 0;
    p->aAttr[p->nAttr].iACode = iACode = findAttr(zTag);
    attrOk = iACode!=0 && (seen & aAttribute[iACode].iMask)==0;
    while( isspace(z[i]) ){ z++; }
................................................................................
  while( p->nStack>i ){
    popStack(p);
  }
}

/*
** Attempt to find a find a tag of type iTag with id zId.  Return -1
** 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--){
    if( p->aStack[i].iCode!=iTag ) continue;
    if( p->aStack[i].zId==0 ) continue;
................................................................................
  n = strlen(zTarget);
  memcpy(zLower, zTarget, n+1);
  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, 
      "SELECT %s FROM ticket "
      " WHERE tkt_uuid>=:lwr AND tkt_uuid<:upr",
      zClosedExpr
    );
    once = 0;
  }
  db_bind_text(&q, ":lwr", zLower);
................................................................................
  const char *zTarget,    /* Hyperlink traget; text within [...] */
  char *zClose,           /* Write hyperlink closing text here */
  int nClose              /* Bytes available in zClose[] */
){
  const char *zTerm = "</a>";
  assert( nClose>10 );

  if( strncmp(zTarget, "http:", 5)==0 
   || strncmp(zTarget, "https:", 6)==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 */ ){
      blob_appendf(p->pOut, "<a href=\"%s%h\">", g.zBaseURL, zTarget);
    }else{
................................................................................
  int n;
  int inlineOnly = (p->state & INLINE_MARKUP_ONLY)!=0;

  while( z[0] ){
    n = nextToken(z, p, &tokenType);
    p->state &= ~(AT_NEWLINE|AT_PARAGRAPH);
    switch( tokenType ){









      case TOKEN_PARAGRAPH: {
        if( inlineOnly ){
          /* blob_append(p->pOut, " &para; ", -1); */
          blob_append(p->pOut, " &nbsp;&nbsp; ", -1);
        }else{
          if( p->wikiList ){
            popStackToTag(p, p->wikiList);
................................................................................
      case TOKEN_MARKUP: {
        const char *zId;
        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 
        ** </div>
        */
        if( markup.iCode==MARKUP_DIV && markup.endTag &&
             (zId = markupId(&markup))!=0 &&
             (iDiv = findTagWithId(p, MARKUP_DIV, zId))>=0
        ){
          if( p->inVerbatim ){
................................................................................
          }
          assert( p->nStack==iDiv+1 );
          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);
          }else{
            unparseMarkup(&markup);
................................................................................
        if( markup.iCode==MARKUP_DIV ){
          pushStackWithId(p, markup.iCode, markupId(&markup),
                          (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. 
        */
        if( markup.iCode==MARKUP_VERBATIM ){
          if( markup.nAttr==1 ){
            p->zVerbatimId = markup.aAttr[0].zValue;
          }else{
            p->zVerbatimId = 0;
          }
................................................................................
** initialized.  The output is merely appended to pOut.
** If pOut is NULL, then the output is appended to the CGI
** 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;
  }
  if( flags & WIKI_INLINE ){
    renderer.wantAutoParagraph = 0;






|







 







|







 







>
|
|
|
|
|
|
|
|
|
|
|
|
|







 







|


|



|



|






>




|


|





|



|







 







>
|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|







 







>
|
>
>
>
>
|
|
>







 







|







 







|











|







 







|







 







|







 







|

|







 







>
>
>
>
>
>
>
>
>







 







|







 







|







 







|







 







|







5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
...
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
...
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
...
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
...
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
...
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
...
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
...
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
...
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
...
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
...
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
...
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
...
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
....
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
....
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
....
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
....
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
....
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
** modify it under the terms of the GNU General Public
** License version 2 as published by the Free Software Foundation.
**
** 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.
**
** Author contact information:
**   drh@hwaci.com
................................................................................


/*
** 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
** in aAllowedMarkup[].
*/
#define MARKUP_INVALID           0
#define MARKUP_A                 1
#define MARKUP_ADDRESS           2
#define MARKUP_B                 3
#define MARKUP_BIG               4
................................................................................
#define MARKUP_NOWIKI           29
#define MARKUP_OL               30
#define MARKUP_P                31
#define MARKUP_PRE              32
#define MARKUP_S                33
#define MARKUP_SAMP             34
#define MARKUP_SMALL            35
#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> */
#define MUTYPE_BLOCK       0x0002   /* Forms a new paragraph. ex: <p>, <h2> */
#define MUTYPE_FONT        0x0004   /* Font changes. ex: <b>, <font>, <sub> */
................................................................................
                    AMSK_COLOR|AMSK_FACE|AMSK_SIZE   },
 { "h1",            MARKUP_H1,           MUTYPE_BLOCK,         AMSK_ALIGN  },
 { "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,
                    AMSK_ALIGN|AMSK_COLOR|AMSK_SIZE|AMSK_WIDTH  },
 { "i",             MARKUP_I,            MUTYPE_FONT,          0  },
 { "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,
                    AMSK_TYPE|AMSK_VALUE  },
 { "nobr",          MARKUP_NOBR,         MUTYPE_FONT,          0  },
 { "nowiki",        MARKUP_NOWIKI,       MUTYPE_SPECIAL,       0  },
 { "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,
                    AMSK_ALIGN|AMSK_BGCOLOR|AMSK_BORDER|AMSK_CELLPADDING|
                    AMSK_CELLSPACING|AMSK_HSPACE|AMSK_VSPACE  },
 { "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,
                    AMSK_ALIGN|AMSK_BGCOLOR||AMSK_VALIGN  },
 { "tt",            MARKUP_TT,           MUTYPE_FONT,          0  },
 { "u",             MARKUP_U,            MUTYPE_FONT,          0  },
 { "ul",            MARKUP_UL,           MUTYPE_LIST,
                    AMSK_TYPE|AMSK_COMPACT  },
 { "var",           MARKUP_VAR,          MUTYPE_FONT,          0  },
 { "verbatim",      MARKUP_VERBATIM,     MUTYPE_SPECIAL,       AMSK_ID },
};

/*
** Use binary search to locate a tag in the aMarkup[] table.
................................................................................
#define TOKEN_CHARACTER     2    /* "&" or "<" not part of markup */
#define TOKEN_LINK          3    /* [...] */
#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_COMMENT       9    /* <!-- --> */
#define TOKEN_TEXT         10    /* None of the above */

/*
** State flags
*/
#define AT_NEWLINE          0x001  /* At start of a line */
#define AT_PARAGRAPH        0x002  /* At start of a paragraph */
#define ALLOW_WIKI          0x004  /* Allow wiki markup */
................................................................................
** a valid markup.  If it is, return the total number of characters in
** the markup including the initial "<" and the terminating ">".  If
** 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) ){
    if( z[n]=='"' ){
      inparen = !inparen;
................................................................................
  int n = 0;
  int c;
  while( (c = z[0])!=0 && c!='<' && c!='&' &&
               (useWiki==0 || (c!='[' && c!='\n')) ){
    n++;
    z++;
  }
  return n;
}

/*
** Return true if z[] begins with an HTML character element.
*/
static int isElement(const char *z){
  int i;
................................................................................
** z points to the start of a token.  Return the number of
** characters in that token.  Write the token type into *pTokenType.
*/
static int nextToken(const char *z, Renderer *p, int *pTokenType){
  int n;
  if( z[0]=='<' ){
    n = markupLength(z);

    if( n>1 ){
      if (z[1]=='!'){
        *pTokenType = TOKEN_COMMENT;
        return n;
      } else {
        *pTokenType = TOKEN_MARKUP;
        return n;
      }
    }else{
      *pTokenType = TOKEN_CHARACTER;
      return 1;
    }
  }
  if( z[0]=='&' && (p->inVerbatim || !isElement(z)) ){
    *pTokenType = TOKEN_CHARACTER;
................................................................................
  } aAttr[10];
};

/*
** 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
** to lowercase and by inserting some "\000" characters.
*/
static void parseMarkup(ParsedMarkup *p, char *z){
  int i, j, c;
  int iACode;
  char *zValue;
  int seen = 0;
................................................................................
    p->endTag = 1;
    i = 2;
  }else{
    p->endTag = 0;
    i = 1;
  }
  j = 0;
  while( isalnum(z[i]) ){
    if( j<sizeof(zTag)-1 ) zTag[j++] = tolower(z[i]);
    i++;
  }
  zTag[j] = 0;
  p->iCode = findTag(zTag);
  p->iType = aMarkup[p->iCode].iType;
  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]) ){
      if( j<sizeof(zTag)-1 ) zTag[j++] = tolower(z[i]);
      i++;
    }
    zTag[j] = 0;
    p->aAttr[p->nAttr].iACode = iACode = findAttr(zTag);
    attrOk = iACode!=0 && (seen & aAttribute[iACode].iMask)==0;
    while( isspace(z[i]) ){ z++; }
................................................................................
  while( p->nStack>i ){
    popStack(p);
  }
}

/*
** Attempt to find a find a tag of type iTag with id zId.  Return -1
** 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--){
    if( p->aStack[i].iCode!=iTag ) continue;
    if( p->aStack[i].zId==0 ) continue;
................................................................................
  n = strlen(zTarget);
  memcpy(zLower, zTarget, n+1);
  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,
      "SELECT %s FROM ticket "
      " WHERE tkt_uuid>=:lwr AND tkt_uuid<:upr",
      zClosedExpr
    );
    once = 0;
  }
  db_bind_text(&q, ":lwr", zLower);
................................................................................
  const char *zTarget,    /* Hyperlink traget; text within [...] */
  char *zClose,           /* Write hyperlink closing text here */
  int nClose              /* Bytes available in zClose[] */
){
  const char *zTerm = "</a>";
  assert( nClose>10 );

  if( strncmp(zTarget, "http:", 5)==0
   || strncmp(zTarget, "https:", 6)==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 */ ){
      blob_appendf(p->pOut, "<a href=\"%s%h\">", g.zBaseURL, zTarget);
    }else{
................................................................................
  int n;
  int inlineOnly = (p->state & INLINE_MARKUP_ONLY)!=0;

  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{
          if( p->wikiList ){
            popStackToTag(p, p->wikiList);
................................................................................
      case TOKEN_MARKUP: {
        const char *zId;
        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
        ** </div>
        */
        if( markup.iCode==MARKUP_DIV && markup.endTag &&
             (zId = markupId(&markup))!=0 &&
             (iDiv = findTagWithId(p, MARKUP_DIV, zId))>=0
        ){
          if( p->inVerbatim ){
................................................................................
          }
          assert( p->nStack==iDiv+1 );
          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);
          }else{
            unparseMarkup(&markup);
................................................................................
        if( markup.iCode==MARKUP_DIV ){
          pushStackWithId(p, markup.iCode, markupId(&markup),
                          (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.
        */
        if( markup.iCode==MARKUP_VERBATIM ){
          if( markup.nAttr==1 ){
            p->zVerbatimId = markup.aAttr[0].zValue;
          }else{
            p->zVerbatimId = 0;
          }
................................................................................
** initialized.  The output is merely appended to pOut.
** If pOut is NULL, then the output is appended to the CGI
** 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;
  }
  if( flags & WIKI_INLINE ){
    renderer.wantAutoParagraph = 0;