File Annotation
Not logged in
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Copyright (c) 2007 D. Richard Hipp
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** This program is free software; you can redistribute it and/or
dbda8d6ce9 2007-07-21       drh: ** modify it under the terms of the GNU General Public
dbda8d6ce9 2007-07-21       drh: ** License version 2 as published by the Free Software Foundation.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** This program is distributed in the hope that it will be useful,
dbda8d6ce9 2007-07-21       drh: ** but WITHOUT ANY WARRANTY; without even the implied warranty of
dbda8d6ce9 2007-07-21       drh: ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
dbda8d6ce9 2007-07-21       drh: ** General Public License for more details.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** You should have received a copy of the GNU General Public
dbda8d6ce9 2007-07-21       drh: ** License along with this library; if not, write to the
dbda8d6ce9 2007-07-21       drh: ** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
dbda8d6ce9 2007-07-21       drh: ** Boston, MA  02111-1307, USA.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** Author contact information:
dbda8d6ce9 2007-07-21       drh: **   drh@hwaci.com
dbda8d6ce9 2007-07-21       drh: **   http://www.hwaci.com/drh/
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: *******************************************************************************
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** This file contains code to do formatting of wiki text.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: #include <assert.h>
dbda8d6ce9 2007-07-21       drh: #include "config.h"
dbda8d6ce9 2007-07-21       drh: #include "wikiformat.h"
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: #if INTERFACE
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Allowed wiki transformation operations
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: #define WIKI_NOFOLLOW       0x001
dbda8d6ce9 2007-07-21       drh: #define WIKI_HTML           0x002
c963a7763d 2007-10-13       drh: #define WIKI_INLINE         0x004  /* Do not surround with <p>..</p> */
ebb2765954 2007-12-04       drh: #define WIKI_NOBLOCK        0x008  /* No block markup of any kind */
dbda8d6ce9 2007-07-21       drh: #endif
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** These are the only markup attributes allowed.
dbda8d6ce9 2007-07-21       drh: */
c963a7763d 2007-10-13       drh: #define ATTR_ALIGN              0x0000001
c963a7763d 2007-10-13       drh: #define ATTR_ALT                0x0000002
c963a7763d 2007-10-13       drh: #define ATTR_BGCOLOR            0x0000004
c963a7763d 2007-10-13       drh: #define ATTR_BORDER             0x0000008
c963a7763d 2007-10-13       drh: #define ATTR_CELLPADDING        0x0000010
c963a7763d 2007-10-13       drh: #define ATTR_CELLSPACING        0x0000020
c963a7763d 2007-10-13       drh: #define ATTR_CLEAR              0x0000040
c963a7763d 2007-10-13       drh: #define ATTR_COLOR              0x0000080
c963a7763d 2007-10-13       drh: #define ATTR_COLSPAN            0x0000100
c963a7763d 2007-10-13       drh: #define ATTR_COMPACT            0x0000200
c963a7763d 2007-10-13       drh: #define ATTR_FACE               0x0000400
c963a7763d 2007-10-13       drh: #define ATTR_HEIGHT             0x0000800
c963a7763d 2007-10-13       drh: #define ATTR_HREF               0x0001000
c963a7763d 2007-10-13       drh: #define ATTR_HSPACE             0x0002000
c963a7763d 2007-10-13       drh: #define ATTR_ID                 0x0004000
c963a7763d 2007-10-13       drh: #define ATTR_NAME               0x0008000
c963a7763d 2007-10-13       drh: #define ATTR_ROWSPAN            0x0010000
c963a7763d 2007-10-13       drh: #define ATTR_SIZE               0x0020000
c963a7763d 2007-10-13       drh: #define ATTR_SRC                0x0040000
c963a7763d 2007-10-13       drh: #define ATTR_START              0x0080000
c963a7763d 2007-10-13       drh: #define ATTR_TYPE               0x0100000
c963a7763d 2007-10-13       drh: #define ATTR_VALIGN             0x0200000
c963a7763d 2007-10-13       drh: #define ATTR_VALUE              0x0400000
c963a7763d 2007-10-13       drh: #define ATTR_VSPACE             0x0800000
c963a7763d 2007-10-13       drh: #define ATTR_WIDTH              0x1000000
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: static const struct AllowedAttribute {
dbda8d6ce9 2007-07-21       drh:   const char *zName;
dbda8d6ce9 2007-07-21       drh:   unsigned int iMask;
dbda8d6ce9 2007-07-21       drh: } aAttribute[] = {
df646a7f4c 2007-10-12       drh:   { 0, 0 },
dbda8d6ce9 2007-07-21       drh:   { "align",         ATTR_ALIGN,          },
dbda8d6ce9 2007-07-21       drh:   { "alt",           ATTR_ALT,            },
dbda8d6ce9 2007-07-21       drh:   { "bgcolor",       ATTR_BGCOLOR,        },
dbda8d6ce9 2007-07-21       drh:   { "border",        ATTR_BORDER,         },
dbda8d6ce9 2007-07-21       drh:   { "cellpadding",   ATTR_CELLPADDING,    },
dbda8d6ce9 2007-07-21       drh:   { "cellspacing",   ATTR_CELLSPACING,    },
dbda8d6ce9 2007-07-21       drh:   { "clear",         ATTR_CLEAR,          },
dbda8d6ce9 2007-07-21       drh:   { "color",         ATTR_COLOR,          },
dbda8d6ce9 2007-07-21       drh:   { "colspan",       ATTR_COLSPAN,        },
dbda8d6ce9 2007-07-21       drh:   { "compact",       ATTR_COMPACT,        },
dbda8d6ce9 2007-07-21       drh:   { "face",          ATTR_FACE,           },
dbda8d6ce9 2007-07-21       drh:   { "height",        ATTR_HEIGHT,         },
dbda8d6ce9 2007-07-21       drh:   { "href",          ATTR_HREF,           },
dbda8d6ce9 2007-07-21       drh:   { "hspace",        ATTR_HSPACE,         },
dbda8d6ce9 2007-07-21       drh:   { "id",            ATTR_ID,             },
c963a7763d 2007-10-13       drh:   { "name",          ATTR_NAME,           },
dbda8d6ce9 2007-07-21       drh:   { "rowspan",       ATTR_ROWSPAN,        },
dbda8d6ce9 2007-07-21       drh:   { "size",          ATTR_SIZE,           },
dbda8d6ce9 2007-07-21       drh:   { "src",           ATTR_SRC,            },
dbda8d6ce9 2007-07-21       drh:   { "start",         ATTR_START,          },
dbda8d6ce9 2007-07-21       drh:   { "type",          ATTR_TYPE,           },
dbda8d6ce9 2007-07-21       drh:   { "valign",        ATTR_VALIGN,         },
dbda8d6ce9 2007-07-21       drh:   { "value",         ATTR_VALUE,          },
dbda8d6ce9 2007-07-21       drh:   { "vspace",        ATTR_VSPACE,         },
dbda8d6ce9 2007-07-21       drh:   { "width",         ATTR_WIDTH,          },
dbda8d6ce9 2007-07-21       drh: };
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Use binary search to locate a tag in the aAttribute[] table.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static int findAttr(const char *z){
dbda8d6ce9 2007-07-21       drh:   int i, c, first, last;
df646a7f4c 2007-10-12       drh:   first = 1;
dbda8d6ce9 2007-07-21       drh:   last = sizeof(aAttribute)/sizeof(aAttribute[0]) - 1;
dbda8d6ce9 2007-07-21       drh:   while( first<=last ){
dbda8d6ce9 2007-07-21       drh:     i = (first+last)/2;
dbda8d6ce9 2007-07-21       drh:     c = strcmp(aAttribute[i].zName, z);
dbda8d6ce9 2007-07-21       drh:     if( c==0 ){
df646a7f4c 2007-10-12       drh:       return i;
dbda8d6ce9 2007-07-21       drh:     }else if( c<0 ){
dbda8d6ce9 2007-07-21       drh:       first = i+1;
dbda8d6ce9 2007-07-21       drh:     }else{
dbda8d6ce9 2007-07-21       drh:       last = i-1;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   return 0;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Allowed markup.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** Except for MARKUP_INVALID, this must all be in alphabetical order
dbda8d6ce9 2007-07-21       drh: ** and in numerical sequence.  The first markup type must be zero.
dbda8d6ce9 2007-07-21       drh: ** The value for MARKUP_XYZ must correspond to the <xyz> entry
dbda8d6ce9 2007-07-21       drh: ** in aAllowedMarkup[].
dbda8d6ce9 2007-07-21       drh: */
ab637af752 2007-09-28       drh: #define MARKUP_INVALID           0
ab637af752 2007-09-28       drh: #define MARKUP_A                 1
ab637af752 2007-09-28       drh: #define MARKUP_ADDRESS           2
ab637af752 2007-09-28       drh: #define MARKUP_B                 3
ab637af752 2007-09-28       drh: #define MARKUP_BIG               4
ab637af752 2007-09-28       drh: #define MARKUP_BLOCKQUOTE        5
ab637af752 2007-09-28       drh: #define MARKUP_BR                6
ab637af752 2007-09-28       drh: #define MARKUP_CENTER            7
ab637af752 2007-09-28       drh: #define MARKUP_CITE              8
ab637af752 2007-09-28       drh: #define MARKUP_CODE              9
ab637af752 2007-09-28       drh: #define MARKUP_DD               10
ab637af752 2007-09-28       drh: #define MARKUP_DFN              11
ab637af752 2007-09-28       drh: #define MARKUP_DL               12
ab637af752 2007-09-28       drh: #define MARKUP_DT               13
ab637af752 2007-09-28       drh: #define MARKUP_EM               14
ab637af752 2007-09-28       drh: #define MARKUP_FONT             15
ab637af752 2007-09-28       drh: #define MARKUP_H1               16
ab637af752 2007-09-28       drh: #define MARKUP_H2               17
ab637af752 2007-09-28       drh: #define MARKUP_H3               18
ab637af752 2007-09-28       drh: #define MARKUP_H4               19
ab637af752 2007-09-28       drh: #define MARKUP_H5               20
ab637af752 2007-09-28       drh: #define MARKUP_H6               21
ab637af752 2007-09-28       drh: #define MARKUP_HR               22
dbda8d6ce9 2007-07-21       drh: #define MARKUP_I                23
7351b6346d 2008-05-15       drh: #define MARKUP_IMG              24
ab637af752 2007-09-28       drh: #define MARKUP_KBD              25
ab637af752 2007-09-28       drh: #define MARKUP_LI               26
ab637af752 2007-09-28       drh: #define MARKUP_NOBR             27
ab637af752 2007-09-28       drh: #define MARKUP_NOWIKI           28
ab637af752 2007-09-28       drh: #define MARKUP_OL               29
ab637af752 2007-09-28       drh: #define MARKUP_P                30
ab637af752 2007-09-28       drh: #define MARKUP_PRE              31
ab637af752 2007-09-28       drh: #define MARKUP_S                32
ab637af752 2007-09-28       drh: #define MARKUP_SAMP             33
ab637af752 2007-09-28       drh: #define MARKUP_SMALL            34
ab637af752 2007-09-28       drh: #define MARKUP_STRIKE           35
ab637af752 2007-09-28       drh: #define MARKUP_STRONG           36
ab637af752 2007-09-28       drh: #define MARKUP_SUB              37
ab637af752 2007-09-28       drh: #define MARKUP_SUP              38
ab637af752 2007-09-28       drh: #define MARKUP_TABLE            39
ab637af752 2007-09-28       drh: #define MARKUP_TD               40
ab637af752 2007-09-28       drh: #define MARKUP_TH               41
ab637af752 2007-09-28       drh: #define MARKUP_TR               42
ab637af752 2007-09-28       drh: #define MARKUP_TT               43
dbda8d6ce9 2007-07-21       drh: #define MARKUP_U                44
ab637af752 2007-09-28       drh: #define MARKUP_UL               45
ab637af752 2007-09-28       drh: #define MARKUP_VAR              46
ab637af752 2007-09-28       drh: #define MARKUP_VERBATIM         47
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** The various markup is divided into the following types:
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: #define MUTYPE_SINGLE      0x0001   /* <img>, <br>, or <hr> */
dbda8d6ce9 2007-07-21       drh: #define MUTYPE_BLOCK       0x0002   /* Forms a new paragraph. ex: <p>, <h2> */
dbda8d6ce9 2007-07-21       drh: #define MUTYPE_FONT        0x0004   /* Font changes. ex: <b>, <font>, <sub> */
dbda8d6ce9 2007-07-21       drh: #define MUTYPE_LIST        0x0010   /* Lists.  <ol>, <ul>, or <dl> */
dbda8d6ce9 2007-07-21       drh: #define MUTYPE_LI          0x0020   /* List items.  <li>, <dd>, <dt> */
dbda8d6ce9 2007-07-21       drh: #define MUTYPE_TABLE       0x0040   /* <table> */
dbda8d6ce9 2007-07-21       drh: #define MUTYPE_TR          0x0080   /* <tr> */
dbda8d6ce9 2007-07-21       drh: #define MUTYPE_TD          0x0100   /* <td> or <th> */
dbda8d6ce9 2007-07-21       drh: #define MUTYPE_SPECIAL     0x0200   /* <nowiki> or <verbatim> */
dbda8d6ce9 2007-07-21       drh: #define MUTYPE_HYPERLINK   0x0400   /* <a> */
dbda8d6ce9 2007-07-21       drh: 
c963a7763d 2007-10-13       drh: /*
c963a7763d 2007-10-13       drh: ** These markup types must have an end tag.
c963a7763d 2007-10-13       drh: */
dbda8d6ce9 2007-07-21       drh: #define MUTYPE_STACK  (MUTYPE_BLOCK | MUTYPE_FONT | MUTYPE_LIST | MUTYPE_TABLE)
c963a7763d 2007-10-13       drh: 
ebb2765954 2007-12-04       drh: /*
ebb2765954 2007-12-04       drh: ** This markup types are allowed for "inline" text.
ebb2765954 2007-12-04       drh: */
ebb2765954 2007-12-04       drh: #define MUTYPE_INLINE (MUTYPE_FONT | MUTYPE_HYPERLINK)
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: static const struct AllowedMarkup {
dbda8d6ce9 2007-07-21       drh:   const char *zName;       /* Name of the markup */
dbda8d6ce9 2007-07-21       drh:   char iCode;              /* The MARKUP_* code */
dbda8d6ce9 2007-07-21       drh:   short int iType;         /* The MUTYPE_* code */
dbda8d6ce9 2007-07-21       drh:   int allowedAttr;         /* Allowed attributes on this markup */
dbda8d6ce9 2007-07-21       drh: } aMarkup[] = {
ab637af752 2007-09-28       drh:  { 0,               MARKUP_INVALID,      0,                    0  },
c963a7763d 2007-10-13       drh:  { "a",             MARKUP_A,            MUTYPE_HYPERLINK,
c963a7763d 2007-10-13       drh:                     ATTR_HREF|ATTR_NAME },
dbda8d6ce9 2007-07-21       drh:  { "address",       MARKUP_ADDRESS,      MUTYPE_BLOCK,         0  },
55dc2abc60 2007-09-24       jnc:  { "b",             MARKUP_B,            MUTYPE_FONT,          0  },
dbda8d6ce9 2007-07-21       drh:  { "big",           MARKUP_BIG,          MUTYPE_FONT,          0  },
dbda8d6ce9 2007-07-21       drh:  { "blockquote",    MARKUP_BLOCKQUOTE,   MUTYPE_BLOCK,         0  },
dbda8d6ce9 2007-07-21       drh:  { "br",            MARKUP_BR,           MUTYPE_SINGLE,        ATTR_CLEAR  },
dbda8d6ce9 2007-07-21       drh:  { "center",        MARKUP_CENTER,       MUTYPE_BLOCK,         0  },
dbda8d6ce9 2007-07-21       drh:  { "cite",          MARKUP_CITE,         MUTYPE_FONT,          0  },
dbda8d6ce9 2007-07-21       drh:  { "code",          MARKUP_CODE,         MUTYPE_FONT,          0  },
dbda8d6ce9 2007-07-21       drh:  { "dd",            MARKUP_DD,           MUTYPE_LI,            0  },
dbda8d6ce9 2007-07-21       drh:  { "dfn",           MARKUP_DFN,          MUTYPE_FONT,          0  },
dbda8d6ce9 2007-07-21       drh:  { "dl",            MARKUP_DL,           MUTYPE_LIST,          ATTR_COMPACT },
dbda8d6ce9 2007-07-21       drh:  { "dt",            MARKUP_DT,           MUTYPE_LI,            0  },
dbda8d6ce9 2007-07-21       drh:  { "em",            MARKUP_EM,           MUTYPE_FONT,          0  },
dbda8d6ce9 2007-07-21       drh:  { "font",          MARKUP_FONT,         MUTYPE_FONT,
dbda8d6ce9 2007-07-21       drh:                     ATTR_COLOR|ATTR_FACE|ATTR_SIZE   },
dbda8d6ce9 2007-07-21       drh:  { "h1",            MARKUP_H1,           MUTYPE_BLOCK,         ATTR_ALIGN  },
dbda8d6ce9 2007-07-21       drh:  { "h2",            MARKUP_H2,           MUTYPE_BLOCK,         ATTR_ALIGN  },
dbda8d6ce9 2007-07-21       drh:  { "h3",            MARKUP_H3,           MUTYPE_BLOCK,         ATTR_ALIGN  },
dbda8d6ce9 2007-07-21       drh:  { "h4",            MARKUP_H4,           MUTYPE_BLOCK,         ATTR_ALIGN  },
dbda8d6ce9 2007-07-21       drh:  { "h5",            MARKUP_H5,           MUTYPE_BLOCK,         ATTR_ALIGN  },
dbda8d6ce9 2007-07-21       drh:  { "h6",            MARKUP_H6,           MUTYPE_BLOCK,         ATTR_ALIGN  },
dbda8d6ce9 2007-07-21       drh:  { "hr",            MARKUP_HR,           MUTYPE_SINGLE,
dbda8d6ce9 2007-07-21       drh:                     ATTR_ALIGN|ATTR_COLOR|ATTR_SIZE|ATTR_WIDTH  },
7351b6346d 2008-05-15       drh:  { "i",             MARKUP_I,            MUTYPE_FONT,          0  },
dbda8d6ce9 2007-07-21       drh:  { "img",           MARKUP_IMG,          MUTYPE_SINGLE,
dbda8d6ce9 2007-07-21       drh:                     ATTR_ALIGN|ATTR_ALT|ATTR_BORDER|ATTR_HEIGHT|
dbda8d6ce9 2007-07-21       drh:                     ATTR_HSPACE|ATTR_SRC|ATTR_VSPACE|ATTR_WIDTH  },
dbda8d6ce9 2007-07-21       drh:  { "kbd",           MARKUP_KBD,          MUTYPE_FONT,          0  },
dbda8d6ce9 2007-07-21       drh:  { "li",            MARKUP_LI,           MUTYPE_LI,
dbda8d6ce9 2007-07-21       drh:                     ATTR_TYPE|ATTR_VALUE  },
dbda8d6ce9 2007-07-21       drh:  { "nobr",          MARKUP_NOBR,         MUTYPE_FONT,          0  },
dbda8d6ce9 2007-07-21       drh:  { "nowiki",        MARKUP_NOWIKI,       MUTYPE_SPECIAL,       0  },
dbda8d6ce9 2007-07-21       drh:  { "ol",            MARKUP_OL,           MUTYPE_LIST,
dbda8d6ce9 2007-07-21       drh:                     ATTR_START|ATTR_TYPE|ATTR_COMPACT  },
dbda8d6ce9 2007-07-21       drh:  { "p",             MARKUP_P,            MUTYPE_BLOCK,         ATTR_ALIGN  },
dbda8d6ce9 2007-07-21       drh:  { "pre",           MARKUP_PRE,          MUTYPE_BLOCK,         0  },
55dc2abc60 2007-09-24       jnc:  { "s",             MARKUP_S,            MUTYPE_FONT,          0  },
dbda8d6ce9 2007-07-21       drh:  { "samp",          MARKUP_SAMP,         MUTYPE_FONT,          0  },
dbda8d6ce9 2007-07-21       drh:  { "small",         MARKUP_SMALL,        MUTYPE_FONT,          0  },
dbda8d6ce9 2007-07-21       drh:  { "strike",        MARKUP_STRIKE,       MUTYPE_FONT,          0  },
dbda8d6ce9 2007-07-21       drh:  { "strong",        MARKUP_STRONG,       MUTYPE_FONT,          0  },
dbda8d6ce9 2007-07-21       drh:  { "sub",           MARKUP_SUB,          MUTYPE_FONT,          0  },
dbda8d6ce9 2007-07-21       drh:  { "sup",           MARKUP_SUP,          MUTYPE_FONT,          0  },
dbda8d6ce9 2007-07-21       drh:  { "table",         MARKUP_TABLE,        MUTYPE_TABLE,
dbda8d6ce9 2007-07-21       drh:                     ATTR_ALIGN|ATTR_BGCOLOR|ATTR_BORDER|ATTR_CELLPADDING|
dbda8d6ce9 2007-07-21       drh:                     ATTR_CELLSPACING|ATTR_HSPACE|ATTR_VSPACE  },
dbda8d6ce9 2007-07-21       drh:  { "td",            MARKUP_TD,           MUTYPE_TD,
dbda8d6ce9 2007-07-21       drh:                     ATTR_ALIGN|ATTR_BGCOLOR|ATTR_COLSPAN|
dbda8d6ce9 2007-07-21       drh:                     ATTR_ROWSPAN|ATTR_VALIGN  },
dbda8d6ce9 2007-07-21       drh:  { "th",            MARKUP_TH,           MUTYPE_TD,
dbda8d6ce9 2007-07-21       drh:                     ATTR_ALIGN|ATTR_BGCOLOR|ATTR_COLSPAN|
dbda8d6ce9 2007-07-21       drh:                     ATTR_ROWSPAN|ATTR_VALIGN  },
dbda8d6ce9 2007-07-21       drh:  { "tr",            MARKUP_TR,           MUTYPE_TR,
dbda8d6ce9 2007-07-21       drh:                     ATTR_ALIGN|ATTR_BGCOLOR||ATTR_VALIGN  },
dbda8d6ce9 2007-07-21       drh:  { "tt",            MARKUP_TT,           MUTYPE_FONT,          0  },
55dc2abc60 2007-09-24       jnc:  { "u",             MARKUP_U,            MUTYPE_FONT,          0  },
dbda8d6ce9 2007-07-21       drh:  { "ul",            MARKUP_UL,           MUTYPE_LIST,
dbda8d6ce9 2007-07-21       drh:                     ATTR_TYPE|ATTR_COMPACT  },
dbda8d6ce9 2007-07-21       drh:  { "var",           MARKUP_VAR,          MUTYPE_FONT,          0  },
dbda8d6ce9 2007-07-21       drh:  { "verbatim",      MARKUP_VERBATIM,     MUTYPE_SPECIAL,       ATTR_ID },
dbda8d6ce9 2007-07-21       drh: };
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Use binary search to locate a tag in the aMarkup[] table.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static int findTag(const char *z){
dbda8d6ce9 2007-07-21       drh:   int i, c, first, last;
ab637af752 2007-09-28       drh:   first = 1;
dbda8d6ce9 2007-07-21       drh:   last = sizeof(aMarkup)/sizeof(aMarkup[0]) - 1;
dbda8d6ce9 2007-07-21       drh:   while( first<=last ){
dbda8d6ce9 2007-07-21       drh:     i = (first+last)/2;
dbda8d6ce9 2007-07-21       drh:     c = strcmp(aMarkup[i].zName, z);
dbda8d6ce9 2007-07-21       drh:     if( c==0 ){
dbda8d6ce9 2007-07-21       drh:       assert( aMarkup[i].iCode==i );
dbda8d6ce9 2007-07-21       drh:       return i;
dbda8d6ce9 2007-07-21       drh:     }else if( c<0 ){
dbda8d6ce9 2007-07-21       drh:       first = i+1;
dbda8d6ce9 2007-07-21       drh:     }else{
dbda8d6ce9 2007-07-21       drh:       last = i-1;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   return MARKUP_INVALID;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Token types
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: #define TOKEN_MARKUP        1    /* <...> */
dbda8d6ce9 2007-07-21       drh: #define TOKEN_CHARACTER     2    /* "&" or "<" not part of markup */
dbda8d6ce9 2007-07-21       drh: #define TOKEN_LINK          3    /* [...] */
dbda8d6ce9 2007-07-21       drh: #define TOKEN_PARAGRAPH     4    /* blank lines */
dbda8d6ce9 2007-07-21       drh: #define TOKEN_NEWLINE       5    /* A single "\n" */
dbda8d6ce9 2007-07-21       drh: #define TOKEN_BULLET        6    /*  "  *  " */
dbda8d6ce9 2007-07-21       drh: #define TOKEN_ENUM          7    /*  "  \(?\d+[.)]?  " */
dbda8d6ce9 2007-07-21       drh: #define TOKEN_INDENT        8    /*  "   " */
dbda8d6ce9 2007-07-21       drh: #define TOKEN_TEXT          9    /* None of the above */
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** State flags
dbda8d6ce9 2007-07-21       drh: */
ebb2765954 2007-12-04       drh: #define AT_NEWLINE          0x001  /* At start of a line */
ebb2765954 2007-12-04       drh: #define AT_PARAGRAPH        0x002  /* At start of a paragraph */
ebb2765954 2007-12-04       drh: #define ALLOW_WIKI          0x004  /* Allow wiki markup */
ebb2765954 2007-12-04       drh: #define FONT_MARKUP_ONLY    0x008  /* Only allow MUTYPE_FONT markup */
ebb2765954 2007-12-04       drh: #define INLINE_MARKUP_ONLY  0x010  /* Allow only "inline" markup */
ebb2765954 2007-12-04       drh: #define IN_LIST             0x020  /* Within wiki <ul> or <ol> */
ab637af752 2007-09-28       drh: 
ab637af752 2007-09-28       drh: /*
ab637af752 2007-09-28       drh: ** Current state of the rendering engine
ab637af752 2007-09-28       drh: */
ab637af752 2007-09-28       drh: typedef struct Renderer Renderer;
ab637af752 2007-09-28       drh: struct Renderer {
ab637af752 2007-09-28       drh:   Blob *pOut;                 /* Output appended to this blob */
ab637af752 2007-09-28       drh:   int state;                  /* Flag that govern rendering */
ab637af752 2007-09-28       drh:   int wikiList;               /* Current wiki list type */
ab637af752 2007-09-28       drh:   int inVerbatim;             /* True in <verbatim> mode */
ab637af752 2007-09-28       drh:   int preVerbState;           /* Value of state prior to verbatim */
c963a7763d 2007-10-13       drh:   int wantAutoParagraph;      /* True if a <p> is desired */
c963a7763d 2007-10-13       drh:   int inAutoParagraph;        /* True if within an automatic paragraph */
ab637af752 2007-09-28       drh:   const char *zVerbatimId;    /* The id= attribute of <verbatim> */
ab637af752 2007-09-28       drh:   int nStack;                 /* Number of elements on the stack */
ab637af752 2007-09-28       drh:   int nAlloc;                 /* Space allocated for aStack */
ab637af752 2007-09-28       drh:   unsigned char *aStack;      /* Open markup stack */
ab637af752 2007-09-28       drh: };
ab637af752 2007-09-28       drh: 
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** z points to a "<" character.  Check to see if this is the start of
dbda8d6ce9 2007-07-21       drh: ** a valid markup.  If it is, return the total number of characters in
dbda8d6ce9 2007-07-21       drh: ** the markup including the initial "<" and the terminating ">".  If
dbda8d6ce9 2007-07-21       drh: ** it is not well-formed markup, return 0.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static int markupLength(const char *z){
dbda8d6ce9 2007-07-21       drh:   int n = 1;
dbda8d6ce9 2007-07-21       drh:   int inparen = 0;
dbda8d6ce9 2007-07-21       drh:   if( z[n]=='/' ){ n++; }
dbda8d6ce9 2007-07-21       drh:   if( !isalpha(z[n]) ) return 0;
55dc2abc60 2007-09-24       jnc:   while( isalnum(z[n]) ){ n++; }
dbda8d6ce9 2007-07-21       drh:   if( z[n]!='>' && !isspace(z[n]) ) return 0;
dbda8d6ce9 2007-07-21       drh:   while( z[n] && (z[n]!='>' || inparen) ){
dbda8d6ce9 2007-07-21       drh:     if( z[n]=='"' ){
dbda8d6ce9 2007-07-21       drh:       inparen = !inparen;
dbda8d6ce9 2007-07-21       drh:     }
11976cfdc2 2007-09-02       drh:     n++;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( z[n]!='>' ) return 0;
dbda8d6ce9 2007-07-21       drh:   return n+1;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** z points to a "\n" character.  Check to see if this newline is
dbda8d6ce9 2007-07-21       drh: ** followed by one or more blank lines.  If it is, return the number
dbda8d6ce9 2007-07-21       drh: ** of characters through the closing "\n".  If not, return 0.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static int paragraphBreakLength(const char *z){
dbda8d6ce9 2007-07-21       drh:   int i, n;
dbda8d6ce9 2007-07-21       drh:   int nNewline = 1;
dbda8d6ce9 2007-07-21       drh:   for(i=1, n=0; isspace(z[i]); i++){
dbda8d6ce9 2007-07-21       drh:     if( z[i]=='\n' ){
dbda8d6ce9 2007-07-21       drh:       nNewline++;
dbda8d6ce9 2007-07-21       drh:       n = i;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( nNewline>=2 ){
dbda8d6ce9 2007-07-21       drh:     return n+1;
dbda8d6ce9 2007-07-21       drh:   }else{
dbda8d6ce9 2007-07-21       drh:     return 0;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Return the number of characters until the next "interesting"
dbda8d6ce9 2007-07-21       drh: ** characters.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** Interesting characters are:
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: **      <
dbda8d6ce9 2007-07-21       drh: **      &
dbda8d6ce9 2007-07-21       drh: **      \n
dbda8d6ce9 2007-07-21       drh: **      [
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** The "[" and "\n" are only considered interesting if the "useWiki"
dbda8d6ce9 2007-07-21       drh: ** flag is set.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static int textLength(const char *z, int useWiki){
dbda8d6ce9 2007-07-21       drh:   int n = 0;
dbda8d6ce9 2007-07-21       drh:   int c;
dbda8d6ce9 2007-07-21       drh:   while( (c = z[0])!=0 && c!='<' && c!='&' &&
dbda8d6ce9 2007-07-21       drh:                (useWiki==0 || (c!='[' && c!='\n')) ){
dbda8d6ce9 2007-07-21       drh:     n++;
dbda8d6ce9 2007-07-21       drh:     z++;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   return n;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Return true if z[] begins with an HTML character element.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static int isElement(const char *z){
dbda8d6ce9 2007-07-21       drh:   int i;
dbda8d6ce9 2007-07-21       drh:   assert( z[0]=='&' );
dbda8d6ce9 2007-07-21       drh:   if( z[1]=='#' ){
dbda8d6ce9 2007-07-21       drh:     for(i=2; isdigit(z[i]); i++){}
dbda8d6ce9 2007-07-21       drh:     return i>2 && z[i]==';';
dbda8d6ce9 2007-07-21       drh:   }else{
dbda8d6ce9 2007-07-21       drh:     for(i=1; isalpha(z[i]); i++){}
dbda8d6ce9 2007-07-21       drh:     return i>1 && z[i]==';';
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Check to see if the z[] string is the beginning of a wiki bullet.
dbda8d6ce9 2007-07-21       drh: ** If it is, return the length of the bullet text.  Otherwise return 0.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static int bulletLength(const char *z){
dbda8d6ce9 2007-07-21       drh:   int i, n;
dbda8d6ce9 2007-07-21       drh:   n = 0;
dbda8d6ce9 2007-07-21       drh:   i = 0;
dbda8d6ce9 2007-07-21       drh:   while( z[n]==' ' || z[n]=='\t' ){
dbda8d6ce9 2007-07-21       drh:     if( z[n]=='\t' ) i++;
dbda8d6ce9 2007-07-21       drh:     i++;
dbda8d6ce9 2007-07-21       drh:     n++;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( i<2 || z[n]!='*' ) return 0;
dbda8d6ce9 2007-07-21       drh:   n++;
dbda8d6ce9 2007-07-21       drh:   i = 0;
dbda8d6ce9 2007-07-21       drh:   while( z[n]==' ' || z[n]=='\t' ){
dbda8d6ce9 2007-07-21       drh:     if( z[n]=='\t' ) i++;
dbda8d6ce9 2007-07-21       drh:     i++;
dbda8d6ce9 2007-07-21       drh:     n++;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( i<2 || isspace(z[n]) ) return 0;
dbda8d6ce9 2007-07-21       drh:   return n;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
ab637af752 2007-09-28       drh: ** Check to see if the z[] string is the beginning of a enumeration value.
ab637af752 2007-09-28       drh: ** If it is, return the length of the bullet text.  Otherwise return 0.
ab637af752 2007-09-28       drh: **
ab637af752 2007-09-28       drh: ** Syntax:
ab637af752 2007-09-28       drh: **    *  a tab or two or more spaces
ab637af752 2007-09-28       drh: **    *  one or more digits
ab637af752 2007-09-28       drh: **    *  optional "."
c963a7763d 2007-10-13       drh: **    *  another tab or two ore more spaces.
ab637af752 2007-09-28       drh: **
ab637af752 2007-09-28       drh: */
ab637af752 2007-09-28       drh: static int enumLength(const char *z){
ab637af752 2007-09-28       drh:   int i, n;
ab637af752 2007-09-28       drh:   n = 0;
ab637af752 2007-09-28       drh:   i = 0;
ab637af752 2007-09-28       drh:   while( z[n]==' ' || z[n]=='\t' ){
ab637af752 2007-09-28       drh:     if( z[n]=='\t' ) i++;
ab637af752 2007-09-28       drh:     i++;
ab637af752 2007-09-28       drh:     n++;
ab637af752 2007-09-28       drh:   }
ab637af752 2007-09-28       drh:   if( i<2 ) return 0;
ab637af752 2007-09-28       drh:   for(i=0; isdigit(z[n]); i++, n++){}
ab637af752 2007-09-28       drh:   if( i==0 ) return 0;
ab637af752 2007-09-28       drh:   if( z[n]=='.' ){
ab637af752 2007-09-28       drh:     n++;
ab637af752 2007-09-28       drh:   }
ab637af752 2007-09-28       drh:   i = 0;
ab637af752 2007-09-28       drh:   while( z[n]==' ' || z[n]=='\t' ){
ab637af752 2007-09-28       drh:     if( z[n]=='\t' ) i++;
ab637af752 2007-09-28       drh:     i++;
ab637af752 2007-09-28       drh:     n++;
ab637af752 2007-09-28       drh:   }
ab637af752 2007-09-28       drh:   if( i<2 || isspace(z[n]) ) return 0;
ab637af752 2007-09-28       drh:   return n;
ab637af752 2007-09-28       drh: }
ab637af752 2007-09-28       drh: 
ab637af752 2007-09-28       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Check to see if the z[] string is the beginning of an indented
dbda8d6ce9 2007-07-21       drh: ** paragraph.  If it is, return the length of the indent.  Otherwise
dbda8d6ce9 2007-07-21       drh: ** return 0.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static int indentLength(const char *z){
dbda8d6ce9 2007-07-21       drh:   int i, n;
dbda8d6ce9 2007-07-21       drh:   n = 0;
dbda8d6ce9 2007-07-21       drh:   i = 0;
dbda8d6ce9 2007-07-21       drh:   while( z[n]==' ' || z[n]=='\t' ){
dbda8d6ce9 2007-07-21       drh:     if( z[n]=='\t' ) i++;
dbda8d6ce9 2007-07-21       drh:     i++;
dbda8d6ce9 2007-07-21       drh:     n++;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( i<2 || isspace(z[n]) ) return 0;
dbda8d6ce9 2007-07-21       drh:   return n;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Check to see if the z[] string is a wiki hyperlink.  If it is,
dbda8d6ce9 2007-07-21       drh: ** return the length of the hyperlink.  Otherwise return 0.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static int linkLength(const char *z){
dbda8d6ce9 2007-07-21       drh:   int n;
dbda8d6ce9 2007-07-21       drh:   assert( z[0]=='[' );
dbda8d6ce9 2007-07-21       drh:   for(n=0; z[n] && z[n]!=']'; n++){}
dbda8d6ce9 2007-07-21       drh:   if( z[n]==']' ){
dbda8d6ce9 2007-07-21       drh:     return n+1;
dbda8d6ce9 2007-07-21       drh:   }else{
dbda8d6ce9 2007-07-21       drh:     return 0;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** z points to the start of a token.  Return the number of
dbda8d6ce9 2007-07-21       drh: ** characters in that token.  Write the token type into *pTokenType.
dbda8d6ce9 2007-07-21       drh: */
e75f9a2ab4 2007-10-28       drh: static int nextToken(const char *z, Renderer *p, int *pTokenType){
dbda8d6ce9 2007-07-21       drh:   int n;
dbda8d6ce9 2007-07-21       drh:   if( z[0]=='<' ){
dbda8d6ce9 2007-07-21       drh:     n = markupLength(z);
dbda8d6ce9 2007-07-21       drh:     if( n>0 ){
dbda8d6ce9 2007-07-21       drh:       *pTokenType = TOKEN_MARKUP;
dbda8d6ce9 2007-07-21       drh:       return n;
dbda8d6ce9 2007-07-21       drh:     }else{
dbda8d6ce9 2007-07-21       drh:       *pTokenType = TOKEN_CHARACTER;
dbda8d6ce9 2007-07-21       drh:       return 1;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
e75f9a2ab4 2007-10-28       drh:   if( z[0]=='&' && (p->inVerbatim || !isElement(z)) ){
dbda8d6ce9 2007-07-21       drh:     *pTokenType = TOKEN_CHARACTER;
dbda8d6ce9 2007-07-21       drh:     return 1;
dbda8d6ce9 2007-07-21       drh:   }
e75f9a2ab4 2007-10-28       drh:   if( (p->state & ALLOW_WIKI)!=0 ){
dbda8d6ce9 2007-07-21       drh:     if( z[0]=='\n' ){
dbda8d6ce9 2007-07-21       drh:       n = paragraphBreakLength(z);
dbda8d6ce9 2007-07-21       drh:       if( n>0 ){
dbda8d6ce9 2007-07-21       drh:         *pTokenType = TOKEN_PARAGRAPH;
dbda8d6ce9 2007-07-21       drh:         return n;
dbda8d6ce9 2007-07-21       drh:       }else if( isspace(z[1]) ){
dbda8d6ce9 2007-07-21       drh:         *pTokenType = TOKEN_NEWLINE;
dbda8d6ce9 2007-07-21       drh:         return 1;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:     }
e75f9a2ab4 2007-10-28       drh:     if( (p->state & AT_NEWLINE)!=0 && isspace(z[0]) ){
dbda8d6ce9 2007-07-21       drh:       n = bulletLength(z);
dbda8d6ce9 2007-07-21       drh:       if( n>0 ){
dbda8d6ce9 2007-07-21       drh:         *pTokenType = TOKEN_BULLET;
dbda8d6ce9 2007-07-21       drh:         return n;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       n = enumLength(z);
dbda8d6ce9 2007-07-21       drh:       if( n>0 ){
dbda8d6ce9 2007-07-21       drh:         *pTokenType = TOKEN_ENUM;
dbda8d6ce9 2007-07-21       drh:         return n;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:     }
e75f9a2ab4 2007-10-28       drh:     if( (p->state & AT_PARAGRAPH)!=0 && isspace(z[0]) ){
dbda8d6ce9 2007-07-21       drh:       n = indentLength(z);
dbda8d6ce9 2007-07-21       drh:       if( n>0 ){
dbda8d6ce9 2007-07-21       drh:         *pTokenType = TOKEN_INDENT;
dbda8d6ce9 2007-07-21       drh:         return n;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( z[0]=='[' && (n = linkLength(z))>0 ){
dbda8d6ce9 2007-07-21       drh:       *pTokenType = TOKEN_LINK;
dbda8d6ce9 2007-07-21       drh:       return n;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   *pTokenType = TOKEN_TEXT;
e75f9a2ab4 2007-10-28       drh:   return 1 + textLength(z+1, p->state & ALLOW_WIKI);
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** A single markup is parsed into an instance of the following
dbda8d6ce9 2007-07-21       drh: ** structure.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: typedef struct ParsedMarkup ParsedMarkup;
dbda8d6ce9 2007-07-21       drh: struct ParsedMarkup {
dbda8d6ce9 2007-07-21       drh:   unsigned char endTag;   /* True if </...> instead of <...> */
dbda8d6ce9 2007-07-21       drh:   unsigned char iCode;    /* MARKUP_* */
dbda8d6ce9 2007-07-21       drh:   unsigned char nAttr;    /* Number of attributes */
dbda8d6ce9 2007-07-21       drh:   unsigned short iType;   /* MUTYPE_* */
dbda8d6ce9 2007-07-21       drh:   struct {
dbda8d6ce9 2007-07-21       drh:     unsigned char iCode;     /* ATTR_* */
dbda8d6ce9 2007-07-21       drh:     char *zValue;            /* Argument to this attribute.  Might be NULL */
dbda8d6ce9 2007-07-21       drh:     char cTerm;              /* Original argument termination character */
dbda8d6ce9 2007-07-21       drh:   } aAttr[10];
dbda8d6ce9 2007-07-21       drh: };
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
22c1ac41d4 2007-08-23       drh: ** z[] is an HTML markup element - something that begins with '<'.
22c1ac41d4 2007-08-23       drh: ** Parse this element into the p structure.
22c1ac41d4 2007-08-23       drh: **
22c1ac41d4 2007-08-23       drh: ** The content of z[] might be modified by converting characters
22c1ac41d4 2007-08-23       drh: ** to lowercase and by inserting some "\000" characters.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void parseMarkup(ParsedMarkup *p, char *z){
dbda8d6ce9 2007-07-21       drh:   int i, c;
1bbc5b7e6c 2008-05-16       drh:   int iCode;
dbda8d6ce9 2007-07-21       drh:   char *zTag, *zValue;
dbda8d6ce9 2007-07-21       drh:   int seen = 0;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   if( z[1]=='/' ){
dbda8d6ce9 2007-07-21       drh:     p->endTag = 1;
dbda8d6ce9 2007-07-21       drh:     i = 2;
dbda8d6ce9 2007-07-21       drh:   }else{
dbda8d6ce9 2007-07-21       drh:     p->endTag = 0;
dbda8d6ce9 2007-07-21       drh:     i = 1;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   zTag = &z[i];
dbda8d6ce9 2007-07-21       drh:   while( isalnum(z[i]) ){
dbda8d6ce9 2007-07-21       drh:     z[i] = tolower(z[i]);
dbda8d6ce9 2007-07-21       drh:     i++;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   c = z[i];
dbda8d6ce9 2007-07-21       drh:   z[i] = 0;
dbda8d6ce9 2007-07-21       drh:   p->iCode = findTag(zTag);
dbda8d6ce9 2007-07-21       drh:   p->iType = aMarkup[p->iCode].iType;
dbda8d6ce9 2007-07-21       drh:   p->nAttr = 0;
dbda8d6ce9 2007-07-21       drh:   z[i] = c;
dbda8d6ce9 2007-07-21       drh:   while( isspace(z[i]) ){ i++; }
dbda8d6ce9 2007-07-21       drh:   while( p->nAttr<8 && isalpha(z[i]) ){
dbda8d6ce9 2007-07-21       drh:     zTag = &z[i];
dbda8d6ce9 2007-07-21       drh:     while( isalnum(z[i]) ){
dbda8d6ce9 2007-07-21       drh:       z[i] = tolower(z[i]);
dbda8d6ce9 2007-07-21       drh:       i++;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     c = z[i];
dbda8d6ce9 2007-07-21       drh:     z[i] = 0;
1bbc5b7e6c 2008-05-16       drh:     p->aAttr[p->nAttr].iCode = iCode = findAttr(zTag);
dbda8d6ce9 2007-07-21       drh:     z[i] = c;
dbda8d6ce9 2007-07-21       drh:     while( isspace(z[i]) ){ z++; }
dbda8d6ce9 2007-07-21       drh:     if( z[i]!='=' ){
dbda8d6ce9 2007-07-21       drh:       p->aAttr[p->nAttr].zValue = 0;
dbda8d6ce9 2007-07-21       drh:       p->aAttr[p->nAttr].cTerm = 0;
dbda8d6ce9 2007-07-21       drh:       c = 0;
dbda8d6ce9 2007-07-21       drh:     }else{
dbda8d6ce9 2007-07-21       drh:       i++;
dbda8d6ce9 2007-07-21       drh:       while( isspace(z[i]) ){ z++; }
dbda8d6ce9 2007-07-21       drh:       if( z[i]=='"' ){
dbda8d6ce9 2007-07-21       drh:         i++;
dbda8d6ce9 2007-07-21       drh:         zValue = &z[i];
dbda8d6ce9 2007-07-21       drh:         while( z[i] && z[i]!='"' ){ i++; }
dbda8d6ce9 2007-07-21       drh:       }else{
dbda8d6ce9 2007-07-21       drh:         zValue = &z[i];
dbda8d6ce9 2007-07-21       drh:         while( !isspace(z[i]) && z[i]!='>' ){ z++; }
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       p->aAttr[p->nAttr].zValue = zValue;
dbda8d6ce9 2007-07-21       drh:       p->aAttr[p->nAttr].cTerm = c = z[i];
dbda8d6ce9 2007-07-21       drh:       z[i] = 0;
dbda8d6ce9 2007-07-21       drh:       i++;
dbda8d6ce9 2007-07-21       drh:     }
1bbc5b7e6c 2008-05-16       drh:     if( iCode!=0 && (seen & aAttribute[iCode].iMask)==0 ){
1bbc5b7e6c 2008-05-16       drh:       seen |= aAttribute[iCode].iMask;
dbda8d6ce9 2007-07-21       drh:       p->nAttr++;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( c=='>' ) break;
1bbc5b7e6c 2008-05-16       drh:     while( isspace(z[i]) ){ i++; }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Render markup on the given blob.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void renderMarkup(Blob *pOut, ParsedMarkup *p){
dbda8d6ce9 2007-07-21       drh:   int i;
dbda8d6ce9 2007-07-21       drh:   if( p->endTag ){
dbda8d6ce9 2007-07-21       drh:     blob_appendf(pOut, "</%s>", aMarkup[p->iCode].zName);
dbda8d6ce9 2007-07-21       drh:   }else{
dbda8d6ce9 2007-07-21       drh:     blob_appendf(pOut, "<%s", aMarkup[p->iCode].zName);
dbda8d6ce9 2007-07-21       drh:     for(i=0; i<p->nAttr; i++){
df646a7f4c 2007-10-12       drh:       blob_appendf(pOut, " %s", aAttribute[p->aAttr[i].iCode].zName);
dbda8d6ce9 2007-07-21       drh:       if( p->aAttr[i].zValue ){
dbda8d6ce9 2007-07-21       drh:         blob_appendf(pOut, "=\"%s\"", p->aAttr[i].zValue);
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     blob_append(pOut, ">", 1);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** When the markup was parsed, some "\000" may have been inserted.
dbda8d6ce9 2007-07-21       drh: ** This routine restores to those "\000" values back to their
dbda8d6ce9 2007-07-21       drh: ** original content.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void unparseMarkup(ParsedMarkup *p){
dbda8d6ce9 2007-07-21       drh:   int i, n;
dbda8d6ce9 2007-07-21       drh:   for(i=0; i<p->nAttr; i++){
dbda8d6ce9 2007-07-21       drh:     char *z = p->aAttr[i].zValue;
dbda8d6ce9 2007-07-21       drh:     if( z==0 ) continue;
dbda8d6ce9 2007-07-21       drh:     n = strlen(z);
dbda8d6ce9 2007-07-21       drh:     z[n] = p->aAttr[i].cTerm;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Pop a single element off of the stack.  As the element is popped,
dbda8d6ce9 2007-07-21       drh: ** output its end tag.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void popStack(Renderer *p){
dbda8d6ce9 2007-07-21       drh:   if( p->nStack ){
dbda8d6ce9 2007-07-21       drh:     p->nStack--;
dbda8d6ce9 2007-07-21       drh:     blob_appendf(p->pOut, "</%s>", aMarkup[p->aStack[p->nStack]].zName);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Push a new markup value onto the stack.  Enlarge the stack
dbda8d6ce9 2007-07-21       drh: ** if necessary.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void pushStack(Renderer *p, int elem){
dbda8d6ce9 2007-07-21       drh:   if( p->nStack>=p->nAlloc ){
dbda8d6ce9 2007-07-21       drh:     p->nAlloc = p->nAlloc*2 + 100;
dbda8d6ce9 2007-07-21       drh:     p->aStack = realloc(p->aStack, p->nAlloc);
dbda8d6ce9 2007-07-21       drh:     if( p->aStack==0 ){
dbda8d6ce9 2007-07-21       drh:       fossil_panic("out of memory");
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   p->aStack[p->nStack++] = elem;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Pop the stack until the top-most iTag element is removed.
dbda8d6ce9 2007-07-21       drh: ** If there is no iTag element on the stack, this routine
dbda8d6ce9 2007-07-21       drh: ** is a no-op.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void popStackToTag(Renderer *p, int iTag){
dbda8d6ce9 2007-07-21       drh:   int i;
dbda8d6ce9 2007-07-21       drh:   for(i=p->nStack-1; i>=0 && p->aStack[i]!=iTag; i--){}
dbda8d6ce9 2007-07-21       drh:   if( i<0 ) return;
dbda8d6ce9 2007-07-21       drh:   while( p->nStack>i ){
dbda8d6ce9 2007-07-21       drh:     popStack(p);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Pop the stack until the top-most element of the stack
dbda8d6ce9 2007-07-21       drh: ** is an element that matches the type in iMask.  Return
ab637af752 2007-09-28       drh: ** code of the markup element that is on left on top of the stack.
ab637af752 2007-09-28       drh: ** If the stack does not have an element
dbda8d6ce9 2007-07-21       drh: ** that matches iMask, then leave the stack unchanged and
ab637af752 2007-09-28       drh: ** return false (MARKUP_INVALID).
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static int backupToType(Renderer *p, int iMask){
dbda8d6ce9 2007-07-21       drh:   int i;
dbda8d6ce9 2007-07-21       drh:   for(i=p->nStack-1; i>=0 && (aMarkup[p->aStack[i]].iType&iMask)==0; i--){}
dbda8d6ce9 2007-07-21       drh:   if( i<0 ) return 0;
dbda8d6ce9 2007-07-21       drh:   i++;
dbda8d6ce9 2007-07-21       drh:   while( p->nStack>i ){
dbda8d6ce9 2007-07-21       drh:     popStack(p);
dbda8d6ce9 2007-07-21       drh:   }
ab637af752 2007-09-28       drh:   return p->aStack[i-1];
ab637af752 2007-09-28       drh: }
ab637af752 2007-09-28       drh: 
ab637af752 2007-09-28       drh: /*
c963a7763d 2007-10-13       drh: ** Begin a new paragraph if that something that is needed.
c963a7763d 2007-10-13       drh: */
c963a7763d 2007-10-13       drh: static void startAutoParagraph(Renderer *p){
c963a7763d 2007-10-13       drh:   if( p->wantAutoParagraph==0 ) return;
c963a7763d 2007-10-13       drh:   blob_appendf(p->pOut, "<p>", -1);
c963a7763d 2007-10-13       drh:   pushStack(p, MARKUP_P);
c963a7763d 2007-10-13       drh:   p->wantAutoParagraph = 0;
c963a7763d 2007-10-13       drh:   p->inAutoParagraph = 1;
c963a7763d 2007-10-13       drh: }
c963a7763d 2007-10-13       drh: 
c963a7763d 2007-10-13       drh: /*
c963a7763d 2007-10-13       drh: ** End a paragraph if we are in one.
c963a7763d 2007-10-13       drh: */
c963a7763d 2007-10-13       drh: static void endAutoParagraph(Renderer *p){
c963a7763d 2007-10-13       drh:   if( p->inAutoParagraph ){
c963a7763d 2007-10-13       drh:     popStackToTag(p, MARKUP_P);
c963a7763d 2007-10-13       drh:     p->inAutoParagraph = 0;
c963a7763d 2007-10-13       drh:   }
c963a7763d 2007-10-13       drh: }
c963a7763d 2007-10-13       drh: 
c963a7763d 2007-10-13       drh: /*
f394d84560 2007-11-25       drh: ** If the input string corresponds to an existing baseline,
f394d84560 2007-11-25       drh: ** return true.
f394d84560 2007-11-25       drh: */
f394d84560 2007-11-25       drh: static int is_valid_uuid(const char *z){
f394d84560 2007-11-25       drh:   int n = strlen(z);
f394d84560 2007-11-25       drh:   if( n<4 || n>UUID_SIZE ) return 0;
f394d84560 2007-11-25       drh:   if( !validate16(z, n) ) return 0;
dbda8d6ce9 2007-07-21       drh:   return 1;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
d57de28756 2008-05-05       drh: ** Return true if the given hyperlink should be implemented for
d57de28756 2008-05-05       drh: ** the current login.
dbda8d6ce9 2007-07-21       drh: */
d57de28756 2008-05-05       drh: static int okToHyperlink(const char *zTarget){
d57de28756 2008-05-05       drh:   if( g.okHistory ) return 1;
d57de28756 2008-05-05       drh:   if( strncmp(zTarget, "http:", 5)==0
d57de28756 2008-05-05       drh:    || strncmp(zTarget, "https:", 6)==0
d57de28756 2008-05-05       drh:    || strncmp(zTarget, "ftp:", 4)==0
d57de28756 2008-05-05       drh:    || strncmp(zTarget, "mailto:", 7)==0
d57de28756 2008-05-05       drh:   ){
d57de28756 2008-05-05       drh:     return 1;
d57de28756 2008-05-05       drh:   }
d57de28756 2008-05-05       drh:   if( zTarget[0]=='/' || is_valid_uuid(zTarget) ) return 0;
d57de28756 2008-05-05       drh:   if( wiki_name_is_wellformed(zTarget) ) return 1;
d57de28756 2008-05-05       drh:   return 0;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Resolve a hyperlink.  The argument is the content of the [...]
b2e55c0d4d 2007-09-01       drh: ** in the wiki.  Append the URL to the output of the Renderer.
dbda8d6ce9 2007-07-21       drh: */
b2e55c0d4d 2007-09-01       drh: static void resolveHyperlink(const char *zTarget, Renderer *p){
55dc2abc60 2007-09-24       jnc:   if( strncmp(zTarget, "http:", 5)==0
55dc2abc60 2007-09-24       jnc:    || strncmp(zTarget, "https:", 6)==0
55dc2abc60 2007-09-24       jnc:    || strncmp(zTarget, "ftp:", 4)==0
55dc2abc60 2007-09-24       jnc:    || strncmp(zTarget, "mailto:", 7)==0
55dc2abc60 2007-09-24       jnc:   ){
55dc2abc60 2007-09-24       jnc:     blob_appendf(p->pOut, zTarget);
50a58adb76 2007-10-10       drh:   }else if( zTarget[0]=='/' ){
50a58adb76 2007-10-10       drh:     blob_appendf(p->pOut, "%s%h", g.zBaseURL, zTarget);
f394d84560 2007-11-25       drh:   }else if( is_valid_uuid(zTarget) ){
f394d84560 2007-11-25       drh:     blob_appendf(p->pOut, "%s/info/%s", g.zBaseURL, zTarget);
488afb9746 2007-10-06       drh:   }else if( wiki_name_is_wellformed(zTarget) ){
421a1e1fa4 2007-10-27       drh:     blob_appendf(p->pOut, "%s/wiki?name=%T", g.zBaseURL, zTarget);
55dc2abc60 2007-09-24       jnc:   }else{
488afb9746 2007-10-06       drh:     blob_appendf(p->pOut, "error");
55dc2abc60 2007-09-24       jnc:   }
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Check to see if the given parsed markup is the correct
dbda8d6ce9 2007-07-21       drh: ** </verbatim> tag.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static int endVerbatim(Renderer *p, ParsedMarkup *pMarkup){
dbda8d6ce9 2007-07-21       drh:   char *z;
dbda8d6ce9 2007-07-21       drh:   assert( p->inVerbatim );
dbda8d6ce9 2007-07-21       drh:   if( pMarkup->iCode!=MARKUP_VERBATIM ) return 0;
dbda8d6ce9 2007-07-21       drh:   if( !pMarkup->endTag ) return 0;
dbda8d6ce9 2007-07-21       drh:   if( p->zVerbatimId==0 ) return 1;
dbda8d6ce9 2007-07-21       drh:   if( pMarkup->nAttr!=1 ) return 0;
dbda8d6ce9 2007-07-21       drh:   z = pMarkup->aAttr[0].zValue;
dbda8d6ce9 2007-07-21       drh:   return strcmp(z, p->zVerbatimId)==0;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Return the MUTYPE for the top of the stack.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static int stackTopType(Renderer *p){
dbda8d6ce9 2007-07-21       drh:   if( p->nStack<=0 ) return 0;
dbda8d6ce9 2007-07-21       drh:   return aMarkup[p->aStack[p->nStack-1]].iType;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Convert the wiki in z[] into html in the renderer p.  The
dbda8d6ce9 2007-07-21       drh: ** renderer has already been initialized.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** This routine will probably modify the content of z[].
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void wiki_render(Renderer *p, char *z){
dbda8d6ce9 2007-07-21       drh:   int tokenType;
dbda8d6ce9 2007-07-21       drh:   ParsedMarkup markup;
dbda8d6ce9 2007-07-21       drh:   int n;
ebb2765954 2007-12-04       drh:   int inlineOnly = (p->state & INLINE_MARKUP_ONLY)!=0;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   while( z[0] ){
e75f9a2ab4 2007-10-28       drh:     n = nextToken(z, p, &tokenType);
dbda8d6ce9 2007-07-21       drh:     p->state &= ~(AT_NEWLINE|AT_PARAGRAPH);
dbda8d6ce9 2007-07-21       drh:     switch( tokenType ){
dbda8d6ce9 2007-07-21       drh:       case TOKEN_PARAGRAPH: {
ebb2765954 2007-12-04       drh:         if( inlineOnly ){
ebb2765954 2007-12-04       drh:           /* blob_append(p->pOut, " &para; ", -1); */
ebb2765954 2007-12-04       drh:           blob_append(p->pOut, " &nbsp;&nbsp; ", -1);
ebb2765954 2007-12-04       drh:         }else{
ebb2765954 2007-12-04       drh:           if( p->wikiList ){
ebb2765954 2007-12-04       drh:             popStackToTag(p, p->wikiList);
ebb2765954 2007-12-04       drh:             p->wikiList = 0;
ebb2765954 2007-12-04       drh:           }
ebb2765954 2007-12-04       drh:           endAutoParagraph(p);
ebb2765954 2007-12-04       drh:           blob_appendf(p->pOut, "\n\n", 1);
ebb2765954 2007-12-04       drh:           p->wantAutoParagraph = 1;
ab637af752 2007-09-28       drh:         }
c963a7763d 2007-10-13       drh:         p->state |= AT_PARAGRAPH|AT_NEWLINE;
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       case TOKEN_NEWLINE: {
dbda8d6ce9 2007-07-21       drh:         blob_append(p->pOut, "\n", 1);
dbda8d6ce9 2007-07-21       drh:         p->state |= AT_NEWLINE;
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       case TOKEN_BULLET: {
ebb2765954 2007-12-04       drh:         if( inlineOnly ){
ebb2765954 2007-12-04       drh:           blob_append(p->pOut, " &#149; ", -1);
ebb2765954 2007-12-04       drh:         }else{
ebb2765954 2007-12-04       drh:           if( p->wikiList!=MARKUP_UL ){
ebb2765954 2007-12-04       drh:             if( p->wikiList ){
ebb2765954 2007-12-04       drh:               popStackToTag(p, p->wikiList);
ebb2765954 2007-12-04       drh:             }
ebb2765954 2007-12-04       drh:             pushStack(p, MARKUP_UL);
ebb2765954 2007-12-04       drh:             blob_append(p->pOut, "<ul>", 4);
ebb2765954 2007-12-04       drh:             p->wikiList = MARKUP_UL;
ab637af752 2007-09-28       drh:           }
ebb2765954 2007-12-04       drh:           popStackToTag(p, MARKUP_LI);
ebb2765954 2007-12-04       drh:           startAutoParagraph(p);
ebb2765954 2007-12-04       drh:           pushStack(p, MARKUP_LI);
ebb2765954 2007-12-04       drh:           blob_append(p->pOut, "<li>", 4);
ebb2765954 2007-12-04       drh:         }
ab637af752 2007-09-28       drh:         break;
ab637af752 2007-09-28       drh:       }
ab637af752 2007-09-28       drh:       case TOKEN_ENUM: {
ebb2765954 2007-12-04       drh:         if( inlineOnly ){
ebb2765954 2007-12-04       drh:           blob_appendf(p->pOut, " (%d) ", atoi(z));
ebb2765954 2007-12-04       drh:         }else{
ebb2765954 2007-12-04       drh:           if( p->wikiList!=MARKUP_OL ){
ebb2765954 2007-12-04       drh:             if( p->wikiList ){
ebb2765954 2007-12-04       drh:               popStackToTag(p, p->wikiList);
ebb2765954 2007-12-04       drh:             }
ebb2765954 2007-12-04       drh:             pushStack(p, MARKUP_OL);
ebb2765954 2007-12-04       drh:             blob_append(p->pOut, "<ol>", 4);
ebb2765954 2007-12-04       drh:             p->wikiList = MARKUP_OL;
ab637af752 2007-09-28       drh:           }
ebb2765954 2007-12-04       drh:           popStackToTag(p, MARKUP_LI);
ebb2765954 2007-12-04       drh:           startAutoParagraph(p);
ebb2765954 2007-12-04       drh:           pushStack(p, MARKUP_LI);
ebb2765954 2007-12-04       drh:           blob_appendf(p->pOut, "<li value=\"%d\">", atoi(z));
dbda8d6ce9 2007-07-21       drh:         }
ab637af752 2007-09-28       drh:         break;
ab637af752 2007-09-28       drh:       }
ab637af752 2007-09-28       drh:       case TOKEN_INDENT: {
ebb2765954 2007-12-04       drh:         if( inlineOnly ){
ebb2765954 2007-12-04       drh:           assert( p->wikiList==0 );
ebb2765954 2007-12-04       drh:           pushStack(p, MARKUP_BLOCKQUOTE);
ebb2765954 2007-12-04       drh:           blob_append(p->pOut, "<blockquote>", -1);
ebb2765954 2007-12-04       drh:           p->wantAutoParagraph = 0;
ebb2765954 2007-12-04       drh:           p->wikiList = MARKUP_BLOCKQUOTE;
ebb2765954 2007-12-04       drh:         }
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       case TOKEN_CHARACTER: {
c963a7763d 2007-10-13       drh:         startAutoParagraph(p);
dbda8d6ce9 2007-07-21       drh:         if( z[0]=='<' ){
dbda8d6ce9 2007-07-21       drh:           blob_append(p->pOut, "&lt;", 4);
dbda8d6ce9 2007-07-21       drh:         }else if( z[0]=='&' ){
dbda8d6ce9 2007-07-21       drh:           blob_append(p->pOut, "&amp;", 5);
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       case TOKEN_LINK: {
dbda8d6ce9 2007-07-21       drh:         char *zTarget;
dbda8d6ce9 2007-07-21       drh:         char *zDisplay = 0;
488afb9746 2007-10-06       drh:         int i, j;
dbda8d6ce9 2007-07-21       drh:         int savedState;
d57de28756 2008-05-05       drh:         int ok;
c963a7763d 2007-10-13       drh:         startAutoParagraph(p);
dbda8d6ce9 2007-07-21       drh:         zTarget = &z[1];
dbda8d6ce9 2007-07-21       drh:         for(i=1; z[i] && z[i]!=']'; i++){
dbda8d6ce9 2007-07-21       drh:           if( z[i]=='|' && zDisplay==0 ){
dbda8d6ce9 2007-07-21       drh:             zDisplay = &z[i+1];
dbda8d6ce9 2007-07-21       drh:             z[i] = 0;
488afb9746 2007-10-06       drh:             for(j=i-1; j>0 && isspace(z[j]); j--){ z[j] = 0; }
dbda8d6ce9 2007-07-21       drh:           }
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         z[i] = 0;
dbda8d6ce9 2007-07-21       drh:         if( zDisplay==0 ){
dbda8d6ce9 2007-07-21       drh:           zDisplay = zTarget;
dbda8d6ce9 2007-07-21       drh:         }else{
dbda8d6ce9 2007-07-21       drh:           while( isspace(*zDisplay) ) zDisplay++;
dbda8d6ce9 2007-07-21       drh:         }
d57de28756 2008-05-05       drh:         ok = okToHyperlink(zTarget);
d57de28756 2008-05-05       drh:         if( ok ){
d57de28756 2008-05-05       drh:           blob_append(p->pOut, "<a href=\"", -1);
d57de28756 2008-05-05       drh:           resolveHyperlink(zTarget, p);
d57de28756 2008-05-05       drh:           blob_append(p->pOut, "\">", -1);
d57de28756 2008-05-05       drh:         }
dbda8d6ce9 2007-07-21       drh:         savedState = p->state;
dbda8d6ce9 2007-07-21       drh:         p->state &= ~ALLOW_WIKI;
dbda8d6ce9 2007-07-21       drh:         p->state |= FONT_MARKUP_ONLY;
dbda8d6ce9 2007-07-21       drh:         wiki_render(p, zDisplay);
dbda8d6ce9 2007-07-21       drh:         p->state = savedState;
d57de28756 2008-05-05       drh:         if( ok ) blob_append(p->pOut, "</a>", 4);
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       case TOKEN_TEXT: {
c963a7763d 2007-10-13       drh:         startAutoParagraph(p);
dbda8d6ce9 2007-07-21       drh:         blob_append(p->pOut, z, n);
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       case TOKEN_MARKUP: {
dbda8d6ce9 2007-07-21       drh:         parseMarkup(&markup, z);
dbda8d6ce9 2007-07-21       drh:         if( p->inVerbatim ){
dbda8d6ce9 2007-07-21       drh:           if( endVerbatim(p, &markup) ){
dbda8d6ce9 2007-07-21       drh:             p->inVerbatim = 0;
dbda8d6ce9 2007-07-21       drh:             p->state = p->preVerbState;
dbda8d6ce9 2007-07-21       drh:             blob_append(p->pOut, "</pre>", 6);
dbda8d6ce9 2007-07-21       drh:           }else{
dbda8d6ce9 2007-07-21       drh:             unparseMarkup(&markup);
dbda8d6ce9 2007-07-21       drh:             blob_append(p->pOut, "&lt;", 4);
dbda8d6ce9 2007-07-21       drh:             n = 1;
dbda8d6ce9 2007-07-21       drh:           }
dbda8d6ce9 2007-07-21       drh:         }else if( markup.iCode==MARKUP_INVALID ){
c963a7763d 2007-10-13       drh:           unparseMarkup(&markup);
c963a7763d 2007-10-13       drh:           startAutoParagraph(p);
dbda8d6ce9 2007-07-21       drh:           blob_append(p->pOut, "&lt;", 4);
dbda8d6ce9 2007-07-21       drh:           n = 1;
dbda8d6ce9 2007-07-21       drh:         }else if( (markup.iType&MUTYPE_FONT)==0
dbda8d6ce9 2007-07-21       drh:                     && (p->state & FONT_MARKUP_ONLY)!=0 ){
dbda8d6ce9 2007-07-21       drh:           /* Do nothing */
ebb2765954 2007-12-04       drh:         }else if( inlineOnly && (markup.iType&MUTYPE_INLINE)==0 ){
e75f9a2ab4 2007-10-28       drh:           /* Do nothing */
dbda8d6ce9 2007-07-21       drh:         }else if( markup.iCode==MARKUP_NOWIKI ){
dbda8d6ce9 2007-07-21       drh:           if( markup.endTag ){
dbda8d6ce9 2007-07-21       drh:             p->state |= ALLOW_WIKI;
dbda8d6ce9 2007-07-21       drh:           }else{
e75f9a2ab4 2007-10-28       drh:             p->state &= ~ALLOW_WIKI;
dbda8d6ce9 2007-07-21       drh:           }
dbda8d6ce9 2007-07-21       drh:         }else if( markup.endTag ){
dbda8d6ce9 2007-07-21       drh:           popStackToTag(p, markup.iCode);
dbda8d6ce9 2007-07-21       drh:         }else if( markup.iCode==MARKUP_VERBATIM ){
dbda8d6ce9 2007-07-21       drh:           if( markup.nAttr==1 ){
dbda8d6ce9 2007-07-21       drh:             p->zVerbatimId = markup.aAttr[0].zValue;
dbda8d6ce9 2007-07-21       drh:           }else{
dbda8d6ce9 2007-07-21       drh:             p->zVerbatimId = 0;
dbda8d6ce9 2007-07-21       drh:           }
dbda8d6ce9 2007-07-21       drh:           p->inVerbatim = 1;
dbda8d6ce9 2007-07-21       drh:           p->preVerbState = p->state;
dbda8d6ce9 2007-07-21       drh:           p->state &= ~ALLOW_WIKI;
dbda8d6ce9 2007-07-21       drh:           blob_append(p->pOut, "<pre>", 5);
c963a7763d 2007-10-13       drh:           p->wantAutoParagraph = 0;
dbda8d6ce9 2007-07-21       drh:         }else if( markup.iType==MUTYPE_LI ){
dbda8d6ce9 2007-07-21       drh:           if( backupToType(p, MUTYPE_LIST)==0 ){
dbda8d6ce9 2007-07-21       drh:             pushStack(p, MARKUP_UL);
dbda8d6ce9 2007-07-21       drh:             blob_append(p->pOut, "<ul>", 4);
dbda8d6ce9 2007-07-21       drh:           }
dbda8d6ce9 2007-07-21       drh:           pushStack(p, MARKUP_LI);
dbda8d6ce9 2007-07-21       drh:           renderMarkup(p->pOut, &markup);
dbda8d6ce9 2007-07-21       drh:         }else if( markup.iType==MUTYPE_TR ){
dbda8d6ce9 2007-07-21       drh:           if( backupToType(p, MUTYPE_TABLE) ){
dbda8d6ce9 2007-07-21       drh:             pushStack(p, MARKUP_TR);
dbda8d6ce9 2007-07-21       drh:             renderMarkup(p->pOut, &markup);
dbda8d6ce9 2007-07-21       drh:           }
dbda8d6ce9 2007-07-21       drh:         }else if( markup.iType==MUTYPE_TD ){
dbda8d6ce9 2007-07-21       drh:           if( backupToType(p, MUTYPE_TABLE|MUTYPE_TR) ){
dbda8d6ce9 2007-07-21       drh:             if( stackTopType(p)==MUTYPE_TABLE ){
dbda8d6ce9 2007-07-21       drh:               pushStack(p, MARKUP_TR);
dbda8d6ce9 2007-07-21       drh:               blob_append(p->pOut, "<tr>", 4);
dbda8d6ce9 2007-07-21       drh:             }
dbda8d6ce9 2007-07-21       drh:             pushStack(p, markup.iCode);
dbda8d6ce9 2007-07-21       drh:             renderMarkup(p->pOut, &markup);
dbda8d6ce9 2007-07-21       drh:           }
c963a7763d 2007-10-13       drh:         }else if( markup.iType==MUTYPE_HYPERLINK ){
c963a7763d 2007-10-13       drh:           popStackToTag(p, markup.iCode);
c963a7763d 2007-10-13       drh:           startAutoParagraph(p);
c963a7763d 2007-10-13       drh:           renderMarkup(p->pOut, &markup);
c963a7763d 2007-10-13       drh:           pushStack(p, markup.iCode);
dbda8d6ce9 2007-07-21       drh:         }else{
c963a7763d 2007-10-13       drh:           if( markup.iType==MUTYPE_FONT ){
c963a7763d 2007-10-13       drh:             startAutoParagraph(p);
c963a7763d 2007-10-13       drh:           }else if( markup.iType==MUTYPE_BLOCK ){
c963a7763d 2007-10-13       drh:             p->wantAutoParagraph = 0;
c963a7763d 2007-10-13       drh:           }
dbda8d6ce9 2007-07-21       drh:           if( (markup.iType & MUTYPE_STACK )!=0 ){
dbda8d6ce9 2007-07-21       drh:             pushStack(p, markup.iCode);
dbda8d6ce9 2007-07-21       drh:           }
dbda8d6ce9 2007-07-21       drh:           renderMarkup(p->pOut, &markup);
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     z += n;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Transform the text in the pIn blob.  Write the results
dbda8d6ce9 2007-07-21       drh: ** into the pOut blob.  The pOut blob should already be
dbda8d6ce9 2007-07-21       drh: ** initialized.  The output is merely appended to pOut.
ab637af752 2007-09-28       drh: ** If pOut is NULL, then the output is appended to the CGI
ab637af752 2007-09-28       drh: ** reply.
dbda8d6ce9 2007-07-21       drh: */
c963a7763d 2007-10-13       drh: void wiki_convert(Blob *pIn, Blob *pOut, int flags){
4c82c7773f 2007-08-30       drh:   char *z;
dbda8d6ce9 2007-07-21       drh:   Renderer renderer;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   memset(&renderer, 0, sizeof(renderer));
dbda8d6ce9 2007-07-21       drh:   renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH;
ebb2765954 2007-12-04       drh:   if( flags & WIKI_NOBLOCK ){
ebb2765954 2007-12-04       drh:     renderer.state |= INLINE_MARKUP_ONLY;
ebb2765954 2007-12-04       drh:   }
ebb2765954 2007-12-04       drh:   if( flags & WIKI_INLINE ){
ebb2765954 2007-12-04       drh:     renderer.wantAutoParagraph = 0;
ebb2765954 2007-12-04       drh:   }else{
ebb2765954 2007-12-04       drh:     renderer.wantAutoParagraph = 1;
ebb2765954 2007-12-04       drh:   }
ab637af752 2007-09-28       drh:   if( pOut ){
ab637af752 2007-09-28       drh:     renderer.pOut = pOut;
ab637af752 2007-09-28       drh:   }else{
ab637af752 2007-09-28       drh:     renderer.pOut = cgi_output_blob();
ab637af752 2007-09-28       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   z = blob_str(pIn);
dbda8d6ce9 2007-07-21       drh:   wiki_render(&renderer, z);
8f423ad438 2007-10-21       drh:   endAutoParagraph(&renderer);
dbda8d6ce9 2007-07-21       drh:   while( renderer.nStack ){
dbda8d6ce9 2007-07-21       drh:     popStack(&renderer);
dbda8d6ce9 2007-07-21       drh:   }
bf428e6854 2007-10-06       drh:   blob_append(renderer.pOut, "\n", 1);
dbda8d6ce9 2007-07-21       drh:   free(renderer.aStack);
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** COMMAND: test-wiki-render
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: void test_wiki_render(void){
dbda8d6ce9 2007-07-21       drh:   Blob in, out;
dbda8d6ce9 2007-07-21       drh:   if( g.argc!=3 ) usage("FILE");
dbda8d6ce9 2007-07-21       drh:   blob_zero(&out);
dbda8d6ce9 2007-07-21       drh:   blob_read_from_file(&in, g.argv[2]);
c963a7763d 2007-10-13       drh:   wiki_convert(&in, &out, 0);
dbda8d6ce9 2007-07-21       drh:   blob_write_to_file(&out, "-");
dbda8d6ce9 2007-07-21       drh: }