Fossil SCM

Much improved wiki rendering. Automatic paragraph tags now match correctly. All tags should balance.

drh 2007-10-13 01:18 UTC trunk
Commit c963a7763d96836b4f407a837718c14bf391ec08
+1 -1
--- src/timeline.c
+++ src/timeline.c
@@ -161,11 +161,11 @@
161161
}
162162
}else{
163163
hyperlink_to_uuid(zUuid);
164164
}
165165
db_column_blob(pQuery, 3, &comment);
166
- wiki_convert(&comment, 0);
166
+ wiki_convert(&comment, 0, WIKI_INLINE);
167167
blob_reset(&comment);
168168
@ (by %h(zUser))</td></tr>
169169
}
170170
@ </table>
171171
}
172172
--- src/timeline.c
+++ src/timeline.c
@@ -161,11 +161,11 @@
161 }
162 }else{
163 hyperlink_to_uuid(zUuid);
164 }
165 db_column_blob(pQuery, 3, &comment);
166 wiki_convert(&comment, 0);
167 blob_reset(&comment);
168 @ (by %h(zUser))</td></tr>
169 }
170 @ </table>
171 }
172
--- src/timeline.c
+++ src/timeline.c
@@ -161,11 +161,11 @@
161 }
162 }else{
163 hyperlink_to_uuid(zUuid);
164 }
165 db_column_blob(pQuery, 3, &comment);
166 wiki_convert(&comment, 0, WIKI_INLINE);
167 blob_reset(&comment);
168 @ (by %h(zUser))</td></tr>
169 }
170 @ </table>
171 }
172
+3 -3
--- src/wiki.c
+++ src/wiki.c
@@ -146,11 +146,11 @@
146146
mprintf("%s/whistory?name=%T", g.zTop, zPageName));
147147
}
148148
zHtmlPageName = mprintf("%h", zPageName);
149149
style_header(zHtmlPageName);
150150
blob_init(&wiki, zBody, -1);
151
- wiki_convert(&wiki, 0);
151
+ wiki_convert(&wiki, 0, 0);
152152
blob_reset(&wiki);
153153
manifest_clear(&m);
154154
style_footer();
155155
}
156156
@@ -238,11 +238,11 @@
238238
style_header(zHtmlPageName);
239239
if( P("preview")!=0 ){
240240
blob_zero(&wiki);
241241
blob_append(&wiki, zBody, -1);
242242
@ Preview:<hr>
243
- wiki_convert(&wiki, 0);
243
+ wiki_convert(&wiki, 0, 0);
244244
@ <hr>
245245
blob_reset(&wiki);
246246
}
247247
for(n=2, z=zBody; z[0]; z++){
248248
if( z[0]=='\n' ) n++;
@@ -363,11 +363,11 @@
363363
if( P("preview")!=0 ){
364364
Blob preview;
365365
blob_zero(&preview);
366366
appendRemark(&preview);
367367
@ Preview:<hr>
368
- wiki_convert(&preview, 0);
368
+ wiki_convert(&preview, 0, 0);
369369
@ <hr>
370370
blob_reset(&preview);
371371
}
372372
zUser = PD("u", g.zLogin);
373373
@ <form method="POST" action="%s(g.zBaseURL)/wikiappend">
374374
--- src/wiki.c
+++ src/wiki.c
@@ -146,11 +146,11 @@
146 mprintf("%s/whistory?name=%T", g.zTop, zPageName));
147 }
148 zHtmlPageName = mprintf("%h", zPageName);
149 style_header(zHtmlPageName);
150 blob_init(&wiki, zBody, -1);
151 wiki_convert(&wiki, 0);
152 blob_reset(&wiki);
153 manifest_clear(&m);
154 style_footer();
155 }
156
@@ -238,11 +238,11 @@
238 style_header(zHtmlPageName);
239 if( P("preview")!=0 ){
240 blob_zero(&wiki);
241 blob_append(&wiki, zBody, -1);
242 @ Preview:<hr>
243 wiki_convert(&wiki, 0);
244 @ <hr>
245 blob_reset(&wiki);
246 }
247 for(n=2, z=zBody; z[0]; z++){
248 if( z[0]=='\n' ) n++;
@@ -363,11 +363,11 @@
363 if( P("preview")!=0 ){
364 Blob preview;
365 blob_zero(&preview);
366 appendRemark(&preview);
367 @ Preview:<hr>
368 wiki_convert(&preview, 0);
369 @ <hr>
370 blob_reset(&preview);
371 }
372 zUser = PD("u", g.zLogin);
373 @ <form method="POST" action="%s(g.zBaseURL)/wikiappend">
374
--- src/wiki.c
+++ src/wiki.c
@@ -146,11 +146,11 @@
146 mprintf("%s/whistory?name=%T", g.zTop, zPageName));
147 }
148 zHtmlPageName = mprintf("%h", zPageName);
149 style_header(zHtmlPageName);
150 blob_init(&wiki, zBody, -1);
151 wiki_convert(&wiki, 0, 0);
152 blob_reset(&wiki);
153 manifest_clear(&m);
154 style_footer();
155 }
156
@@ -238,11 +238,11 @@
238 style_header(zHtmlPageName);
239 if( P("preview")!=0 ){
240 blob_zero(&wiki);
241 blob_append(&wiki, zBody, -1);
242 @ Preview:<hr>
243 wiki_convert(&wiki, 0, 0);
244 @ <hr>
245 blob_reset(&wiki);
246 }
247 for(n=2, z=zBody; z[0]; z++){
248 if( z[0]=='\n' ) n++;
@@ -363,11 +363,11 @@
363 if( P("preview")!=0 ){
364 Blob preview;
365 blob_zero(&preview);
366 appendRemark(&preview);
367 @ Preview:<hr>
368 wiki_convert(&preview, 0, 0);
369 @ <hr>
370 blob_reset(&preview);
371 }
372 zUser = PD("u", g.zLogin);
373 @ <form method="POST" action="%s(g.zBaseURL)/wikiappend">
374
+80 -39
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -31,40 +31,42 @@
3131
/*
3232
** Allowed wiki transformation operations
3333
*/
3434
#define WIKI_NOFOLLOW 0x001
3535
#define WIKI_HTML 0x002
36
+#define WIKI_INLINE 0x004 /* Do not surround with <p>..</p> */
3637
#endif
3738
3839
3940
/*
4041
** These are the only markup attributes allowed.
4142
*/
42
-#define ATTR_ALIGN 0x000001
43
-#define ATTR_ALT 0x000002
44
-#define ATTR_BGCOLOR 0x000004
45
-#define ATTR_BORDER 0x000008
46
-#define ATTR_CELLPADDING 0x000010
47
-#define ATTR_CELLSPACING 0x000020
48
-#define ATTR_CLEAR 0x000040
49
-#define ATTR_COLOR 0x000080
50
-#define ATTR_COLSPAN 0x000100
51
-#define ATTR_COMPACT 0x000200
52
-#define ATTR_FACE 0x000400
53
-#define ATTR_HEIGHT 0x000800
54
-#define ATTR_HREF 0x001000
55
-#define ATTR_HSPACE 0x002000
56
-#define ATTR_ID 0x004000
57
-#define ATTR_ROWSPAN 0x008000
58
-#define ATTR_SIZE 0x010000
59
-#define ATTR_SRC 0x020000
60
-#define ATTR_START 0x040000
61
-#define ATTR_TYPE 0x080000
62
-#define ATTR_VALIGN 0x100000
63
-#define ATTR_VALUE 0x200000
64
-#define ATTR_VSPACE 0x400000
65
-#define ATTR_WIDTH 0x800000
43
+#define ATTR_ALIGN 0x0000001
44
+#define ATTR_ALT 0x0000002
45
+#define ATTR_BGCOLOR 0x0000004
46
+#define ATTR_BORDER 0x0000008
47
+#define ATTR_CELLPADDING 0x0000010
48
+#define ATTR_CELLSPACING 0x0000020
49
+#define ATTR_CLEAR 0x0000040
50
+#define ATTR_COLOR 0x0000080
51
+#define ATTR_COLSPAN 0x0000100
52
+#define ATTR_COMPACT 0x0000200
53
+#define ATTR_FACE 0x0000400
54
+#define ATTR_HEIGHT 0x0000800
55
+#define ATTR_HREF 0x0001000
56
+#define ATTR_HSPACE 0x0002000
57
+#define ATTR_ID 0x0004000
58
+#define ATTR_NAME 0x0008000
59
+#define ATTR_ROWSPAN 0x0010000
60
+#define ATTR_SIZE 0x0020000
61
+#define ATTR_SRC 0x0040000
62
+#define ATTR_START 0x0080000
63
+#define ATTR_TYPE 0x0100000
64
+#define ATTR_VALIGN 0x0200000
65
+#define ATTR_VALUE 0x0400000
66
+#define ATTR_VSPACE 0x0800000
67
+#define ATTR_WIDTH 0x1000000
6668
6769
static const struct AllowedAttribute {
6870
const char *zName;
6971
unsigned int iMask;
7072
} aAttribute[] = {
@@ -82,10 +84,11 @@
8284
{ "face", ATTR_FACE, },
8385
{ "height", ATTR_HEIGHT, },
8486
{ "href", ATTR_HREF, },
8587
{ "hspace", ATTR_HSPACE, },
8688
{ "id", ATTR_ID, },
89
+ { "name", ATTR_NAME, },
8790
{ "rowspan", ATTR_ROWSPAN, },
8891
{ "size", ATTR_SIZE, },
8992
{ "src", ATTR_SRC, },
9093
{ "start", ATTR_START, },
9194
{ "type", ATTR_TYPE, },
@@ -179,29 +182,32 @@
179182
** The various markup is divided into the following types:
180183
*/
181184
#define MUTYPE_SINGLE 0x0001 /* <img>, <br>, or <hr> */
182185
#define MUTYPE_BLOCK 0x0002 /* Forms a new paragraph. ex: <p>, <h2> */
183186
#define MUTYPE_FONT 0x0004 /* Font changes. ex: <b>, <font>, <sub> */
184
-#define MUTYPE_LINK 0x0008 /* Hyperlink: <a> */
185187
#define MUTYPE_LIST 0x0010 /* Lists. <ol>, <ul>, or <dl> */
186188
#define MUTYPE_LI 0x0020 /* List items. <li>, <dd>, <dt> */
187189
#define MUTYPE_TABLE 0x0040 /* <table> */
188190
#define MUTYPE_TR 0x0080 /* <tr> */
189191
#define MUTYPE_TD 0x0100 /* <td> or <th> */
190192
#define MUTYPE_SPECIAL 0x0200 /* <nowiki> or <verbatim> */
191193
#define MUTYPE_HYPERLINK 0x0400 /* <a> */
192194
195
+/*
196
+** These markup types must have an end tag.
197
+*/
193198
#define MUTYPE_STACK (MUTYPE_BLOCK | MUTYPE_FONT | MUTYPE_LIST | MUTYPE_TABLE)
194199
195200
static const struct AllowedMarkup {
196201
const char *zName; /* Name of the markup */
197202
char iCode; /* The MARKUP_* code */
198203
short int iType; /* The MUTYPE_* code */
199204
int allowedAttr; /* Allowed attributes on this markup */
200205
} aMarkup[] = {
201206
{ 0, MARKUP_INVALID, 0, 0 },
202
- { "a", MARKUP_A, MUTYPE_HYPERLINK, ATTR_HREF },
207
+ { "a", MARKUP_A, MUTYPE_HYPERLINK,
208
+ ATTR_HREF|ATTR_NAME },
203209
{ "address", MARKUP_ADDRESS, MUTYPE_BLOCK, 0 },
204210
{ "b", MARKUP_B, MUTYPE_FONT, 0 },
205211
{ "big", MARKUP_BIG, MUTYPE_FONT, 0 },
206212
{ "blockquote", MARKUP_BLOCKQUOTE, MUTYPE_BLOCK, 0 },
207213
{ "br", MARKUP_BR, MUTYPE_SINGLE, ATTR_CLEAR },
@@ -314,10 +320,12 @@
314320
Blob *pOut; /* Output appended to this blob */
315321
int state; /* Flag that govern rendering */
316322
int wikiList; /* Current wiki list type */
317323
int inVerbatim; /* True in <verbatim> mode */
318324
int preVerbState; /* Value of state prior to verbatim */
325
+ int wantAutoParagraph; /* True if a <p> is desired */
326
+ int inAutoParagraph; /* True if within an automatic paragraph */
319327
const char *zVerbatimId; /* The id= attribute of <verbatim> */
320328
int nStack; /* Number of elements on the stack */
321329
int nAlloc; /* Space allocated for aStack */
322330
unsigned char *aStack; /* Open markup stack */
323331
};
@@ -438,11 +446,11 @@
438446
**
439447
** Syntax:
440448
** * a tab or two or more spaces
441449
** * one or more digits
442450
** * optional "."
443
-** * another tab or two or more additional spaces
451
+** * another tab or two ore more spaces.
444452
**
445453
*/
446454
static int enumLength(const char *z){
447455
int i, n;
448456
n = 0;
@@ -741,17 +749,28 @@
741749
}
742750
return p->aStack[i-1];
743751
}
744752
745753
/*
746
-** Add missing markup in preparation for writing text.
747
-**
748
-** "Missing" markup are things like start tags for table rows
749
-** or table columns or paragraphs that are omitted from input.
754
+** Begin a new paragraph if that something that is needed.
755
+*/
756
+static void startAutoParagraph(Renderer *p){
757
+ if( p->wantAutoParagraph==0 ) return;
758
+ blob_appendf(p->pOut, "<p>", -1);
759
+ pushStack(p, MARKUP_P);
760
+ p->wantAutoParagraph = 0;
761
+ p->inAutoParagraph = 1;
762
+}
763
+
764
+/*
765
+** End a paragraph if we are in one.
750766
*/
751
-static void addMissingMarkup(Renderer *p){
752
- /* TBD */
767
+static void endAutoParagraph(Renderer *p){
768
+ if( p->inAutoParagraph ){
769
+ popStackToTag(p, MARKUP_P);
770
+ p->inAutoParagraph = 0;
771
+ }
753772
}
754773
755774
/*
756775
** Resolve a hyperlink. The argument is the content of the [...]
757776
** in the wiki. Append the URL to the output of the Renderer.
@@ -813,13 +832,14 @@
813832
case TOKEN_PARAGRAPH: {
814833
if( p->wikiList ){
815834
popStackToTag(p, p->wikiList);
816835
p->wikiList = 0;
817836
}
818
- blob_append(p->pOut, "\n\n<p>", -1);
837
+ endAutoParagraph(p);
838
+ blob_appendf(p->pOut, "\n\n", 1);
839
+ p->wantAutoParagraph = 1;
819840
p->state |= AT_PARAGRAPH|AT_NEWLINE;
820
- popStackToTag(p, MARKUP_P);
821841
break;
822842
}
823843
case TOKEN_NEWLINE: {
824844
blob_append(p->pOut, "\n", 1);
825845
p->state |= AT_NEWLINE;
@@ -832,10 +852,12 @@
832852
}
833853
pushStack(p, MARKUP_UL);
834854
blob_append(p->pOut, "<ul>", 4);
835855
p->wikiList = MARKUP_UL;
836856
}
857
+ popStackToTag(p, MARKUP_LI);
858
+ startAutoParagraph(p);
837859
pushStack(p, MARKUP_LI);
838860
blob_append(p->pOut, "<li>", 4);
839861
break;
840862
}
841863
case TOKEN_ENUM: {
@@ -845,22 +867,26 @@
845867
}
846868
pushStack(p, MARKUP_OL);
847869
blob_append(p->pOut, "<ol>", 4);
848870
p->wikiList = MARKUP_OL;
849871
}
872
+ popStackToTag(p, MARKUP_LI);
873
+ startAutoParagraph(p);
850874
pushStack(p, MARKUP_LI);
851875
blob_appendf(p->pOut, "<li value=\"%d\">", atoi(z));
852876
break;
853877
}
854878
case TOKEN_INDENT: {
855879
assert( p->wikiList==0 );
856880
pushStack(p, MARKUP_BLOCKQUOTE);
857881
blob_append(p->pOut, "<blockquote>", -1);
882
+ p->wantAutoParagraph = 0;
858883
p->wikiList = MARKUP_BLOCKQUOTE;
859884
break;
860885
}
861886
case TOKEN_CHARACTER: {
887
+ startAutoParagraph(p);
862888
if( z[0]=='<' ){
863889
blob_append(p->pOut, "&lt;", 4);
864890
}else if( z[0]=='&' ){
865891
blob_append(p->pOut, "&amp;", 5);
866892
}
@@ -869,11 +895,11 @@
869895
case TOKEN_LINK: {
870896
char *zTarget;
871897
char *zDisplay = 0;
872898
int i, j;
873899
int savedState;
874
- addMissingMarkup(p);
900
+ startAutoParagraph(p);
875901
zTarget = &z[1];
876902
for(i=1; z[i] && z[i]!=']'; i++){
877903
if( z[i]=='|' && zDisplay==0 ){
878904
zDisplay = &z[i+1];
879905
z[i] = 0;
@@ -896,11 +922,11 @@
896922
p->state = savedState;
897923
blob_append(p->pOut, "</a>", 4);
898924
break;
899925
}
900926
case TOKEN_TEXT: {
901
- addMissingMarkup(p);
927
+ startAutoParagraph(p);
902928
blob_append(p->pOut, z, n);
903929
break;
904930
}
905931
case TOKEN_MARKUP: {
906932
parseMarkup(&markup, z);
@@ -913,10 +939,12 @@
913939
unparseMarkup(&markup);
914940
blob_append(p->pOut, "&lt;", 4);
915941
n = 1;
916942
}
917943
}else if( markup.iCode==MARKUP_INVALID ){
944
+ unparseMarkup(&markup);
945
+ startAutoParagraph(p);
918946
blob_append(p->pOut, "&lt;", 4);
919947
n = 1;
920948
}else if( (markup.iType&MUTYPE_FONT)==0
921949
&& (p->state & FONT_MARKUP_ONLY)!=0 ){
922950
/* Do nothing */
@@ -936,10 +964,11 @@
936964
}
937965
p->inVerbatim = 1;
938966
p->preVerbState = p->state;
939967
p->state &= ~ALLOW_WIKI;
940968
blob_append(p->pOut, "<pre>", 5);
969
+ p->wantAutoParagraph = 0;
941970
}else if( markup.iType==MUTYPE_LI ){
942971
if( backupToType(p, MUTYPE_LIST)==0 ){
943972
pushStack(p, MARKUP_UL);
944973
blob_append(p->pOut, "<ul>", 4);
945974
}
@@ -957,11 +986,21 @@
957986
blob_append(p->pOut, "<tr>", 4);
958987
}
959988
pushStack(p, markup.iCode);
960989
renderMarkup(p->pOut, &markup);
961990
}
991
+ }else if( markup.iType==MUTYPE_HYPERLINK ){
992
+ popStackToTag(p, markup.iCode);
993
+ startAutoParagraph(p);
994
+ renderMarkup(p->pOut, &markup);
995
+ pushStack(p, markup.iCode);
962996
}else{
997
+ if( markup.iType==MUTYPE_FONT ){
998
+ startAutoParagraph(p);
999
+ }else if( markup.iType==MUTYPE_BLOCK ){
1000
+ p->wantAutoParagraph = 0;
1001
+ }
9631002
if( (markup.iType & MUTYPE_STACK )!=0 ){
9641003
pushStack(p, markup.iCode);
9651004
}
9661005
renderMarkup(p->pOut, &markup);
9671006
}
@@ -968,10 +1007,11 @@
9681007
break;
9691008
}
9701009
}
9711010
z += n;
9721011
}
1012
+ endAutoParagraph(p);
9731013
}
9741014
9751015
9761016
/*
9771017
** Transform the text in the pIn blob. Write the results
@@ -978,16 +1018,17 @@
9781018
** into the pOut blob. The pOut blob should already be
9791019
** initialized. The output is merely appended to pOut.
9801020
** If pOut is NULL, then the output is appended to the CGI
9811021
** reply.
9821022
*/
983
-void wiki_convert(Blob *pIn, Blob *pOut){
1023
+void wiki_convert(Blob *pIn, Blob *pOut, int flags){
9841024
char *z;
9851025
Renderer renderer;
9861026
9871027
memset(&renderer, 0, sizeof(renderer));
9881028
renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH;
1029
+ renderer.wantAutoParagraph = (flags & WIKI_INLINE)==0;
9891030
if( pOut ){
9901031
renderer.pOut = pOut;
9911032
}else{
9921033
renderer.pOut = cgi_output_blob();
9931034
}
@@ -1007,8 +1048,8 @@
10071048
void test_wiki_render(void){
10081049
Blob in, out;
10091050
if( g.argc!=3 ) usage("FILE");
10101051
blob_zero(&out);
10111052
blob_read_from_file(&in, g.argv[2]);
1012
- wiki_convert(&in, &out);
1053
+ wiki_convert(&in, &out, 0);
10131054
blob_write_to_file(&out, "-");
10141055
}
10151056
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -31,40 +31,42 @@
31 /*
32 ** Allowed wiki transformation operations
33 */
34 #define WIKI_NOFOLLOW 0x001
35 #define WIKI_HTML 0x002
 
36 #endif
37
38
39 /*
40 ** These are the only markup attributes allowed.
41 */
42 #define ATTR_ALIGN 0x000001
43 #define ATTR_ALT 0x000002
44 #define ATTR_BGCOLOR 0x000004
45 #define ATTR_BORDER 0x000008
46 #define ATTR_CELLPADDING 0x000010
47 #define ATTR_CELLSPACING 0x000020
48 #define ATTR_CLEAR 0x000040
49 #define ATTR_COLOR 0x000080
50 #define ATTR_COLSPAN 0x000100
51 #define ATTR_COMPACT 0x000200
52 #define ATTR_FACE 0x000400
53 #define ATTR_HEIGHT 0x000800
54 #define ATTR_HREF 0x001000
55 #define ATTR_HSPACE 0x002000
56 #define ATTR_ID 0x004000
57 #define ATTR_ROWSPAN 0x008000
58 #define ATTR_SIZE 0x010000
59 #define ATTR_SRC 0x020000
60 #define ATTR_START 0x040000
61 #define ATTR_TYPE 0x080000
62 #define ATTR_VALIGN 0x100000
63 #define ATTR_VALUE 0x200000
64 #define ATTR_VSPACE 0x400000
65 #define ATTR_WIDTH 0x800000
 
66
67 static const struct AllowedAttribute {
68 const char *zName;
69 unsigned int iMask;
70 } aAttribute[] = {
@@ -82,10 +84,11 @@
82 { "face", ATTR_FACE, },
83 { "height", ATTR_HEIGHT, },
84 { "href", ATTR_HREF, },
85 { "hspace", ATTR_HSPACE, },
86 { "id", ATTR_ID, },
 
87 { "rowspan", ATTR_ROWSPAN, },
88 { "size", ATTR_SIZE, },
89 { "src", ATTR_SRC, },
90 { "start", ATTR_START, },
91 { "type", ATTR_TYPE, },
@@ -179,29 +182,32 @@
179 ** The various markup is divided into the following types:
180 */
181 #define MUTYPE_SINGLE 0x0001 /* <img>, <br>, or <hr> */
182 #define MUTYPE_BLOCK 0x0002 /* Forms a new paragraph. ex: <p>, <h2> */
183 #define MUTYPE_FONT 0x0004 /* Font changes. ex: <b>, <font>, <sub> */
184 #define MUTYPE_LINK 0x0008 /* Hyperlink: <a> */
185 #define MUTYPE_LIST 0x0010 /* Lists. <ol>, <ul>, or <dl> */
186 #define MUTYPE_LI 0x0020 /* List items. <li>, <dd>, <dt> */
187 #define MUTYPE_TABLE 0x0040 /* <table> */
188 #define MUTYPE_TR 0x0080 /* <tr> */
189 #define MUTYPE_TD 0x0100 /* <td> or <th> */
190 #define MUTYPE_SPECIAL 0x0200 /* <nowiki> or <verbatim> */
191 #define MUTYPE_HYPERLINK 0x0400 /* <a> */
192
 
 
 
193 #define MUTYPE_STACK (MUTYPE_BLOCK | MUTYPE_FONT | MUTYPE_LIST | MUTYPE_TABLE)
194
195 static const struct AllowedMarkup {
196 const char *zName; /* Name of the markup */
197 char iCode; /* The MARKUP_* code */
198 short int iType; /* The MUTYPE_* code */
199 int allowedAttr; /* Allowed attributes on this markup */
200 } aMarkup[] = {
201 { 0, MARKUP_INVALID, 0, 0 },
202 { "a", MARKUP_A, MUTYPE_HYPERLINK, ATTR_HREF },
 
203 { "address", MARKUP_ADDRESS, MUTYPE_BLOCK, 0 },
204 { "b", MARKUP_B, MUTYPE_FONT, 0 },
205 { "big", MARKUP_BIG, MUTYPE_FONT, 0 },
206 { "blockquote", MARKUP_BLOCKQUOTE, MUTYPE_BLOCK, 0 },
207 { "br", MARKUP_BR, MUTYPE_SINGLE, ATTR_CLEAR },
@@ -314,10 +320,12 @@
314 Blob *pOut; /* Output appended to this blob */
315 int state; /* Flag that govern rendering */
316 int wikiList; /* Current wiki list type */
317 int inVerbatim; /* True in <verbatim> mode */
318 int preVerbState; /* Value of state prior to verbatim */
 
 
319 const char *zVerbatimId; /* The id= attribute of <verbatim> */
320 int nStack; /* Number of elements on the stack */
321 int nAlloc; /* Space allocated for aStack */
322 unsigned char *aStack; /* Open markup stack */
323 };
@@ -438,11 +446,11 @@
438 **
439 ** Syntax:
440 ** * a tab or two or more spaces
441 ** * one or more digits
442 ** * optional "."
443 ** * another tab or two or more additional spaces
444 **
445 */
446 static int enumLength(const char *z){
447 int i, n;
448 n = 0;
@@ -741,17 +749,28 @@
741 }
742 return p->aStack[i-1];
743 }
744
745 /*
746 ** Add missing markup in preparation for writing text.
747 **
748 ** "Missing" markup are things like start tags for table rows
749 ** or table columns or paragraphs that are omitted from input.
 
 
 
 
 
 
 
 
750 */
751 static void addMissingMarkup(Renderer *p){
752 /* TBD */
 
 
 
753 }
754
755 /*
756 ** Resolve a hyperlink. The argument is the content of the [...]
757 ** in the wiki. Append the URL to the output of the Renderer.
@@ -813,13 +832,14 @@
813 case TOKEN_PARAGRAPH: {
814 if( p->wikiList ){
815 popStackToTag(p, p->wikiList);
816 p->wikiList = 0;
817 }
818 blob_append(p->pOut, "\n\n<p>", -1);
 
 
819 p->state |= AT_PARAGRAPH|AT_NEWLINE;
820 popStackToTag(p, MARKUP_P);
821 break;
822 }
823 case TOKEN_NEWLINE: {
824 blob_append(p->pOut, "\n", 1);
825 p->state |= AT_NEWLINE;
@@ -832,10 +852,12 @@
832 }
833 pushStack(p, MARKUP_UL);
834 blob_append(p->pOut, "<ul>", 4);
835 p->wikiList = MARKUP_UL;
836 }
 
 
837 pushStack(p, MARKUP_LI);
838 blob_append(p->pOut, "<li>", 4);
839 break;
840 }
841 case TOKEN_ENUM: {
@@ -845,22 +867,26 @@
845 }
846 pushStack(p, MARKUP_OL);
847 blob_append(p->pOut, "<ol>", 4);
848 p->wikiList = MARKUP_OL;
849 }
 
 
850 pushStack(p, MARKUP_LI);
851 blob_appendf(p->pOut, "<li value=\"%d\">", atoi(z));
852 break;
853 }
854 case TOKEN_INDENT: {
855 assert( p->wikiList==0 );
856 pushStack(p, MARKUP_BLOCKQUOTE);
857 blob_append(p->pOut, "<blockquote>", -1);
 
858 p->wikiList = MARKUP_BLOCKQUOTE;
859 break;
860 }
861 case TOKEN_CHARACTER: {
 
862 if( z[0]=='<' ){
863 blob_append(p->pOut, "&lt;", 4);
864 }else if( z[0]=='&' ){
865 blob_append(p->pOut, "&amp;", 5);
866 }
@@ -869,11 +895,11 @@
869 case TOKEN_LINK: {
870 char *zTarget;
871 char *zDisplay = 0;
872 int i, j;
873 int savedState;
874 addMissingMarkup(p);
875 zTarget = &z[1];
876 for(i=1; z[i] && z[i]!=']'; i++){
877 if( z[i]=='|' && zDisplay==0 ){
878 zDisplay = &z[i+1];
879 z[i] = 0;
@@ -896,11 +922,11 @@
896 p->state = savedState;
897 blob_append(p->pOut, "</a>", 4);
898 break;
899 }
900 case TOKEN_TEXT: {
901 addMissingMarkup(p);
902 blob_append(p->pOut, z, n);
903 break;
904 }
905 case TOKEN_MARKUP: {
906 parseMarkup(&markup, z);
@@ -913,10 +939,12 @@
913 unparseMarkup(&markup);
914 blob_append(p->pOut, "&lt;", 4);
915 n = 1;
916 }
917 }else if( markup.iCode==MARKUP_INVALID ){
 
 
918 blob_append(p->pOut, "&lt;", 4);
919 n = 1;
920 }else if( (markup.iType&MUTYPE_FONT)==0
921 && (p->state & FONT_MARKUP_ONLY)!=0 ){
922 /* Do nothing */
@@ -936,10 +964,11 @@
936 }
937 p->inVerbatim = 1;
938 p->preVerbState = p->state;
939 p->state &= ~ALLOW_WIKI;
940 blob_append(p->pOut, "<pre>", 5);
 
941 }else if( markup.iType==MUTYPE_LI ){
942 if( backupToType(p, MUTYPE_LIST)==0 ){
943 pushStack(p, MARKUP_UL);
944 blob_append(p->pOut, "<ul>", 4);
945 }
@@ -957,11 +986,21 @@
957 blob_append(p->pOut, "<tr>", 4);
958 }
959 pushStack(p, markup.iCode);
960 renderMarkup(p->pOut, &markup);
961 }
 
 
 
 
 
