@@ -32,43 +32,47 @@
** Allowed wiki transformation operations
*/
#define WIKI_NOFOLLOW 0x001
#define WIKI_HTML 0x002
+#define WIKI_INLINE 0x004 /* Do not surround with <p>..</p> */
+#define WIKI_NOBLOCK 0x008 /* No block markup of any kind */
#endif
/*
** These are the only markup attributes allowed.
*/
-#define ATTR_ALIGN 0x000001
-#define ATTR_ALT 0x000002
-#define ATTR_BGCOLOR 0x000004
-#define ATTR_BORDER 0x000008
-#define ATTR_CELLPADDING 0x000010
-#define ATTR_CELLSPACING 0x000020
-#define ATTR_CLEAR 0x000040
-#define ATTR_COLOR 0x000080
-#define ATTR_COLSPAN 0x000100
-#define ATTR_COMPACT 0x000200
-#define ATTR_FACE 0x000400
-#define ATTR_HEIGHT 0x000800
-#define ATTR_HREF 0x001000
-#define ATTR_HSPACE 0x002000
-#define ATTR_ID 0x004000
-#define ATTR_ROWSPAN 0x008000
-#define ATTR_SIZE 0x010000
-#define ATTR_SRC 0x020000
-#define ATTR_START 0x040000
-#define ATTR_TYPE 0x080000
-#define ATTR_VALIGN 0x100000
-#define ATTR_VALUE 0x200000
-#define ATTR_VSPACE 0x400000
-#define ATTR_WIDTH 0x800000
+#define ATTR_ALIGN 0x0000001
+#define ATTR_ALT 0x0000002
+#define ATTR_BGCOLOR 0x0000004
+#define ATTR_BORDER 0x0000008
+#define ATTR_CELLPADDING 0x0000010
+#define ATTR_CELLSPACING 0x0000020
+#define ATTR_CLEAR 0x0000040
+#define ATTR_COLOR 0x0000080
+#define ATTR_COLSPAN 0x0000100
+#define ATTR_COMPACT 0x0000200
+#define ATTR_FACE 0x0000400
+#define ATTR_HEIGHT 0x0000800
+#define ATTR_HREF 0x0001000
+#define ATTR_HSPACE 0x0002000
+#define ATTR_ID 0x0004000
+#define ATTR_NAME 0x0008000
+#define ATTR_ROWSPAN 0x0010000
+#define ATTR_SIZE 0x0020000
+#define ATTR_SRC 0x0040000
+#define ATTR_START 0x0080000
+#define ATTR_TYPE 0x0100000
+#define ATTR_VALIGN 0x0200000
+#define ATTR_VALUE 0x0400000
+#define ATTR_VSPACE 0x0800000
+#define ATTR_WIDTH 0x1000000
static const struct AllowedAttribute {
const char *zName;
unsigned int iMask;
} aAttribute[] = {
+ { 0, 0 },
{ "align", ATTR_ALIGN, },
{ "alt", ATTR_ALT, },
{ "bgcolor", ATTR_BGCOLOR, },
{ "border", ATTR_BORDER, },
@@ -82,8 +86,9 @@
{ "height", ATTR_HEIGHT, },
{ "href", ATTR_HREF, },
{ "hspace", ATTR_HSPACE, },
{ "id", ATTR_ID, },
+ { "name", ATTR_NAME, },
{ "rowspan", ATTR_ROWSPAN, },
{ "size", ATTR_SIZE, },
{ "src", ATTR_SRC, },
{ "start", ATTR_START, },
@@ -98,15 +103,15 @@
** Use binary search to locate a tag in the aAttribute[] table.
*/
static int findAttr(const char *z){
int i, c, first, last;
- first = 0;
+ first = 1;
last = sizeof(aAttribute)/sizeof(aAttribute[0]) - 1;
while( first<=last ){
i = (first+last)/2;
c = strcmp(aAttribute[i].zName, z);
if( c==0 ){
- return aAttribute[i].iMask;
+ return i;
}else if( c<0 ){
first = i+1;
}else{
last = i-1;
@@ -124,64 +129,63 @@
** 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 255
-#define MARKUP_A 0
-#define MARKUP_ADDRESS 1
-#define MARKUP_BIG 2
-#define MARKUP_BLOCKQUOTE 3
-#define MARKUP_B 4
-#define MARKUP_BR 5
-#define MARKUP_CENTER 6
-#define MARKUP_CITE 7
-#define MARKUP_CODE 8
-#define MARKUP_DD 9
-#define MARKUP_DFN 10
-#define MARKUP_DL 11
-#define MARKUP_DT 12
-#define MARKUP_EM 13
-#define MARKUP_FONT 14
-#define MARKUP_H1 15
-#define MARKUP_H2 16
-#define MARKUP_H3 17
-#define MARKUP_H4 18
-#define MARKUP_H5 19
-#define MARKUP_H6 20
-#define MARKUP_HR 21
-#define MARKUP_IMG 22
-#define MARKUP_I 23
-#define MARKUP_KBD 24
-#define MARKUP_LI 25
-#define MARKUP_NOBR 26
-#define MARKUP_NOWIKI 27
-#define MARKUP_OL 28
-#define MARKUP_P 29
-#define MARKUP_PRE 30
-#define MARKUP_SAMP 31
-#define MARKUP_SMALL 32
-#define MARKUP_S 33
-#define MARKUP_STRIKE 34
-#define MARKUP_STRONG 35
-#define MARKUP_SUB 36
-#define MARKUP_SUP 37
-#define MARKUP_TABLE 38
-#define MARKUP_TD 39
-#define MARKUP_TH 40
-#define MARKUP_TR 41
-#define MARKUP_TT 42
-#define MARKUP_UL 43
+#define MARKUP_INVALID 0
+#define MARKUP_A 1
+#define MARKUP_ADDRESS 2
+#define MARKUP_B 3
+#define MARKUP_BIG 4
+#define MARKUP_BLOCKQUOTE 5
+#define MARKUP_BR 6
+#define MARKUP_CENTER 7
+#define MARKUP_CITE 8
+#define MARKUP_CODE 9
+#define MARKUP_DD 10
+#define MARKUP_DFN 11
+#define MARKUP_DL 12
+#define MARKUP_DT 13
+#define MARKUP_EM 14
+#define MARKUP_FONT 15
+#define MARKUP_H1 16
+#define MARKUP_H2 17
+#define MARKUP_H3 18
+#define MARKUP_H4 19
+#define MARKUP_H5 20
+#define MARKUP_H6 21
+#define MARKUP_HR 22
+#define MARKUP_IMG 23
+#define MARKUP_I 24
+#define MARKUP_KBD 25
+#define MARKUP_LI 26
+#define MARKUP_NOBR 27
+#define MARKUP_NOWIKI 28
+#define MARKUP_OL 29
+#define MARKUP_P 30
+#define MARKUP_PRE 31
+#define MARKUP_S 32
+#define MARKUP_SAMP 33
+#define MARKUP_SMALL 34
+#define MARKUP_STRIKE 35
+#define MARKUP_STRONG 36
+#define MARKUP_SUB 37
+#define MARKUP_SUP 38
+#define MARKUP_TABLE 39
+#define MARKUP_TD 40
+#define MARKUP_TH 41
+#define MARKUP_TR 42
+#define MARKUP_TT 43
#define MARKUP_U 44
-#define MARKUP_VAR 45
-#define MARKUP_VERBATIM 46
+#define MARKUP_UL 45
+#define MARKUP_VAR 46
+#define MARKUP_VERBATIM 47
/*
** 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> */
-#define MUTYPE_LINK 0x0008 /* Hyperlink: <a> */
#define MUTYPE_LIST 0x0010 /* Lists. <ol>, <ul>, or <dl> */
#define MUTYPE_LI 0x0020 /* List items. <li>, <dd>, <dt> */
#define MUTYPE_TABLE 0x0040 /* <table> */
#define MUTYPE_TR 0x0080 /* <tr> */
@@ -188,21 +192,31 @@
#define MUTYPE_TD 0x0100 /* <td> or <th> */
#define MUTYPE_SPECIAL 0x0200 /* <nowiki> or <verbatim> */
#define MUTYPE_HYPERLINK 0x0400 /* <a> */
+/*
+** These markup types must have an end tag.
+*/
#define MUTYPE_STACK (MUTYPE_BLOCK | MUTYPE_FONT | MUTYPE_LIST | MUTYPE_TABLE)
+
+/*
+** This markup types are allowed for "inline" text.
+*/
+#define MUTYPE_INLINE (MUTYPE_FONT | MUTYPE_HYPERLINK)
static const struct AllowedMarkup {
const char *zName; /* Name of the markup */
char iCode; /* The MARKUP_* code */
short int iType; /* The MUTYPE_* code */
int allowedAttr; /* Allowed attributes on this markup */
} aMarkup[] = {
- { "a", MARKUP_A, MUTYPE_HYPERLINK, ATTR_HREF },
+ { 0, MARKUP_INVALID, 0, 0 },
+ { "a", MARKUP_A, MUTYPE_HYPERLINK,
+ ATTR_HREF|ATTR_NAME },
{ "address", MARKUP_ADDRESS, MUTYPE_BLOCK, 0 },
+ { "b", MARKUP_B, MUTYPE_FONT, 0 },
{ "big", MARKUP_BIG, MUTYPE_FONT, 0 },
{ "blockquote", MARKUP_BLOCKQUOTE, MUTYPE_BLOCK, 0 },
- { "b", MARKUP_B, MUTYPE_FONT, 0 },
{ "br", MARKUP_BR, MUTYPE_SINGLE, ATTR_CLEAR },
{ "center", MARKUP_CENTER, MUTYPE_BLOCK, 0 },
{ "cite", MARKUP_CITE, MUTYPE_FONT, 0 },
{ "code", MARKUP_CODE, MUTYPE_FONT, 0 },
@@ -233,11 +247,11 @@
{ "ol", MARKUP_OL, MUTYPE_LIST,
ATTR_START|ATTR_TYPE|ATTR_COMPACT },
{ "p", MARKUP_P, MUTYPE_BLOCK, ATTR_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 },
- { "s", MARKUP_S, 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 },
@@ -252,11 +266,11 @@
ATTR_ROWSPAN|ATTR_VALIGN },
{ "tr", MARKUP_TR, MUTYPE_TR,
ATTR_ALIGN|ATTR_BGCOLOR||ATTR_VALIGN },
{ "tt", MARKUP_TT, MUTYPE_FONT, 0 },
+ { "u", MARKUP_U, MUTYPE_FONT, 0 },
{ "ul", MARKUP_UL, MUTYPE_LIST,
ATTR_TYPE|ATTR_COMPACT },
- { "u", MARKUP_U, MUTYPE_FONT, 0 },
{ "var", MARKUP_VAR, MUTYPE_FONT, 0 },
{ "verbatim", MARKUP_VERBATIM, MUTYPE_SPECIAL, ATTR_ID },
};
@@ -264,9 +278,9 @@
** Use binary search to locate a tag in the aMarkup[] table.
*/
static int findTag(const char *z){
int i, c, first, last;
- first = 0;
+ first = 1;
last = sizeof(aMarkup)/sizeof(aMarkup[0]) - 1;
while( first<=last ){
i = (first+last)/2;
c = strcmp(aMarkup[i].zName, z);
@@ -297,13 +311,33 @@
/*
** 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 */
-#define FONT_MARKUP_ONLY 0x008 /* Only allow MUTYPE_FONT markup */
-#define IN_LIST 0x010 /* Within <ul> */
+#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 */
+#define FONT_MARKUP_ONLY 0x008 /* Only allow MUTYPE_FONT markup */
+#define INLINE_MARKUP_ONLY 0x010 /* Allow only "inline" markup */
+#define IN_LIST 0x020 /* Within wiki <ul> or <ol> */
+
+/*
+** Current state of the rendering engine
+*/
+typedef struct Renderer Renderer;
+struct Renderer {
+ Blob *pOut; /* Output appended to this blob */
+ int state; /* Flag that govern rendering */
+ int wikiList; /* Current wiki list type */
+ int inVerbatim; /* True in <verbatim> mode */
+ int preVerbState; /* Value of state prior to verbatim */
+ int wantAutoParagraph; /* True if a <p> is desired */
+ int inAutoParagraph; /* True if within an automatic paragraph */
+ const char *zVerbatimId; /* The id= attribute of <verbatim> */
+ int nStack; /* Number of elements on the stack */
+ int nAlloc; /* Space allocated for aStack */
+ unsigned char *aStack; /* Open markup stack */
+};
+
/*
** z points to a "<" character. Check to see if this is the start of
** a valid markup. If it is, return the total number of characters in
@@ -314,9 +348,9 @@
int n = 1;
int inparen = 0;
if( z[n]=='/' ){ n++; }
if( !isalpha(z[n]) ) return 0;
- while( isalpha(z[n]) ){ n++; }
+ while( isalnum(z[n]) ){ n++; }
if( z[n]!='>' && !isspace(z[n]) ) return 0;
while( z[n] && (z[n]!='>' || inparen) ){
if( z[n]=='"' ){
inparen = !inparen;
@@ -413,8 +447,44 @@
return n;
}
/*
+** Check to see if the z[] string is the beginning of a enumeration value.
+** If it is, return the length of the bullet text. Otherwise return 0.
+**
+** Syntax:
+** * a tab or two or more spaces
+** * one or more digits
+** * optional "."
+** * another tab or two ore more spaces.
+**
+*/
+static int enumLength(const char *z){
+ int i, n;
+ n = 0;
+ i = 0;
+ while( z[n]==' ' || z[n]=='\t' ){
+ if( z[n]=='\t' ) i++;
+ i++;
+ n++;
+ }
+ if( i<2 ) return 0;
+ for(i=0; isdigit(z[n]); i++, n++){}
+ if( i==0 ) return 0;
+ if( z[n]=='.' ){
+ n++;
+ }
+ i = 0;
+ while( z[n]==' ' || z[n]=='\t' ){
+ if( z[n]=='\t' ) i++;
+ i++;
+ n++;
+ }
+ if( i<2 || isspace(z[n]) ) return 0;
+ return n;
+}
+
+/*
** Check to see if the z[] string is the beginning of an indented
** paragraph. If it is, return the length of the indent. Otherwise
** return 0.
*/
@@ -450,9 +520,9 @@
/*
** 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, int state, int *pTokenType){
+static int nextToken(const char *z, Renderer *p, int *pTokenType){
int n;
if( z[0]=='<' ){
n = markupLength(z);
if( n>0 ){
@@ -462,13 +532,13 @@
*pTokenType = TOKEN_CHARACTER;
return 1;
}
}
- if( z[0]=='&' && !isElement(z) ){
+ if( z[0]=='&' && (p->inVerbatim || !isElement(z)) ){
*pTokenType = TOKEN_CHARACTER;
return 1;
}
- if( (state & ALLOW_WIKI)!=0 ){
+ if( (p->state & ALLOW_WIKI)!=0 ){
if( z[0]=='\n' ){
n = paragraphBreakLength(z);
if( n>0 ){
*pTokenType = TOKEN_PARAGRAPH;
@@ -477,24 +547,21 @@
*pTokenType = TOKEN_NEWLINE;
return 1;
}
}
- if( (state & AT_NEWLINE)!=0 /* && (state & (AT_PARAGRAPH|IN_LIST))!=0 */
- && isspace(z[0]) ){
+ if( (p->state & AT_NEWLINE)!=0 && isspace(z[0]) ){
n = bulletLength(z);
if( n>0 ){
*pTokenType = TOKEN_BULLET;
return n;
}
-#if 0
n = enumLength(z);
if( n>0 ){
*pTokenType = TOKEN_ENUM;
return n;
}
-#endif
}
- if( (state & AT_PARAGRAPH)!=0 && isspace(z[0]) ){
+ if( (p->state & AT_PARAGRAPH)!=0 && isspace(z[0]) ){
n = indentLength(z);
if( n>0 ){
*pTokenType = TOKEN_INDENT;
return n;
@@ -505,9 +572,9 @@
return n;
}
}
*pTokenType = TOKEN_TEXT;
- return 1 + textLength(z+1, state & ALLOW_WIKI);
+ return 1 + textLength(z+1, p->state & ALLOW_WIKI);
}
/*
** A single markup is parsed into an instance of the following
@@ -605,9 +672,9 @@
blob_appendf(pOut, "</%s>", aMarkup[p->iCode].zName);
}else{
blob_appendf(pOut, "<%s", aMarkup[p->iCode].zName);
for(i=0; i<p->nAttr; i++){
- blob_appendf(pOut, " %s", aAttribute[p->aAttr[i].iCode]);
+ blob_appendf(pOut, " %s", aAttribute[p->aAttr[i].iCode].zName);
if( p->aAttr[i].zValue ){
blob_appendf(pOut, "=\"%s\"", p->aAttr[i].zValue);
}
}
@@ -628,23 +695,8 @@
n = strlen(z);
z[n] = p->aAttr[i].cTerm;
}
}
-
-/*
-** Current state of the rendering engine
-*/
-typedef struct Renderer Renderer;
-struct Renderer {
- Blob *pOut; /* Output appended to this blob */
- int state; /* Flag that govern rendering */
- int inVerbatim; /* True in <verbatim> mode */
- int preVerbState; /* Value of state prior to verbatim */
- const char *zVerbatimId; /* The id= attribute of <verbatim> */
- int nStack; /* Number of elements on the stack */
- int nAlloc; /* Space allocated for aStack */
- unsigned char *aStack; /* Open markup stack */
-};
/*
** Pop a single element off of the stack. As the element is popped,
** output its end tag.
@@ -687,11 +739,12 @@
/*
** Pop the stack until the top-most element of the stack
** is an element that matches the type in iMask. Return
-** true on success. If the stack does not have an element
+** code of the markup element that is on left on top of the stack.
+** If the stack does not have an element
** that matches iMask, then leave the stack unchanged and
-** return false.
+** return false (MARKUP_INVALID).
*/
static int backupToType(Renderer *p, int iMask){
int i;
for(i=p->nStack-1; i>=0 && (aMarkup[p->aStack[i]].iType&iMask)==0; i--){}
@@ -699,27 +752,63 @@
i++;
while( p->nStack>i ){
popStack(p);
}
- return 1;
+ return p->aStack[i-1];
+}
+
+/*
+** Begin a new paragraph if that something that is needed.
+*/
+static void startAutoParagraph(Renderer *p){
+ if( p->wantAutoParagraph==0 ) return;
+ blob_appendf(p->pOut, "<p>", -1);
+ pushStack(p, MARKUP_P);
+ p->wantAutoParagraph = 0;
+ p->inAutoParagraph = 1;
+}
+
+/*
+** End a paragraph if we are in one.
+*/
+static void endAutoParagraph(Renderer *p){
+ if( p->inAutoParagraph ){
+ popStackToTag(p, MARKUP_P);
+ p->inAutoParagraph = 0;
+ }
}
/*
-** Add missing markup in preparation for writing text.
-**
-** "Missing" markup are things like start tags for table rows
-** or table columns or paragraphs that are omitted from input.
+** If the input string corresponds to an existing baseline,
+** return true.
*/
-static void addMissingMarkup(Renderer *p){
- /* TBD */
+static int is_valid_uuid(const char *z){
+ int n = strlen(z);
+ if( n<4 || n>UUID_SIZE ) return 0;
+ if( !validate16(z, n) ) return 0;
+ return 1;
}
/*
** Resolve a hyperlink. The argument is the content of the [...]
** in the wiki. Append the URL to the output of the Renderer.
*/
static void resolveHyperlink(const char *zTarget, Renderer *p){
- blob_appendf(p->pOut, "http://www.fossil-scm.org/test-%T", zTarget);
+ 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, zTarget);
+ }else if( zTarget[0]=='/' ){
+ blob_appendf(p->pOut, "%s%h", g.zBaseURL, zTarget);
+ }else if( is_valid_uuid(zTarget) ){
+ blob_appendf(p->pOut, "%s/info/%s", g.zBaseURL, zTarget);
+ }else if( wiki_name_is_wellformed(zTarget) ){
+ blob_appendf(p->pOut, "%s/wiki?name=%T", g.zBaseURL, zTarget);
+ }else{
+ blob_appendf(p->pOut, "error");
+ }
}
/*
** Check to see if the given parsed markup is the correct
@@ -753,17 +842,28 @@
static void wiki_render(Renderer *p, char *z){
int tokenType;
ParsedMarkup markup;
int n;
+ int inlineOnly = (p->state & INLINE_MARKUP_ONLY)!=0;
while( z[0] ){
- n = nextToken(z, p->state, &tokenType);
+ n = nextToken(z, p, &tokenType);
p->state &= ~(AT_NEWLINE|AT_PARAGRAPH);
switch( tokenType ){
case TOKEN_PARAGRAPH: {
- blob_append(p->pOut, "\n\n<p>", -1);
- p->state |= AT_PARAGRAPH|AT_NEWLINE;
- popStackToTag(p, MARKUP_P);
+ if( inlineOnly ){
+ /* blob_append(p->pOut, " ¶ ", -1); */
+ blob_append(p->pOut, " ", -1);
+ }else{
+ if( p->wikiList ){
+ popStackToTag(p, p->wikiList);
+ p->wikiList = 0;
+ }
+ endAutoParagraph(p);
+ blob_appendf(p->pOut, "\n\n", 1);
+ p->wantAutoParagraph = 1;
+ }
+ p->state |= AT_PARAGRAPH|AT_NEWLINE;
break;
}
case TOKEN_NEWLINE: {
blob_append(p->pOut, "\n", 1);
@@ -770,17 +870,57 @@
p->state |= AT_NEWLINE;
break;
}
case TOKEN_BULLET: {
- if( backupToType(p, MUTYPE_LIST)==0 ){
- pushStack(p, MARKUP_UL);
- blob_append(p->pOut, "<ul>", 4);
+ if( inlineOnly ){
+ blob_append(p->pOut, " • ", -1);
+ }else{
+ if( p->wikiList!=MARKUP_UL ){
+ if( p->wikiList ){
+ popStackToTag(p, p->wikiList);
+ }
+ pushStack(p, MARKUP_UL);
+ blob_append(p->pOut, "<ul>", 4);
+ p->wikiList = MARKUP_UL;
+ }
+ popStackToTag(p, MARKUP_LI);
+ startAutoParagraph(p);
+ pushStack(p, MARKUP_LI);
+ blob_append(p->pOut, "<li>", 4);
+ }
+ break;
+ }
+ case TOKEN_ENUM: {
+ if( inlineOnly ){
+ blob_appendf(p->pOut, " (%d) ", atoi(z));
+ }else{
+ if( p->wikiList!=MARKUP_OL ){
+ if( p->wikiList ){
+ popStackToTag(p, p->wikiList);
+ }
+ pushStack(p, MARKUP_OL);
+ blob_append(p->pOut, "<ol>", 4);
+ p->wikiList = MARKUP_OL;
+ }
+ popStackToTag(p, MARKUP_LI);
+ startAutoParagraph(p);
+ pushStack(p, MARKUP_LI);
+ blob_appendf(p->pOut, "<li value=\"%d\">", atoi(z));
}
- pushStack(p, MARKUP_LI);
- blob_append(p->pOut, "<li>", 4);
+ break;
+ }
+ case TOKEN_INDENT: {
+ if( inlineOnly ){
+ assert( p->wikiList==0 );
+ pushStack(p, MARKUP_BLOCKQUOTE);
+ blob_append(p->pOut, "<blockquote>", -1);
+ p->wantAutoParagraph = 0;
+ p->wikiList = MARKUP_BLOCKQUOTE;
+ }
break;
}
case TOKEN_CHARACTER: {
+ startAutoParagraph(p);
if( z[0]=='<' ){
blob_append(p->pOut, "<", 4);
}else if( z[0]=='&' ){
blob_append(p->pOut, "&", 5);
@@ -789,16 +929,17 @@
}
case TOKEN_LINK: {
char *zTarget;
char *zDisplay = 0;
- int i;
+ int i, j;
int savedState;
- addMissingMarkup(p);
+ startAutoParagraph(p);
zTarget = &z[1];
for(i=1; z[i] && z[i]!=']'; i++){
if( z[i]=='|' && zDisplay==0 ){
zDisplay = &z[i+1];
z[i] = 0;
+ for(j=i-1; j>0 && isspace(z[j]); j--){ z[j] = 0; }
}
}
z[i] = 0;
if( zDisplay==0 ){
@@ -817,9 +958,9 @@
blob_append(p->pOut, "</a>", 4);
break;
}
case TOKEN_TEXT: {
- addMissingMarkup(p);
+ startAutoParagraph(p);
blob_append(p->pOut, z, n);
break;
}
case TOKEN_MARKUP: {
@@ -834,18 +975,22 @@
blob_append(p->pOut, "<", 4);
n = 1;
}
}else if( markup.iCode==MARKUP_INVALID ){
+ unparseMarkup(&markup);
+ startAutoParagraph(p);
blob_append(p->pOut, "<", 4);
n = 1;
}else if( (markup.iType&MUTYPE_FONT)==0
&& (p->state & FONT_MARKUP_ONLY)!=0 ){
/* Do nothing */
+ }else if( inlineOnly && (markup.iType&MUTYPE_INLINE)==0 ){
+ /* Do nothing */
}else if( markup.iCode==MARKUP_NOWIKI ){
if( markup.endTag ){
p->state |= ALLOW_WIKI;
}else{
- p->state &= ALLOW_WIKI;
+ p->state &= ~ALLOW_WIKI;
}
}else if( markup.endTag ){
popStackToTag(p, markup.iCode);
}else if( markup.iCode==MARKUP_VERBATIM ){
@@ -857,8 +1002,9 @@
p->inVerbatim = 1;
p->preVerbState = p->state;
p->state &= ~ALLOW_WIKI;
blob_append(p->pOut, "<pre>", 5);
+ p->wantAutoParagraph = 0;
}else if( markup.iType==MUTYPE_LI ){
if( backupToType(p, MUTYPE_LIST)==0 ){
pushStack(p, MARKUP_UL);
blob_append(p->pOut, "<ul>", 4);
@@ -878,9 +1024,19 @@
}
pushStack(p, markup.iCode);
renderMarkup(p->pOut, &markup);
}
+ }else if( markup.iType==MUTYPE_HYPERLINK ){
+ popStackToTag(p, markup.iCode);
+ startAutoParagraph(p);
+ renderMarkup(p->pOut, &markup);
+ pushStack(p, markup.iCode);
}else{
+ if( markup.iType==MUTYPE_FONT ){
+ startAutoParagraph(p);
+ }else if( markup.iType==MUTYPE_BLOCK ){
+ p->wantAutoParagraph = 0;
+ }
if( (markup.iType & MUTYPE_STACK )!=0 ){
pushStack(p, markup.iCode);
}
renderMarkup(p->pOut, &markup);
@@ -896,41 +1052,40 @@
/*
** Transform the text in the pIn blob. Write the results
** into the pOut blob. The pOut blob should already be
** initialized. The output is merely appended to pOut.
-**
-** The transformations carried out depend on the ops flag:
-**
-** WIKI_NOFOLLOW
-**
-** * Add the nofollow attribute to external links
-**
-** WIKI_HTML
-**
-** * Convert wiki into HTML
-** * Remove <nowiki> and <verbatium>
-** * Convert & into &
-** * Unrecognized markup and markup within <verbatim>
-** is converted into <...>
-** * Unauthorized attributes on markup are removed
+** If pOut is NULL, then the output is appended to the CGI
+** reply.
*/
-void wiki_convert(Blob *pIn, Blob *pOut, int ops){
+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;
- renderer.pOut = pOut;
+ if( flags & WIKI_NOBLOCK ){
+ renderer.state |= INLINE_MARKUP_ONLY;
+ }
+ if( flags & WIKI_INLINE ){
+ renderer.wantAutoParagraph = 0;
+ }else{
+ renderer.wantAutoParagraph = 1;
+ }
+ if( pOut ){
+ renderer.pOut = pOut;
+ }else{
+ renderer.pOut = cgi_output_blob();
+ }
z = blob_str(pIn);
wiki_render(&renderer, z);
+ endAutoParagraph(&renderer);
while( renderer.nStack ){
popStack(&renderer);
}
- blob_append(pOut, "\n", 1);
+ blob_append(renderer.pOut, "\n", 1);
free(renderer.aStack);
}
-
/*
** COMMAND: test-wiki-render
*/
@@ -938,7 +1093,7 @@
Blob in, out;
if( g.argc!=3 ) usage("FILE");
blob_zero(&out);
blob_read_from_file(&in, g.argv[2]);
- wiki_convert(&in, &out, WIKI_HTML);
+ wiki_convert(&in, &out, 0);
blob_write_to_file(&out, "-");
}