962 }else{
 
 
 
 
 
963 if( (markup.iType & MUTYPE_STACK )!=0 ){
964 pushStack(p, markup.iCode);
965 }
966 renderMarkup(p->pOut, &markup);
967 }
@@ -968,10 +1007,11 @@
968 break;
969 }
970 }
971 z += n;
972 }
 
973 }
974
975
976 /*
977 ** Transform the text in the pIn blob. Write the results
@@ -978,16 +1018,17 @@
978 ** into the pOut blob. The pOut blob should already be
979 ** initialized. The output is merely appended to pOut.
980 ** If pOut is NULL, then the output is appended to the CGI
981 ** reply.
982 */
983 void wiki_convert(Blob *pIn, Blob *pOut){
984 char *z;
985 Renderer renderer;
986
987 memset(&renderer, 0, sizeof(renderer));
988 renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH;
 
989 if( pOut ){
990 renderer.pOut = pOut;
991 }else{
992 renderer.pOut = cgi_output_blob();
993 }
@@ -1007,8 +1048,8 @@
1007 void test_wiki_render(void){
1008 Blob in, out;
1009 if( g.argc!=3 ) usage("FILE");
1010 blob_zero(&out);
1011 blob_read_from_file(&in, g.argv[2]);
1012 wiki_convert(&in, &out);
1013 blob_write_to_file(&out, "-");
1014 }
1015
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -31,40 +31,42 @@
31 /*
32 ** Allowed wiki transformation operations
33 */
34 #define WIKI_NOFOLLOW 0x001
35 #define WIKI_HTML 0x002
36 #define WIKI_INLINE 0x004 /* Do not surround with <p>..</p> */
37 #endif
38
39
40 /*
41 ** These are the only markup attributes allowed.
42 */
43 #define ATTR_ALIGN 0x0000001
44 #define ATTR_ALT 0x0000002
45 #define ATTR_BGCOLOR 0x0000004
46 #define ATTR_BORDER 0x0000008
47 #define ATTR_CELLPADDING 0x0000010
48 #define ATTR_CELLSPACING 0x0000020
49 #define ATTR_CLEAR 0x0000040
50 #define ATTR_COLOR 0x0000080
51 #define ATTR_COLSPAN 0x0000100
52 #define ATTR_COMPACT 0x0000200
53 #define ATTR_FACE 0x0000400
54 #define ATTR_HEIGHT 0x0000800
55 #define ATTR_HREF 0x0001000
56 #define ATTR_HSPACE 0x0002000
57 #define ATTR_ID 0x0004000
58 #define ATTR_NAME 0x0008000
59 #define ATTR_ROWSPAN 0x0010000
60 #define ATTR_SIZE 0x0020000
61 #define ATTR_SRC 0x0040000
62 #define ATTR_START 0x0080000
63 #define ATTR_TYPE 0x0100000
64 #define ATTR_VALIGN 0x0200000
65 #define ATTR_VALUE 0x0400000
66 #define ATTR_VSPACE 0x0800000
67 #define ATTR_WIDTH 0x1000000
68
69 static const struct AllowedAttribute {
70 const char *zName;
71 unsigned int iMask;
72 } aAttribute[] = {
@@ -82,10 +84,11 @@
84 { "face", ATTR_FACE, },
85 { "height", ATTR_HEIGHT, },
86 { "href", ATTR_HREF, },
87 { "hspace", ATTR_HSPACE, },
88 { "id", ATTR_ID, },
89 { "name", ATTR_NAME, },
90 { "rowspan", ATTR_ROWSPAN, },
91 { "size", ATTR_SIZE, },
92 { "src", ATTR_SRC, },
93 { "start", ATTR_START, },
94 { "type", ATTR_TYPE, },
@@ -179,29 +182,32 @@
182 ** The various markup is divided into the following types:
183 */
184 #define MUTYPE_SINGLE 0x0001 /* <img>, <br>, or <hr> */
185 #define MUTYPE_BLOCK 0x0002 /* Forms a new paragraph. ex: <p>, <h2> */
186 #define MUTYPE_FONT 0x0004 /* Font changes. ex: <b>, <font>, <sub> */
 
187 #define MUTYPE_LIST 0x0010 /* Lists. <ol>, <ul>, or <dl> */
188 #define MUTYPE_LI 0x0020 /* List items. <li>, <dd>, <dt> */
189 #define MUTYPE_TABLE 0x0040 /* <table> */
190 #define MUTYPE_TR 0x0080 /* <tr> */
191 #define MUTYPE_TD 0x0100 /* <td> or <th> */
192 #define MUTYPE_SPECIAL 0x0200 /* <nowiki> or <verbatim> */
193 #define MUTYPE_HYPERLINK 0x0400 /* <a> */
194
195 /*
196 ** These markup types must have an end tag.
197 */
198 #define MUTYPE_STACK (MUTYPE_BLOCK | MUTYPE_FONT | MUTYPE_LIST | MUTYPE_TABLE)
199
200 static const struct AllowedMarkup {
201 const char *zName; /* Name of the markup */
202 char iCode; /* The MARKUP_* code */
203 short int iType; /* The MUTYPE_* code */
204 int allowedAttr; /* Allowed attributes on this markup */
205 } aMarkup[] = {
206 { 0, MARKUP_INVALID, 0, 0 },
207 { "a", MARKUP_A, MUTYPE_HYPERLINK,
208 ATTR_HREF|ATTR_NAME },
209 { "address", MARKUP_ADDRESS, MUTYPE_BLOCK, 0 },
210 { "b", MARKUP_B, MUTYPE_FONT, 0 },
211 { "big", MARKUP_BIG, MUTYPE_FONT, 0 },
212 { "blockquote", MARKUP_BLOCKQUOTE, MUTYPE_BLOCK, 0 },
213 { "br", MARKUP_BR, MUTYPE_SINGLE, ATTR_CLEAR },
@@ -314,10 +320,12 @@
320 Blob *pOut; /* Output appended to this blob */
321 int state; /* Flag that govern rendering */
322 int wikiList; /* Current wiki list type */
323 int inVerbatim; /* True in <verbatim> mode */
324 int preVerbState; /* Value of state prior to verbatim */
325 int wantAutoParagraph; /* True if a <p> is desired */
326 int inAutoParagraph; /* True if within an automatic paragraph */
327 const char *zVerbatimId; /* The id= attribute of <verbatim> */
328 int nStack; /* Number of elements on the stack */
329 int nAlloc; /* Space allocated for aStack */
330 unsigned char *aStack; /* Open markup stack */
331 };
@@ -438,11 +446,11 @@
446 **
447 ** Syntax:
448 ** * a tab or two or more spaces
449 ** * one or more digits
450 ** * optional "."
451 ** * another tab or two ore more spaces.
452 **
453 */
454 static int enumLength(const char *z){
455 int i, n;
456 n = 0;
@@ -741,17 +749,28 @@
749 }
750 return p->aStack[i-1];
751 }
752
753 /*
754 ** Begin a new paragraph if that something that is needed.
755 */
756 static void startAutoParagraph(Renderer *p){
757 if( p->wantAutoParagraph==0 ) return;
758 blob_appendf(p->pOut, "<p>", -1);
759 pushStack(p, MARKUP_P);
760 p->wantAutoParagraph = 0;
761 p->inAutoParagraph = 1;
762 }
763
764 /*
765 ** End a paragraph if we are in one.
766 */
767 static void endAutoParagraph(Renderer *p){
768 if( p->inAutoParagraph ){
769 popStackToTag(p, MARKUP_P);
770 p->inAutoParagraph = 0;
771 }
772 }
773
774 /*
775 ** Resolve a hyperlink. The argument is the content of the [...]
776 ** in the wiki. Append the URL to the output of the Renderer.
@@ -813,13 +832,14 @@
832 case TOKEN_PARAGRAPH: {
833 if( p->wikiList ){
834 popStackToTag(p, p->wikiList);
835 p->wikiList = 0;
836 }
837 endAutoParagraph(p);
838 blob_appendf(p->pOut, "\n\n", 1);
839 p->wantAutoParagraph = 1;
840 p->state |= AT_PARAGRAPH|AT_NEWLINE;
 
841 break;
842 }
843 case TOKEN_NEWLINE: {
844 blob_append(p->pOut, "\n", 1);
845 p->state |= AT_NEWLINE;
@@ -832,10 +852,12 @@
852 }
853 pushStack(p, MARKUP_UL);
854 blob_append(p->pOut, "<ul>", 4);
855 p->wikiList = MARKUP_UL;
856 }
857 popStackToTag(p, MARKUP_LI);
858 startAutoParagraph(p);
859 pushStack(p, MARKUP_LI);
860 blob_append(p->pOut, "<li>", 4);
861 break;
862 }
863 case TOKEN_ENUM: {
@@ -845,22 +867,26 @@
867 }
868 pushStack(p, MARKUP_OL);
869 blob_append(p->pOut, "<ol>", 4);
870 p->wikiList = MARKUP_OL;
871 }
872 popStackToTag(p, MARKUP_LI);
873 startAutoParagraph(p);
874 pushStack(p, MARKUP_LI);
875 blob_appendf(p->pOut, "<li value=\"%d\">", atoi(z));
876 break;
877 }
878 case TOKEN_INDENT: {
879 assert( p->wikiList==0 );
880 pushStack(p, MARKUP_BLOCKQUOTE);
881 blob_append(p->pOut, "<blockquote>", -1);
882 p->wantAutoParagraph = 0;
883 p->wikiList = MARKUP_BLOCKQUOTE;
884 break;
885 }
886 case TOKEN_CHARACTER: {
887 startAutoParagraph(p);
888 if( z[0]=='<' ){
889 blob_append(p->pOut, "&lt;", 4);
890 }else if( z[0]=='&' ){
891 blob_append(p->pOut, "&amp;", 5);
892 }
@@ -869,11 +895,11 @@
895 case TOKEN_LINK: {
896 char *zTarget;
897 char *zDisplay = 0;
898 int i, j;
899 int savedState;
900 startAutoParagraph(p);
901 zTarget = &z[1];
902 for(i=1; z[i] && z[i]!=']'; i++){
903 if( z[i]=='|' && zDisplay==0 ){
904 zDisplay = &z[i+1];
905 z[i] = 0;
@@ -896,11 +922,11 @@
922 p->state = savedState;
923 blob_append(p->pOut, "</a>", 4);
924 break;
925 }
926 case TOKEN_TEXT: {
927 startAutoParagraph(p);
928 blob_append(p->pOut, z, n);
929 break;
930 }
931 case TOKEN_MARKUP: {
932 parseMarkup(&markup, z);
@@ -913,10 +939,12 @@
939 unparseMarkup(&markup);
940 blob_append(p->pOut, "&lt;", 4);
941 n = 1;
942 }
943 }else if( markup.iCode==MARKUP_INVALID ){
944 unparseMarkup(&markup);
945 startAutoParagraph(p);
946 blob_append(p->pOut, "&lt;", 4);
947 n = 1;
948 }else if( (markup.iType&MUTYPE_FONT)==0
949 && (p->state & FONT_MARKUP_ONLY)!=0 ){
950 /* Do nothing */
@@ -936,10 +964,11 @@
964 }
965 p->inVerbatim = 1;
966 p->preVerbState = p->state;
967 p->state &= ~ALLOW_WIKI;
968 blob_append(p->pOut, "<pre>", 5);
969 p->wantAutoParagraph = 0;
970 }else if( markup.iType==MUTYPE_LI ){
971 if( backupToType(p, MUTYPE_LIST)==0 ){
972 pushStack(p, MARKUP_UL);
973 blob_append(p->pOut, "<ul>", 4);
974 }
@@ -957,11 +986,21 @@
986 blob_append(p->pOut, "<tr>", 4);
987 }
988 pushStack(p, markup.iCode);
989 renderMarkup(p->pOut, &markup);
990 }
991 }else if( markup.iType==MUTYPE_HYPERLINK ){
992 popStackToTag(p, markup.iCode);
993 startAutoParagraph(p);
994 renderMarkup(p->pOut, &markup);
995 pushStack(p, markup.iCode);
996 }else{
997 if( markup.iType==MUTYPE_FONT ){
998 startAutoParagraph(p);
999 }else if( markup.iType==MUTYPE_BLOCK ){
1000 p->wantAutoParagraph = 0;
1001 }
1002 if( (markup.iType & MUTYPE_STACK )!=0 ){
1003 pushStack(p, markup.iCode);
1004 }
1005 renderMarkup(p->pOut, &markup);
1006 }
@@ -968,10 +1007,11 @@
1007 break;
1008 }
1009 }
1010 z += n;
1011 }
1012 endAutoParagraph(p);
1013 }
1014
1015
1016 /*
1017 ** Transform the text in the pIn blob. Write the results
@@ -978,16 +1018,17 @@
1018 ** into the pOut blob. The pOut blob should already be
1019 ** initialized. The output is merely appended to pOut.
1020 ** If pOut is NULL, then the output is appended to the CGI
1021 ** reply.
1022 */
1023 void wiki_convert(Blob *pIn, Blob *pOut, int flags){
1024 char *z;
1025 Renderer renderer;
1026
1027 memset(&renderer, 0, sizeof(renderer));
1028 renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH;
1029 renderer.wantAutoParagraph = (flags & WIKI_INLINE)==0;
1030 if( pOut ){
1031 renderer.pOut = pOut;
1032 }else{
1033 renderer.pOut = cgi_output_blob();
1034 }
@@ -1007,8 +1048,8 @@
1048 void test_wiki_render(void){
1049 Blob in, out;
1050 if( g.argc!=3 ) usage("FILE");
1051 blob_zero(&out);
1052 blob_read_from_file(&in, g.argv[2]);
1053 wiki_convert(&in, &out, 0);
1054 blob_write_to_file(&out, "-");
1055 }
1056

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button