Fossil SCM

Clean up and merge updates from trunk

robert 2009-09-26 08:17 creole merge
Commit 7a39dde24bbc2436e41d32085410b76f4aa4ed55
--- src/configure.c
+++ src/configure.c
@@ -76,10 +76,12 @@
7676
int groupMask; /* Which config groups is it part of */
7777
} aConfig[] = {
7878
{ "css", CONFIGSET_SKIN },
7979
{ "header", CONFIGSET_SKIN },
8080
{ "footer", CONFIGSET_SKIN },
81
+ { "logo-mimetype", CONFIGSET_SKIN },
82
+ { "logo-image", CONFIGSET_SKIN },
8183
{ "project-name", CONFIGSET_PROJ },
8284
{ "project-description", CONFIGSET_PROJ },
8385
{ "index-page", CONFIGSET_SKIN },
8486
{ "timeline-block-markup", CONFIGSET_SKIN },
8587
{ "timeline-max-comment", CONFIGSET_SKIN },
8688
--- src/configure.c
+++ src/configure.c
@@ -76,10 +76,12 @@
76 int groupMask; /* Which config groups is it part of */
77 } aConfig[] = {
78 { "css", CONFIGSET_SKIN },
79 { "header", CONFIGSET_SKIN },
80 { "footer", CONFIGSET_SKIN },
 
 
81 { "project-name", CONFIGSET_PROJ },
82 { "project-description", CONFIGSET_PROJ },
83 { "index-page", CONFIGSET_SKIN },
84 { "timeline-block-markup", CONFIGSET_SKIN },
85 { "timeline-max-comment", CONFIGSET_SKIN },
86
--- src/configure.c
+++ src/configure.c
@@ -76,10 +76,12 @@
76 int groupMask; /* Which config groups is it part of */
77 } aConfig[] = {
78 { "css", CONFIGSET_SKIN },
79 { "header", CONFIGSET_SKIN },
80 { "footer", CONFIGSET_SKIN },
81 { "logo-mimetype", CONFIGSET_SKIN },
82 { "logo-image", CONFIGSET_SKIN },
83 { "project-name", CONFIGSET_PROJ },
84 { "project-description", CONFIGSET_PROJ },
85 { "index-page", CONFIGSET_SKIN },
86 { "timeline-block-markup", CONFIGSET_SKIN },
87 { "timeline-max-comment", CONFIGSET_SKIN },
88
--- src/configure.c
+++ src/configure.c
@@ -76,10 +76,12 @@
7676
int groupMask; /* Which config groups is it part of */
7777
} aConfig[] = {
7878
{ "css", CONFIGSET_SKIN },
7979
{ "header", CONFIGSET_SKIN },
8080
{ "footer", CONFIGSET_SKIN },
81
+ { "logo-mimetype", CONFIGSET_SKIN },
82
+ { "logo-image", CONFIGSET_SKIN },
8183
{ "project-name", CONFIGSET_PROJ },
8284
{ "project-description", CONFIGSET_PROJ },
8385
{ "index-page", CONFIGSET_SKIN },
8486
{ "timeline-block-markup", CONFIGSET_SKIN },
8587
{ "timeline-max-comment", CONFIGSET_SKIN },
8688
--- src/configure.c
+++ src/configure.c
@@ -76,10 +76,12 @@
76 int groupMask; /* Which config groups is it part of */
77 } aConfig[] = {
78 { "css", CONFIGSET_SKIN },
79 { "header", CONFIGSET_SKIN },
80 { "footer", CONFIGSET_SKIN },
 
 
81 { "project-name", CONFIGSET_PROJ },
82 { "project-description", CONFIGSET_PROJ },
83 { "index-page", CONFIGSET_SKIN },
84 { "timeline-block-markup", CONFIGSET_SKIN },
85 { "timeline-max-comment", CONFIGSET_SKIN },
86
--- src/configure.c
+++ src/configure.c
@@ -76,10 +76,12 @@
76 int groupMask; /* Which config groups is it part of */
77 } aConfig[] = {
78 { "css", CONFIGSET_SKIN },
79 { "header", CONFIGSET_SKIN },
80 { "footer", CONFIGSET_SKIN },
81 { "logo-mimetype", CONFIGSET_SKIN },
82 { "logo-image", CONFIGSET_SKIN },
83 { "project-name", CONFIGSET_PROJ },
84 { "project-description", CONFIGSET_PROJ },
85 { "index-page", CONFIGSET_SKIN },
86 { "timeline-block-markup", CONFIGSET_SKIN },
87 { "timeline-max-comment", CONFIGSET_SKIN },
88
+818 -834
--- src/creoleparser.c
+++ src/creoleparser.c
@@ -28,11 +28,11 @@
2828
#include <assert.h>
2929
#include "config.h"
3030
#include "creoleparser.h"
3131
3232
#if INTERFACE
33
-#define HAVE_MACRO_EXTENSIONS 1
33
+#define HAVE_CREOLE_MACRO 1
3434
#endif
3535
3636
//{{{ LOCAL INTERFACE
3737
#if LOCAL_INTERFACE
3838
@@ -61,59 +61,59 @@
6161
6262
#define KIND_TABLE_ROW 0x0010000
6363
//}}}
6464
//{{{ FLAG
6565
// keep first four bits free
66
-#define FLAG_CENTER 0x0000100
66
+#define FLAG_CENTER 0x0000100
6767
//}}}
6868
struct Node {//{{{
6969
70
- char *start;
71
- char *end;
72
-
73
- int kind;
74
- int level;
75
- int flags;
76
-
77
- Node *parent;
78
- Node *next;
79
- Node *children;
70
+ char *start;
71
+ char *end;
72
+
73
+ int kind;
74
+ int level;
75
+ int flags;
76
+
77
+ Node *parent;
78
+ Node *next;
79
+ Node *children;
8080
8181
};
8282
//}}}
8383
struct NodePool {//{{{
84
- NodePool *next;
85
- Node a[POOL_CHUNK_SIZE];
84
+ NodePool *next;
85
+ Node a[POOL_CHUNK_SIZE];
8686
}
8787
//}}}
8888
struct Parser {//{{{
8989
90
- Blob *pOut; /* Output appended to this blob */
91
- Renderer *r;
90
+ Blob *pOut; /* Output appended to this blob */
91
+ Renderer *r;
9292
93
- NodePool *pool;
94
- int nFree;
93
+ NodePool *pool;
94
+ int nFree;
9595
9696
Node *this;
97
- Node *previous;
98
- Node *list;
99
-
100
- char *cursor;
101
-
102
- int lineWasBlank;
103
- int charCount;
104
-
105
- Node *item;
106
- Node *istack;
107
- char *icursor;
108
- char *iend;
109
-
110
- int inLink;
111
- int inTable;
112
- int iesc;
113
-
114
- Blob *iblob;
97
+ Node *previous;
98
+ Node *list;
99
+
100
+ char *cursor;
101
+
102
+ int lineWasBlank;
103
+ int charCount;
104
+
105
+ Node *item;
106
+ Node *istack;
107
+ char *icursor;
108
+ char *iend;
109
+
110
+ int inLink;
111
+ int inTable;
112
+ int iesc;
113
+
114
+ Blob *iblob;
115115
116116
117117
118118
119119
};
@@ -126,484 +126,485 @@
126126
//}}}
127127
128128
//{{{ POOL MANAGEMENT
129129
static Node *pool_new(Parser *p){
130130
131
- if ( p->pool == NULL || p->nFree == 0){
132
-
133
- NodePool *temp = p->pool;
134
-
135
- p->pool = malloc(sizeof(NodePool));
136
- if( p->pool == NULL ) fossil_panic("out of memory");
137
-
138
- p->pool->next = temp;
139
- p->nFree = POOL_CHUNK_SIZE;
140
- }
141
- p->nFree -= 1;
142
- Node *node = &(p->pool->a[p->nFree]);
143
- memset(node, 0, sizeof(*node));
144
-
145
- return node;
131
+ if ( p->pool == NULL || p->nFree == 0){
132
+
133
+ NodePool *temp = p->pool;
134
+
135
+ p->pool = malloc(sizeof(NodePool));
136
+ if( p->pool == NULL ) fossil_panic("out of memory");
137
+
138
+ p->pool->next = temp;
139
+ p->nFree = POOL_CHUNK_SIZE;
140
+ }
141
+ p->nFree -= 1;
142
+ Node *node = &(p->pool->a[p->nFree]);
143
+ memset(node, 0, sizeof(*node));
144
+
145
+ return node;
146146
}
147147
148148
149149
static void pool_free(Parser *p){
150150
151
- NodePool *temp;
151
+ NodePool *temp;
152152
153
- while (p->pool != NULL){
154
- temp = p->pool;
155
- p->pool = temp->next;
156
- free(temp);
157
- }
153
+ while (p->pool != NULL){
154
+ temp = p->pool;
155
+ p->pool = temp->next;
156
+ free(temp);
157
+ }
158158
159159
}
160160
//}}}
161161
162162
//{{{ Utility Methods
163163
164164
static char *cr_skipBlanks(Parser *p, char* z){//{{{
165
- char *s = z;
166
- while (z[0] == ' ' || z[0] == '\t') z++;
167
- p->charCount = z - s;
168
- return z;
165
+ char *s = z;
166
+ while (z[0] == ' ' || z[0] == '\t') z++;
167
+ p->charCount = z - s;
168
+ return z;
169169
}
170170
//}}}
171171
static int cr_countBlanks(Parser *p, char* z){//{{{
172
- cr_skipBlanks(p, z);
173
- return p->charCount;
172
+ cr_skipBlanks(p, z);
173
+ return p->charCount;
174174
}
175175
//}}}
176176
static char *cr_skipChars(Parser *p, char *z, char c){//{{{
177
- char *s = z;
178
- while (z[0] == c) z++;
179
- p->charCount = z - s;
180
- return z;
177
+ char *s = z;
178
+ while (z[0] == c) z++;
179
+ p->charCount = z - s;
180
+ return z;
181181
}
182182
//}}}
183183
static int cr_countChars(Parser *p, char *z, char c){//{{{
184
- cr_skipChars(p, z, c);
185
- return p->charCount;
184
+ cr_skipChars(p, z, c);
185
+ return p->charCount;
186186
}
187187
//}}}
188188
static char *cr_nextLine(Parser *p, char *z){//{{{
189189
190
- p->lineWasBlank = 1;
191
-
192
- while (1){
193
-
194
- switch (z[0]){
195
-
196
- case '\r':
197
- if (z[1] == '\n') {
198
- z[0] = ' ';
199
- return z + 2;
200
- }
201
- z[0] = '\n';
202
- return z + 1;
203
-
204
- case'\n':
205
- return z + 1;
206
-
207
- case '\t':
208
- z[0] = ' ';
209
- z++;
210
- break;
211
-
212
- case ' ':
213
- z++;
214
- break;
215
-
216
- case '\0':
217
- return z;
218
-
219
- default:
220
- p->lineWasBlank = 0;
221
- z++;
222
- }
223
- }
190
+ p->lineWasBlank = 1;
191
+
192
+ while (1){
193
+
194
+ switch (z[0]){
195
+
196
+ case '\r':
197
+ if (z[1] == '\n') {
198
+ z[0] = ' ';
199
+ return z + 2;
200
+ }
201
+ z[0] = '\n';
202
+ return z + 1;
203
+
204
+ case'\n':
205
+ return z + 1;
206
+
207
+ case '\t':
208
+ z[0] = ' ';
209
+ z++;
210
+ break;
211
+
212
+ case ' ':
213
+ z++;
214
+ break;
215
+
216
+ case '\0':
217
+ return z;
218
+
219
+ default:
220
+ p->lineWasBlank = 0;
221
+ z++;
222
+ }
223
+ }
224224
}
225225
//}}}
226226
//}}}
227227
228228
//{{{ INLINE PARSER
229229
230230
static int cr_isEsc(Parser *p){//{{{
231
- if (p->iesc){
232
- blob_append(p->iblob, p->icursor, 1);
233
- p->iesc = 0;
234
- p->icursor += 1;
235
- return 1;
236
- }
237
- return 0;
231
+ if (p->iesc){
232
+ blob_append(p->iblob, p->icursor, 1);
233
+ p->iesc = 0;
234
+ p->icursor += 1;
235
+ return 1;
236
+ }
237
+ return 0;
238238
}
239239
//}}}
240240
static int cr_iOpen(Parser *p, int kind){//{{{
241241
242
- switch (kind){
243
-
244
- case KIND_BOLD:
245
- blob_append(p->iblob, "<strong>", 8);
246
- return 1;
247
-
248
- case KIND_ITALIC:
249
- blob_append(p->iblob, "<em>", 4);
250
- return 1;
251
-
252
- case KIND_SUPERSCRIPT:
253
- blob_append(p->iblob, "<sup>", 5);
254
- return 1;
255
-
256
- case KIND_SUBSCRIPT:
257
- blob_append(p->iblob, "<sub>", 5);
258
- return 1;
259
-
260
- case KIND_MONOSPACED:
261
- blob_append(p->iblob, "<tt>", 4);
262
- return 1;
263
- }
264
- return 0;
242
+ switch (kind){
243
+
244
+ case KIND_BOLD:
245
+ blob_append(p->iblob, "<strong>", 8);
246
+ return 1;
247
+
248
+ case KIND_ITALIC:
249
+ blob_append(p->iblob, "<em>", 4);
250
+ return 1;
251
+
252
+ case KIND_SUPERSCRIPT:
253
+ blob_append(p->iblob, "<sup>", 5);
254
+ return 1;
255
+
256
+ case KIND_SUBSCRIPT:
257
+ blob_append(p->iblob, "<sub>", 5);
258
+ return 1;
259
+
260
+ case KIND_MONOSPACED:
261
+ blob_append(p->iblob, "<tt>", 4);
262
+ return 1;
263
+ }
264
+ return 0;
265265
}
266266
//}}}
267267
static int cr_iClose(Parser *p, int kind){//{{{
268268
269
- switch (kind){
270
-
271
- case KIND_BOLD:
272
- blob_append(p->iblob, "</strong>", 9);
273
- return 1;
274
-
275
- case KIND_ITALIC:
276
- blob_append(p->iblob, "</em>", 5);
277
- return 1;
278
-
279
- case KIND_SUPERSCRIPT:
280
- blob_append(p->iblob, "</sup>", 6);
281
- return 1;
282
-
283
- case KIND_SUBSCRIPT:
284
- blob_append(p->iblob, "</sub>", 6);
285
- return 1;
286
-
287
- case KIND_MONOSPACED:
288
- blob_append(p->iblob, "</tt>", 5);
289
- return 1;
290
- }
291
- return 0;
269
+ switch (kind){
270
+
271
+ case KIND_BOLD:
272
+ blob_append(p->iblob, "</strong>", 9);
273
+ return 1;
274
+
275
+ case KIND_ITALIC:
276
+ blob_append(p->iblob, "</em>", 5);
277
+ return 1;
278
+
279
+ case KIND_SUPERSCRIPT:
280
+ blob_append(p->iblob, "</sup>", 6);
281
+ return 1;
282
+
283
+ case KIND_SUBSCRIPT:
284
+ blob_append(p->iblob, "</sub>", 6);
285
+ return 1;
286
+
287
+ case KIND_MONOSPACED:
288
+ blob_append(p->iblob, "</tt>", 5);
289
+ return 1;
290
+ }
291
+ return 0;
292292
}
293293
//}}}
294294
295295
296296
static void cr_iMarkup(Parser *p, int kind){//{{{
297297
298
- if (p->iesc) {
299
- blob_append(p->iblob, p->icursor, 1);
300
- p->icursor +=1;
301
- p->iesc =0;
302
- return;
303
- }
304
-
305
- if (p->icursor[1] != p->icursor[0]) {
306
- blob_append(p->iblob, p->icursor, 1);
307
- p->icursor +=1;
308
- return;
309
- }
310
-
311
- p->icursor += 2;
312
-
313
- if (kind & KIND_BREAK) {
314
- blob_append(p->iblob, "<br />", 6);
315
- return;
316
- }
317
-
318
- if (kind & KIND_ITALIC && p->icursor[-3] == ':'){
319
- blob_append(p->iblob, "//", 2);
320
- return;
321
- }
322
-
323
- Node *n = p->istack;
324
-
325
- int found = 0;
326
- while (n) {
327
- if (n->kind & kind) {
328
- found = 1;
329
- break;
330
- }
331
- n = n->next;
332
- }
333
-
334
- if (!found) {
335
- n = pool_new(p);
336
- n->kind = kind;
337
- n->next = p->istack;
338
- p->istack = n;
339
-
340
- assert(cr_iOpen(p, kind));
341
- return;
342
- };
343
-
344
- n= p->istack;
345
- while (n){
346
- p->istack = n->next;
347
-
348
- assert(cr_iClose(p, n->kind));
349
-
350
- if (kind == n->kind) return;
351
- n = p->istack;
352
- }
298
+ if (p->iesc) {
299
+ blob_append(p->iblob, p->icursor, 1);
300
+ p->icursor +=1;
301
+ p->iesc =0;
302
+ return;
303
+ }
304
+
305
+ if (p->icursor[1] != p->icursor[0]) {
306
+ blob_append(p->iblob, p->icursor, 1);
307
+ p->icursor +=1;
308
+ return;
309
+ }
310
+
311
+ p->icursor += 2;
312
+
313
+ if (kind & KIND_BREAK) {
314
+ blob_append(p->iblob, "<br />", 6);
315
+ return;
316
+ }
317
+
318
+ if (kind & KIND_ITALIC && p->icursor[-3] == ':'){
319
+ blob_append(p->iblob, "//", 2);
320
+ return;
321
+ }
322
+
323
+ Node *n = p->istack;
324
+
325
+ int found = 0;
326
+ while (n) {
327
+ if (n->kind & kind) {
328
+ found = 1;
329
+ break;
330
+ }
331
+ n = n->next;
332
+ }
333
+
334
+ if (!found) {
335
+ n = pool_new(p);
336
+ n->kind = kind;
337
+ n->next = p->istack;
338
+ p->istack = n;
339
+
340
+ assert(cr_iOpen(p, kind));
341
+ return;
342
+ };
343
+
344
+ n= p->istack;
345
+ while (n){
346
+ p->istack = n->next;
347
+
348
+ assert(cr_iClose(p, n->kind));
349
+
350
+ if (kind == n->kind) return;
351
+ n = p->istack;
352
+ }
353353
}
354354
//}}}
355355
static int cr_iNoWiki(Parser *p){//{{{
356356
357
- if ((p->iend - p->icursor)<6) return 0;
358
-
359
- if (p->icursor[1]!='{' || p->icursor[2]!='{')
360
- return 0;
361
-
362
- char *s = p->icursor + 3;
363
-
364
- int count = p->iend - p->icursor - 6;
365
- while (count--){
366
- if (s[0]=='}' && s[1]=='}' && s[2]=='}' && s[3]!='}'){
367
- blob_appendf(p->iblob, "<tt style='background:oldlace'>%s</tt>", htmlize(p->icursor + 3, s - p->icursor-3));
368
- p->icursor = s + 3;
369
- return 1;
370
- }
371
- s++;
372
- }
373
- return 0;
357
+ if ((p->iend - p->icursor)<6) return 0;
358
+
359
+ if (p->icursor[1]!='{' || p->icursor[2]!='{')
360
+ return 0;
361
+
362
+ char *s = p->icursor + 3;
363
+
364
+ int count = p->iend - p->icursor - 6;
365
+ while (count--){
366
+ if (s[0]=='}' && s[1]=='}' && s[2]=='}' && s[3]!='}'){
367
+ blob_appendf(p->iblob, "<tt style='background:oldlace'>%s</tt>", htmlize(p->icursor + 3, s - p->icursor-3));
368
+ p->icursor = s + 3;
369
+ return 1;
370
+ }
371
+ s++;
372
+ }
373
+ return 0;
374374
}
375375
376376
//}}}
377377
static int cr_iImage(Parser *p){//{{{
378378
379
- if (p->inLink) return 0;
380
- if ((p->iend - p->icursor)<3) return 0;
381
-
382
- if (p->icursor[1]!='{') return 0;
383
-
384
- char *s = p->icursor + 2;
385
- char *bar = NULL;
386
-
387
- int count = p->iend - p->icursor - 4;
388
- while (count--){
389
- if (s[0]=='}' && s[1]=='}'){
390
- if (!bar) bar = p->icursor + 2;
391
- blob_appendf(p->iblob, "<span style='color:green;border:1px solid green;'>%s</span>", htmlize(bar, s - bar ));
392
- p->icursor = s + 2;
393
- return 1;
394
- }
395
- if (!bar && s[0]=='|') bar=s+1;
396
- s++;
397
- }
398
- return 0;
379
+ if (p->inLink) return 0;
380
+ if ((p->iend - p->icursor)<3) return 0;
381
+
382
+ if (p->icursor[1]!='{') return 0;
383
+
384
+ char *s = p->icursor + 2;
385
+ char *bar = NULL;
386
+
387
+ int count = p->iend - p->icursor - 4;
388
+ while (count--){
389
+ if (s[0]=='}' && s[1]=='}'){
390
+ if (!bar) bar = p->icursor + 2;
391
+ blob_appendf(p->iblob, "<span style='color:green;border:1px solid green;'>%s</span>", htmlize(bar, s - bar ));
392
+ p->icursor = s + 2;
393
+ return 1;
394
+ }
395
+ if (!bar && s[0]=='|') bar=s+1;
396
+ s++;
397
+ }
398
+ return 0;
399399
}
400400
//}}}
401401
static int cr_iMacro(Parser *p){//{{{
402402
403
- if (p->inLink) return 0;
404
- if ((p->iend - p->icursor)<3) return 0;
405
-
406
- if (p->icursor[1]!='<') return 0;
407
-
408
- char *s = p->icursor + 2;
409
-
410
- int count = p->iend - p->icursor - 4;
411
- while (count--){
412
- if (s[0]=='>' && s[1]=='>'){
413
- blob_appendf(p->iblob, "<span style='color:red;border:1px solid red;'>%s</span>", htmlize(p->icursor, s - p->icursor + 2));
414
- p->icursor = s + 2;
415
- return 1;
416
- }
417
- s++;
418
- }
419
- return 0;
403
+ if (p->inLink) return 0;
404
+ if ((p->iend - p->icursor)<3) return 0;
405
+
406
+ if (p->icursor[1]!='<') return 0;
407
+
408
+ char *s = p->icursor + 2;
409
+
410
+ int count = p->iend - p->icursor - 3;
411
+ while (count--){
412
+ blob_appendf(p->iblob, "|~%s|", s,2 );
413
+ if (s[0]=='>' && s[1]=='>'){
414
+ blob_appendf(p->iblob, "<span style='color:red;border:1px solid red;'>%s</span>", htmlize(p->icursor, s - p->icursor + 2));
415
+ p->icursor = s + 2;
416
+ return 1;
417
+ }
418
+ s++;
419
+ }
420
+ return 0;
420421
421422
}
422423
//}}}
423424
424425
static void cr_renderLink(Parser *p, char *s, char *bar, char *e){//{{{
425426
426
- int tsize = bar-s;
427
- int dsize = e - bar-1;
428
-
429
- if (tsize < 1) return;
430
- if (dsize < 1) dsize = 0;
431
-
432
- char zTarget[tsize + 1];
433
- memcpy(zTarget, s, tsize);
434
- zTarget[tsize] = '\0';
435
-
436
- char zClose[20];
437
-
438
- Blob *pOut = p->r->pOut;
439
-
440
- p->r->pOut = p->iblob;
441
- wf_openHyperlink(p->r, zTarget, zClose, sizeof(zClose));
442
- p->r->pOut = pOut;
443
-
444
- if (dsize)
445
- cr_parseInline(p, bar+1, e) ;
446
- else
447
- blob_append(p->iblob, htmlize(s, tsize), -1);
448
- blob_append(p->iblob, zClose, -1);
427
+ int tsize = bar-s;
428
+ int dsize = e - bar-1;
429
+
430
+ if (tsize < 1) return;
431
+ if (dsize < 1) dsize = 0;
432
+
433
+ char zTarget[tsize + 1];
434
+ memcpy(zTarget, s, tsize);
435
+ zTarget[tsize] = '\0';
436
+
437
+ char zClose[20];
438
+
439
+ Blob *pOut = p->r->pOut;
440
+
441
+ p->r->pOut = p->iblob;
442
+ wf_openHyperlink(p->r, zTarget, zClose, sizeof(zClose));
443
+ p->r->pOut = pOut;
444
+
445
+ if (dsize)
446
+ cr_parseInline(p, bar+1, e) ;
447
+ else
448
+ blob_append(p->iblob, htmlize(s, tsize), -1);
449
+ blob_append(p->iblob, zClose, -1);
449450
}
450451
//}}}
451452
452453
static int cr_iLink(Parser *p){//{{{
453454
454
- if (p->inLink) return 0;
455
- if ((p->iend - p->icursor)<3) return 0;
456
-
457
- if (p->icursor[1]!='[') return 0;
458
-
459
- char *s = p->icursor + 2;
460
- char *bar = NULL;
461
-
462
- int count = p->iend - p->icursor -3;
463
- while (count--){
464
- if (s[0]==']' && s[1]==']'){
465
- if (!bar) bar = s;
466
- p->inLink = 1;
467
- cr_renderLink(p, p->icursor+2, bar, s);
468
- p->inLink = 0;
469
- p->icursor = s + 2;
470
- return 1;
471
- }
472
- if (!bar && s[0]=='|') bar=s;
473
- s++;
474
- }
475
- return 0;
455
+ if (p->inLink) return 0;
456
+ if ((p->iend - p->icursor)<3) return 0;
457
+
458
+ if (p->icursor[1]!='[') return 0;
459
+
460
+ char *s = p->icursor + 2;
461
+ char *bar = NULL;
462
+
463
+ int count = p->iend - p->icursor -3;
464
+ while (count--){
465
+ if (s[0]==']' && s[1]==']'){
466
+ if (!bar) bar = s;
467
+ p->inLink = 1;
468
+ cr_renderLink(p, p->icursor+2, bar, s);
469
+ p->inLink = 0;
470
+ p->icursor = s + 2;
471
+ return 1;
472
+ }
473
+ if (!bar && s[0]=='|') bar=s;
474
+ s++;
475
+ }
476
+ return 0;
476477
}
477478
//}}}
478479
479480
LOCAL char *cr_parseInline(Parser *p, char *s, char *e){//{{{
480481
481
- int save_iesc = p->iesc;
482
- char *save_iend = p->iend;
483
- Node *save_istack = p->istack;
484
-
485
- p->iesc = 0;
486
- p->iend = e;
487
- p->istack = NULL;
488
-
489
- p->icursor = s;
490
-
491
- char *eof = NULL;
492
- while (!eof && p->icursor < p->iend ){
493
-
494
- switch (*p->icursor) {//{{{
495
-
496
- case '~':
497
- if (p->iesc) {
498
- blob_append(p->iblob, "~", 1);
499
- p->iesc = 0;
500
- }
501
- p->iesc = !p->iesc;
502
- p->icursor+=1;
503
- break;
504
-
505
- case '*':
506
- cr_iMarkup(p, KIND_BOLD);
507
- break;
508
-
509
- case '/':
510
- cr_iMarkup(p, KIND_ITALIC);
511
- break;
512
-
513
- case '^':
514
- cr_iMarkup(p, KIND_SUPERSCRIPT);
515
- break;
516
-
517
- case ',':
518
- cr_iMarkup(p, KIND_SUBSCRIPT);
519
- break;
520
-
521
- case '#':
522
- cr_iMarkup(p, KIND_MONOSPACED);
523
- break;
524
-
525
- case '\\':
526
- cr_iMarkup(p, KIND_BREAK);
527
- break;
528
-
529
- case '{':
530
- if (cr_isEsc(p)) break;
531
- if (cr_iNoWiki(p)) break;
532
- if (cr_iImage(p)) break;
533
- blob_append(p->iblob, p->icursor, 1);
534
- p->icursor += 1;
535
- break;
536
-
537
- case '[':
538
- if (cr_isEsc(p)) break;
539
- if (cr_iLink(p)) break;
540
- blob_append(p->iblob, p->icursor, 1);
541
- p->icursor += 1;
542
- break;
543
-
544
-
545
- case '<':
546
- if (cr_isEsc(p)) break;
547
- if (cr_iMacro(p)) break;
548
-
549
- blob_append(p->iblob, "&lt;", 4);
550
- p->icursor += 1;
551
- break;
552
-
553
- case '>':
554
- if (p->iesc) {
555
- blob_append(p->iblob, "~", 1);
556
- p->iesc = 0;
557
- }
558
- blob_append(p->iblob, "&gt;", 4);
559
- p->icursor += 1;
560
- break;
561
-
562
- case '&':
563
- if (p->iesc) {
564
- blob_append(p->iblob, "~", 1);
565
- p->iesc = 0;
566
- }
567
- blob_append(p->iblob, "&amp;", 5);
568
- p->icursor += 1;
569
- break;
570
-
571
- case '|':
572
- if (p->inTable){
573
- if (p->iesc) {
574
- blob_append(p->iblob, p->icursor, 1);
575
- p->iesc = 0;
576
- p->icursor += 1;
577
- break;
578
- }
579
- eof = p->icursor + 1;
580
- break;
581
- }
582
- // fall through to default
583
-
584
- default:
585
- if (p->iesc) {
586
- blob_append(p->iblob, "~", 1);
587
- p->iesc = 0;
588
- }
589
- blob_append(p->iblob, p->icursor, 1);
590
- p->icursor +=1;
591
- }//}}}
592
-
593
- }
594
-
595
- while (p->istack){
596
- cr_iClose(p, p->istack->kind);
597
- p->istack = p->istack->next;
598
- }
599
-
600
- p->iesc = save_iesc;
601
- p->iend = save_iend;
602
- p->istack = save_istack;
603
-
604
- return eof;
482
+ int save_iesc = p->iesc;
483
+ char *save_iend = p->iend;
484
+ Node *save_istack = p->istack;
485
+
486
+ p->iesc = 0;
487
+ p->iend = e;
488
+ p->istack = NULL;
489
+
490
+ p->icursor = s;
491
+
492
+ char *eof = NULL;
493
+ while (!eof && p->icursor < p->iend ){
494
+
495
+ switch (*p->icursor) {//{{{
496
+
497
+ case '~':
498
+ if (p->iesc) {
499
+ blob_append(p->iblob, "~", 1);
500
+ p->iesc = 0;
501
+ }
502
+ p->iesc = !p->iesc;
503
+ p->icursor+=1;
504
+ break;
505
+
506
+ case '*':
507
+ cr_iMarkup(p, KIND_BOLD);
508
+ break;
509
+
510
+ case '/':
511
+ cr_iMarkup(p, KIND_ITALIC);
512
+ break;
513
+
514
+ case '^':
515
+ cr_iMarkup(p, KIND_SUPERSCRIPT);
516
+ break;
517
+
518
+ case ',':
519
+ cr_iMarkup(p, KIND_SUBSCRIPT);
520
+ break;
521
+
522
+ case '#':
523
+ cr_iMarkup(p, KIND_MONOSPACED);
524
+ break;
525
+
526
+ case '\\':
527
+ cr_iMarkup(p, KIND_BREAK);
528
+ break;
529
+
530
+ case '{':
531
+ if (cr_isEsc(p)) break;
532
+ if (cr_iNoWiki(p)) break;
533
+ if (cr_iImage(p)) break;
534
+ blob_append(p->iblob, p->icursor, 1);
535
+ p->icursor += 1;
536
+ break;
537
+
538
+ case '[':
539
+ if (cr_isEsc(p)) break;
540
+ if (cr_iLink(p)) break;
541
+ blob_append(p->iblob, p->icursor, 1);
542
+ p->icursor += 1;
543
+ break;
544
+
545
+
546
+ case '<':
547
+ if (cr_isEsc(p)) break;
548
+ if (cr_iMacro(p)) break;
549
+
550
+ blob_append(p->iblob, "&lt;", 4);
551
+ p->icursor += 1;
552
+ break;
553
+
554
+ case '>':
555
+ if (p->iesc) {
556
+ blob_append(p->iblob, "~", 1);
557
+ p->iesc = 0;
558
+ }
559
+ blob_append(p->iblob, "&gt;", 4);
560
+ p->icursor += 1;
561
+ break;
562
+
563
+ case '&':
564
+ if (p->iesc) {
565
+ blob_append(p->iblob, "~", 1);
566
+ p->iesc = 0;
567
+ }
568
+ blob_append(p->iblob, "&amp;", 5);
569
+ p->icursor += 1;
570
+ break;
571
+
572
+ case '|':
573
+ if (p->inTable){
574
+ if (p->iesc) {
575
+ blob_append(p->iblob, p->icursor, 1);
576
+ p->iesc = 0;
577
+ p->icursor += 1;
578
+ break;
579
+ }
580
+ eof = p->icursor + 1;
581
+ break;
582
+ }
583
+ // fall through to default
584
+
585
+ default:
586
+ if (p->iesc) {
587
+ blob_append(p->iblob, "~", 1);
588
+ p->iesc = 0;
589
+ }
590
+ blob_append(p->iblob, p->icursor, 1);
591
+ p->icursor +=1;
592
+ }//}}}
593
+
594
+ }
595
+
596
+ while (p->istack){
597
+ cr_iClose(p, p->istack->kind);
598
+ p->istack = p->istack->next;
599
+ }
600
+
601
+ p->iesc = save_iesc;
602
+ p->iend = save_iend;
603
+ p->istack = save_istack;
604
+
605
+ return eof;
605606
606607
}
607608
//}}}
608609
//}}}
609610
@@ -610,472 +611,455 @@
610611
//{{{ BLOCK PARSER
611612
612613
static void cr_renderListItem(Parser *p, Node *n){//{{{
613614
614615
615
- blob_append(p->iblob, "<li>", 4);
616
- cr_parseInline(p, n->start, n->end);
617
-
618
- if (n->children){
619
-
620
- int ord = (n->children->kind & KIND_ORDERED_LIST);
621
-
622
- if (ord) blob_append(p->iblob, "<ol>", 4);
623
- else blob_append(p->iblob, "<ul>", 4);
624
-
625
- n = n->children;
626
- while (n){
627
- cr_renderListItem(p, n);
628
- n = n->next;
629
- }
630
-
631
- if (ord) blob_append(p->iblob, "</ol>", 5);
632
- else blob_append(p->iblob, "</ul>", 5);
633
- }
634
- blob_append(p->iblob, "</li>", 5);
616
+ blob_append(p->iblob, "<li>", 4);
617
+ cr_parseInline(p, n->start, n->end);
618
+
619
+ if (n->children){
620
+
621
+ int ord = (n->children->kind & KIND_ORDERED_LIST);
622
+
623
+ if (ord) blob_append(p->iblob, "<ol>", 4);
624
+ else blob_append(p->iblob, "<ul>", 4);
625
+
626
+ n = n->children;
627
+ while (n){
628
+ cr_renderListItem(p, n);
629
+ n = n->next;
630
+ }
631
+
632
+ if (ord) blob_append(p->iblob, "</ol>", 5);
633
+ else blob_append(p->iblob, "</ul>", 5);
634
+ }
635
+ blob_append(p->iblob, "</li>", 5);
635636
}
636637
//}}}
637638
static void cr_renderList(Parser *p){//{{{
638639
639
- Node *n = p->list;
640
-
641
- while (n->parent !=n) n = n->parent;
642
-
643
- int ord = (n->kind & KIND_ORDERED_LIST);
644
-
645
- if (ord) blob_append(p->iblob, "\n\n<ol>", -1);
646
- else blob_append(p->iblob, "\n\n<ul>", -1);
647
-
648
- while (n) {
649
- cr_renderListItem(p, n);
650
- n = n->next;
651
- }
652
-
653
- if (ord) blob_append(p->iblob, "</ol>", 5);
654
- else blob_append(p->iblob, "</ul>", 5);
640
+ Node *n = p->list;
641
+
642
+ while (n->parent !=n) n = n->parent;
643
+
644
+ int ord = (n->kind & KIND_ORDERED_LIST);
645
+
646
+ if (ord) blob_append(p->iblob, "\n\n<ol>", -1);
647
+ else blob_append(p->iblob, "\n\n<ul>", -1);
648
+
649
+ while (n) {
650
+ cr_renderListItem(p, n);
651
+ n = n->next;
652
+ }
653
+
654
+ if (ord) blob_append(p->iblob, "</ol>", 5);
655
+ else blob_append(p->iblob, "</ul>", 5);
655656
}
656657
657658
//}}}
658659
659660
static void cr_renderTableRow(Parser *p, Node *row){//{{{
660661
661
- char *s = row->start;
662
- int th;
663
-
664
- blob_append(p->iblob, "\n<tr>", -1);
665
-
666
- while (s && s < row->end){
667
-
668
- if ((th = *s == '=')) {
669
- s++;
670
- blob_append(p->iblob, "<th>", -1);
671
- }
672
- else {
673
- blob_append(p->iblob, "<td>", -1);
674
- }
675
-
676
- s = cr_parseInline(p, s, row->end);
677
-
678
- if (th)
679
- blob_append(p->iblob, "</th>\n", -1);
680
- else
681
- blob_append(p->iblob, "</td>\n", -1);
682
-
683
- if (!s) break;
684
- }
685
- blob_append(p->iblob, "</tr>", 5);
662
+ char *s = row->start;
663
+ int th;
664
+
665
+ blob_append(p->iblob, "\n<tr>", -1);
666
+
667
+ while (s && s < row->end){
668
+
669
+ if ((th = *s == '=')) {
670
+ s++;
671
+ blob_append(p->iblob, "<th>", -1);
672
+ }
673
+ else {
674
+ blob_append(p->iblob, "<td>", -1);
675
+ }
676
+
677
+ s = cr_parseInline(p, s, row->end);
678
+
679
+ if (th)
680
+ blob_append(p->iblob, "</th>\n", -1);
681
+ else
682
+ blob_append(p->iblob, "</td>\n", -1);
683
+
684
+ if (!s) break;
685
+ }
686
+ blob_append(p->iblob, "</tr>", 5);
686687
}
687688
//}}}
688689
static void cr_renderTable(Parser *p, Node *n){//{{{
689690
690
- Node *row = n->children;
691
-
692
- blob_append(p->iblob, "<table class='creoletable'>", -1);
693
- p->inTable = 1;
694
- while (row){
695
-
696
- cr_renderTableRow(p, row);
697
- row = row->next;
698
-
699
- }
700
- blob_append(p->iblob, "</table>", -1);
701
- p->inTable = 0;
691
+ Node *row = n->children;
692
+
693
+ blob_append(p->iblob, "<table class='creoletable'>", -1);
694
+ p->inTable = 1;
695
+ while (row){
696
+
697
+ cr_renderTableRow(p, row);
698
+ row = row->next;
699
+
700
+ }
701
+ blob_append(p->iblob, "</table>", -1);
702
+ p->inTable = 0;
702703
703704
}
704705
//}}}
705706
706707
static void cr_render(Parser *p, Node *node){//{{{
707708
708
- if (node->kind & KIND_PARAGRAPH){
709
- blob_append(p->iblob, "\n<p>", -1);
710
- cr_parseInline(p, node->start, node->end );
711
- blob_append(p->iblob, "</p>\n", -1 );
712
- }
713
-
714
- if (node->kind & KIND_HEADING){
715
- blob_appendf(p->iblob,
716
- "\n<h%d %s>",
717
- node->level,
718
- (node->flags & FLAG_CENTER) ? " style='text-align:center;'" : ""
719
- );
720
- cr_parseInline(p, node->start, node->end);
721
- blob_appendf(p->iblob, "</h%d>\n", node->level );
722
- return;
723
- }
724
-
725
- if (node->kind & KIND_HORIZONTAL_RULE){
726
- blob_append(p->iblob, "<hr />", -1);
727
- return;
728
- }
729
-
730
- if (node->kind & KIND_LIST){
731
- cr_renderList(p);
732
- p->list = NULL;
733
- return;
734
- }
735
-
736
- if (node->kind & KIND_TABLE){
737
- cr_renderTable(p, node);
738
- return;
739
- }
740
-
741
- if (node->kind & KIND_NO_WIKI_BLOCK){
742
- blob_appendf(p->iblob,
743
- "\n<blockquote style='background:oldlace'><pre>%s</pre></blockquote>\n",
744
- htmlize( node->start, node->end - node->start)
745
- );
746
- }
709
+ if (node->kind & KIND_PARAGRAPH){
710
+ blob_append(p->iblob, "\n<p>", -1);
711
+ cr_parseInline(p, node->start, node->end );
712
+ blob_append(p->iblob, "</p>\n", -1 );
713
+ }
714
+
715
+ if (node->kind & KIND_HEADING){
716
+ blob_appendf(p->iblob,
717
+ "\n<h%d %s>",
718
+ node->level,
719
+ (node->flags & FLAG_CENTER) ? " style='text-align:center;'" : ""
720
+ );
721
+ cr_parseInline(p, node->start, node->end);
722
+ blob_appendf(p->iblob, "</h%d>\n", node->level );
723
+ return;
724
+ }
725
+
726
+ if (node->kind & KIND_HORIZONTAL_RULE){
727
+ blob_append(p->iblob, "<hr />", -1);
728
+ return;
729
+ }
730
+
731
+ if (node->kind & KIND_LIST){
732
+ cr_renderList(p);
733
+ p->list = NULL;
734
+ return;
735
+ }
736
+
737
+ if (node->kind & KIND_TABLE){
738
+ cr_renderTable(p, node);
739
+ return;
740
+ }
741
+
742
+ if (node->kind & KIND_NO_WIKI_BLOCK){
743
+ blob_appendf(p->iblob,
744
+ "\n<blockquote style='background:oldlace'><pre>%s</pre></blockquote>\n",
745
+ htmlize( node->start, node->end - node->start)
746
+ );
747
+ }
747748
}
748749
//}}}
749750
750751
static char *cr_findEndOfBlock(Parser *p, char *s, char c){//{{{
751752
752
- char *end;
753
- while (s[0]){
754
-
755
- end = s;
756
- if (s[0] == c && s[0] == c && s[0] == c) {
757
- s = cr_nextLine(p, s + 3);
758
- if (p->lineWasBlank) {
759
- p->cursor = s;
760
- return end;
761
- }
762
- }
763
- else {
764
- s = cr_nextLine(p, s);
765
- }
766
- }
767
- return 0;
753
+ char *end;
754
+ while (s[0]){
755
+
756
+ end = s;
757
+ if (s[0] == c && s[0] == c && s[0] == c) {
758
+ s = cr_nextLine(p, s + 3);
759
+ if (p->lineWasBlank) {
760
+ p->cursor = s;
761
+ return end;
762
+ }
763
+ }
764
+ else {
765
+ s = cr_nextLine(p, s);
766
+ }
767
+ }
768
+ return 0;
768769
}
769770
//}}}
770771
static int cr_addListItem(Parser *p, Node *n){//{{{
771772
772
- n->parent = n;
773
- n->next = n->children = NULL;
774
-
775
- if (!p->list) {
776
- if (n->level != 1) return 0;
777
- p->list = n;
778
- return 1;
779
- }
780
-
781
- Node *list = p->list;
782
-
783
- while (n->level < list->level){
784
- list = list->parent;
785
- }
786
-
787
- if (n->level == list->level){
788
-
789
- if (n->kind != list->kind){
790
- if (n->level>1) return 0;
791
- cr_renderList(p);
792
- p->list = n;
793
- return 1;
794
- }
795
- n->parent = list->parent;
796
- p->list = list->next = n;
797
- return 1;
798
- }
799
-
800
- if ( (n->level - list->level) > 1 ) return 0;
801
- n->parent = p->list;
802
- p->list->children = n;
803
- p->list = n;
804
- return 1;
773
+ n->parent = n;
774
+ n->next = n->children = NULL;
775
+
776
+ if (!p->list) {
777
+ if (n->level != 1) return 0;
778
+ p->list = n;
779
+ return 1;
780
+ }
781
+
782
+ Node *list = p->list;
783
+
784
+ while (n->level < list->level){
785
+ list = list->parent;
786
+ }
787
+
788
+ if (n->level == list->level){
789
+
790
+ if (n->kind != list->kind){
791
+ if (n->level>1) return 0;
792
+ cr_renderList(p);
793
+ p->list = n;
794
+ return 1;
795
+ }
796
+ n->parent = list->parent;
797
+ p->list = list->next = n;
798
+ return 1;
799
+ }
800
+
801
+ if ( (n->level - list->level) > 1 ) return 0;
802
+ n->parent = p->list;
803
+ p->list->children = n;
804
+ p->list = n;
805
+ return 1;
805806
806807
}
807808
//}}}
808809
809810
static int isEndWikiMarker(Parser *p){//{{{
810811
811
- char *s = p->cursor;
812
- if (memcmp(s, "<<fossil>>", 10)) return 0;
813
- p->this->start = s;
814
- p->this->kind = KIND_END_WIKI_MARKER;
815
- p->cursor += 10;
816
- return 1;
812
+ char *s = p->cursor;
813
+ if (memcmp(s, "<<fossil>>", 10)) return 0;
814
+ p->this->start = s;
815
+ p->this->kind = KIND_END_WIKI_MARKER;
816
+ p->cursor += 10;
817
+ return 1;
817818
}
818819
///}}}
819820
static int isNoWikiBlock(Parser *p){//{{{
820821
821
- char *s = p->cursor;
822
-
823
- if (s[0] != '{') return 0; s++;
824
- if (s[0] != '{') return 0; s++;
825
- if (s[0] != '{') return 0; s++;
826
-
827
- s = cr_nextLine(p, s);
828
- if (!p->lineWasBlank) return 0;
829
-
830
- p->this->start = s;
831
-
832
- s = cr_findEndOfBlock(p, s, '}');
833
-
834
- if (!s) return 0;
835
-
836
- // p->cursor was set by findEndOfBlock
837
- p->this->kind = KIND_NO_WIKI_BLOCK;
838
- p->this->end = s;
839
- return 1;
822
+ char *s = p->cursor;
823
+
824
+ if (s[0] != '{') return 0; s++;
825
+ if (s[0] != '{') return 0; s++;
826
+ if (s[0] != '{') return 0; s++;
827
+
828
+ s = cr_nextLine(p, s);
829
+ if (!p->lineWasBlank) return 0;
830
+
831
+ p->this->start = s;
832
+
833
+ s = cr_findEndOfBlock(p, s, '}');
834
+
835
+ if (!s) return 0;
836
+
837
+ // p->cursor was set by findEndOfBlock
838
+ p->this->kind = KIND_NO_WIKI_BLOCK;
839
+ p->this->end = s;
840
+ return 1;
840841
}
841842
842843
//}}}
843844
static int isParaBreak(Parser *p){//{{{
844845
845
- char *s = cr_nextLine(p, p->cursor);
846
- if (!p->lineWasBlank) return 0;
846
+ char *s = cr_nextLine(p, p->cursor);
847
+ if (!p->lineWasBlank) return 0;
847848
848
- p->cursor = s;
849
- p->this->kind = KIND_PARA_BREAK;
850
- return 1;
849
+ p->cursor = s;
850
+ p->this->kind = KIND_PARA_BREAK;
851
+ return 1;
851852
}
852853
//}}}
853854
static int isHeading(Parser *p){//{{{
854855
855
- char *s = cr_skipBlanks(p, p->cursor);
856
-
857
- int flags = 0;
858
- int level = cr_countChars(p, s, '=');
859
- if (!level) return 0;
860
-
861
- s += level;
862
-
863
- if (s[0] == '<' && s[1] == '>') {
864
- flags |= FLAG_CENTER;
865
- s += 2;
866
- }
867
- s = cr_skipBlanks(p, s);
868
-
869
- p->this->start = s;
870
-
871
- s = cr_nextLine(p, s);
872
- char *z = s;
873
-
874
- if (s[-1] == '\n') s--;
875
- while(s[-1] == ' ' || s[-1]=='\t') s--;
876
- while(s[-1] == '=' ) s--;
877
- if (p->this->start < s){
878
- p->cursor = z;
879
- p->this->kind = KIND_HEADING;
880
- p->this->end = s;
881
- p->this->level = level;
882
- p->this->flags |= flags;
883
- return 1;
884
- }
885
- return 0;
856
+ char *s = cr_skipBlanks(p, p->cursor);
857
+
858
+ int flags = 0;
859
+ int level = cr_countChars(p, s, '=');
860
+ if (!level) return 0;
861
+
862
+ s += level;
863
+
864
+ if (s[0] == '<' && s[1] == '>') {
865
+ flags |= FLAG_CENTER;
866
+ s += 2;
867
+ }
868
+ s = cr_skipBlanks(p, s);
869
+
870
+ p->this->start = s;
871
+
872
+ s = cr_nextLine(p, s);
873
+ char *z = s;
874
+
875
+ if (s[-1] == '\n') s--;
876
+ while(s[-1] == ' ' || s[-1]=='\t') s--;
877
+ while(s[-1] == '=' ) s--;
878
+ if (p->this->start < s){
879
+ p->cursor = z;
880
+ p->this->kind = KIND_HEADING;
881
+ p->this->end = s;
882
+ p->this->level = level;
883
+ p->this->flags |= flags;
884
+ return 1;
885
+ }
886
+ return 0;
886887
}
887888
//}}}
888889
static int isHorizontalRule(Parser *p){//{{{
889890
890
- char *s = cr_skipBlanks(p, p->cursor);
891
-
892
- int level = cr_countChars(p, s, '-');
893
-
894
- if (level < 4) return 0;
895
- s = cr_nextLine(p, s + level);
896
- if (!p->lineWasBlank) return 0;
897
-
898
- p->cursor = s;
899
- p->this->kind = KIND_HORIZONTAL_RULE;
900
-
901
- return 1;
891
+ char *s = cr_skipBlanks(p, p->cursor);
892
+
893
+ int level = cr_countChars(p, s, '-');
894
+
895
+ if (level < 4) return 0;
896
+ s = cr_nextLine(p, s + level);
897
+ if (!p->lineWasBlank) return 0;
898
+
899
+ p->cursor = s;
900
+ p->this->kind = KIND_HORIZONTAL_RULE;
901
+
902
+ return 1;
902903
}
903904
//}}}
904905
static int isListItem(Parser *p){//{{{
905906
906
- char *s = cr_skipBlanks(p, p->cursor);
907
-
908
- int level = cr_countChars(p, s, '#');
909
- if (!level) level = cr_countChars(p, s, '*');
910
-
911
- if ( !level) return 0;
912
-
913
- p->this->kind = (s[0] == '#') ? KIND_ORDERED_LIST : KIND_UNORDERED_LIST;
914
- p->this->level = level;
915
-
916
- s = cr_skipBlanks(p, s + level);
917
- p->this->start = s;
918
-
919
- s = cr_nextLine(p, s);
920
- if (p->lineWasBlank) return 0;
921
-
922
- if (cr_addListItem(p, p->this)){
923
- p->cursor = p->this->end = s;
924
- return 1;
925
- }
926
- p->this->kind = 0;
927
- return 0;
907
+ char *s = cr_skipBlanks(p, p->cursor);
908
+
909
+ int level = cr_countChars(p, s, '#');
910
+ if (!level) level = cr_countChars(p, s, '*');
911
+
912
+ if ( !level) return 0;
913
+
914
+ p->this->kind = (s[0] == '#') ? KIND_ORDERED_LIST : KIND_UNORDERED_LIST;
915
+ p->this->level = level;
916
+
917
+ s = cr_skipBlanks(p, s + level);
918
+ p->this->start = s;
919
+
920
+ s = cr_nextLine(p, s);
921
+ if (p->lineWasBlank) return 0;
922
+
923
+ if (cr_addListItem(p, p->this)){
924
+ p->cursor = p->this->end = s;
925
+ return 1;
926
+ }
927
+ p->this->kind = 0;
928
+ return 0;
928929
}
929930
//}}}
930931
static int isTable(Parser *p){//{{{
931932
932
- p->this->start = p->cursor;
933
- char *s = cr_skipBlanks(p, p->cursor);
934
- if (s[0] != '|') return 0;
933
+ p->this->start = p->cursor;
934
+ char *s = cr_skipBlanks(p, p->cursor);
935
+ if (s[0] != '|') return 0;
935936
s +=1;
936
- p->this->kind = KIND_TABLE;
937
-
938
-
939
- //p->cursor = p->this->end = cr_nextLine(p, s);
940
- Node *row;
941
- Node *tail = NULL;
942
-
943
- while (1) {
944
-
945
- row = pool_new(p);
946
- row->kind = KIND_TABLE_ROW;
947
-
948
- if (tail) tail = tail->next = row;
949
- else p->this->children = tail = row;
950
-
951
- row->start = s;
952
- p->cursor = s = row->end = p->this->end = cr_nextLine(p, s);
953
-
954
- if (row->end[-1] == '\n') row->end -= 1;
955
- while(row->end[-1] == ' ' ) row->end -= 1;
956
- if (row->end[-1] == '|') row->end -= 1;
957
-
958
- if (!*s) break;
959
-
960
- // blanks *not* normalized
961
- s = cr_skipBlanks(p, p->cursor);
962
- if (s[0] != '|') break;
963
- s++;
964
-
965
- }
966
- return 1;
937
+ p->this->kind = KIND_TABLE;
938
+
939
+
940
+ //p->cursor = p->this->end = cr_nextLine(p, s);
941
+ Node *row;
942
+ Node *tail = NULL;
943
+
944
+ while (1) {
945
+
946
+ row = pool_new(p);
947
+ row->kind = KIND_TABLE_ROW;
948
+
949
+ if (tail) tail = tail->next = row;
950
+ else p->this->children = tail = row;
951
+
952
+ row->start = s;
953
+ p->cursor = s = row->end = p->this->end = cr_nextLine(p, s);
954
+
955
+ if (row->end[-1] == '\n') row->end -= 1;
956
+ while(row->end[-1] == ' ' ) row->end -= 1;
957
+ if (row->end[-1] == '|') row->end -= 1;
958
+
959
+ if (!*s) break;
960
+
961
+ // blanks *not* normalized
962
+ s = cr_skipBlanks(p, p->cursor);
963
+ if (s[0] != '|') break;
964
+ s++;
965
+
966
+ }
967
+ return 1;
967968
968969
};
969970
//}}}
970971
static int isParagraph(Parser *p){//{{{
971972
972
- char *s = p->cursor;
973
- p->this->start = s;
974
-
975
- s = cr_nextLine(p, s);
976
- p->cursor = p->this->end = s;
977
- p->this->kind = KIND_PARAGRAPH;
978
- return 1;
979
-
980
-}
981
-//}}}
982
-static void cr_parse(Parser *p, char* z){//{{{
983
-
984
- p->previous = pool_new(p);
985
- p->previous->kind = KIND_PARA_BREAK;
986
-
987
- p->this = pool_new(p);
988
- p->this->kind = KIND_PARA_BREAK;
989
-
990
- p->inLink = 0;
991
- p->inTable = 0;
992
-
993
- p->cursor = z;
994
- p->list = NULL;
995
- p->istack = NULL;
996
-
997
- while (p->cursor[0]) {
998
-
999
- while (1){
1000
-
1001
- // must be first
1002
- if (isNoWikiBlock(p)) break;
1003
- if (isParaBreak(p)) break;
1004
-
1005
- // order not important
1006
- if (isHeading(p)) break;
1007
- if (isHorizontalRule(p)) break;
1008
- if (isListItem(p)) break;
1009
- if (isTable(p)) break;
1010
-
1011
- // here for efficiency?
1012
- if (isEndWikiMarker(p)) break;
1013
-
1014
- // must be last
1015
- if (isParagraph(p)); break;
1016
-
1017
- // doh!
1018
- assert(0);
1019
- }
1020
-
1021
- int kind = p->this->kind;
1022
- int prev = p->previous->kind;
1023
-
1024
- if (kind & KIND_END_WIKI_MARKER) return;
1025
-
1026
- if (kind == KIND_PARAGRAPH && prev & KIND_LIST_OR_PARAGRAPH) {
1027
- p->previous->end = p->this->end;
1028
- p->this = pool_new(p);
1029
- continue;
1030
- }
1031
-
1032
- if ( !(kind & KIND_LIST && prev & KIND_LIST) )
1033
- cr_render(p, p->previous);
1034
-
1035
- p->previous = p->this;
1036
- p->this = pool_new(p);
1037
-
1038
- }
1039
-}
1040
-//}}}
1041
-
1042
-//}}}
1043
-
1044
-char *wiki_render_creole(Renderer *r, char *z){//{{{
1045
-
1046
- Parser parser;
1047
- Parser *p = &parser;
1048
-
1049
- p->r = r;
1050
- p->iblob = r->pOut;
1051
-
1052
- p->nFree = 0;
1053
- p->pool = NULL;
1054
-
1055
- cr_parse(p, z);
1056
-
1057
- cr_render(p, p->previous);
1058
-
1059
- pool_free(p);
1060
-
1061
- return p->cursor;
1062
-
1063
-}
1064
-//}}}
1065
-
1066
-
1067
-char *wiki_render_macro(Renderer *p, char *z, int *tokenType){
1068
- if (!memcmp(z, "<<fossil>>", 9)){
1069
- *tokenType = 1;
1070
- return z + 10;
1071
- }
1072
- if (memcmp(z, "<<creole>>", 9)) {
1073
- *tokenType = 0;
1074
- return z;
1075
- }
1076
- *tokenType = 1;
1077
- return wiki_render_creole(p, z+10);
1078
-
1079
-}
1080
-
1081
-/* :folding=explicit:collapseFolds=1:tabSize=2:indentSize=2:noTabs=false: */
973
+ char *s = p->cursor;
974
+ p->this->start = s;
975
+
976
+ s = cr_nextLine(p, s);
977
+ p->cursor = p->this->end = s;
978
+ p->this->kind = KIND_PARAGRAPH;
979
+ return 1;
980
+
981
+}
982
+//}}}
983
+static void cr_parse(Parser *p, char* z){//{{{
984
+
985
+ p->previous = pool_new(p);
986
+ p->previous->kind = KIND_PARA_BREAK;
987
+
988
+ p->this = pool_new(p);
989
+ p->this->kind = KIND_PARA_BREAK;
990
+
991
+ p->inLink = 0;
992
+ p->inTable = 0;
993
+
994
+ p->cursor = z;
995
+ p->list = NULL;
996
+ p->istack = NULL;
997
+
998
+ while (p->cursor[0]) {
999
+
1000
+ while (1){
1001
+
1002
+ // must be first
1003
+ if (isNoWikiBlock(p)) break;
1004
+ if (isParaBreak(p)) break;
1005
+
1006
+ // order not important
1007
+ if (isHeading(p)) break;
1008
+ if (isHorizontalRule(p)) break;
1009
+ if (isListItem(p)) break;
1010
+ if (isTable(p)) break;
1011
+
1012
+ // here for efficiency?
1013
+ if (isEndWikiMarker(p)) break;
1014
+
1015
+ // must be last
1016
+ if (isParagraph(p)); break;
1017
+
1018
+ // doh!
1019
+ assert(0);
1020
+ }
1021
+
1022
+ int kind = p->this->kind;
1023
+ int prev = p->previous->kind;
1024
+
1025
+ if (kind & KIND_END_WIKI_MARKER) return;
1026
+
1027
+ if (kind == KIND_PARAGRAPH && prev & KIND_LIST_OR_PARAGRAPH) {
1028
+ p->previous->end = p->this->end;
1029
+ p->this = pool_new(p);
1030
+ continue;
1031
+ }
1032
+
1033
+ if ( !(kind & KIND_LIST && prev & KIND_LIST) )
1034
+ cr_render(p, p->previous);
1035
+
1036
+ p->previous = p->this;
1037
+ p->this = pool_new(p);
1038
+
1039
+ }
1040
+}
1041
+//}}}
1042
+
1043
+//}}}
1044
+
1045
+char *wiki_render_creole(Renderer *r, char *z){
1046
+
1047
+ Parser parser;
1048
+ Parser *p = &parser;
1049
+
1050
+ p->r = r;
1051
+ p->iblob = r->pOut;
1052
+
1053
+ p->nFree = 0;
1054
+ p->pool = NULL;
1055
+
1056
+ cr_parse(p, z);
1057
+
1058
+ cr_render(p, p->previous);
1059
+
1060
+ pool_free(p);
1061
+
1062
+ return p->cursor;
1063
+
1064
+}
1065
+
10821066
--- src/creoleparser.c
+++ src/creoleparser.c
@@ -28,11 +28,11 @@
28 #include <assert.h>
29 #include "config.h"
30 #include "creoleparser.h"
31
32 #if INTERFACE
33 #define HAVE_MACRO_EXTENSIONS 1
34 #endif
35
36 //{{{ LOCAL INTERFACE
37 #if LOCAL_INTERFACE
38
@@ -61,59 +61,59 @@
61
62 #define KIND_TABLE_ROW 0x0010000
63 //}}}
64 //{{{ FLAG
65 // keep first four bits free
66 #define FLAG_CENTER 0x0000100
67 //}}}
68 struct Node {//{{{
69
70 char *start;
71 char *end;
72
73 int kind;
74 int level;
75 int flags;
76
77 Node *parent;
78 Node *next;
79 Node *children;
80
81 };
82 //}}}
83 struct NodePool {//{{{
84 NodePool *next;
85 Node a[POOL_CHUNK_SIZE];
86 }
87 //}}}
88 struct Parser {//{{{
89
90 Blob *pOut; /* Output appended to this blob */
91 Renderer *r;
92
93 NodePool *pool;
94 int nFree;
95
96 Node *this;
97 Node *previous;
98 Node *list;
99
100 char *cursor;
101
102 int lineWasBlank;
103 int charCount;
104
105 Node *item;
106 Node *istack;
107 char *icursor;
108 char *iend;
109
110 int inLink;
111 int inTable;
112 int iesc;
113
114 Blob *iblob;
115
116
117
118
119 };
@@ -126,484 +126,485 @@
126 //}}}
127
128 //{{{ POOL MANAGEMENT
129 static Node *pool_new(Parser *p){
130
131 if ( p->pool == NULL || p->nFree == 0){
132
133 NodePool *temp = p->pool;
134
135 p->pool = malloc(sizeof(NodePool));
136 if( p->pool == NULL ) fossil_panic("out of memory");
137
138 p->pool->next = temp;
139 p->nFree = POOL_CHUNK_SIZE;
140 }
141 p->nFree -= 1;
142 Node *node = &(p->pool->a[p->nFree]);
143 memset(node, 0, sizeof(*node));
144
145 return node;
146 }
147
148
149 static void pool_free(Parser *p){
150
151 NodePool *temp;
152
153 while (p->pool != NULL){
154 temp = p->pool;
155 p->pool = temp->next;
156 free(temp);
157 }
158
159 }
160 //}}}
161
162 //{{{ Utility Methods
163
164 static char *cr_skipBlanks(Parser *p, char* z){//{{{
165 char *s = z;
166 while (z[0] == ' ' || z[0] == '\t') z++;
167 p->charCount = z - s;
168 return z;
169 }
170 //}}}
171 static int cr_countBlanks(Parser *p, char* z){//{{{
172 cr_skipBlanks(p, z);
173 return p->charCount;
174 }
175 //}}}
176 static char *cr_skipChars(Parser *p, char *z, char c){//{{{
177 char *s = z;
178 while (z[0] == c) z++;
179 p->charCount = z - s;
180 return z;
181 }
182 //}}}
183 static int cr_countChars(Parser *p, char *z, char c){//{{{
184 cr_skipChars(p, z, c);
185 return p->charCount;
186 }
187 //}}}
188 static char *cr_nextLine(Parser *p, char *z){//{{{
189
190 p->lineWasBlank = 1;
191
192 while (1){
193
194 switch (z[0]){
195
196 case '\r':
197 if (z[1] == '\n') {
198 z[0] = ' ';
199 return z + 2;
200 }
201 z[0] = '\n';
202 return z + 1;
203
204 case'\n':
205 return z + 1;
206
207 case '\t':
208 z[0] = ' ';
209 z++;
210 break;
211
212 case ' ':
213 z++;
214 break;
215
216 case '\0':
217 return z;
218
219 default:
220 p->lineWasBlank = 0;
221 z++;
222 }
223 }
224 }
225 //}}}
226 //}}}
227
228 //{{{ INLINE PARSER
229
230 static int cr_isEsc(Parser *p){//{{{
231 if (p->iesc){
232 blob_append(p->iblob, p->icursor, 1);
233 p->iesc = 0;
234 p->icursor += 1;
235 return 1;
236 }
237 return 0;
238 }
239 //}}}
240 static int cr_iOpen(Parser *p, int kind){//{{{
241
242 switch (kind){
243
244 case KIND_BOLD:
245 blob_append(p->iblob, "<strong>", 8);
246 return 1;
247
248 case KIND_ITALIC:
249 blob_append(p->iblob, "<em>", 4);
250 return 1;
251
252 case KIND_SUPERSCRIPT:
253 blob_append(p->iblob, "<sup>", 5);
254 return 1;
255
256 case KIND_SUBSCRIPT:
257 blob_append(p->iblob, "<sub>", 5);
258 return 1;
259
260 case KIND_MONOSPACED:
261 blob_append(p->iblob, "<tt>", 4);
262 return 1;
263 }
264 return 0;
265 }
266 //}}}
267 static int cr_iClose(Parser *p, int kind){//{{{
268
269 switch (kind){
270
271 case KIND_BOLD:
272 blob_append(p->iblob, "</strong>", 9);
273 return 1;
274
275 case KIND_ITALIC:
276 blob_append(p->iblob, "</em>", 5);
277 return 1;
278
279 case KIND_SUPERSCRIPT:
280 blob_append(p->iblob, "</sup>", 6);
281 return 1;
282
283 case KIND_SUBSCRIPT:
284 blob_append(p->iblob, "</sub>", 6);
285 return 1;
286
287 case KIND_MONOSPACED:
288 blob_append(p->iblob, "</tt>", 5);
289 return 1;
290 }
291 return 0;
292 }
293 //}}}
294
295
296 static void cr_iMarkup(Parser *p, int kind){//{{{
297
298 if (p->iesc) {
299 blob_append(p->iblob, p->icursor, 1);
300 p->icursor +=1;
301 p->iesc =0;
302 return;
303 }
304
305 if (p->icursor[1] != p->icursor[0]) {
306 blob_append(p->iblob, p->icursor, 1);
307 p->icursor +=1;
308 return;
309 }
310
311 p->icursor += 2;
312
313 if (kind & KIND_BREAK) {
314 blob_append(p->iblob, "<br />", 6);
315 return;
316 }
317
318 if (kind & KIND_ITALIC && p->icursor[-3] == ':'){
319 blob_append(p->iblob, "//", 2);
320 return;
321 }
322
323 Node *n = p->istack;
324
325 int found = 0;
326 while (n) {
327 if (n->kind & kind) {
328 found = 1;
329 break;
330 }
331 n = n->next;
332 }
333
334 if (!found) {
335 n = pool_new(p);
336 n->kind = kind;
337 n->next = p->istack;
338 p->istack = n;
339
340 assert(cr_iOpen(p, kind));
341 return;
342 };
343
344 n= p->istack;
345 while (n){
346 p->istack = n->next;
347
348 assert(cr_iClose(p, n->kind));
349
350 if (kind == n->kind) return;
351 n = p->istack;
352 }
353 }
354 //}}}
355 static int cr_iNoWiki(Parser *p){//{{{
356
357 if ((p->iend - p->icursor)<6) return 0;
358
359 if (p->icursor[1]!='{' || p->icursor[2]!='{')
360 return 0;
361
362 char *s = p->icursor + 3;
363
364 int count = p->iend - p->icursor - 6;
365 while (count--){
366 if (s[0]=='}' && s[1]=='}' && s[2]=='}' && s[3]!='}'){
367 blob_appendf(p->iblob, "<tt style='background:oldlace'>%s</tt>", htmlize(p->icursor + 3, s - p->icursor-3));
368 p->icursor = s + 3;
369 return 1;
370 }
371 s++;
372 }
373 return 0;
374 }
375
376 //}}}
377 static int cr_iImage(Parser *p){//{{{
378
379 if (p->inLink) return 0;
380 if ((p->iend - p->icursor)<3) return 0;
381
382 if (p->icursor[1]!='{') return 0;
383
384 char *s = p->icursor + 2;
385 char *bar = NULL;
386
387 int count = p->iend - p->icursor - 4;
388 while (count--){
389 if (s[0]=='}' && s[1]=='}'){
390 if (!bar) bar = p->icursor + 2;
391 blob_appendf(p->iblob, "<span style='color:green;border:1px solid green;'>%s</span>", htmlize(bar, s - bar ));
392 p->icursor = s + 2;
393 return 1;
394 }
395 if (!bar && s[0]=='|') bar=s+1;
396 s++;
397 }
398 return 0;
399 }
400 //}}}
401 static int cr_iMacro(Parser *p){//{{{
402
403 if (p->inLink) return 0;
404 if ((p->iend - p->icursor)<3) return 0;
405
406 if (p->icursor[1]!='<') return 0;
407
408 char *s = p->icursor + 2;
409
410 int count = p->iend - p->icursor - 4;
411 while (count--){
412 if (s[0]=='>' && s[1]=='>'){
413 blob_appendf(p->iblob, "<span style='color:red;border:1px solid red;'>%s</span>", htmlize(p->icursor, s - p->icursor + 2));
414 p->icursor = s + 2;
415 return 1;
416 }
417 s++;
418 }
419 return 0;
 
420
421 }
422 //}}}
423
424 static void cr_renderLink(Parser *p, char *s, char *bar, char *e){//{{{
425
426 int tsize = bar-s;
427 int dsize = e - bar-1;
428
429 if (tsize < 1) return;
430 if (dsize < 1) dsize = 0;
431
432 char zTarget[tsize + 1];
433 memcpy(zTarget, s, tsize);
434 zTarget[tsize] = '\0';
435
436 char zClose[20];
437
438 Blob *pOut = p->r->pOut;
439
440 p->r->pOut = p->iblob;
441 wf_openHyperlink(p->r, zTarget, zClose, sizeof(zClose));
442 p->r->pOut = pOut;
443
444 if (dsize)
445 cr_parseInline(p, bar+1, e) ;
446 else
447 blob_append(p->iblob, htmlize(s, tsize), -1);
448 blob_append(p->iblob, zClose, -1);
449 }
450 //}}}
451
452 static int cr_iLink(Parser *p){//{{{
453
454 if (p->inLink) return 0;
455 if ((p->iend - p->icursor)<3) return 0;
456
457 if (p->icursor[1]!='[') return 0;
458
459 char *s = p->icursor + 2;
460 char *bar = NULL;
461
462 int count = p->iend - p->icursor -3;
463 while (count--){
464 if (s[0]==']' && s[1]==']'){
465 if (!bar) bar = s;
466 p->inLink = 1;
467 cr_renderLink(p, p->icursor+2, bar, s);
468 p->inLink = 0;
469 p->icursor = s + 2;
470 return 1;
471 }
472 if (!bar && s[0]=='|') bar=s;
473 s++;
474 }
475 return 0;
476 }
477 //}}}
478
479 LOCAL char *cr_parseInline(Parser *p, char *s, char *e){//{{{
480
481 int save_iesc = p->iesc;
482 char *save_iend = p->iend;
483 Node *save_istack = p->istack;
484
485 p->iesc = 0;
486 p->iend = e;
487 p->istack = NULL;
488
489 p->icursor = s;
490
491 char *eof = NULL;
492 while (!eof && p->icursor < p->iend ){
493
494 switch (*p->icursor) {//{{{
495
496 case '~':
497 if (p->iesc) {
498 blob_append(p->iblob, "~", 1);
499 p->iesc = 0;
500 }
501 p->iesc = !p->iesc;
502 p->icursor+=1;
503 break;
504
505 case '*':
506 cr_iMarkup(p, KIND_BOLD);
507 break;
508
509 case '/':
510 cr_iMarkup(p, KIND_ITALIC);
511 break;
512
513 case '^':
514 cr_iMarkup(p, KIND_SUPERSCRIPT);
515 break;
516
517 case ',':
518 cr_iMarkup(p, KIND_SUBSCRIPT);
519 break;
520
521 case '#':
522 cr_iMarkup(p, KIND_MONOSPACED);
523 break;
524
525 case '\\':
526 cr_iMarkup(p, KIND_BREAK);
527 break;
528
529 case '{':
530 if (cr_isEsc(p)) break;
531 if (cr_iNoWiki(p)) break;
532 if (cr_iImage(p)) break;
533 blob_append(p->iblob, p->icursor, 1);
534 p->icursor += 1;
535 break;
536
537 case '[':
538 if (cr_isEsc(p)) break;
539 if (cr_iLink(p)) break;
540 blob_append(p->iblob, p->icursor, 1);
541 p->icursor += 1;
542 break;
543
544
545 case '<':
546 if (cr_isEsc(p)) break;
547 if (cr_iMacro(p)) break;
548
549 blob_append(p->iblob, "&lt;", 4);
550 p->icursor += 1;
551 break;
552
553 case '>':
554 if (p->iesc) {
555 blob_append(p->iblob, "~", 1);
556 p->iesc = 0;
557 }
558 blob_append(p->iblob, "&gt;", 4);
559 p->icursor += 1;
560 break;
561
562 case '&':
563 if (p->iesc) {
564 blob_append(p->iblob, "~", 1);
565 p->iesc = 0;
566 }
567 blob_append(p->iblob, "&amp;", 5);
568 p->icursor += 1;
569 break;
570
571 case '|':
572 if (p->inTable){
573 if (p->iesc) {
574 blob_append(p->iblob, p->icursor, 1);
575 p->iesc = 0;
576 p->icursor += 1;
577 break;
578 }
579 eof = p->icursor + 1;
580 break;
581 }
582 // fall through to default
583
584 default:
585 if (p->iesc) {
586 blob_append(p->iblob, "~", 1);
587 p->iesc = 0;
588 }
589 blob_append(p->iblob, p->icursor, 1);
590 p->icursor +=1;
591 }//}}}
592
593 }
594
595 while (p->istack){
596 cr_iClose(p, p->istack->kind);
597 p->istack = p->istack->next;
598 }
599
600 p->iesc = save_iesc;
601 p->iend = save_iend;
602 p->istack = save_istack;
603
604 return eof;
605
606 }
607 //}}}
608 //}}}
609
@@ -610,472 +611,455 @@
610 //{{{ BLOCK PARSER
611
612 static void cr_renderListItem(Parser *p, Node *n){//{{{
613
614
615 blob_append(p->iblob, "<li>", 4);
616 cr_parseInline(p, n->start, n->end);
617
618 if (n->children){
619
620 int ord = (n->children->kind & KIND_ORDERED_LIST);
621
622 if (ord) blob_append(p->iblob, "<ol>", 4);
623 else blob_append(p->iblob, "<ul>", 4);
624
625 n = n->children;
626 while (n){
627 cr_renderListItem(p, n);
628 n = n->next;
629 }
630
631 if (ord) blob_append(p->iblob, "</ol>", 5);
632 else blob_append(p->iblob, "</ul>", 5);
633 }
634 blob_append(p->iblob, "</li>", 5);
635 }
636 //}}}
637 static void cr_renderList(Parser *p){//{{{
638
639 Node *n = p->list;
640
641 while (n->parent !=n) n = n->parent;
642
643 int ord = (n->kind & KIND_ORDERED_LIST);
644
645 if (ord) blob_append(p->iblob, "\n\n<ol>", -1);
646 else blob_append(p->iblob, "\n\n<ul>", -1);
647
648 while (n) {
649 cr_renderListItem(p, n);
650 n = n->next;
651 }
652
653 if (ord) blob_append(p->iblob, "</ol>", 5);
654 else blob_append(p->iblob, "</ul>", 5);
655 }
656
657 //}}}
658
659 static void cr_renderTableRow(Parser *p, Node *row){//{{{
660
661 char *s = row->start;
662 int th;
663
664 blob_append(p->iblob, "\n<tr>", -1);
665
666 while (s && s < row->end){
667
668 if ((th = *s == '=')) {
669 s++;
670 blob_append(p->iblob, "<th>", -1);
671 }
672 else {
673 blob_append(p->iblob, "<td>", -1);
674 }
675
676 s = cr_parseInline(p, s, row->end);
677
678 if (th)
679 blob_append(p->iblob, "</th>\n", -1);
680 else
681 blob_append(p->iblob, "</td>\n", -1);
682
683 if (!s) break;
684 }
685 blob_append(p->iblob, "</tr>", 5);
686 }
687 //}}}
688 static void cr_renderTable(Parser *p, Node *n){//{{{
689
690 Node *row = n->children;
691
692 blob_append(p->iblob, "<table class='creoletable'>", -1);
693 p->inTable = 1;
694 while (row){
695
696 cr_renderTableRow(p, row);
697 row = row->next;
698
699 }
700 blob_append(p->iblob, "</table>", -1);
701 p->inTable = 0;
702
703 }
704 //}}}
705
706 static void cr_render(Parser *p, Node *node){//{{{
707
708 if (node->kind & KIND_PARAGRAPH){
709 blob_append(p->iblob, "\n<p>", -1);
710 cr_parseInline(p, node->start, node->end );
711 blob_append(p->iblob, "</p>\n", -1 );
712 }
713
714 if (node->kind & KIND_HEADING){
715 blob_appendf(p->iblob,
716 "\n<h%d %s>",
717 node->level,
718 (node->flags & FLAG_CENTER) ? " style='text-align:center;'" : ""
719 );
720 cr_parseInline(p, node->start, node->end);
721 blob_appendf(p->iblob, "</h%d>\n", node->level );
722 return;
723 }
724
725 if (node->kind & KIND_HORIZONTAL_RULE){
726 blob_append(p->iblob, "<hr />", -1);
727 return;
728 }
729
730 if (node->kind & KIND_LIST){
731 cr_renderList(p);
732 p->list = NULL;
733 return;
734 }
735
736 if (node->kind & KIND_TABLE){
737 cr_renderTable(p, node);
738 return;
739 }
740
741 if (node->kind & KIND_NO_WIKI_BLOCK){
742 blob_appendf(p->iblob,
743 "\n<blockquote style='background:oldlace'><pre>%s</pre></blockquote>\n",
744 htmlize( node->start, node->end - node->start)
745 );
746 }
747 }
748 //}}}
749
750 static char *cr_findEndOfBlock(Parser *p, char *s, char c){//{{{
751
752 char *end;
753 while (s[0]){
754
755 end = s;
756 if (s[0] == c && s[0] == c && s[0] == c) {
757 s = cr_nextLine(p, s + 3);
758 if (p->lineWasBlank) {
759 p->cursor = s;
760 return end;
761 }
762 }
763 else {
764 s = cr_nextLine(p, s);
765 }
766 }
767 return 0;
768 }
769 //}}}
770 static int cr_addListItem(Parser *p, Node *n){//{{{
771
772 n->parent = n;
773 n->next = n->children = NULL;
774
775 if (!p->list) {
776 if (n->level != 1) return 0;
777 p->list = n;
778 return 1;
779 }
780
781 Node *list = p->list;
782
783 while (n->level < list->level){
784 list = list->parent;
785 }
786
787 if (n->level == list->level){
788
789 if (n->kind != list->kind){
790 if (n->level>1) return 0;
791 cr_renderList(p);
792 p->list = n;
793 return 1;
794 }
795 n->parent = list->parent;
796 p->list = list->next = n;
797 return 1;
798 }
799
800 if ( (n->level - list->level) > 1 ) return 0;
801 n->parent = p->list;
802 p->list->children = n;
803 p->list = n;
804 return 1;
805
806 }
807 //}}}
808
809 static int isEndWikiMarker(Parser *p){//{{{
810
811 char *s = p->cursor;
812 if (memcmp(s, "<<fossil>>", 10)) return 0;
813 p->this->start = s;
814 p->this->kind = KIND_END_WIKI_MARKER;
815 p->cursor += 10;
816 return 1;
817 }
818 ///}}}
819 static int isNoWikiBlock(Parser *p){//{{{
820
821 char *s = p->cursor;
822
823 if (s[0] != '{') return 0; s++;
824 if (s[0] != '{') return 0; s++;
825 if (s[0] != '{') return 0; s++;
826
827 s = cr_nextLine(p, s);
828 if (!p->lineWasBlank) return 0;
829
830 p->this->start = s;
831
832 s = cr_findEndOfBlock(p, s, '}');
833
834 if (!s) return 0;
835
836 // p->cursor was set by findEndOfBlock
837 p->this->kind = KIND_NO_WIKI_BLOCK;
838 p->this->end = s;
839 return 1;
840 }
841
842 //}}}
843 static int isParaBreak(Parser *p){//{{{
844
845 char *s = cr_nextLine(p, p->cursor);
846 if (!p->lineWasBlank) return 0;
847
848 p->cursor = s;
849 p->this->kind = KIND_PARA_BREAK;
850 return 1;
851 }
852 //}}}
853 static int isHeading(Parser *p){//{{{
854
855 char *s = cr_skipBlanks(p, p->cursor);
856
857 int flags = 0;
858 int level = cr_countChars(p, s, '=');
859 if (!level) return 0;
860
861 s += level;
862
863 if (s[0] == '<' && s[1] == '>') {
864 flags |= FLAG_CENTER;
865 s += 2;
866 }
867 s = cr_skipBlanks(p, s);
868
869 p->this->start = s;
870
871 s = cr_nextLine(p, s);
872 char *z = s;
873
874 if (s[-1] == '\n') s--;
875 while(s[-1] == ' ' || s[-1]=='\t') s--;
876 while(s[-1] == '=' ) s--;
877 if (p->this->start < s){
878 p->cursor = z;
879 p->this->kind = KIND_HEADING;
880 p->this->end = s;
881 p->this->level = level;
882 p->this->flags |= flags;
883 return 1;
884 }
885 return 0;
886 }
887 //}}}
888 static int isHorizontalRule(Parser *p){//{{{
889
890 char *s = cr_skipBlanks(p, p->cursor);
891
892 int level = cr_countChars(p, s, '-');
893
894 if (level < 4) return 0;
895 s = cr_nextLine(p, s + level);
896 if (!p->lineWasBlank) return 0;
897
898 p->cursor = s;
899 p->this->kind = KIND_HORIZONTAL_RULE;
900
901 return 1;
902 }
903 //}}}
904 static int isListItem(Parser *p){//{{{
905
906 char *s = cr_skipBlanks(p, p->cursor);
907
908 int level = cr_countChars(p, s, '#');
909 if (!level) level = cr_countChars(p, s, '*');
910
911 if ( !level) return 0;
912
913 p->this->kind = (s[0] == '#') ? KIND_ORDERED_LIST : KIND_UNORDERED_LIST;
914 p->this->level = level;
915
916 s = cr_skipBlanks(p, s + level);
917 p->this->start = s;
918
919 s = cr_nextLine(p, s);
920 if (p->lineWasBlank) return 0;
921
922 if (cr_addListItem(p, p->this)){
923 p->cursor = p->this->end = s;
924 return 1;
925 }
926 p->this->kind = 0;
927 return 0;
928 }
929 //}}}
930 static int isTable(Parser *p){//{{{
931
932 p->this->start = p->cursor;
933 char *s = cr_skipBlanks(p, p->cursor);
934 if (s[0] != '|') return 0;
935 s +=1;
936 p->this->kind = KIND_TABLE;
937
938
939 //p->cursor = p->this->end = cr_nextLine(p, s);
940 Node *row;
941 Node *tail = NULL;
942
943 while (1) {
944
945 row = pool_new(p);
946 row->kind = KIND_TABLE_ROW;
947
948 if (tail) tail = tail->next = row;
949 else p->this->children = tail = row;
950
951 row->start = s;
952 p->cursor = s = row->end = p->this->end = cr_nextLine(p, s);
953
954 if (row->end[-1] == '\n') row->end -= 1;
955 while(row->end[-1] == ' ' ) row->end -= 1;
956 if (row->end[-1] == '|') row->end -= 1;
957
958 if (!*s) break;
959
960 // blanks *not* normalized
961 s = cr_skipBlanks(p, p->cursor);
962 if (s[0] != '|') break;
963 s++;
964
965 }
966 return 1;
967
968 };
969 //}}}
970 static int isParagraph(Parser *p){//{{{
971
972 char *s = p->cursor;
973 p->this->start = s;
974
975 s = cr_nextLine(p, s);
976 p->cursor = p->this->end = s;
977 p->this->kind = KIND_PARAGRAPH;
978 return 1;
979
980 }
981 //}}}
982 static void cr_parse(Parser *p, char* z){//{{{
983
984 p->previous = pool_new(p);
985 p->previous->kind = KIND_PARA_BREAK;
986
987 p->this = pool_new(p);
988 p->this->kind = KIND_PARA_BREAK;
989
990 p->inLink = 0;
991 p->inTable = 0;
992
993 p->cursor = z;
994 p->list = NULL;
995 p->istack = NULL;
996
997 while (p->cursor[0]) {
998
999 while (1){
1000
1001 // must be first
1002 if (isNoWikiBlock(p)) break;
1003 if (isParaBreak(p)) break;
1004
1005 // order not important
1006 if (isHeading(p)) break;
1007 if (isHorizontalRule(p)) break;
1008 if (isListItem(p)) break;
1009 if (isTable(p)) break;
1010
1011 // here for efficiency?
1012 if (isEndWikiMarker(p)) break;
1013
1014 // must be last
1015 if (isParagraph(p)); break;
1016
1017 // doh!
1018 assert(0);
1019 }
1020
1021 int kind = p->this->kind;
1022 int prev = p->previous->kind;
1023
1024 if (kind & KIND_END_WIKI_MARKER) return;
1025
1026 if (kind == KIND_PARAGRAPH && prev & KIND_LIST_OR_PARAGRAPH) {
1027 p->previous->end = p->this->end;
1028 p->this = pool_new(p);
1029 continue;
1030 }
1031
1032 if ( !(kind & KIND_LIST && prev & KIND_LIST) )
1033 cr_render(p, p->previous);
1034
1035 p->previous = p->this;
1036 p->this = pool_new(p);
1037
1038 }
1039 }
1040 //}}}
1041
1042 //}}}
1043
1044 char *wiki_render_creole(Renderer *r, char *z){//{{{
1045
1046 Parser parser;
1047 Parser *p = &parser;
1048
1049 p->r = r;
1050 p->iblob = r->pOut;
1051
1052 p->nFree = 0;
1053 p->pool = NULL;
1054
1055 cr_parse(p, z);
1056
1057 cr_render(p, p->previous);
1058
1059 pool_free(p);
1060
1061 return p->cursor;
1062
1063 }
1064 //}}}
1065
1066
1067 char *wiki_render_macro(Renderer *p, char *z, int *tokenType){
1068 if (!memcmp(z, "<<fossil>>", 9)){
1069 *tokenType = 1;
1070 return z + 10;
1071 }
1072 if (memcmp(z, "<<creole>>", 9)) {
1073 *tokenType = 0;
1074 return z;
1075 }
1076 *tokenType = 1;
1077 return wiki_render_creole(p, z+10);
1078
1079 }
1080
1081 /* :folding=explicit:collapseFolds=1:tabSize=2:indentSize=2:noTabs=false: */
1082
--- src/creoleparser.c
+++ src/creoleparser.c
@@ -28,11 +28,11 @@
28 #include <assert.h>
29 #include "config.h"
30 #include "creoleparser.h"
31
32 #if INTERFACE
33 #define HAVE_CREOLE_MACRO 1
34 #endif
35
36 //{{{ LOCAL INTERFACE
37 #if LOCAL_INTERFACE
38
@@ -61,59 +61,59 @@
61
62 #define KIND_TABLE_ROW 0x0010000
63 //}}}
64 //{{{ FLAG
65 // keep first four bits free
66 #define FLAG_CENTER 0x0000100
67 //}}}
68 struct Node {//{{{
69
70 char *start;
71 char *end;
72
73 int kind;
74 int level;
75 int flags;
76
77 Node *parent;
78 Node *next;
79 Node *children;
80
81 };
82 //}}}
83 struct NodePool {//{{{
84 NodePool *next;
85 Node a[POOL_CHUNK_SIZE];
86 }
87 //}}}
88 struct Parser {//{{{
89
90 Blob *pOut; /* Output appended to this blob */
91 Renderer *r;
92
93 NodePool *pool;
94 int nFree;
95
96 Node *this;
97 Node *previous;
98 Node *list;
99
100 char *cursor;
101
102 int lineWasBlank;
103 int charCount;
104
105 Node *item;
106 Node *istack;
107 char *icursor;
108 char *iend;
109
110 int inLink;
111 int inTable;
112 int iesc;
113
114 Blob *iblob;
115
116
117
118
119 };
@@ -126,484 +126,485 @@
126 //}}}
127
128 //{{{ POOL MANAGEMENT
129 static Node *pool_new(Parser *p){
130
131 if ( p->pool == NULL || p->nFree == 0){
132
133 NodePool *temp = p->pool;
134
135 p->pool = malloc(sizeof(NodePool));
136 if( p->pool == NULL ) fossil_panic("out of memory");
137
138 p->pool->next = temp;
139 p->nFree = POOL_CHUNK_SIZE;
140 }
141 p->nFree -= 1;
142 Node *node = &(p->pool->a[p->nFree]);
143 memset(node, 0, sizeof(*node));
144
145 return node;
146 }
147
148
149 static void pool_free(Parser *p){
150
151 NodePool *temp;
152
153 while (p->pool != NULL){
154 temp = p->pool;
155 p->pool = temp->next;
156 free(temp);
157 }
158
159 }
160 //}}}
161
162 //{{{ Utility Methods
163
164 static char *cr_skipBlanks(Parser *p, char* z){//{{{
165 char *s = z;
166 while (z[0] == ' ' || z[0] == '\t') z++;
167 p->charCount = z - s;
168 return z;
169 }
170 //}}}
171 static int cr_countBlanks(Parser *p, char* z){//{{{
172 cr_skipBlanks(p, z);
173 return p->charCount;
174 }
175 //}}}
176 static char *cr_skipChars(Parser *p, char *z, char c){//{{{
177 char *s = z;
178 while (z[0] == c) z++;
179 p->charCount = z - s;
180 return z;
181 }
182 //}}}
183 static int cr_countChars(Parser *p, char *z, char c){//{{{
184 cr_skipChars(p, z, c);
185 return p->charCount;
186 }
187 //}}}
188 static char *cr_nextLine(Parser *p, char *z){//{{{
189
190 p->lineWasBlank = 1;
191
192 while (1){
193
194 switch (z[0]){
195
196 case '\r':
197 if (z[1] == '\n') {
198 z[0] = ' ';
199 return z + 2;
200 }
201 z[0] = '\n';
202 return z + 1;
203
204 case'\n':
205 return z + 1;
206
207 case '\t':
208 z[0] = ' ';
209 z++;
210 break;
211
212 case ' ':
213 z++;
214 break;
215
216 case '\0':
217 return z;
218
219 default:
220 p->lineWasBlank = 0;
221 z++;
222 }
223 }
224 }
225 //}}}
226 //}}}
227
228 //{{{ INLINE PARSER
229
230 static int cr_isEsc(Parser *p){//{{{
231 if (p->iesc){
232 blob_append(p->iblob, p->icursor, 1);
233 p->iesc = 0;
234 p->icursor += 1;
235 return 1;
236 }
237 return 0;
238 }
239 //}}}
240 static int cr_iOpen(Parser *p, int kind){//{{{
241
242 switch (kind){
243
244 case KIND_BOLD:
245 blob_append(p->iblob, "<strong>", 8);
246 return 1;
247
248 case KIND_ITALIC:
249 blob_append(p->iblob, "<em>", 4);
250 return 1;
251
252 case KIND_SUPERSCRIPT:
253 blob_append(p->iblob, "<sup>", 5);
254 return 1;
255
256 case KIND_SUBSCRIPT:
257 blob_append(p->iblob, "<sub>", 5);
258 return 1;
259
260 case KIND_MONOSPACED:
261 blob_append(p->iblob, "<tt>", 4);
262 return 1;
263 }
264 return 0;
265 }
266 //}}}
267 static int cr_iClose(Parser *p, int kind){//{{{
268
269 switch (kind){
270
271 case KIND_BOLD:
272 blob_append(p->iblob, "</strong>", 9);
273 return 1;
274
275 case KIND_ITALIC:
276 blob_append(p->iblob, "</em>", 5);
277 return 1;
278
279 case KIND_SUPERSCRIPT:
280 blob_append(p->iblob, "</sup>", 6);
281 return 1;
282
283 case KIND_SUBSCRIPT:
284 blob_append(p->iblob, "</sub>", 6);
285 return 1;
286
287 case KIND_MONOSPACED:
288 blob_append(p->iblob, "</tt>", 5);
289 return 1;
290 }
291 return 0;
292 }
293 //}}}
294
295
296 static void cr_iMarkup(Parser *p, int kind){//{{{
297
298 if (p->iesc) {
299 blob_append(p->iblob, p->icursor, 1);
300 p->icursor +=1;
301 p->iesc =0;
302 return;
303 }
304
305 if (p->icursor[1] != p->icursor[0]) {
306 blob_append(p->iblob, p->icursor, 1);
307 p->icursor +=1;
308 return;
309 }
310
311 p->icursor += 2;
312
313 if (kind & KIND_BREAK) {
314 blob_append(p->iblob, "<br />", 6);
315 return;
316 }
317
318 if (kind & KIND_ITALIC && p->icursor[-3] == ':'){
319 blob_append(p->iblob, "//", 2);
320 return;
321 }
322
323 Node *n = p->istack;
324
325 int found = 0;
326 while (n) {
327 if (n->kind & kind) {
328 found = 1;
329 break;
330 }
331 n = n->next;
332 }
333
334 if (!found) {
335 n = pool_new(p);
336 n->kind = kind;
337 n->next = p->istack;
338 p->istack = n;
339
340 assert(cr_iOpen(p, kind));
341 return;
342 };
343
344 n= p->istack;
345 while (n){
346 p->istack = n->next;
347
348 assert(cr_iClose(p, n->kind));
349
350 if (kind == n->kind) return;
351 n = p->istack;
352 }
353 }
354 //}}}
355 static int cr_iNoWiki(Parser *p){//{{{
356
357 if ((p->iend - p->icursor)<6) return 0;
358
359 if (p->icursor[1]!='{' || p->icursor[2]!='{')
360 return 0;
361
362 char *s = p->icursor + 3;
363
364 int count = p->iend - p->icursor - 6;
365 while (count--){
366 if (s[0]=='}' && s[1]=='}' && s[2]=='}' && s[3]!='}'){
367 blob_appendf(p->iblob, "<tt style='background:oldlace'>%s</tt>", htmlize(p->icursor + 3, s - p->icursor-3));
368 p->icursor = s + 3;
369 return 1;
370 }
371 s++;
372 }
373 return 0;
374 }
375
376 //}}}
377 static int cr_iImage(Parser *p){//{{{
378
379 if (p->inLink) return 0;
380 if ((p->iend - p->icursor)<3) return 0;
381
382 if (p->icursor[1]!='{') return 0;
383
384 char *s = p->icursor + 2;
385 char *bar = NULL;
386
387 int count = p->iend - p->icursor - 4;
388 while (count--){
389 if (s[0]=='}' && s[1]=='}'){
390 if (!bar) bar = p->icursor + 2;
391 blob_appendf(p->iblob, "<span style='color:green;border:1px solid green;'>%s</span>", htmlize(bar, s - bar ));
392 p->icursor = s + 2;
393 return 1;
394 }
395 if (!bar && s[0]=='|') bar=s+1;
396 s++;
397 }
398 return 0;
399 }
400 //}}}
401 static int cr_iMacro(Parser *p){//{{{
402
403 if (p->inLink) return 0;
404 if ((p->iend - p->icursor)<3) return 0;
405
406 if (p->icursor[1]!='<') return 0;
407
408 char *s = p->icursor + 2;
409
410 int count = p->iend - p->icursor - 3;
411 while (count--){
412 blob_appendf(p->iblob, "|~%s|", s,2 );
413 if (s[0]=='>' && s[1]=='>'){
414 blob_appendf(p->iblob, "<span style='color:red;border:1px solid red;'>%s</span>", htmlize(p->icursor, s - p->icursor + 2));
415 p->icursor = s + 2;
416 return 1;
417 }
418 s++;
419 }
420 return 0;
421
422 }
423 //}}}
424
425 static void cr_renderLink(Parser *p, char *s, char *bar, char *e){//{{{
426
427 int tsize = bar-s;
428 int dsize = e - bar-1;
429
430 if (tsize < 1) return;
431 if (dsize < 1) dsize = 0;
432
433 char zTarget[tsize + 1];
434 memcpy(zTarget, s, tsize);
435 zTarget[tsize] = '\0';
436
437 char zClose[20];
438
439 Blob *pOut = p->r->pOut;
440
441 p->r->pOut = p->iblob;
442 wf_openHyperlink(p->r, zTarget, zClose, sizeof(zClose));
443 p->r->pOut = pOut;
444
445 if (dsize)
446 cr_parseInline(p, bar+1, e) ;
447 else
448 blob_append(p->iblob, htmlize(s, tsize), -1);
449 blob_append(p->iblob, zClose, -1);
450 }
451 //}}}
452
453 static int cr_iLink(Parser *p){//{{{
454
455 if (p->inLink) return 0;
456 if ((p->iend - p->icursor)<3) return 0;
457
458 if (p->icursor[1]!='[') return 0;
459
460 char *s = p->icursor + 2;
461 char *bar = NULL;
462
463 int count = p->iend - p->icursor -3;
464 while (count--){
465 if (s[0]==']' && s[1]==']'){
466 if (!bar) bar = s;
467 p->inLink = 1;
468 cr_renderLink(p, p->icursor+2, bar, s);
469 p->inLink = 0;
470 p->icursor = s + 2;
471 return 1;
472 }
473 if (!bar && s[0]=='|') bar=s;
474 s++;
475 }
476 return 0;
477 }
478 //}}}
479
480 LOCAL char *cr_parseInline(Parser *p, char *s, char *e){//{{{
481
482 int save_iesc = p->iesc;
483 char *save_iend = p->iend;
484 Node *save_istack = p->istack;
485
486 p->iesc = 0;
487 p->iend = e;
488 p->istack = NULL;
489
490 p->icursor = s;
491
492 char *eof = NULL;
493 while (!eof && p->icursor < p->iend ){
494
495 switch (*p->icursor) {//{{{
496
497 case '~':
498 if (p->iesc) {
499 blob_append(p->iblob, "~", 1);
500 p->iesc = 0;
501 }
502 p->iesc = !p->iesc;
503 p->icursor+=1;
504 break;
505
506 case '*':
507 cr_iMarkup(p, KIND_BOLD);
508 break;
509
510 case '/':
511 cr_iMarkup(p, KIND_ITALIC);
512 break;
513
514 case '^':
515 cr_iMarkup(p, KIND_SUPERSCRIPT);
516 break;
517
518 case ',':
519 cr_iMarkup(p, KIND_SUBSCRIPT);
520 break;
521
522 case '#':
523 cr_iMarkup(p, KIND_MONOSPACED);
524 break;
525
526 case '\\':
527 cr_iMarkup(p, KIND_BREAK);
528 break;
529
530 case '{':
531 if (cr_isEsc(p)) break;
532 if (cr_iNoWiki(p)) break;
533 if (cr_iImage(p)) break;
534 blob_append(p->iblob, p->icursor, 1);
535 p->icursor += 1;
536 break;
537
538 case '[':
539 if (cr_isEsc(p)) break;
540 if (cr_iLink(p)) break;
541 blob_append(p->iblob, p->icursor, 1);
542 p->icursor += 1;
543 break;
544
545
546 case '<':
547 if (cr_isEsc(p)) break;
548 if (cr_iMacro(p)) break;
549
550 blob_append(p->iblob, "&lt;", 4);
551 p->icursor += 1;
552 break;
553
554 case '>':
555 if (p->iesc) {
556 blob_append(p->iblob, "~", 1);
557 p->iesc = 0;
558 }
559 blob_append(p->iblob, "&gt;", 4);
560 p->icursor += 1;
561 break;
562
563 case '&':
564 if (p->iesc) {
565 blob_append(p->iblob, "~", 1);
566 p->iesc = 0;
567 }
568 blob_append(p->iblob, "&amp;", 5);
569 p->icursor += 1;
570 break;
571
572 case '|':
573 if (p->inTable){
574 if (p->iesc) {
575 blob_append(p->iblob, p->icursor, 1);
576 p->iesc = 0;
577 p->icursor += 1;
578 break;
579 }
580 eof = p->icursor + 1;
581 break;
582 }
583 // fall through to default
584
585 default:
586 if (p->iesc) {
587 blob_append(p->iblob, "~", 1);
588 p->iesc = 0;
589 }
590 blob_append(p->iblob, p->icursor, 1);
591 p->icursor +=1;
592 }//}}}
593
594 }
595
596 while (p->istack){
597 cr_iClose(p, p->istack->kind);
598 p->istack = p->istack->next;
599 }
600
601 p->iesc = save_iesc;
602 p->iend = save_iend;
603 p->istack = save_istack;
604
605 return eof;
606
607 }
608 //}}}
609 //}}}
610
@@ -610,472 +611,455 @@
611 //{{{ BLOCK PARSER
612
613 static void cr_renderListItem(Parser *p, Node *n){//{{{
614
615
616 blob_append(p->iblob, "<li>", 4);
617 cr_parseInline(p, n->start, n->end);
618
619 if (n->children){
620
621 int ord = (n->children->kind & KIND_ORDERED_LIST);
622
623 if (ord) blob_append(p->iblob, "<ol>", 4);
624 else blob_append(p->iblob, "<ul>", 4);
625
626 n = n->children;
627 while (n){
628 cr_renderListItem(p, n);
629 n = n->next;
630 }
631
632 if (ord) blob_append(p->iblob, "</ol>", 5);
633 else blob_append(p->iblob, "</ul>", 5);
634 }
635 blob_append(p->iblob, "</li>", 5);
636 }
637 //}}}
638 static void cr_renderList(Parser *p){//{{{
639
640 Node *n = p->list;
641
642 while (n->parent !=n) n = n->parent;
643
644 int ord = (n->kind & KIND_ORDERED_LIST);
645
646 if (ord) blob_append(p->iblob, "\n\n<ol>", -1);
647 else blob_append(p->iblob, "\n\n<ul>", -1);
648
649 while (n) {
650 cr_renderListItem(p, n);
651 n = n->next;
652 }
653
654 if (ord) blob_append(p->iblob, "</ol>", 5);
655 else blob_append(p->iblob, "</ul>", 5);
656 }
657
658 //}}}
659
660 static void cr_renderTableRow(Parser *p, Node *row){//{{{
661
662 char *s = row->start;
663 int th;
664
665 blob_append(p->iblob, "\n<tr>", -1);
666
667 while (s && s < row->end){
668
669 if ((th = *s == '=')) {
670 s++;
671 blob_append(p->iblob, "<th>", -1);
672 }
673 else {
674 blob_append(p->iblob, "<td>", -1);
675 }
676
677 s = cr_parseInline(p, s, row->end);
678
679 if (th)
680 blob_append(p->iblob, "</th>\n", -1);
681 else
682 blob_append(p->iblob, "</td>\n", -1);
683
684 if (!s) break;
685 }
686 blob_append(p->iblob, "</tr>", 5);
687 }
688 //}}}
689 static void cr_renderTable(Parser *p, Node *n){//{{{
690
691 Node *row = n->children;
692
693 blob_append(p->iblob, "<table class='creoletable'>", -1);
694 p->inTable = 1;
695 while (row){
696
697 cr_renderTableRow(p, row);
698 row = row->next;
699
700 }
701 blob_append(p->iblob, "</table>", -1);
702 p->inTable = 0;
703
704 }
705 //}}}
706
707 static void cr_render(Parser *p, Node *node){//{{{
708
709 if (node->kind & KIND_PARAGRAPH){
710 blob_append(p->iblob, "\n<p>", -1);
711 cr_parseInline(p, node->start, node->end );
712 blob_append(p->iblob, "</p>\n", -1 );
713 }
714
715 if (node->kind & KIND_HEADING){
716 blob_appendf(p->iblob,
717 "\n<h%d %s>",
718 node->level,
719 (node->flags & FLAG_CENTER) ? " style='text-align:center;'" : ""
720 );
721 cr_parseInline(p, node->start, node->end);
722 blob_appendf(p->iblob, "</h%d>\n", node->level );
723 return;
724 }
725
726 if (node->kind & KIND_HORIZONTAL_RULE){
727 blob_append(p->iblob, "<hr />", -1);
728 return;
729 }
730
731 if (node->kind & KIND_LIST){
732 cr_renderList(p);
733 p->list = NULL;
734 return;
735 }
736
737 if (node->kind & KIND_TABLE){
738 cr_renderTable(p, node);
739 return;
740 }
741
742 if (node->kind & KIND_NO_WIKI_BLOCK){
743 blob_appendf(p->iblob,
744 "\n<blockquote style='background:oldlace'><pre>%s</pre></blockquote>\n",
745 htmlize( node->start, node->end - node->start)
746 );
747 }
748 }
749 //}}}
750
751 static char *cr_findEndOfBlock(Parser *p, char *s, char c){//{{{
752
753 char *end;
754 while (s[0]){
755
756 end = s;
757 if (s[0] == c && s[0] == c && s[0] == c) {
758 s = cr_nextLine(p, s + 3);
759 if (p->lineWasBlank) {
760 p->cursor = s;
761 return end;
762 }
763 }
764 else {
765 s = cr_nextLine(p, s);
766 }
767 }
768 return 0;
769 }
770 //}}}
771 static int cr_addListItem(Parser *p, Node *n){//{{{
772
773 n->parent = n;
774 n->next = n->children = NULL;
775
776 if (!p->list) {
777 if (n->level != 1) return 0;
778 p->list = n;
779 return 1;
780 }
781
782 Node *list = p->list;
783
784 while (n->level < list->level){
785 list = list->parent;
786 }
787
788 if (n->level == list->level){
789
790 if (n->kind != list->kind){
791 if (n->level>1) return 0;
792 cr_renderList(p);
793 p->list = n;
794 return 1;
795 }
796 n->parent = list->parent;
797 p->list = list->next = n;
798 return 1;
799 }
800
801 if ( (n->level - list->level) > 1 ) return 0;
802 n->parent = p->list;
803 p->list->children = n;
804 p->list = n;
805 return 1;
806
807 }
808 //}}}
809
810 static int isEndWikiMarker(Parser *p){//{{{
811
812 char *s = p->cursor;
813 if (memcmp(s, "<<fossil>>", 10)) return 0;
814 p->this->start = s;
815 p->this->kind = KIND_END_WIKI_MARKER;
816 p->cursor += 10;
817 return 1;
818 }
819 ///}}}
820 static int isNoWikiBlock(Parser *p){//{{{
821
822 char *s = p->cursor;
823
824 if (s[0] != '{') return 0; s++;
825 if (s[0] != '{') return 0; s++;
826 if (s[0] != '{') return 0; s++;
827
828 s = cr_nextLine(p, s);
829 if (!p->lineWasBlank) return 0;
830
831 p->this->start = s;
832
833 s = cr_findEndOfBlock(p, s, '}');
834
835 if (!s) return 0;
836
837 // p->cursor was set by findEndOfBlock
838 p->this->kind = KIND_NO_WIKI_BLOCK;
839 p->this->end = s;
840 return 1;
841 }
842
843 //}}}
844 static int isParaBreak(Parser *p){//{{{
845
846 char *s = cr_nextLine(p, p->cursor);
847 if (!p->lineWasBlank) return 0;
848
849 p->cursor = s;
850 p->this->kind = KIND_PARA_BREAK;
851 return 1;
852 }
853 //}}}
854 static int isHeading(Parser *p){//{{{
855
856 char *s = cr_skipBlanks(p, p->cursor);
857
858 int flags = 0;
859 int level = cr_countChars(p, s, '=');
860 if (!level) return 0;
861
862 s += level;
863
864 if (s[0] == '<' && s[1] == '>') {
865 flags |= FLAG_CENTER;
866 s += 2;
867 }
868 s = cr_skipBlanks(p, s);
869
870 p->this->start = s;
871
872 s = cr_nextLine(p, s);
873 char *z = s;
874
875 if (s[-1] == '\n') s--;
876 while(s[-1] == ' ' || s[-1]=='\t') s--;
877 while(s[-1] == '=' ) s--;
878 if (p->this->start < s){
879 p->cursor = z;
880 p->this->kind = KIND_HEADING;
881 p->this->end = s;
882 p->this->level = level;
883 p->this->flags |= flags;
884 return 1;
885 }
886 return 0;
887 }
888 //}}}
889 static int isHorizontalRule(Parser *p){//{{{
890
891 char *s = cr_skipBlanks(p, p->cursor);
892
893 int level = cr_countChars(p, s, '-');
894
895 if (level < 4) return 0;
896 s = cr_nextLine(p, s + level);
897 if (!p->lineWasBlank) return 0;
898
899 p->cursor = s;
900 p->this->kind = KIND_HORIZONTAL_RULE;
901
902 return 1;
903 }
904 //}}}
905 static int isListItem(Parser *p){//{{{
906
907 char *s = cr_skipBlanks(p, p->cursor);
908
909 int level = cr_countChars(p, s, '#');
910 if (!level) level = cr_countChars(p, s, '*');
911
912 if ( !level) return 0;
913
914 p->this->kind = (s[0] == '#') ? KIND_ORDERED_LIST : KIND_UNORDERED_LIST;
915 p->this->level = level;
916
917 s = cr_skipBlanks(p, s + level);
918 p->this->start = s;
919
920 s = cr_nextLine(p, s);
921 if (p->lineWasBlank) return 0;
922
923 if (cr_addListItem(p, p->this)){
924 p->cursor = p->this->end = s;
925 return 1;
926 }
927 p->this->kind = 0;
928 return 0;
929 }
930 //}}}
931 static int isTable(Parser *p){//{{{
932
933 p->this->start = p->cursor;
934 char *s = cr_skipBlanks(p, p->cursor);
935 if (s[0] != '|') return 0;
936 s +=1;
937 p->this->kind = KIND_TABLE;
938
939
940 //p->cursor = p->this->end = cr_nextLine(p, s);
941 Node *row;
942 Node *tail = NULL;
943
944 while (1) {
945
946 row = pool_new(p);
947 row->kind = KIND_TABLE_ROW;
948
949 if (tail) tail = tail->next = row;
950 else p->this->children = tail = row;
951
952 row->start = s;
953 p->cursor = s = row->end = p->this->end = cr_nextLine(p, s);
954
955 if (row->end[-1] == '\n') row->end -= 1;
956 while(row->end[-1] == ' ' ) row->end -= 1;
957 if (row->end[-1] == '|') row->end -= 1;
958
959 if (!*s) break;
960
961 // blanks *not* normalized
962 s = cr_skipBlanks(p, p->cursor);
963 if (s[0] != '|') break;
964 s++;
965
966 }
967 return 1;
968
969 };
970 //}}}
971 static int isParagraph(Parser *p){//{{{
972
973 char *s = p->cursor;
974 p->this->start = s;
975
976 s = cr_nextLine(p, s);
977 p->cursor = p->this->end = s;
978 p->this->kind = KIND_PARAGRAPH;
979 return 1;
980
981 }
982 //}}}
983 static void cr_parse(Parser *p, char* z){//{{{
984
985 p->previous = pool_new(p);
986 p->previous->kind = KIND_PARA_BREAK;
987
988 p->this = pool_new(p);
989 p->this->kind = KIND_PARA_BREAK;
990
991 p->inLink = 0;
992 p->inTable = 0;
993
994 p->cursor = z;
995 p->list = NULL;
996 p->istack = NULL;
997
998 while (p->cursor[0]) {
999
1000 while (1){
1001
1002 // must be first
1003 if (isNoWikiBlock(p)) break;
1004 if (isParaBreak(p)) break;
1005
1006 // order not important
1007 if (isHeading(p)) break;
1008 if (isHorizontalRule(p)) break;
1009 if (isListItem(p)) break;
1010 if (isTable(p)) break;
1011
1012 // here for efficiency?
1013 if (isEndWikiMarker(p)) break;
1014
1015 // must be last
1016 if (isParagraph(p)); break;
1017
1018 // doh!
1019 assert(0);
1020 }
1021
1022 int kind = p->this->kind;
1023 int prev = p->previous->kind;
1024
1025 if (kind & KIND_END_WIKI_MARKER) return;
1026
1027 if (kind == KIND_PARAGRAPH && prev & KIND_LIST_OR_PARAGRAPH) {
1028 p->previous->end = p->this->end;
1029 p->this = pool_new(p);
1030 continue;
1031 }
1032
1033 if ( !(kind & KIND_LIST && prev & KIND_LIST) )
1034 cr_render(p, p->previous);
1035
1036 p->previous = p->this;
1037 p->this = pool_new(p);
1038
1039 }
1040 }
1041 //}}}
1042
1043 //}}}
1044
1045 char *wiki_render_creole(Renderer *r, char *z){
1046
1047 Parser parser;
1048 Parser *p = &parser;
1049
1050 p->r = r;
1051 p->iblob = r->pOut;
1052
1053 p->nFree = 0;
1054 p->pool = NULL;
1055
1056 cr_parse(p, z);
1057
1058 cr_render(p, p->previous);
1059
1060 pool_free(p);
1061
1062 return p->cursor;
1063
1064 }
1065
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1066
+818 -834
--- src/creoleparser.c
+++ src/creoleparser.c
@@ -28,11 +28,11 @@
2828
#include <assert.h>
2929
#include "config.h"
3030
#include "creoleparser.h"
3131
3232
#if INTERFACE
33
-#define HAVE_MACRO_EXTENSIONS 1
33
+#define HAVE_CREOLE_MACRO 1
3434
#endif
3535
3636
//{{{ LOCAL INTERFACE
3737
#if LOCAL_INTERFACE
3838
@@ -61,59 +61,59 @@
6161
6262
#define KIND_TABLE_ROW 0x0010000
6363
//}}}
6464
//{{{ FLAG
6565
// keep first four bits free
66
-#define FLAG_CENTER 0x0000100
66
+#define FLAG_CENTER 0x0000100
6767
//}}}
6868
struct Node {//{{{
6969
70
- char *start;
71
- char *end;
72
-
73
- int kind;
74
- int level;
75
- int flags;
76
-
77
- Node *parent;
78
- Node *next;
79
- Node *children;
70
+ char *start;
71
+ char *end;
72
+
73
+ int kind;
74
+ int level;
75
+ int flags;
76
+
77
+ Node *parent;
78
+ Node *next;
79
+ Node *children;
8080
8181
};
8282
//}}}
8383
struct NodePool {//{{{
84
- NodePool *next;
85
- Node a[POOL_CHUNK_SIZE];
84
+ NodePool *next;
85
+ Node a[POOL_CHUNK_SIZE];
8686
}
8787
//}}}
8888
struct Parser {//{{{
8989
90
- Blob *pOut; /* Output appended to this blob */
91
- Renderer *r;
90
+ Blob *pOut; /* Output appended to this blob */
91
+ Renderer *r;
9292
93
- NodePool *pool;
94
- int nFree;
93
+ NodePool *pool;
94
+ int nFree;
9595
9696
Node *this;
97
- Node *previous;
98
- Node *list;
99
-
100
- char *cursor;
101
-
102
- int lineWasBlank;
103
- int charCount;
104
-
105
- Node *item;
106
- Node *istack;
107
- char *icursor;
108
- char *iend;
109
-
110
- int inLink;
111
- int inTable;
112
- int iesc;
113
-
114
- Blob *iblob;
97
+ Node *previous;
98
+ Node *list;
99
+
100
+ char *cursor;
101
+
102
+ int lineWasBlank;
103
+ int charCount;
104
+
105
+ Node *item;
106
+ Node *istack;
107
+ char *icursor;
108
+ char *iend;
109
+
110
+ int inLink;
111
+ int inTable;
112
+ int iesc;
113
+
114
+ Blob *iblob;
115115
116116
117117
118118
119119
};
@@ -126,484 +126,485 @@
126126
//}}}
127127
128128
//{{{ POOL MANAGEMENT
129129
static Node *pool_new(Parser *p){
130130
131
- if ( p->pool == NULL || p->nFree == 0){
132
-
133
- NodePool *temp = p->pool;
134
-
135
- p->pool = malloc(sizeof(NodePool));
136
- if( p->pool == NULL ) fossil_panic("out of memory");
137
-
138
- p->pool->next = temp;
139
- p->nFree = POOL_CHUNK_SIZE;
140
- }
141
- p->nFree -= 1;
142
- Node *node = &(p->pool->a[p->nFree]);
143
- memset(node, 0, sizeof(*node));
144
-
145
- return node;
131
+ if ( p->pool == NULL || p->nFree == 0){
132
+
133
+ NodePool *temp = p->pool;
134
+
135
+ p->pool = malloc(sizeof(NodePool));
136
+ if( p->pool == NULL ) fossil_panic("out of memory");
137
+
138
+ p->pool->next = temp;
139
+ p->nFree = POOL_CHUNK_SIZE;
140
+ }
141
+ p->nFree -= 1;
142
+ Node *node = &(p->pool->a[p->nFree]);
143
+ memset(node, 0, sizeof(*node));
144
+
145
+ return node;
146146
}
147147
148148
149149
static void pool_free(Parser *p){
150150
151
- NodePool *temp;
151
+ NodePool *temp;
152152
153
- while (p->pool != NULL){
154
- temp = p->pool;
155
- p->pool = temp->next;
156
- free(temp);
157
- }
153
+ while (p->pool != NULL){
154
+ temp = p->pool;
155
+ p->pool = temp->next;
156
+ free(temp);
157
+ }
158158
159159
}
160160
//}}}
161161
162162
//{{{ Utility Methods
163163
164164
static char *cr_skipBlanks(Parser *p, char* z){//{{{
165
- char *s = z;
166
- while (z[0] == ' ' || z[0] == '\t') z++;
167
- p->charCount = z - s;
168
- return z;
165
+ char *s = z;
166
+ while (z[0] == ' ' || z[0] == '\t') z++;
167
+ p->charCount = z - s;
168
+ return z;
169169
}
170170
//}}}
171171
static int cr_countBlanks(Parser *p, char* z){//{{{
172
- cr_skipBlanks(p, z);
173
- return p->charCount;
172
+ cr_skipBlanks(p, z);
173
+ return p->charCount;
174174
}
175175
//}}}
176176
static char *cr_skipChars(Parser *p, char *z, char c){//{{{
177
- char *s = z;
178
- while (z[0] == c) z++;
179
- p->charCount = z - s;
180
- return z;
177
+ char *s = z;
178
+ while (z[0] == c) z++;
179
+ p->charCount = z - s;
180
+ return z;
181181
}
182182
//}}}
183183
static int cr_countChars(Parser *p, char *z, char c){//{{{
184
- cr_skipChars(p, z, c);
185
- return p->charCount;
184
+ cr_skipChars(p, z, c);
185
+ return p->charCount;
186186
}
187187
//}}}
188188
static char *cr_nextLine(Parser *p, char *z){//{{{
189189
190
- p->lineWasBlank = 1;
191
-
192
- while (1){
193
-
194
- switch (z[0]){
195
-
196
- case '\r':
197
- if (z[1] == '\n') {
198
- z[0] = ' ';
199
- return z + 2;
200
- }
201
- z[0] = '\n';
202
- return z + 1;
203
-
204
- case'\n':
205
- return z + 1;
206
-
207
- case '\t':
208
- z[0] = ' ';
209
- z++;
210
- break;
211
-
212
- case ' ':
213
- z++;
214
- break;
215
-
216
- case '\0':
217
- return z;
218
-
219
- default:
220
- p->lineWasBlank = 0;
221
- z++;
222
- }
223
- }
190
+ p->lineWasBlank = 1;
191
+
192
+ while (1){
193
+
194
+ switch (z[0]){
195
+
196
+ case '\r':
197
+ if (z[1] == '\n') {
198
+ z[0] = ' ';
199
+ return z + 2;
200
+ }
201
+ z[0] = '\n';
202
+ return z + 1;
203
+
204
+ case'\n':
205
+ return z + 1;
206
+
207
+ case '\t':
208
+ z[0] = ' ';
209
+ z++;
210
+ break;
211
+
212
+ case ' ':
213
+ z++;
214
+ break;
215
+
216
+ case '\0':
217
+ return z;
218
+
219
+ default:
220
+ p->lineWasBlank = 0;
221
+ z++;
222
+ }
223
+ }
224224
}
225225
//}}}
226226
//}}}
227227
228228
//{{{ INLINE PARSER
229229
230230
static int cr_isEsc(Parser *p){//{{{
231
- if (p->iesc){
232
- blob_append(p->iblob, p->icursor, 1);
233
- p->iesc = 0;
234
- p->icursor += 1;
235
- return 1;
236
- }
237
- return 0;
231
+ if (p->iesc){
232
+ blob_append(p->iblob, p->icursor, 1);
233
+ p->iesc = 0;
234
+ p->icursor += 1;
235
+ return 1;
236
+ }
237
+ return 0;
238238
}
239239
//}}}
240240
static int cr_iOpen(Parser *p, int kind){//{{{
241241
242
- switch (kind){
243
-
244
- case KIND_BOLD:
245
- blob_append(p->iblob, "<strong>", 8);
246
- return 1;
247
-
248
- case KIND_ITALIC:
249
- blob_append(p->iblob, "<em>", 4);
250
- return 1;
251
-
252
- case KIND_SUPERSCRIPT:
253
- blob_append(p->iblob, "<sup>", 5);
254
- return 1;
255
-
256
- case KIND_SUBSCRIPT:
257
- blob_append(p->iblob, "<sub>", 5);
258
- return 1;
259
-
260
- case KIND_MONOSPACED:
261
- blob_append(p->iblob, "<tt>", 4);
262
- return 1;
263
- }
264
- return 0;
242
+ switch (kind){
243
+
244
+ case KIND_BOLD:
245
+ blob_append(p->iblob, "<strong>", 8);
246
+ return 1;
247
+
248
+ case KIND_ITALIC:
249
+ blob_append(p->iblob, "<em>", 4);
250
+ return 1;
251
+
252
+ case KIND_SUPERSCRIPT:
253
+ blob_append(p->iblob, "<sup>", 5);
254
+ return 1;
255
+
256
+ case KIND_SUBSCRIPT:
257
+ blob_append(p->iblob, "<sub>", 5);
258
+ return 1;
259
+
260
+ case KIND_MONOSPACED:
261
+ blob_append(p->iblob, "<tt>", 4);
262
+ return 1;
263
+ }
264
+ return 0;
265265
}
266266
//}}}
267267
static int cr_iClose(Parser *p, int kind){//{{{
268268
269
- switch (kind){
270
-
271
- case KIND_BOLD:
272
- blob_append(p->iblob, "</strong>", 9);
273
- return 1;
274
-
275
- case KIND_ITALIC:
276
- blob_append(p->iblob, "</em>", 5);
277
- return 1;
278
-
279
- case KIND_SUPERSCRIPT:
280
- blob_append(p->iblob, "</sup>", 6);
281
- return 1;
282
-
283
- case KIND_SUBSCRIPT:
284
- blob_append(p->iblob, "</sub>", 6);
285
- return 1;
286
-
287
- case KIND_MONOSPACED:
288
- blob_append(p->iblob, "</tt>", 5);
289
- return 1;
290
- }
291
- return 0;
269
+ switch (kind){
270
+
271
+ case KIND_BOLD:
272
+ blob_append(p->iblob, "</strong>", 9);
273
+ return 1;
274
+
275
+ case KIND_ITALIC:
276
+ blob_append(p->iblob, "</em>", 5);
277
+ return 1;
278
+
279
+ case KIND_SUPERSCRIPT:
280
+ blob_append(p->iblob, "</sup>", 6);
281
+ return 1;
282
+
283
+ case KIND_SUBSCRIPT:
284
+ blob_append(p->iblob, "</sub>", 6);
285
+ return 1;
286
+
287
+ case KIND_MONOSPACED:
288
+ blob_append(p->iblob, "</tt>", 5);
289
+ return 1;
290
+ }
291
+ return 0;
292292
}
293293
//}}}
294294
295295
296296
static void cr_iMarkup(Parser *p, int kind){//{{{
297297
298
- if (p->iesc) {
299
- blob_append(p->iblob, p->icursor, 1);
300
- p->icursor +=1;
301
- p->iesc =0;
302
- return;
303
- }
304
-
305
- if (p->icursor[1] != p->icursor[0]) {
306
- blob_append(p->iblob, p->icursor, 1);
307
- p->icursor +=1;
308
- return;
309
- }
310
-
311
- p->icursor += 2;
312
-
313
- if (kind & KIND_BREAK) {
314
- blob_append(p->iblob, "<br />", 6);
315
- return;
316
- }
317
-
318
- if (kind & KIND_ITALIC && p->icursor[-3] == ':'){
319
- blob_append(p->iblob, "//", 2);
320
- return;
321
- }
322
-
323
- Node *n = p->istack;
324
-
325
- int found = 0;
326
- while (n) {
327
- if (n->kind & kind) {
328
- found = 1;
329
- break;
330
- }
331
- n = n->next;
332
- }
333
-
334
- if (!found) {
335
- n = pool_new(p);
336
- n->kind = kind;
337
- n->next = p->istack;
338
- p->istack = n;
339
-
340
- assert(cr_iOpen(p, kind));
341
- return;
342
- };
343
-
344
- n= p->istack;
345
- while (n){
346
- p->istack = n->next;
347
-
348
- assert(cr_iClose(p, n->kind));
349
-
350
- if (kind == n->kind) return;
351
- n = p->istack;
352
- }
298
+ if (p->iesc) {
299
+ blob_append(p->iblob, p->icursor, 1);
300
+ p->icursor +=1;
301
+ p->iesc =0;
302
+ return;
303
+ }
304
+
305
+ if (p->icursor[1] != p->icursor[0]) {
306
+ blob_append(p->iblob, p->icursor, 1);
307
+ p->icursor +=1;
308
+ return;
309
+ }
310
+
311
+ p->icursor += 2;
312
+
313
+ if (kind & KIND_BREAK) {
314
+ blob_append(p->iblob, "<br />", 6);
315
+ return;
316
+ }
317
+
318
+ if (kind & KIND_ITALIC && p->icursor[-3] == ':'){
319
+ blob_append(p->iblob, "//", 2);
320
+ return;
321
+ }
322
+
323
+ Node *n = p->istack;
324
+
325
+ int found = 0;
326
+ while (n) {
327
+ if (n->kind & kind) {
328
+ found = 1;
329
+ break;
330
+ }
331
+ n = n->next;
332
+ }
333
+
334
+ if (!found) {
335
+ n = pool_new(p);
336
+ n->kind = kind;
337
+ n->next = p->istack;
338
+ p->istack = n;
339
+
340
+ assert(cr_iOpen(p, kind));
341
+ return;
342
+ };
343
+
344
+ n= p->istack;
345
+ while (n){
346
+ p->istack = n->next;
347
+
348
+ assert(cr_iClose(p, n->kind));
349
+
350
+ if (kind == n->kind) return;
351
+ n = p->istack;
352
+ }
353353
}
354354
//}}}
355355
static int cr_iNoWiki(Parser *p){//{{{
356356
357
- if ((p->iend - p->icursor)<6) return 0;
358
-
359
- if (p->icursor[1]!='{' || p->icursor[2]!='{')
360
- return 0;
361
-
362
- char *s = p->icursor + 3;
363
-
364
- int count = p->iend - p->icursor - 6;
365
- while (count--){
366
- if (s[0]=='}' && s[1]=='}' && s[2]=='}' && s[3]!='}'){
367
- blob_appendf(p->iblob, "<tt style='background:oldlace'>%s</tt>", htmlize(p->icursor + 3, s - p->icursor-3));
368
- p->icursor = s + 3;
369
- return 1;
370
- }
371
- s++;
372
- }
373
- return 0;
357
+ if ((p->iend - p->icursor)<6) return 0;
358
+
359
+ if (p->icursor[1]!='{' || p->icursor[2]!='{')
360
+ return 0;
361
+
362
+ char *s = p->icursor + 3;
363
+
364
+ int count = p->iend - p->icursor - 6;
365
+ while (count--){
366
+ if (s[0]=='}' && s[1]=='}' && s[2]=='}' && s[3]!='}'){
367
+ blob_appendf(p->iblob, "<tt style='background:oldlace'>%s</tt>", htmlize(p->icursor + 3, s - p->icursor-3));
368
+ p->icursor = s + 3;
369
+ return 1;
370
+ }
371
+ s++;
372
+ }
373
+ return 0;
374374
}
375375
376376
//}}}
377377
static int cr_iImage(Parser *p){//{{{
378378
379
- if (p->inLink) return 0;
380
- if ((p->iend - p->icursor)<3) return 0;
381
-
382
- if (p->icursor[1]!='{') return 0;
383
-
384
- char *s = p->icursor + 2;
385
- char *bar = NULL;
386
-
387
- int count = p->iend - p->icursor - 4;
388
- while (count--){
389
- if (s[0]=='}' && s[1]=='}'){
390
- if (!bar) bar = p->icursor + 2;
391
- blob_appendf(p->iblob, "<span style='color:green;border:1px solid green;'>%s</span>", htmlize(bar, s - bar ));
392
- p->icursor = s + 2;
393
- return 1;
394
- }
395
- if (!bar && s[0]=='|') bar=s+1;
396
- s++;
397
- }
398
- return 0;
379
+ if (p->inLink) return 0;
380
+ if ((p->iend - p->icursor)<3) return 0;
381
+
382
+ if (p->icursor[1]!='{') return 0;
383
+
384
+ char *s = p->icursor + 2;
385
+ char *bar = NULL;
386
+
387
+ int count = p->iend - p->icursor - 4;
388
+ while (count--){
389
+ if (s[0]=='}' && s[1]=='}'){
390
+ if (!bar) bar = p->icursor + 2;
391
+ blob_appendf(p->iblob, "<span style='color:green;border:1px solid green;'>%s</span>", htmlize(bar, s - bar ));
392
+ p->icursor = s + 2;
393
+ return 1;
394
+ }
395
+ if (!bar && s[0]=='|') bar=s+1;
396
+ s++;
397
+ }
398
+ return 0;
399399
}
400400
//}}}
401401
static int cr_iMacro(Parser *p){//{{{
402402
403
- if (p->inLink) return 0;
404
- if ((p->iend - p->icursor)<3) return 0;
405
-
406
- if (p->icursor[1]!='<') return 0;
407
-
408
- char *s = p->icursor + 2;
409
-
410
- int count = p->iend - p->icursor - 4;
411
- while (count--){
412
- if (s[0]=='>' && s[1]=='>'){
413
- blob_appendf(p->iblob, "<span style='color:red;border:1px solid red;'>%s</span>", htmlize(p->icursor, s - p->icursor + 2));
414
- p->icursor = s + 2;
415
- return 1;
416
- }
417
- s++;
418
- }
419
- return 0;
403
+ if (p->inLink) return 0;
404
+ if ((p->iend - p->icursor)<3) return 0;
405
+
406
+ if (p->icursor[1]!='<') return 0;
407
+
408
+ char *s = p->icursor + 2;
409
+
410
+ int count = p->iend - p->icursor - 3;
411
+ while (count--){
412
+ blob_appendf(p->iblob, "|~%s|", s,2 );
413
+ if (s[0]=='>' && s[1]=='>'){
414
+ blob_appendf(p->iblob, "<span style='color:red;border:1px solid red;'>%s</span>", htmlize(p->icursor, s - p->icursor + 2));
415
+ p->icursor = s + 2;
416
+ return 1;
417
+ }
418
+ s++;
419
+ }
420
+ return 0;
420421
421422
}
422423
//}}}
423424
424425
static void cr_renderLink(Parser *p, char *s, char *bar, char *e){//{{{
425426
426
- int tsize = bar-s;
427
- int dsize = e - bar-1;
428
-
429
- if (tsize < 1) return;
430
- if (dsize < 1) dsize = 0;
431
-
432
- char zTarget[tsize + 1];
433
- memcpy(zTarget, s, tsize);
434
- zTarget[tsize] = '\0';
435
-
436
- char zClose[20];
437
-
438
- Blob *pOut = p->r->pOut;
439
-
440
- p->r->pOut = p->iblob;
441
- wf_openHyperlink(p->r, zTarget, zClose, sizeof(zClose));
442
- p->r->pOut = pOut;
443
-
444
- if (dsize)
445
- cr_parseInline(p, bar+1, e) ;
446
- else
447
- blob_append(p->iblob, htmlize(s, tsize), -1);
448
- blob_append(p->iblob, zClose, -1);
427
+ int tsize = bar-s;
428
+ int dsize = e - bar-1;
429
+
430
+ if (tsize < 1) return;
431
+ if (dsize < 1) dsize = 0;
432
+
433
+ char zTarget[tsize + 1];
434
+ memcpy(zTarget, s, tsize);
435
+ zTarget[tsize] = '\0';
436
+
437
+ char zClose[20];
438
+
439
+ Blob *pOut = p->r->pOut;
440
+
441
+ p->r->pOut = p->iblob;
442
+ wf_openHyperlink(p->r, zTarget, zClose, sizeof(zClose));
443
+ p->r->pOut = pOut;
444
+
445
+ if (dsize)
446
+ cr_parseInline(p, bar+1, e) ;
447
+ else
448
+ blob_append(p->iblob, htmlize(s, tsize), -1);
449
+ blob_append(p->iblob, zClose, -1);
449450
}
450451
//}}}
451452
452453
static int cr_iLink(Parser *p){//{{{
453454
454
- if (p->inLink) return 0;
455
- if ((p->iend - p->icursor)<3) return 0;
456
-
457
- if (p->icursor[1]!='[') return 0;
458
-
459
- char *s = p->icursor + 2;
460
- char *bar = NULL;
461
-
462
- int count = p->iend - p->icursor -3;
463
- while (count--){
464
- if (s[0]==']' && s[1]==']'){
465
- if (!bar) bar = s;
466
- p->inLink = 1;
467
- cr_renderLink(p, p->icursor+2, bar, s);
468
- p->inLink = 0;
469
- p->icursor = s + 2;
470
- return 1;
471
- }
472
- if (!bar && s[0]=='|') bar=s;
473
- s++;
474
- }
475
- return 0;
455
+ if (p->inLink) return 0;
456
+ if ((p->iend - p->icursor)<3) return 0;
457
+
458
+ if (p->icursor[1]!='[') return 0;
459
+
460
+ char *s = p->icursor + 2;
461
+ char *bar = NULL;
462
+
463
+ int count = p->iend - p->icursor -3;
464
+ while (count--){
465
+ if (s[0]==']' && s[1]==']'){
466
+ if (!bar) bar = s;
467
+ p->inLink = 1;
468
+ cr_renderLink(p, p->icursor+2, bar, s);
469
+ p->inLink = 0;
470
+ p->icursor = s + 2;
471
+ return 1;
472
+ }
473
+ if (!bar && s[0]=='|') bar=s;
474
+ s++;
475
+ }
476
+ return 0;
476477
}
477478
//}}}
478479
479480
LOCAL char *cr_parseInline(Parser *p, char *s, char *e){//{{{
480481
481
- int save_iesc = p->iesc;
482
- char *save_iend = p->iend;
483
- Node *save_istack = p->istack;
484
-
485
- p->iesc = 0;
486
- p->iend = e;
487
- p->istack = NULL;
488
-
489
- p->icursor = s;
490
-
491
- char *eof = NULL;
492
- while (!eof && p->icursor < p->iend ){
493
-
494
- switch (*p->icursor) {//{{{
495
-
496
- case '~':
497
- if (p->iesc) {
498
- blob_append(p->iblob, "~", 1);
499
- p->iesc = 0;
500
- }
501
- p->iesc = !p->iesc;
502
- p->icursor+=1;
503
- break;
504
-
505
- case '*':
506
- cr_iMarkup(p, KIND_BOLD);
507
- break;
508
-
509
- case '/':
510
- cr_iMarkup(p, KIND_ITALIC);
511
- break;
512
-
513
- case '^':
514
- cr_iMarkup(p, KIND_SUPERSCRIPT);
515
- break;
516
-
517
- case ',':
518
- cr_iMarkup(p, KIND_SUBSCRIPT);
519
- break;
520
-
521
- case '#':
522
- cr_iMarkup(p, KIND_MONOSPACED);
523
- break;
524
-
525
- case '\\':
526
- cr_iMarkup(p, KIND_BREAK);
527
- break;
528
-
529
- case '{':
530
- if (cr_isEsc(p)) break;
531
- if (cr_iNoWiki(p)) break;
532
- if (cr_iImage(p)) break;
533
- blob_append(p->iblob, p->icursor, 1);
534
- p->icursor += 1;
535
- break;
536
-
537
- case '[':
538
- if (cr_isEsc(p)) break;
539
- if (cr_iLink(p)) break;
540
- blob_append(p->iblob, p->icursor, 1);
541
- p->icursor += 1;
542
- break;
543
-
544
-
545
- case '<':
546
- if (cr_isEsc(p)) break;
547
- if (cr_iMacro(p)) break;
548
-
549
- blob_append(p->iblob, "&lt;", 4);
550
- p->icursor += 1;
551
- break;
552
-
553
- case '>':
554
- if (p->iesc) {
555
- blob_append(p->iblob, "~", 1);
556
- p->iesc = 0;
557
- }
558
- blob_append(p->iblob, "&gt;", 4);
559
- p->icursor += 1;
560
- break;
561
-
562
- case '&':
563
- if (p->iesc) {
564
- blob_append(p->iblob, "~", 1);
565
- p->iesc = 0;
566
- }
567
- blob_append(p->iblob, "&amp;", 5);
568
- p->icursor += 1;
569
- break;
570
-
571
- case '|':
572
- if (p->inTable){
573
- if (p->iesc) {
574
- blob_append(p->iblob, p->icursor, 1);
575
- p->iesc = 0;
576
- p->icursor += 1;
577
- break;
578
- }
579
- eof = p->icursor + 1;
580
- break;
581
- }
582
- // fall through to default
583
-
584
- default:
585
- if (p->iesc) {
586
- blob_append(p->iblob, "~", 1);
587
- p->iesc = 0;
588
- }
589
- blob_append(p->iblob, p->icursor, 1);
590
- p->icursor +=1;
591
- }//}}}
592
-
593
- }
594
-
595
- while (p->istack){
596
- cr_iClose(p, p->istack->kind);
597
- p->istack = p->istack->next;
598
- }
599
-
600
- p->iesc = save_iesc;
601
- p->iend = save_iend;
602
- p->istack = save_istack;
603
-
604
- return eof;
482
+ int save_iesc = p->iesc;
483
+ char *save_iend = p->iend;
484
+ Node *save_istack = p->istack;
485
+
486
+ p->iesc = 0;
487
+ p->iend = e;
488
+ p->istack = NULL;
489
+
490
+ p->icursor = s;
491
+
492
+ char *eof = NULL;
493
+ while (!eof && p->icursor < p->iend ){
494
+
495
+ switch (*p->icursor) {//{{{
496
+
497
+ case '~':
498
+ if (p->iesc) {
499
+ blob_append(p->iblob, "~", 1);
500
+ p->iesc = 0;
501
+ }
502
+ p->iesc = !p->iesc;
503
+ p->icursor+=1;
504
+ break;
505
+
506
+ case '*':
507
+ cr_iMarkup(p, KIND_BOLD);
508
+ break;
509
+
510
+ case '/':
511
+ cr_iMarkup(p, KIND_ITALIC);
512
+ break;
513
+
514
+ case '^':
515
+ cr_iMarkup(p, KIND_SUPERSCRIPT);
516
+ break;
517
+
518
+ case ',':
519
+ cr_iMarkup(p, KIND_SUBSCRIPT);
520
+ break;
521
+
522
+ case '#':
523
+ cr_iMarkup(p, KIND_MONOSPACED);
524
+ break;
525
+
526
+ case '\\':
527
+ cr_iMarkup(p, KIND_BREAK);
528
+ break;
529
+
530
+ case '{':
531
+ if (cr_isEsc(p)) break;
532
+ if (cr_iNoWiki(p)) break;
533
+ if (cr_iImage(p)) break;
534
+ blob_append(p->iblob, p->icursor, 1);
535
+ p->icursor += 1;
536
+ break;
537
+
538
+ case '[':
539
+ if (cr_isEsc(p)) break;
540
+ if (cr_iLink(p)) break;
541
+ blob_append(p->iblob, p->icursor, 1);
542
+ p->icursor += 1;
543
+ break;
544
+
545
+
546
+ case '<':
547
+ if (cr_isEsc(p)) break;
548
+ if (cr_iMacro(p)) break;
549
+
550
+ blob_append(p->iblob, "&lt;", 4);
551
+ p->icursor += 1;
552
+ break;
553
+
554
+ case '>':
555
+ if (p->iesc) {
556
+ blob_append(p->iblob, "~", 1);
557
+ p->iesc = 0;
558
+ }
559
+ blob_append(p->iblob, "&gt;", 4);
560
+ p->icursor += 1;
561
+ break;
562
+
563
+ case '&':
564
+ if (p->iesc) {
565
+ blob_append(p->iblob, "~", 1);
566
+ p->iesc = 0;
567
+ }
568
+ blob_append(p->iblob, "&amp;", 5);
569
+ p->icursor += 1;
570
+ break;
571
+
572
+ case '|':
573
+ if (p->inTable){
574
+ if (p->iesc) {
575
+ blob_append(p->iblob, p->icursor, 1);
576
+ p->iesc = 0;
577
+ p->icursor += 1;
578
+ break;
579
+ }
580
+ eof = p->icursor + 1;
581
+ break;
582
+ }
583
+ // fall through to default
584
+
585
+ default:
586
+ if (p->iesc) {
587
+ blob_append(p->iblob, "~", 1);
588
+ p->iesc = 0;
589
+ }
590
+ blob_append(p->iblob, p->icursor, 1);
591
+ p->icursor +=1;
592
+ }//}}}
593
+
594
+ }
595
+
596
+ while (p->istack){
597
+ cr_iClose(p, p->istack->kind);
598
+ p->istack = p->istack->next;
599
+ }
600
+
601
+ p->iesc = save_iesc;
602
+ p->iend = save_iend;
603
+ p->istack = save_istack;
604
+
605
+ return eof;
605606
606607
}
607608
//}}}
608609
//}}}
609610
@@ -610,472 +611,455 @@
610611
//{{{ BLOCK PARSER
611612
612613
static void cr_renderListItem(Parser *p, Node *n){//{{{
613614
614615
615
- blob_append(p->iblob, "<li>", 4);
616
- cr_parseInline(p, n->start, n->end);
617
-
618
- if (n->children){
619
-
620
- int ord = (n->children->kind & KIND_ORDERED_LIST);
621
-
622
- if (ord) blob_append(p->iblob, "<ol>", 4);
623
- else blob_append(p->iblob, "<ul>", 4);
624
-
625
- n = n->children;
626
- while (n){
627
- cr_renderListItem(p, n);
628
- n = n->next;
629
- }
630
-
631
- if (ord) blob_append(p->iblob, "</ol>", 5);
632
- else blob_append(p->iblob, "</ul>", 5);
633
- }
634
- blob_append(p->iblob, "</li>", 5);
616
+ blob_append(p->iblob, "<li>", 4);
617
+ cr_parseInline(p, n->start, n->end);
618
+
619
+ if (n->children){
620
+
621
+ int ord = (n->children->kind & KIND_ORDERED_LIST);
622
+
623
+ if (ord) blob_append(p->iblob, "<ol>", 4);
624
+ else blob_append(p->iblob, "<ul>", 4);
625
+
626
+ n = n->children;
627
+ while (n){
628
+ cr_renderListItem(p, n);
629
+ n = n->next;
630
+ }
631
+
632
+ if (ord) blob_append(p->iblob, "</ol>", 5);
633
+ else blob_append(p->iblob, "</ul>", 5);
634
+ }
635
+ blob_append(p->iblob, "</li>", 5);
635636
}
636637
//}}}
637638
static void cr_renderList(Parser *p){//{{{
638639
639
- Node *n = p->list;
640
-
641
- while (n->parent !=n) n = n->parent;
642
-
643
- int ord = (n->kind & KIND_ORDERED_LIST);
644
-
645
- if (ord) blob_append(p->iblob, "\n\n<ol>", -1);
646
- else blob_append(p->iblob, "\n\n<ul>", -1);
647
-
648
- while (n) {
649
- cr_renderListItem(p, n);
650
- n = n->next;
651
- }
652
-
653
- if (ord) blob_append(p->iblob, "</ol>", 5);
654
- else blob_append(p->iblob, "</ul>", 5);
640
+ Node *n = p->list;
641
+
642
+ while (n->parent !=n) n = n->parent;
643
+
644
+ int ord = (n->kind & KIND_ORDERED_LIST);
645
+
646
+ if (ord) blob_append(p->iblob, "\n\n<ol>", -1);
647
+ else blob_append(p->iblob, "\n\n<ul>", -1);
648
+
649
+ while (n) {
650
+ cr_renderListItem(p, n);
651
+ n = n->next;
652
+ }
653
+
654
+ if (ord) blob_append(p->iblob, "</ol>", 5);
655
+ else blob_append(p->iblob, "</ul>", 5);
655656
}
656657
657658
//}}}
658659
659660
static void cr_renderTableRow(Parser *p, Node *row){//{{{
660661
661
- char *s = row->start;
662
- int th;
663
-
664
- blob_append(p->iblob, "\n<tr>", -1);
665
-
666
- while (s && s < row->end){
667
-
668
- if ((th = *s == '=')) {
669
- s++;
670
- blob_append(p->iblob, "<th>", -1);
671
- }
672
- else {
673
- blob_append(p->iblob, "<td>", -1);
674
- }
675
-
676
- s = cr_parseInline(p, s, row->end);
677
-
678
- if (th)
679
- blob_append(p->iblob, "</th>\n", -1);
680
- else
681
- blob_append(p->iblob, "</td>\n", -1);
682
-
683
- if (!s) break;
684
- }
685
- blob_append(p->iblob, "</tr>", 5);
662
+ char *s = row->start;
663
+ int th;
664
+
665
+ blob_append(p->iblob, "\n<tr>", -1);
666
+
667
+ while (s && s < row->end){
668
+
669
+ if ((th = *s == '=')) {
670
+ s++;
671
+ blob_append(p->iblob, "<th>", -1);
672
+ }
673
+ else {
674
+ blob_append(p->iblob, "<td>", -1);
675
+ }
676
+
677
+ s = cr_parseInline(p, s, row->end);
678
+
679
+ if (th)
680
+ blob_append(p->iblob, "</th>\n", -1);
681
+ else
682
+ blob_append(p->iblob, "</td>\n", -1);
683
+
684
+ if (!s) break;
685
+ }
686
+ blob_append(p->iblob, "</tr>", 5);
686687
}
687688
//}}}
688689
static void cr_renderTable(Parser *p, Node *n){//{{{
689690
690
- Node *row = n->children;
691
-
692
- blob_append(p->iblob, "<table class='creoletable'>", -1);
693
- p->inTable = 1;
694
- while (row){
695
-
696
- cr_renderTableRow(p, row);
697
- row = row->next;
698
-
699
- }
700
- blob_append(p->iblob, "</table>", -1);
701
- p->inTable = 0;
691
+ Node *row = n->children;
692
+
693
+ blob_append(p->iblob, "<table class='creoletable'>", -1);
694
+ p->inTable = 1;
695
+ while (row){
696
+
697
+ cr_renderTableRow(p, row);
698
+ row = row->next;
699
+
700
+ }
701
+ blob_append(p->iblob, "</table>", -1);
702
+ p->inTable = 0;
702703
703704
}
704705
//}}}
705706
706707
static void cr_render(Parser *p, Node *node){//{{{
707708
708
- if (node->kind & KIND_PARAGRAPH){
709
- blob_append(p->iblob, "\n<p>", -1);
710
- cr_parseInline(p, node->start, node->end );
711
- blob_append(p->iblob, "</p>\n", -1 );
712
- }
713
-
714
- if (node->kind & KIND_HEADING){
715
- blob_appendf(p->iblob,
716
- "\n<h%d %s>",
717
- node->level,
718
- (node->flags & FLAG_CENTER) ? " style='text-align:center;'" : ""
719
- );
720
- cr_parseInline(p, node->start, node->end);
721
- blob_appendf(p->iblob, "</h%d>\n", node->level );
722
- return;
723
- }
724
-
725
- if (node->kind & KIND_HORIZONTAL_RULE){
726
- blob_append(p->iblob, "<hr />", -1);
727
- return;
728
- }
729
-
730
- if (node->kind & KIND_LIST){
731
- cr_renderList(p);
732
- p->list = NULL;
733
- return;
734
- }
735
-
736
- if (node->kind & KIND_TABLE){
737
- cr_renderTable(p, node);
738
- return;
739
- }
740
-
741
- if (node->kind & KIND_NO_WIKI_BLOCK){
742
- blob_appendf(p->iblob,
743
- "\n<blockquote style='background:oldlace'><pre>%s</pre></blockquote>\n",
744
- htmlize( node->start, node->end - node->start)
745
- );
746
- }
709
+ if (node->kind & KIND_PARAGRAPH){
710
+ blob_append(p->iblob, "\n<p>", -1);
711
+ cr_parseInline(p, node->start, node->end );
712
+ blob_append(p->iblob, "</p>\n", -1 );
713
+ }
714
+
715
+ if (node->kind & KIND_HEADING){
716
+ blob_appendf(p->iblob,
717
+ "\n<h%d %s>",
718
+ node->level,
719
+ (node->flags & FLAG_CENTER) ? " style='text-align:center;'" : ""
720
+ );
721
+ cr_parseInline(p, node->start, node->end);
722
+ blob_appendf(p->iblob, "</h%d>\n", node->level );
723
+ return;
724
+ }
725
+
726
+ if (node->kind & KIND_HORIZONTAL_RULE){
727
+ blob_append(p->iblob, "<hr />", -1);
728
+ return;
729
+ }
730
+
731
+ if (node->kind & KIND_LIST){
732
+ cr_renderList(p);
733
+ p->list = NULL;
734
+ return;
735
+ }
736
+
737
+ if (node->kind & KIND_TABLE){
738
+ cr_renderTable(p, node);
739
+ return;
740
+ }
741
+
742
+ if (node->kind & KIND_NO_WIKI_BLOCK){
743
+ blob_appendf(p->iblob,
744
+ "\n<blockquote style='background:oldlace'><pre>%s</pre></blockquote>\n",
745
+ htmlize( node->start, node->end - node->start)
746
+ );
747
+ }
747748
}
748749
//}}}
749750
750751
static char *cr_findEndOfBlock(Parser *p, char *s, char c){//{{{
751752
752
- char *end;
753
- while (s[0]){
754
-
755
- end = s;
756
- if (s[0] == c && s[0] == c && s[0] == c) {
757
- s = cr_nextLine(p, s + 3);
758
- if (p->lineWasBlank) {
759
- p->cursor = s;
760
- return end;
761
- }
762
- }
763
- else {
764
- s = cr_nextLine(p, s);
765
- }
766
- }
767
- return 0;
753
+ char *end;
754
+ while (s[0]){
755
+
756
+ end = s;
757
+ if (s[0] == c && s[0] == c && s[0] == c) {
758
+ s = cr_nextLine(p, s + 3);
759
+ if (p->lineWasBlank) {
760
+ p->cursor = s;
761
+ return end;
762
+ }
763
+ }
764
+ else {
765
+ s = cr_nextLine(p, s);
766
+ }
767
+ }
768
+ return 0;
768769
}
769770
//}}}
770771
static int cr_addListItem(Parser *p, Node *n){//{{{
771772
772
- n->parent = n;
773
- n->next = n->children = NULL;
774
-
775
- if (!p->list) {
776
- if (n->level != 1) return 0;
777
- p->list = n;
778
- return 1;
779
- }
780
-
781
- Node *list = p->list;
782
-
783
- while (n->level < list->level){
784
- list = list->parent;
785
- }
786
-
787
- if (n->level == list->level){
788
-
789
- if (n->kind != list->kind){
790
- if (n->level>1) return 0;
791
- cr_renderList(p);
792
- p->list = n;
793
- return 1;
794
- }
795
- n->parent = list->parent;
796
- p->list = list->next = n;
797
- return 1;
798
- }
799
-
800
- if ( (n->level - list->level) > 1 ) return 0;
801
- n->parent = p->list;
802
- p->list->children = n;
803
- p->list = n;
804
- return 1;
773
+ n->parent = n;
774
+ n->next = n->children = NULL;
775
+
776
+ if (!p->list) {
777
+ if (n->level != 1) return 0;
778
+ p->list = n;
779
+ return 1;
780
+ }
781
+
782
+ Node *list = p->list;
783
+
784
+ while (n->level < list->level){
785
+ list = list->parent;
786
+ }
787
+
788
+ if (n->level == list->level){
789
+
790
+ if (n->kind != list->kind){
791
+ if (n->level>1) return 0;
792
+ cr_renderList(p);
793
+ p->list = n;
794
+ return 1;
795
+ }
796
+ n->parent = list->parent;
797
+ p->list = list->next = n;
798
+ return 1;
799
+ }
800
+
801
+ if ( (n->level - list->level) > 1 ) return 0;
802
+ n->parent = p->list;
803
+ p->list->children = n;
804
+ p->list = n;
805
+ return 1;
805806
806807
}
807808
//}}}
808809
809810
static int isEndWikiMarker(Parser *p){//{{{
810811
811
- char *s = p->cursor;
812
- if (memcmp(s, "<<fossil>>", 10)) return 0;
813
- p->this->start = s;
814
- p->this->kind = KIND_END_WIKI_MARKER;
815
- p->cursor += 10;
816
- return 1;
812
+ char *s = p->cursor;
813
+ if (memcmp(s, "<<fossil>>", 10)) return 0;
814
+ p->this->start = s;
815
+ p->this->kind = KIND_END_WIKI_MARKER;
816
+ p->cursor += 10;
817
+ return 1;
817818
}
818819
///}}}
819820
static int isNoWikiBlock(Parser *p){//{{{
820821
821
- char *s = p->cursor;
822
-
823
- if (s[0] != '{') return 0; s++;
824
- if (s[0] != '{') return 0; s++;
825
- if (s[0] != '{') return 0; s++;
826
-
827
- s = cr_nextLine(p, s);
828
- if (!p->lineWasBlank) return 0;
829
-
830
- p->this->start = s;
831
-
832
- s = cr_findEndOfBlock(p, s, '}');
833
-
834
- if (!s) return 0;
835
-
836
- // p->cursor was set by findEndOfBlock
837
- p->this->kind = KIND_NO_WIKI_BLOCK;
838
- p->this->end = s;
839
- return 1;
822
+ char *s = p->cursor;
823
+
824
+ if (s[0] != '{') return 0; s++;
825
+ if (s[0] != '{') return 0; s++;
826
+ if (s[0] != '{') return 0; s++;
827
+
828
+ s = cr_nextLine(p, s);
829
+ if (!p->lineWasBlank) return 0;
830
+
831
+ p->this->start = s;
832
+
833
+ s = cr_findEndOfBlock(p, s, '}');
834
+
835
+ if (!s) return 0;
836
+
837
+ // p->cursor was set by findEndOfBlock
838
+ p->this->kind = KIND_NO_WIKI_BLOCK;
839
+ p->this->end = s;
840
+ return 1;
840841
}
841842
842843
//}}}
843844
static int isParaBreak(Parser *p){//{{{
844845
845
- char *s = cr_nextLine(p, p->cursor);
846
- if (!p->lineWasBlank) return 0;
846
+ char *s = cr_nextLine(p, p->cursor);
847
+ if (!p->lineWasBlank) return 0;
847848
848
- p->cursor = s;
849
- p->this->kind = KIND_PARA_BREAK;
850
- return 1;
849
+ p->cursor = s;
850
+ p->this->kind = KIND_PARA_BREAK;
851
+ return 1;
851852
}
852853
//}}}
853854
static int isHeading(Parser *p){//{{{
854855
855
- char *s = cr_skipBlanks(p, p->cursor);
856
-
857
- int flags = 0;
858
- int level = cr_countChars(p, s, '=');
859
- if (!level) return 0;
860
-
861
- s += level;
862
-
863
- if (s[0] == '<' && s[1] == '>') {
864
- flags |= FLAG_CENTER;
865
- s += 2;
866
- }
867
- s = cr_skipBlanks(p, s);
868
-
869
- p->this->start = s;
870
-
871
- s = cr_nextLine(p, s);
872
- char *z = s;
873
-
874
- if (s[-1] == '\n') s--;
875
- while(s[-1] == ' ' || s[-1]=='\t') s--;
876
- while(s[-1] == '=' ) s--;
877
- if (p->this->start < s){
878
- p->cursor = z;
879
- p->this->kind = KIND_HEADING;
880
- p->this->end = s;
881
- p->this->level = level;
882
- p->this->flags |= flags;
883
- return 1;
884
- }
885
- return 0;
856
+ char *s = cr_skipBlanks(p, p->cursor);
857
+
858
+ int flags = 0;
859
+ int level = cr_countChars(p, s, '=');
860
+ if (!level) return 0;
861
+
862
+ s += level;
863
+
864
+ if (s[0] == '<' && s[1] == '>') {
865
+ flags |= FLAG_CENTER;
866
+ s += 2;
867
+ }
868
+ s = cr_skipBlanks(p, s);
869
+
870
+ p->this->start = s;
871
+
872
+ s = cr_nextLine(p, s);
873
+ char *z = s;
874
+
875
+ if (s[-1] == '\n') s--;
876
+ while(s[-1] == ' ' || s[-1]=='\t') s--;
877
+ while(s[-1] == '=' ) s--;
878
+ if (p->this->start < s){
879
+ p->cursor = z;
880
+ p->this->kind = KIND_HEADING;
881
+ p->this->end = s;
882
+ p->this->level = level;
883
+ p->this->flags |= flags;
884
+ return 1;
885
+ }
886
+ return 0;
886887
}
887888
//}}}
888889
static int isHorizontalRule(Parser *p){//{{{
889890
890
- char *s = cr_skipBlanks(p, p->cursor);
891
-
892
- int level = cr_countChars(p, s, '-');
893
-
894
- if (level < 4) return 0;
895
- s = cr_nextLine(p, s + level);
896
- if (!p->lineWasBlank) return 0;
897
-
898
- p->cursor = s;
899
- p->this->kind = KIND_HORIZONTAL_RULE;
900
-
901
- return 1;
891
+ char *s = cr_skipBlanks(p, p->cursor);
892
+
893
+ int level = cr_countChars(p, s, '-');
894
+
895
+ if (level < 4) return 0;
896
+ s = cr_nextLine(p, s + level);
897
+ if (!p->lineWasBlank) return 0;
898
+
899
+ p->cursor = s;
900
+ p->this->kind = KIND_HORIZONTAL_RULE;
901
+
902
+ return 1;
902903
}
903904
//}}}
904905
static int isListItem(Parser *p){//{{{
905906
906
- char *s = cr_skipBlanks(p, p->cursor);
907
-
908
- int level = cr_countChars(p, s, '#');
909
- if (!level) level = cr_countChars(p, s, '*');
910
-
911
- if ( !level) return 0;
912
-
913
- p->this->kind = (s[0] == '#') ? KIND_ORDERED_LIST : KIND_UNORDERED_LIST;
914
- p->this->level = level;
915
-
916
- s = cr_skipBlanks(p, s + level);
917
- p->this->start = s;
918
-
919
- s = cr_nextLine(p, s);
920
- if (p->lineWasBlank) return 0;
921
-
922
- if (cr_addListItem(p, p->this)){
923
- p->cursor = p->this->end = s;
924
- return 1;
925
- }
926
- p->this->kind = 0;
927
- return 0;
907
+ char *s = cr_skipBlanks(p, p->cursor);
908
+
909
+ int level = cr_countChars(p, s, '#');
910
+ if (!level) level = cr_countChars(p, s, '*');
911
+
912
+ if ( !level) return 0;
913
+
914
+ p->this->kind = (s[0] == '#') ? KIND_ORDERED_LIST : KIND_UNORDERED_LIST;
915
+ p->this->level = level;
916
+
917
+ s = cr_skipBlanks(p, s + level);
918
+ p->this->start = s;
919
+
920
+ s = cr_nextLine(p, s);
921
+ if (p->lineWasBlank) return 0;
922
+
923
+ if (cr_addListItem(p, p->this)){
924
+ p->cursor = p->this->end = s;
925
+ return 1;
926
+ }
927
+ p->this->kind = 0;
928
+ return 0;
928929
}
929930
//}}}
930931
static int isTable(Parser *p){//{{{
931932
932
- p->this->start = p->cursor;
933
- char *s = cr_skipBlanks(p, p->cursor);
934
- if (s[0] != '|') return 0;
933
+ p->this->start = p->cursor;
934
+ char *s = cr_skipBlanks(p, p->cursor);
935
+ if (s[0] != '|') return 0;
935936
s +=1;
936
- p->this->kind = KIND_TABLE;
937
-
938
-
939
- //p->cursor = p->this->end = cr_nextLine(p, s);
940
- Node *row;
941
- Node *tail = NULL;
942
-
943
- while (1) {
944
-
945
- row = pool_new(p);
946
- row->kind = KIND_TABLE_ROW;
947
-
948
- if (tail) tail = tail->next = row;
949
- else p->this->children = tail = row;
950
-
951
- row->start = s;
952
- p->cursor = s = row->end = p->this->end = cr_nextLine(p, s);
953
-
954
- if (row->end[-1] == '\n') row->end -= 1;
955
- while(row->end[-1] == ' ' ) row->end -= 1;
956
- if (row->end[-1] == '|') row->end -= 1;
957
-
958
- if (!*s) break;
959
-
960
- // blanks *not* normalized
961
- s = cr_skipBlanks(p, p->cursor);
962
- if (s[0] != '|') break;
963
- s++;
964
-
965
- }
966
- return 1;
937
+ p->this->kind = KIND_TABLE;
938
+
939
+
940
+ //p->cursor = p->this->end = cr_nextLine(p, s);
941
+ Node *row;
942
+ Node *tail = NULL;
943
+
944
+ while (1) {
945
+
946
+ row = pool_new(p);
947
+ row->kind = KIND_TABLE_ROW;
948
+
949
+ if (tail) tail = tail->next = row;
950
+ else p->this->children = tail = row;
951
+
952
+ row->start = s;
953
+ p->cursor = s = row->end = p->this->end = cr_nextLine(p, s);
954
+
955
+ if (row->end[-1] == '\n') row->end -= 1;
956
+ while(row->end[-1] == ' ' ) row->end -= 1;
957
+ if (row->end[-1] == '|') row->end -= 1;
958
+
959
+ if (!*s) break;
960
+
961
+ // blanks *not* normalized
962
+ s = cr_skipBlanks(p, p->cursor);
963
+ if (s[0] != '|') break;
964
+ s++;
965
+
966
+ }
967
+ return 1;
967968
968969
};
969970
//}}}
970971
static int isParagraph(Parser *p){//{{{
971972
972
- char *s = p->cursor;
973
- p->this->start = s;
974
-
975
- s = cr_nextLine(p, s);
976
- p->cursor = p->this->end = s;
977
- p->this->kind = KIND_PARAGRAPH;
978
- return 1;
979
-
980
-}
981
-//}}}
982
-static void cr_parse(Parser *p, char* z){//{{{
983
-
984
- p->previous = pool_new(p);
985
- p->previous->kind = KIND_PARA_BREAK;
986
-
987
- p->this = pool_new(p);
988
- p->this->kind = KIND_PARA_BREAK;
989
-
990
- p->inLink = 0;
991
- p->inTable = 0;
992
-
993
- p->cursor = z;
994
- p->list = NULL;
995
- p->istack = NULL;
996
-
997
- while (p->cursor[0]) {
998
-
999
- while (1){
1000
-
1001
- // must be first
1002
- if (isNoWikiBlock(p)) break;
1003
- if (isParaBreak(p)) break;
1004
-
1005
- // order not important
1006
- if (isHeading(p)) break;
1007
- if (isHorizontalRule(p)) break;
1008
- if (isListItem(p)) break;
1009
- if (isTable(p)) break;
1010
-
1011
- // here for efficiency?
1012
- if (isEndWikiMarker(p)) break;
1013
-
1014
- // must be last
1015
- if (isParagraph(p)); break;
1016
-
1017
- // doh!
1018
- assert(0);
1019
- }
1020
-
1021
- int kind = p->this->kind;
1022
- int prev = p->previous->kind;
1023
-
1024
- if (kind & KIND_END_WIKI_MARKER) return;
1025
-
1026
- if (kind == KIND_PARAGRAPH && prev & KIND_LIST_OR_PARAGRAPH) {
1027
- p->previous->end = p->this->end;
1028
- p->this = pool_new(p);
1029
- continue;
1030
- }
1031
-
1032
- if ( !(kind & KIND_LIST && prev & KIND_LIST) )
1033
- cr_render(p, p->previous);
1034
-
1035
- p->previous = p->this;
1036
- p->this = pool_new(p);
1037
-
1038
- }
1039
-}
1040
-//}}}
1041
-
1042
-//}}}
1043
-
1044
-char *wiki_render_creole(Renderer *r, char *z){//{{{
1045
-
1046
- Parser parser;
1047
- Parser *p = &parser;
1048
-
1049
- p->r = r;
1050
- p->iblob = r->pOut;
1051
-
1052
- p->nFree = 0;
1053
- p->pool = NULL;
1054
-
1055
- cr_parse(p, z);
1056
-
1057
- cr_render(p, p->previous);
1058
-
1059
- pool_free(p);
1060
-
1061
- return p->cursor;
1062
-
1063
-}
1064
-//}}}
1065
-
1066
-
1067
-char *wiki_render_macro(Renderer *p, char *z, int *tokenType){
1068
- if (!memcmp(z, "<<fossil>>", 9)){
1069
- *tokenType = 1;
1070
- return z + 10;
1071
- }
1072
- if (memcmp(z, "<<creole>>", 9)) {
1073
- *tokenType = 0;
1074
- return z;
1075
- }
1076
- *tokenType = 1;
1077
- return wiki_render_creole(p, z+10);
1078
-
1079
-}
1080
-
1081
-/* :folding=explicit:collapseFolds=1:tabSize=2:indentSize=2:noTabs=false: */
973
+ char *s = p->cursor;
974
+ p->this->start = s;
975
+
976
+ s = cr_nextLine(p, s);
977
+ p->cursor = p->this->end = s;
978
+ p->this->kind = KIND_PARAGRAPH;
979
+ return 1;
980
+
981
+}
982
+//}}}
983
+static void cr_parse(Parser *p, char* z){//{{{
984
+
985
+ p->previous = pool_new(p);
986
+ p->previous->kind = KIND_PARA_BREAK;
987
+
988
+ p->this = pool_new(p);
989
+ p->this->kind = KIND_PARA_BREAK;
990
+
991
+ p->inLink = 0;
992
+ p->inTable = 0;
993
+
994
+ p->cursor = z;
995
+ p->list = NULL;
996
+ p->istack = NULL;
997
+
998
+ while (p->cursor[0]) {
999
+
1000
+ while (1){
1001
+
1002
+ // must be first
1003
+ if (isNoWikiBlock(p)) break;
1004
+ if (isParaBreak(p)) break;
1005
+
1006
+ // order not important
1007
+ if (isHeading(p)) break;
1008
+ if (isHorizontalRule(p)) break;
1009
+ if (isListItem(p)) break;
1010
+ if (isTable(p)) break;
1011
+
1012
+ // here for efficiency?
1013
+ if (isEndWikiMarker(p)) break;
1014
+
1015
+ // must be last
1016
+ if (isParagraph(p)); break;
1017
+
1018
+ // doh!
1019
+ assert(0);
1020
+ }
1021
+
1022
+ int kind = p->this->kind;
1023
+ int prev = p->previous->kind;
1024
+
1025
+ if (kind & KIND_END_WIKI_MARKER) return;
1026
+
1027
+ if (kind == KIND_PARAGRAPH && prev & KIND_LIST_OR_PARAGRAPH) {
1028
+ p->previous->end = p->this->end;
1029
+ p->this = pool_new(p);
1030
+ continue;
1031
+ }
1032
+
1033
+ if ( !(kind & KIND_LIST && prev & KIND_LIST) )
1034
+ cr_render(p, p->previous);
1035
+
1036
+ p->previous = p->this;
1037
+ p->this = pool_new(p);
1038
+
1039
+ }
1040
+}
1041
+//}}}
1042
+
1043
+//}}}
1044
+
1045
+char *wiki_render_creole(Renderer *r, char *z){
1046
+
1047
+ Parser parser;
1048
+ Parser *p = &parser;
1049
+
1050
+ p->r = r;
1051
+ p->iblob = r->pOut;
1052
+
1053
+ p->nFree = 0;
1054
+ p->pool = NULL;
1055
+
1056
+ cr_parse(p, z);
1057
+
1058
+ cr_render(p, p->previous);
1059
+
1060
+ pool_free(p);
1061
+
1062
+ return p->cursor;
1063
+
1064
+}
1065
+
10821066
--- src/creoleparser.c
+++ src/creoleparser.c
@@ -28,11 +28,11 @@
28 #include <assert.h>
29 #include "config.h"
30 #include "creoleparser.h"
31
32 #if INTERFACE
33 #define HAVE_MACRO_EXTENSIONS 1
34 #endif
35
36 //{{{ LOCAL INTERFACE
37 #if LOCAL_INTERFACE
38
@@ -61,59 +61,59 @@
61
62 #define KIND_TABLE_ROW 0x0010000
63 //}}}
64 //{{{ FLAG
65 // keep first four bits free
66 #define FLAG_CENTER 0x0000100
67 //}}}
68 struct Node {//{{{
69
70 char *start;
71 char *end;
72
73 int kind;
74 int level;
75 int flags;
76
77 Node *parent;
78 Node *next;
79 Node *children;
80
81 };
82 //}}}
83 struct NodePool {//{{{
84 NodePool *next;
85 Node a[POOL_CHUNK_SIZE];
86 }
87 //}}}
88 struct Parser {//{{{
89
90 Blob *pOut; /* Output appended to this blob */
91 Renderer *r;
92
93 NodePool *pool;
94 int nFree;
95
96 Node *this;
97 Node *previous;
98 Node *list;
99
100 char *cursor;
101
102 int lineWasBlank;
103 int charCount;
104
105 Node *item;
106 Node *istack;
107 char *icursor;
108 char *iend;
109
110 int inLink;
111 int inTable;
112 int iesc;
113
114 Blob *iblob;
115
116
117
118
119 };
@@ -126,484 +126,485 @@
126 //}}}
127
128 //{{{ POOL MANAGEMENT
129 static Node *pool_new(Parser *p){
130
131 if ( p->pool == NULL || p->nFree == 0){
132
133 NodePool *temp = p->pool;
134
135 p->pool = malloc(sizeof(NodePool));
136 if( p->pool == NULL ) fossil_panic("out of memory");
137
138 p->pool->next = temp;
139 p->nFree = POOL_CHUNK_SIZE;
140 }
141 p->nFree -= 1;
142 Node *node = &(p->pool->a[p->nFree]);
143 memset(node, 0, sizeof(*node));
144
145 return node;
146 }
147
148
149 static void pool_free(Parser *p){
150
151 NodePool *temp;
152
153 while (p->pool != NULL){
154 temp = p->pool;
155 p->pool = temp->next;
156 free(temp);
157 }
158
159 }
160 //}}}
161
162 //{{{ Utility Methods
163
164 static char *cr_skipBlanks(Parser *p, char* z){//{{{
165 char *s = z;
166 while (z[0] == ' ' || z[0] == '\t') z++;
167 p->charCount = z - s;
168 return z;
169 }
170 //}}}
171 static int cr_countBlanks(Parser *p, char* z){//{{{
172 cr_skipBlanks(p, z);
173 return p->charCount;
174 }
175 //}}}
176 static char *cr_skipChars(Parser *p, char *z, char c){//{{{
177 char *s = z;
178 while (z[0] == c) z++;
179 p->charCount = z - s;
180 return z;
181 }
182 //}}}
183 static int cr_countChars(Parser *p, char *z, char c){//{{{
184 cr_skipChars(p, z, c);
185 return p->charCount;
186 }
187 //}}}
188 static char *cr_nextLine(Parser *p, char *z){//{{{
189
190 p->lineWasBlank = 1;
191
192 while (1){
193
194 switch (z[0]){
195
196 case '\r':
197 if (z[1] == '\n') {
198 z[0] = ' ';
199 return z + 2;
200 }
201 z[0] = '\n';
202 return z + 1;
203
204 case'\n':
205 return z + 1;
206
207 case '\t':
208 z[0] = ' ';
209 z++;
210 break;
211
212 case ' ':
213 z++;
214 break;
215
216 case '\0':
217 return z;
218
219 default:
220 p->lineWasBlank = 0;
221 z++;
222 }
223 }
224 }
225 //}}}
226 //}}}
227
228 //{{{ INLINE PARSER
229
230 static int cr_isEsc(Parser *p){//{{{
231 if (p->iesc){
232 blob_append(p->iblob, p->icursor, 1);
233 p->iesc = 0;
234 p->icursor += 1;
235 return 1;
236 }
237 return 0;
238 }
239 //}}}
240 static int cr_iOpen(Parser *p, int kind){//{{{
241
242 switch (kind){
243
244 case KIND_BOLD:
245 blob_append(p->iblob, "<strong>", 8);
246 return 1;
247
248 case KIND_ITALIC:
249 blob_append(p->iblob, "<em>", 4);
250 return 1;
251
252 case KIND_SUPERSCRIPT:
253 blob_append(p->iblob, "<sup>", 5);
254 return 1;
255
256 case KIND_SUBSCRIPT:
257 blob_append(p->iblob, "<sub>", 5);
258 return 1;
259
260 case KIND_MONOSPACED:
261 blob_append(p->iblob, "<tt>", 4);
262 return 1;
263 }
264 return 0;
265 }
266 //}}}
267 static int cr_iClose(Parser *p, int kind){//{{{
268
269 switch (kind){
270
271 case KIND_BOLD:
272 blob_append(p->iblob, "</strong>", 9);
273 return 1;
274
275 case KIND_ITALIC:
276 blob_append(p->iblob, "</em>", 5);
277 return 1;
278
279 case KIND_SUPERSCRIPT:
280 blob_append(p->iblob, "</sup>", 6);
281 return 1;
282
283 case KIND_SUBSCRIPT:
284 blob_append(p->iblob, "</sub>", 6);
285 return 1;
286
287 case KIND_MONOSPACED:
288 blob_append(p->iblob, "</tt>", 5);
289 return 1;
290 }
291 return 0;
292 }
293 //}}}
294
295
296 static void cr_iMarkup(Parser *p, int kind){//{{{
297
298 if (p->iesc) {
299 blob_append(p->iblob, p->icursor, 1);
300 p->icursor +=1;
301 p->iesc =0;
302 return;
303 }
304
305 if (p->icursor[1] != p->icursor[0]) {
306 blob_append(p->iblob, p->icursor, 1);
307 p->icursor +=1;
308 return;
309 }
310
311 p->icursor += 2;
312
313 if (kind & KIND_BREAK) {
314 blob_append(p->iblob, "<br />", 6);
315 return;
316 }
317
318 if (kind & KIND_ITALIC && p->icursor[-3] == ':'){
319 blob_append(p->iblob, "//", 2);
320 return;
321 }
322
323 Node *n = p->istack;
324
325 int found = 0;
326 while (n) {
327 if (n->kind & kind) {
328 found = 1;
329 break;
330 }
331 n = n->next;
332 }
333
334 if (!found) {
335 n = pool_new(p);
336 n->kind = kind;
337 n->next = p->istack;
338 p->istack = n;
339
340 assert(cr_iOpen(p, kind));
341 return;
342 };
343
344 n= p->istack;
345 while (n){
346 p->istack = n->next;
347
348 assert(cr_iClose(p, n->kind));
349
350 if (kind == n->kind) return;
351 n = p->istack;
352 }
353 }
354 //}}}
355 static int cr_iNoWiki(Parser *p){//{{{
356
357 if ((p->iend - p->icursor)<6) return 0;
358
359 if (p->icursor[1]!='{' || p->icursor[2]!='{')
360 return 0;
361
362 char *s = p->icursor + 3;
363
364 int count = p->iend - p->icursor - 6;
365 while (count--){
366 if (s[0]=='}' && s[1]=='}' && s[2]=='}' && s[3]!='}'){
367 blob_appendf(p->iblob, "<tt style='background:oldlace'>%s</tt>", htmlize(p->icursor + 3, s - p->icursor-3));
368 p->icursor = s + 3;
369 return 1;
370 }
371 s++;
372 }
373 return 0;
374 }
375
376 //}}}
377 static int cr_iImage(Parser *p){//{{{
378
379 if (p->inLink) return 0;
380 if ((p->iend - p->icursor)<3) return 0;
381
382 if (p->icursor[1]!='{') return 0;
383
384 char *s = p->icursor + 2;
385 char *bar = NULL;
386
387 int count = p->iend - p->icursor - 4;
388 while (count--){
389 if (s[0]=='}' && s[1]=='}'){
390 if (!bar) bar = p->icursor + 2;
391 blob_appendf(p->iblob, "<span style='color:green;border:1px solid green;'>%s</span>", htmlize(bar, s - bar ));
392 p->icursor = s + 2;
393 return 1;
394 }
395 if (!bar && s[0]=='|') bar=s+1;
396 s++;
397 }
398 return 0;
399 }
400 //}}}
401 static int cr_iMacro(Parser *p){//{{{
402
403 if (p->inLink) return 0;
404 if ((p->iend - p->icursor)<3) return 0;
405
406 if (p->icursor[1]!='<') return 0;
407
408 char *s = p->icursor + 2;
409
410 int count = p->iend - p->icursor - 4;
411 while (count--){
412 if (s[0]=='>' && s[1]=='>'){
413 blob_appendf(p->iblob, "<span style='color:red;border:1px solid red;'>%s</span>", htmlize(p->icursor, s - p->icursor + 2));
414 p->icursor = s + 2;
415 return 1;
416 }
417 s++;
418 }
419 return 0;
 
420
421 }
422 //}}}
423
424 static void cr_renderLink(Parser *p, char *s, char *bar, char *e){//{{{
425
426 int tsize = bar-s;
427 int dsize = e - bar-1;
428
429 if (tsize < 1) return;
430 if (dsize < 1) dsize = 0;
431
432 char zTarget[tsize + 1];
433 memcpy(zTarget, s, tsize);
434 zTarget[tsize] = '\0';
435
436 char zClose[20];
437
438 Blob *pOut = p->r->pOut;
439
440 p->r->pOut = p->iblob;
441 wf_openHyperlink(p->r, zTarget, zClose, sizeof(zClose));
442 p->r->pOut = pOut;
443
444 if (dsize)
445 cr_parseInline(p, bar+1, e) ;
446 else
447 blob_append(p->iblob, htmlize(s, tsize), -1);
448 blob_append(p->iblob, zClose, -1);
449 }
450 //}}}
451
452 static int cr_iLink(Parser *p){//{{{
453
454 if (p->inLink) return 0;
455 if ((p->iend - p->icursor)<3) return 0;
456
457 if (p->icursor[1]!='[') return 0;
458
459 char *s = p->icursor + 2;
460 char *bar = NULL;
461
462 int count = p->iend - p->icursor -3;
463 while (count--){
464 if (s[0]==']' && s[1]==']'){
465 if (!bar) bar = s;
466 p->inLink = 1;
467 cr_renderLink(p, p->icursor+2, bar, s);
468 p->inLink = 0;
469 p->icursor = s + 2;
470 return 1;
471 }
472 if (!bar && s[0]=='|') bar=s;
473 s++;
474 }
475 return 0;
476 }
477 //}}}
478
479 LOCAL char *cr_parseInline(Parser *p, char *s, char *e){//{{{
480
481 int save_iesc = p->iesc;
482 char *save_iend = p->iend;
483 Node *save_istack = p->istack;
484
485 p->iesc = 0;
486 p->iend = e;
487 p->istack = NULL;
488
489 p->icursor = s;
490
491 char *eof = NULL;
492 while (!eof && p->icursor < p->iend ){
493
494 switch (*p->icursor) {//{{{
495
496 case '~':
497 if (p->iesc) {
498 blob_append(p->iblob, "~", 1);
499 p->iesc = 0;
500 }
501 p->iesc = !p->iesc;
502 p->icursor+=1;
503 break;
504
505 case '*':
506 cr_iMarkup(p, KIND_BOLD);
507 break;
508
509 case '/':
510 cr_iMarkup(p, KIND_ITALIC);
511 break;
512
513 case '^':
514 cr_iMarkup(p, KIND_SUPERSCRIPT);
515 break;
516
517 case ',':
518 cr_iMarkup(p, KIND_SUBSCRIPT);
519 break;
520
521 case '#':
522 cr_iMarkup(p, KIND_MONOSPACED);
523 break;
524
525 case '\\':
526 cr_iMarkup(p, KIND_BREAK);
527 break;
528
529 case '{':
530 if (cr_isEsc(p)) break;
531 if (cr_iNoWiki(p)) break;
532 if (cr_iImage(p)) break;
533 blob_append(p->iblob, p->icursor, 1);
534 p->icursor += 1;
535 break;
536
537 case '[':
538 if (cr_isEsc(p)) break;
539 if (cr_iLink(p)) break;
540 blob_append(p->iblob, p->icursor, 1);
541 p->icursor += 1;
542 break;
543
544
545 case '<':
546 if (cr_isEsc(p)) break;
547 if (cr_iMacro(p)) break;
548
549 blob_append(p->iblob, "&lt;", 4);
550 p->icursor += 1;
551 break;
552
553 case '>':
554 if (p->iesc) {
555 blob_append(p->iblob, "~", 1);
556 p->iesc = 0;
557 }
558 blob_append(p->iblob, "&gt;", 4);
559 p->icursor += 1;
560 break;
561
562 case '&':
563 if (p->iesc) {
564 blob_append(p->iblob, "~", 1);
565 p->iesc = 0;
566 }
567 blob_append(p->iblob, "&amp;", 5);
568 p->icursor += 1;
569 break;
570
571 case '|':
572 if (p->inTable){
573 if (p->iesc) {
574 blob_append(p->iblob, p->icursor, 1);
575 p->iesc = 0;
576 p->icursor += 1;
577 break;
578 }
579 eof = p->icursor + 1;
580 break;
581 }
582 // fall through to default
583
584 default:
585 if (p->iesc) {
586 blob_append(p->iblob, "~", 1);
587 p->iesc = 0;
588 }
589 blob_append(p->iblob, p->icursor, 1);
590 p->icursor +=1;
591 }//}}}
592
593 }
594
595 while (p->istack){
596 cr_iClose(p, p->istack->kind);
597 p->istack = p->istack->next;
598 }
599
600 p->iesc = save_iesc;
601 p->iend = save_iend;
602 p->istack = save_istack;
603
604 return eof;
605
606 }
607 //}}}
608 //}}}
609
@@ -610,472 +611,455 @@
610 //{{{ BLOCK PARSER
611
612 static void cr_renderListItem(Parser *p, Node *n){//{{{
613
614
615 blob_append(p->iblob, "<li>", 4);
616 cr_parseInline(p, n->start, n->end);
617
618 if (n->children){
619
620 int ord = (n->children->kind & KIND_ORDERED_LIST);
621
622 if (ord) blob_append(p->iblob, "<ol>", 4);
623 else blob_append(p->iblob, "<ul>", 4);
624
625 n = n->children;
626 while (n){
627 cr_renderListItem(p, n);
628 n = n->next;
629 }
630
631 if (ord) blob_append(p->iblob, "</ol>", 5);
632 else blob_append(p->iblob, "</ul>", 5);
633 }
634 blob_append(p->iblob, "</li>", 5);
635 }
636 //}}}
637 static void cr_renderList(Parser *p){//{{{
638
639 Node *n = p->list;
640
641 while (n->parent !=n) n = n->parent;
642
643 int ord = (n->kind & KIND_ORDERED_LIST);
644
645 if (ord) blob_append(p->iblob, "\n\n<ol>", -1);
646 else blob_append(p->iblob, "\n\n<ul>", -1);
647
648 while (n) {
649 cr_renderListItem(p, n);
650 n = n->next;
651 }
652
653 if (ord) blob_append(p->iblob, "</ol>", 5);
654 else blob_append(p->iblob, "</ul>", 5);
655 }
656
657 //}}}
658
659 static void cr_renderTableRow(Parser *p, Node *row){//{{{
660
661 char *s = row->start;
662 int th;
663
664 blob_append(p->iblob, "\n<tr>", -1);
665
666 while (s && s < row->end){
667
668 if ((th = *s == '=')) {
669 s++;
670 blob_append(p->iblob, "<th>", -1);
671 }
672 else {
673 blob_append(p->iblob, "<td>", -1);
674 }
675
676 s = cr_parseInline(p, s, row->end);
677
678 if (th)
679 blob_append(p->iblob, "</th>\n", -1);
680 else
681 blob_append(p->iblob, "</td>\n", -1);
682
683 if (!s) break;
684 }
685 blob_append(p->iblob, "</tr>", 5);
686 }
687 //}}}
688 static void cr_renderTable(Parser *p, Node *n){//{{{
689
690 Node *row = n->children;
691
692 blob_append(p->iblob, "<table class='creoletable'>", -1);
693 p->inTable = 1;
694 while (row){
695
696 cr_renderTableRow(p, row);
697 row = row->next;
698
699 }
700 blob_append(p->iblob, "</table>", -1);
701 p->inTable = 0;
702
703 }
704 //}}}
705
706 static void cr_render(Parser *p, Node *node){//{{{
707
708 if (node->kind & KIND_PARAGRAPH){
709 blob_append(p->iblob, "\n<p>", -1);
710 cr_parseInline(p, node->start, node->end );
711 blob_append(p->iblob, "</p>\n", -1 );
712 }
713
714 if (node->kind & KIND_HEADING){
715 blob_appendf(p->iblob,
716 "\n<h%d %s>",
717 node->level,
718 (node->flags & FLAG_CENTER) ? " style='text-align:center;'" : ""
719 );
720 cr_parseInline(p, node->start, node->end);
721 blob_appendf(p->iblob, "</h%d>\n", node->level );
722 return;
723 }
724
725 if (node->kind & KIND_HORIZONTAL_RULE){
726 blob_append(p->iblob, "<hr />", -1);
727 return;
728 }
729
730 if (node->kind & KIND_LIST){
731 cr_renderList(p);
732 p->list = NULL;
733 return;
734 }
735
736 if (node->kind & KIND_TABLE){
737 cr_renderTable(p, node);
738 return;
739 }
740
741 if (node->kind & KIND_NO_WIKI_BLOCK){
742 blob_appendf(p->iblob,
743 "\n<blockquote style='background:oldlace'><pre>%s</pre></blockquote>\n",
744 htmlize( node->start, node->end - node->start)
745 );
746 }
747 }
748 //}}}
749
750 static char *cr_findEndOfBlock(Parser *p, char *s, char c){//{{{
751
752 char *end;
753 while (s[0]){
754
755 end = s;
756 if (s[0] == c && s[0] == c && s[0] == c) {
757 s = cr_nextLine(p, s + 3);
758 if (p->lineWasBlank) {
759 p->cursor = s;
760 return end;
761 }
762 }
763 else {
764 s = cr_nextLine(p, s);
765 }
766 }
767 return 0;
768 }
769 //}}}
770 static int cr_addListItem(Parser *p, Node *n){//{{{
771
772 n->parent = n;
773 n->next = n->children = NULL;
774
775 if (!p->list) {
776 if (n->level != 1) return 0;
777 p->list = n;
778 return 1;
779 }
780
781 Node *list = p->list;
782
783 while (n->level < list->level){
784 list = list->parent;
785 }
786
787 if (n->level == list->level){
788
789 if (n->kind != list->kind){
790 if (n->level>1) return 0;
791 cr_renderList(p);
792 p->list = n;
793 return 1;
794 }
795 n->parent = list->parent;
796 p->list = list->next = n;
797 return 1;
798 }
799
800 if ( (n->level - list->level) > 1 ) return 0;
801 n->parent = p->list;
802 p->list->children = n;
803 p->list = n;
804 return 1;
805
806 }
807 //}}}
808
809 static int isEndWikiMarker(Parser *p){//{{{
810
811 char *s = p->cursor;
812 if (memcmp(s, "<<fossil>>", 10)) return 0;
813 p->this->start = s;
814 p->this->kind = KIND_END_WIKI_MARKER;
815 p->cursor += 10;
816 return 1;
817 }
818 ///}}}
819 static int isNoWikiBlock(Parser *p){//{{{
820
821 char *s = p->cursor;
822
823 if (s[0] != '{') return 0; s++;
824 if (s[0] != '{') return 0; s++;
825 if (s[0] != '{') return 0; s++;
826
827 s = cr_nextLine(p, s);
828 if (!p->lineWasBlank) return 0;
829
830 p->this->start = s;
831
832 s = cr_findEndOfBlock(p, s, '}');
833
834 if (!s) return 0;
835
836 // p->cursor was set by findEndOfBlock
837 p->this->kind = KIND_NO_WIKI_BLOCK;
838 p->this->end = s;
839 return 1;
840 }
841
842 //}}}
843 static int isParaBreak(Parser *p){//{{{
844
845 char *s = cr_nextLine(p, p->cursor);
846 if (!p->lineWasBlank) return 0;
847
848 p->cursor = s;
849 p->this->kind = KIND_PARA_BREAK;
850 return 1;
851 }
852 //}}}
853 static int isHeading(Parser *p){//{{{
854
855 char *s = cr_skipBlanks(p, p->cursor);
856
857 int flags = 0;
858 int level = cr_countChars(p, s, '=');
859 if (!level) return 0;
860
861 s += level;
862
863 if (s[0] == '<' && s[1] == '>') {
864 flags |= FLAG_CENTER;
865 s += 2;
866 }
867 s = cr_skipBlanks(p, s);
868
869 p->this->start = s;
870
871 s = cr_nextLine(p, s);
872 char *z = s;
873
874 if (s[-1] == '\n') s--;
875 while(s[-1] == ' ' || s[-1]=='\t') s--;
876 while(s[-1] == '=' ) s--;
877 if (p->this->start < s){
878 p->cursor = z;
879 p->this->kind = KIND_HEADING;
880 p->this->end = s;
881 p->this->level = level;
882 p->this->flags |= flags;
883 return 1;
884 }
885 return 0;
886 }
887 //}}}
888 static int isHorizontalRule(Parser *p){//{{{
889
890 char *s = cr_skipBlanks(p, p->cursor);
891
892 int level = cr_countChars(p, s, '-');
893
894 if (level < 4) return 0;
895 s = cr_nextLine(p, s + level);
896 if (!p->lineWasBlank) return 0;
897
898 p->cursor = s;
899 p->this->kind = KIND_HORIZONTAL_RULE;
900
901 return 1;
902 }
903 //}}}
904 static int isListItem(Parser *p){//{{{
905
906 char *s = cr_skipBlanks(p, p->cursor);
907
908 int level = cr_countChars(p, s, '#');
909 if (!level) level = cr_countChars(p, s, '*');
910
911 if ( !level) return 0;
912
913 p->this->kind = (s[0] == '#') ? KIND_ORDERED_LIST : KIND_UNORDERED_LIST;
914 p->this->level = level;
915
916 s = cr_skipBlanks(p, s + level);
917 p->this->start = s;
918
919 s = cr_nextLine(p, s);
920 if (p->lineWasBlank) return 0;
921
922 if (cr_addListItem(p, p->this)){
923 p->cursor = p->this->end = s;
924 return 1;
925 }
926 p->this->kind = 0;
927 return 0;
928 }
929 //}}}
930 static int isTable(Parser *p){//{{{
931
932 p->this->start = p->cursor;
933 char *s = cr_skipBlanks(p, p->cursor);
934 if (s[0] != '|') return 0;
935 s +=1;
936 p->this->kind = KIND_TABLE;
937
938
939 //p->cursor = p->this->end = cr_nextLine(p, s);
940 Node *row;
941 Node *tail = NULL;
942
943 while (1) {
944
945 row = pool_new(p);
946 row->kind = KIND_TABLE_ROW;
947
948 if (tail) tail = tail->next = row;
949 else p->this->children = tail = row;
950
951 row->start = s;
952 p->cursor = s = row->end = p->this->end = cr_nextLine(p, s);
953
954 if (row->end[-1] == '\n') row->end -= 1;
955 while(row->end[-1] == ' ' ) row->end -= 1;
956 if (row->end[-1] == '|') row->end -= 1;
957
958 if (!*s) break;
959
960 // blanks *not* normalized
961 s = cr_skipBlanks(p, p->cursor);
962 if (s[0] != '|') break;
963 s++;
964
965 }
966 return 1;
967
968 };
969 //}}}
970 static int isParagraph(Parser *p){//{{{
971
972 char *s = p->cursor;
973 p->this->start = s;
974
975 s = cr_nextLine(p, s);
976 p->cursor = p->this->end = s;
977 p->this->kind = KIND_PARAGRAPH;
978 return 1;
979
980 }
981 //}}}
982 static void cr_parse(Parser *p, char* z){//{{{
983
984 p->previous = pool_new(p);
985 p->previous->kind = KIND_PARA_BREAK;
986
987 p->this = pool_new(p);
988 p->this->kind = KIND_PARA_BREAK;
989
990 p->inLink = 0;
991 p->inTable = 0;
992
993 p->cursor = z;
994 p->list = NULL;
995 p->istack = NULL;
996
997 while (p->cursor[0]) {
998
999 while (1){
1000
1001 // must be first
1002 if (isNoWikiBlock(p)) break;
1003 if (isParaBreak(p)) break;
1004
1005 // order not important
1006 if (isHeading(p)) break;
1007 if (isHorizontalRule(p)) break;
1008 if (isListItem(p)) break;
1009 if (isTable(p)) break;
1010
1011 // here for efficiency?
1012 if (isEndWikiMarker(p)) break;
1013
1014 // must be last
1015 if (isParagraph(p)); break;
1016
1017 // doh!
1018 assert(0);
1019 }
1020
1021 int kind = p->this->kind;
1022 int prev = p->previous->kind;
1023
1024 if (kind & KIND_END_WIKI_MARKER) return;
1025
1026 if (kind == KIND_PARAGRAPH && prev & KIND_LIST_OR_PARAGRAPH) {
1027 p->previous->end = p->this->end;
1028 p->this = pool_new(p);
1029 continue;
1030 }
1031
1032 if ( !(kind & KIND_LIST && prev & KIND_LIST) )
1033 cr_render(p, p->previous);
1034
1035 p->previous = p->this;
1036 p->this = pool_new(p);
1037
1038 }
1039 }
1040 //}}}
1041
1042 //}}}
1043
1044 char *wiki_render_creole(Renderer *r, char *z){//{{{
1045
1046 Parser parser;
1047 Parser *p = &parser;
1048
1049 p->r = r;
1050 p->iblob = r->pOut;
1051
1052 p->nFree = 0;
1053 p->pool = NULL;
1054
1055 cr_parse(p, z);
1056
1057 cr_render(p, p->previous);
1058
1059 pool_free(p);
1060
1061 return p->cursor;
1062
1063 }
1064 //}}}
1065
1066
1067 char *wiki_render_macro(Renderer *p, char *z, int *tokenType){
1068 if (!memcmp(z, "<<fossil>>", 9)){
1069 *tokenType = 1;
1070 return z + 10;
1071 }
1072 if (memcmp(z, "<<creole>>", 9)) {
1073 *tokenType = 0;
1074 return z;
1075 }
1076 *tokenType = 1;
1077 return wiki_render_creole(p, z+10);
1078
1079 }
1080
1081 /* :folding=explicit:collapseFolds=1:tabSize=2:indentSize=2:noTabs=false: */
1082
--- src/creoleparser.c
+++ src/creoleparser.c
@@ -28,11 +28,11 @@
28 #include <assert.h>
29 #include "config.h"
30 #include "creoleparser.h"
31
32 #if INTERFACE
33 #define HAVE_CREOLE_MACRO 1
34 #endif
35
36 //{{{ LOCAL INTERFACE
37 #if LOCAL_INTERFACE
38
@@ -61,59 +61,59 @@
61
62 #define KIND_TABLE_ROW 0x0010000
63 //}}}
64 //{{{ FLAG
65 // keep first four bits free
66 #define FLAG_CENTER 0x0000100
67 //}}}
68 struct Node {//{{{
69
70 char *start;
71 char *end;
72
73 int kind;
74 int level;
75 int flags;
76
77 Node *parent;
78 Node *next;
79 Node *children;
80
81 };
82 //}}}
83 struct NodePool {//{{{
84 NodePool *next;
85 Node a[POOL_CHUNK_SIZE];
86 }
87 //}}}
88 struct Parser {//{{{
89
90 Blob *pOut; /* Output appended to this blob */
91 Renderer *r;
92
93 NodePool *pool;
94 int nFree;
95
96 Node *this;
97 Node *previous;
98 Node *list;
99
100 char *cursor;
101
102 int lineWasBlank;
103 int charCount;
104
105 Node *item;
106 Node *istack;
107 char *icursor;
108 char *iend;
109
110 int inLink;
111 int inTable;
112 int iesc;
113
114 Blob *iblob;
115
116
117
118
119 };
@@ -126,484 +126,485 @@
126 //}}}
127
128 //{{{ POOL MANAGEMENT
129 static Node *pool_new(Parser *p){
130
131 if ( p->pool == NULL || p->nFree == 0){
132
133 NodePool *temp = p->pool;
134
135 p->pool = malloc(sizeof(NodePool));
136 if( p->pool == NULL ) fossil_panic("out of memory");
137
138 p->pool->next = temp;
139 p->nFree = POOL_CHUNK_SIZE;
140 }
141 p->nFree -= 1;
142 Node *node = &(p->pool->a[p->nFree]);
143 memset(node, 0, sizeof(*node));
144
145 return node;
146 }
147
148
149 static void pool_free(Parser *p){
150
151 NodePool *temp;
152
153 while (p->pool != NULL){
154 temp = p->pool;
155 p->pool = temp->next;
156 free(temp);
157 }
158
159 }
160 //}}}
161
162 //{{{ Utility Methods
163
164 static char *cr_skipBlanks(Parser *p, char* z){//{{{
165 char *s = z;
166 while (z[0] == ' ' || z[0] == '\t') z++;
167 p->charCount = z - s;
168 return z;
169 }
170 //}}}
171 static int cr_countBlanks(Parser *p, char* z){//{{{
172 cr_skipBlanks(p, z);
173 return p->charCount;
174 }
175 //}}}
176 static char *cr_skipChars(Parser *p, char *z, char c){//{{{
177 char *s = z;
178 while (z[0] == c) z++;
179 p->charCount = z - s;
180 return z;
181 }
182 //}}}
183 static int cr_countChars(Parser *p, char *z, char c){//{{{
184 cr_skipChars(p, z, c);
185 return p->charCount;
186 }
187 //}}}
188 static char *cr_nextLine(Parser *p, char *z){//{{{
189
190 p->lineWasBlank = 1;
191
192 while (1){
193
194 switch (z[0]){
195
196 case '\r':
197 if (z[1] == '\n') {
198 z[0] = ' ';
199 return z + 2;
200 }
201 z[0] = '\n';
202 return z + 1;
203
204 case'\n':
205 return z + 1;
206
207 case '\t':
208 z[0] = ' ';
209 z++;
210 break;
211
212 case ' ':
213 z++;
214 break;
215
216 case '\0':
217 return z;
218
219 default:
220 p->lineWasBlank = 0;
221 z++;
222 }
223 }
224 }
225 //}}}
226 //}}}
227
228 //{{{ INLINE PARSER
229
230 static int cr_isEsc(Parser *p){//{{{
231 if (p->iesc){
232 blob_append(p->iblob, p->icursor, 1);
233 p->iesc = 0;
234 p->icursor += 1;
235 return 1;
236 }
237 return 0;
238 }
239 //}}}
240 static int cr_iOpen(Parser *p, int kind){//{{{
241
242 switch (kind){
243
244 case KIND_BOLD:
245 blob_append(p->iblob, "<strong>", 8);
246 return 1;
247
248 case KIND_ITALIC:
249 blob_append(p->iblob, "<em>", 4);
250 return 1;
251
252 case KIND_SUPERSCRIPT:
253 blob_append(p->iblob, "<sup>", 5);
254 return 1;
255
256 case KIND_SUBSCRIPT:
257 blob_append(p->iblob, "<sub>", 5);
258 return 1;
259
260 case KIND_MONOSPACED:
261 blob_append(p->iblob, "<tt>", 4);
262 return 1;
263 }
264 return 0;
265 }
266 //}}}
267 static int cr_iClose(Parser *p, int kind){//{{{
268
269 switch (kind){
270
271 case KIND_BOLD:
272 blob_append(p->iblob, "</strong>", 9);
273 return 1;
274
275 case KIND_ITALIC:
276 blob_append(p->iblob, "</em>", 5);
277 return 1;
278
279 case KIND_SUPERSCRIPT:
280 blob_append(p->iblob, "</sup>", 6);
281 return 1;
282
283 case KIND_SUBSCRIPT:
284 blob_append(p->iblob, "</sub>", 6);
285 return 1;
286
287 case KIND_MONOSPACED:
288 blob_append(p->iblob, "</tt>", 5);
289 return 1;
290 }
291 return 0;
292 }
293 //}}}
294
295
296 static void cr_iMarkup(Parser *p, int kind){//{{{
297
298 if (p->iesc) {
299 blob_append(p->iblob, p->icursor, 1);
300 p->icursor +=1;
301 p->iesc =0;
302 return;
303 }
304
305 if (p->icursor[1] != p->icursor[0]) {
306 blob_append(p->iblob, p->icursor, 1);
307 p->icursor +=1;
308 return;
309 }
310
311 p->icursor += 2;
312
313 if (kind & KIND_BREAK) {
314 blob_append(p->iblob, "<br />", 6);
315 return;
316 }
317
318 if (kind & KIND_ITALIC && p->icursor[-3] == ':'){
319 blob_append(p->iblob, "//", 2);
320 return;
321 }
322
323 Node *n = p->istack;
324
325 int found = 0;
326 while (n) {
327 if (n->kind & kind) {
328 found = 1;
329 break;
330 }
331 n = n->next;
332 }
333
334 if (!found) {
335 n = pool_new(p);
336 n->kind = kind;
337 n->next = p->istack;
338 p->istack = n;
339
340 assert(cr_iOpen(p, kind));
341 return;
342 };
343
344 n= p->istack;
345 while (n){
346 p->istack = n->next;
347
348 assert(cr_iClose(p, n->kind));
349
350 if (kind == n->kind) return;
351 n = p->istack;
352 }
353 }
354 //}}}
355 static int cr_iNoWiki(Parser *p){//{{{
356
357 if ((p->iend - p->icursor)<6) return 0;
358
359 if (p->icursor[1]!='{' || p->icursor[2]!='{')
360 return 0;
361
362 char *s = p->icursor + 3;
363
364 int count = p->iend - p->icursor - 6;
365 while (count--){
366 if (s[0]=='}' && s[1]=='}' && s[2]=='}' && s[3]!='}'){
367 blob_appendf(p->iblob, "<tt style='background:oldlace'>%s</tt>", htmlize(p->icursor + 3, s - p->icursor-3));
368 p->icursor = s + 3;
369 return 1;
370 }
371 s++;
372 }
373 return 0;
374 }
375
376 //}}}
377 static int cr_iImage(Parser *p){//{{{
378
379 if (p->inLink) return 0;
380 if ((p->iend - p->icursor)<3) return 0;
381
382 if (p->icursor[1]!='{') return 0;
383
384 char *s = p->icursor + 2;
385 char *bar = NULL;
386
387 int count = p->iend - p->icursor - 4;
388 while (count--){
389 if (s[0]=='}' && s[1]=='}'){
390 if (!bar) bar = p->icursor + 2;
391 blob_appendf(p->iblob, "<span style='color:green;border:1px solid green;'>%s</span>", htmlize(bar, s - bar ));
392 p->icursor = s + 2;
393 return 1;
394 }
395 if (!bar && s[0]=='|') bar=s+1;
396 s++;
397 }
398 return 0;
399 }
400 //}}}
401 static int cr_iMacro(Parser *p){//{{{
402
403 if (p->inLink) return 0;
404 if ((p->iend - p->icursor)<3) return 0;
405
406 if (p->icursor[1]!='<') return 0;
407
408 char *s = p->icursor + 2;
409
410 int count = p->iend - p->icursor - 3;
411 while (count--){
412 blob_appendf(p->iblob, "|~%s|", s,2 );
413 if (s[0]=='>' && s[1]=='>'){
414 blob_appendf(p->iblob, "<span style='color:red;border:1px solid red;'>%s</span>", htmlize(p->icursor, s - p->icursor + 2));
415 p->icursor = s + 2;
416 return 1;
417 }
418 s++;
419 }
420 return 0;
421
422 }
423 //}}}
424
425 static void cr_renderLink(Parser *p, char *s, char *bar, char *e){//{{{
426
427 int tsize = bar-s;
428 int dsize = e - bar-1;
429
430 if (tsize < 1) return;
431 if (dsize < 1) dsize = 0;
432
433 char zTarget[tsize + 1];
434 memcpy(zTarget, s, tsize);
435 zTarget[tsize] = '\0';
436
437 char zClose[20];
438
439 Blob *pOut = p->r->pOut;
440
441 p->r->pOut = p->iblob;
442 wf_openHyperlink(p->r, zTarget, zClose, sizeof(zClose));
443 p->r->pOut = pOut;
444
445 if (dsize)
446 cr_parseInline(p, bar+1, e) ;
447 else
448 blob_append(p->iblob, htmlize(s, tsize), -1);
449 blob_append(p->iblob, zClose, -1);
450 }
451 //}}}
452
453 static int cr_iLink(Parser *p){//{{{
454
455 if (p->inLink) return 0;
456 if ((p->iend - p->icursor)<3) return 0;
457
458 if (p->icursor[1]!='[') return 0;
459
460 char *s = p->icursor + 2;
461 char *bar = NULL;
462
463 int count = p->iend - p->icursor -3;
464 while (count--){
465 if (s[0]==']' && s[1]==']'){
466 if (!bar) bar = s;
467 p->inLink = 1;
468 cr_renderLink(p, p->icursor+2, bar, s);
469 p->inLink = 0;
470 p->icursor = s + 2;
471 return 1;
472 }
473 if (!bar && s[0]=='|') bar=s;
474 s++;
475 }
476 return 0;
477 }
478 //}}}
479
480 LOCAL char *cr_parseInline(Parser *p, char *s, char *e){//{{{
481
482 int save_iesc = p->iesc;
483 char *save_iend = p->iend;
484 Node *save_istack = p->istack;
485
486 p->iesc = 0;
487 p->iend = e;
488 p->istack = NULL;
489
490 p->icursor = s;
491
492 char *eof = NULL;
493 while (!eof && p->icursor < p->iend ){
494
495 switch (*p->icursor) {//{{{
496
497 case '~':
498 if (p->iesc) {
499 blob_append(p->iblob, "~", 1);
500 p->iesc = 0;
501 }
502 p->iesc = !p->iesc;
503 p->icursor+=1;
504 break;
505
506 case '*':
507 cr_iMarkup(p, KIND_BOLD);
508 break;
509
510 case '/':
511 cr_iMarkup(p, KIND_ITALIC);
512 break;
513
514 case '^':
515 cr_iMarkup(p, KIND_SUPERSCRIPT);
516 break;
517
518 case ',':
519 cr_iMarkup(p, KIND_SUBSCRIPT);
520 break;
521
522 case '#':
523 cr_iMarkup(p, KIND_MONOSPACED);
524 break;
525
526 case '\\':
527 cr_iMarkup(p, KIND_BREAK);
528 break;
529
530 case '{':
531 if (cr_isEsc(p)) break;
532 if (cr_iNoWiki(p)) break;
533 if (cr_iImage(p)) break;
534 blob_append(p->iblob, p->icursor, 1);
535 p->icursor += 1;
536 break;
537
538 case '[':
539 if (cr_isEsc(p)) break;
540 if (cr_iLink(p)) break;
541 blob_append(p->iblob, p->icursor, 1);
542 p->icursor += 1;
543 break;
544
545
546 case '<':
547 if (cr_isEsc(p)) break;
548 if (cr_iMacro(p)) break;
549
550 blob_append(p->iblob, "&lt;", 4);
551 p->icursor += 1;
552 break;
553
554 case '>':
555 if (p->iesc) {
556 blob_append(p->iblob, "~", 1);
557 p->iesc = 0;
558 }
559 blob_append(p->iblob, "&gt;", 4);
560 p->icursor += 1;
561 break;
562
563 case '&':
564 if (p->iesc) {
565 blob_append(p->iblob, "~", 1);
566 p->iesc = 0;
567 }
568 blob_append(p->iblob, "&amp;", 5);
569 p->icursor += 1;
570 break;
571
572 case '|':
573 if (p->inTable){
574 if (p->iesc) {
575 blob_append(p->iblob, p->icursor, 1);
576 p->iesc = 0;
577 p->icursor += 1;
578 break;
579 }
580 eof = p->icursor + 1;
581 break;
582 }
583 // fall through to default
584
585 default:
586 if (p->iesc) {
587 blob_append(p->iblob, "~", 1);
588 p->iesc = 0;
589 }
590 blob_append(p->iblob, p->icursor, 1);
591 p->icursor +=1;
592 }//}}}
593
594 }
595
596 while (p->istack){
597 cr_iClose(p, p->istack->kind);
598 p->istack = p->istack->next;
599 }
600
601 p->iesc = save_iesc;
602 p->iend = save_iend;
603 p->istack = save_istack;
604
605 return eof;
606
607 }
608 //}}}
609 //}}}
610
@@ -610,472 +611,455 @@
611 //{{{ BLOCK PARSER
612
613 static void cr_renderListItem(Parser *p, Node *n){//{{{
614
615
616 blob_append(p->iblob, "<li>", 4);
617 cr_parseInline(p, n->start, n->end);
618
619 if (n->children){
620
621 int ord = (n->children->kind & KIND_ORDERED_LIST);
622
623 if (ord) blob_append(p->iblob, "<ol>", 4);
624 else blob_append(p->iblob, "<ul>", 4);
625
626 n = n->children;
627 while (n){
628 cr_renderListItem(p, n);
629 n = n->next;
630 }
631
632 if (ord) blob_append(p->iblob, "</ol>", 5);
633 else blob_append(p->iblob, "</ul>", 5);
634 }
635 blob_append(p->iblob, "</li>", 5);
636 }
637 //}}}
638 static void cr_renderList(Parser *p){//{{{
639
640 Node *n = p->list;
641
642 while (n->parent !=n) n = n->parent;
643
644 int ord = (n->kind & KIND_ORDERED_LIST);
645
646 if (ord) blob_append(p->iblob, "\n\n<ol>", -1);
647 else blob_append(p->iblob, "\n\n<ul>", -1);
648
649 while (n) {
650 cr_renderListItem(p, n);
651 n = n->next;
652 }
653
654 if (ord) blob_append(p->iblob, "</ol>", 5);
655 else blob_append(p->iblob, "</ul>", 5);
656 }
657
658 //}}}
659
660 static void cr_renderTableRow(Parser *p, Node *row){//{{{
661
662 char *s = row->start;
663 int th;
664
665 blob_append(p->iblob, "\n<tr>", -1);
666
667 while (s && s < row->end){
668
669 if ((th = *s == '=')) {
670 s++;
671 blob_append(p->iblob, "<th>", -1);
672 }
673 else {
674 blob_append(p->iblob, "<td>", -1);
675 }
676
677 s = cr_parseInline(p, s, row->end);
678
679 if (th)
680 blob_append(p->iblob, "</th>\n", -1);
681 else
682 blob_append(p->iblob, "</td>\n", -1);
683
684 if (!s) break;
685 }
686 blob_append(p->iblob, "</tr>", 5);
687 }
688 //}}}
689 static void cr_renderTable(Parser *p, Node *n){//{{{
690
691 Node *row = n->children;
692
693 blob_append(p->iblob, "<table class='creoletable'>", -1);
694 p->inTable = 1;
695 while (row){
696
697 cr_renderTableRow(p, row);
698 row = row->next;
699
700 }
701 blob_append(p->iblob, "</table>", -1);
702 p->inTable = 0;
703
704 }
705 //}}}
706
707 static void cr_render(Parser *p, Node *node){//{{{
708
709 if (node->kind & KIND_PARAGRAPH){
710 blob_append(p->iblob, "\n<p>", -1);
711 cr_parseInline(p, node->start, node->end );
712 blob_append(p->iblob, "</p>\n", -1 );
713 }
714
715 if (node->kind & KIND_HEADING){
716 blob_appendf(p->iblob,
717 "\n<h%d %s>",
718 node->level,
719 (node->flags & FLAG_CENTER) ? " style='text-align:center;'" : ""
720 );
721 cr_parseInline(p, node->start, node->end);
722 blob_appendf(p->iblob, "</h%d>\n", node->level );
723 return;
724 }
725
726 if (node->kind & KIND_HORIZONTAL_RULE){
727 blob_append(p->iblob, "<hr />", -1);
728 return;
729 }
730
731 if (node->kind & KIND_LIST){
732 cr_renderList(p);
733 p->list = NULL;
734 return;
735 }
736
737 if (node->kind & KIND_TABLE){
738 cr_renderTable(p, node);
739 return;
740 }
741
742 if (node->kind & KIND_NO_WIKI_BLOCK){
743 blob_appendf(p->iblob,
744 "\n<blockquote style='background:oldlace'><pre>%s</pre></blockquote>\n",
745 htmlize( node->start, node->end - node->start)
746 );
747 }
748 }
749 //}}}
750
751 static char *cr_findEndOfBlock(Parser *p, char *s, char c){//{{{
752
753 char *end;
754 while (s[0]){
755
756 end = s;
757 if (s[0] == c && s[0] == c && s[0] == c) {
758 s = cr_nextLine(p, s + 3);
759 if (p->lineWasBlank) {
760 p->cursor = s;
761 return end;
762 }
763 }
764 else {
765 s = cr_nextLine(p, s);
766 }
767 }
768 return 0;
769 }
770 //}}}
771 static int cr_addListItem(Parser *p, Node *n){//{{{
772
773 n->parent = n;
774 n->next = n->children = NULL;
775
776 if (!p->list) {
777 if (n->level != 1) return 0;
778 p->list = n;
779 return 1;
780 }
781
782 Node *list = p->list;
783
784 while (n->level < list->level){
785 list = list->parent;
786 }
787
788 if (n->level == list->level){
789
790 if (n->kind != list->kind){
791 if (n->level>1) return 0;
792 cr_renderList(p);
793 p->list = n;
794 return 1;
795 }
796 n->parent = list->parent;
797 p->list = list->next = n;
798 return 1;
799 }
800
801 if ( (n->level - list->level) > 1 ) return 0;
802 n->parent = p->list;
803 p->list->children = n;
804 p->list = n;
805 return 1;
806
807 }
808 //}}}
809
810 static int isEndWikiMarker(Parser *p){//{{{
811
812 char *s = p->cursor;
813 if (memcmp(s, "<<fossil>>", 10)) return 0;
814 p->this->start = s;
815 p->this->kind = KIND_END_WIKI_MARKER;
816 p->cursor += 10;
817 return 1;
818 }
819 ///}}}
820 static int isNoWikiBlock(Parser *p){//{{{
821
822 char *s = p->cursor;
823
824 if (s[0] != '{') return 0; s++;
825 if (s[0] != '{') return 0; s++;
826 if (s[0] != '{') return 0; s++;
827
828 s = cr_nextLine(p, s);
829 if (!p->lineWasBlank) return 0;
830
831 p->this->start = s;
832
833 s = cr_findEndOfBlock(p, s, '}');
834
835 if (!s) return 0;
836
837 // p->cursor was set by findEndOfBlock
838 p->this->kind = KIND_NO_WIKI_BLOCK;
839 p->this->end = s;
840 return 1;
841 }
842
843 //}}}
844 static int isParaBreak(Parser *p){//{{{
845
846 char *s = cr_nextLine(p, p->cursor);
847 if (!p->lineWasBlank) return 0;
848
849 p->cursor = s;
850 p->this->kind = KIND_PARA_BREAK;
851 return 1;
852 }
853 //}}}
854 static int isHeading(Parser *p){//{{{
855
856 char *s = cr_skipBlanks(p, p->cursor);
857
858 int flags = 0;
859 int level = cr_countChars(p, s, '=');
860 if (!level) return 0;
861
862 s += level;
863
864 if (s[0] == '<' && s[1] == '>') {
865 flags |= FLAG_CENTER;
866 s += 2;
867 }
868 s = cr_skipBlanks(p, s);
869
870 p->this->start = s;
871
872 s = cr_nextLine(p, s);
873 char *z = s;
874
875 if (s[-1] == '\n') s--;
876 while(s[-1] == ' ' || s[-1]=='\t') s--;
877 while(s[-1] == '=' ) s--;
878 if (p->this->start < s){
879 p->cursor = z;
880 p->this->kind = KIND_HEADING;
881 p->this->end = s;
882 p->this->level = level;
883 p->this->flags |= flags;
884 return 1;
885 }
886 return 0;
887 }
888 //}}}
889 static int isHorizontalRule(Parser *p){//{{{
890
891 char *s = cr_skipBlanks(p, p->cursor);
892
893 int level = cr_countChars(p, s, '-');
894
895 if (level < 4) return 0;
896 s = cr_nextLine(p, s + level);
897 if (!p->lineWasBlank) return 0;
898
899 p->cursor = s;
900 p->this->kind = KIND_HORIZONTAL_RULE;
901
902 return 1;
903 }
904 //}}}
905 static int isListItem(Parser *p){//{{{
906
907 char *s = cr_skipBlanks(p, p->cursor);
908
909 int level = cr_countChars(p, s, '#');
910 if (!level) level = cr_countChars(p, s, '*');
911
912 if ( !level) return 0;
913
914 p->this->kind = (s[0] == '#') ? KIND_ORDERED_LIST : KIND_UNORDERED_LIST;
915 p->this->level = level;
916
917 s = cr_skipBlanks(p, s + level);
918 p->this->start = s;
919
920 s = cr_nextLine(p, s);
921 if (p->lineWasBlank) return 0;
922
923 if (cr_addListItem(p, p->this)){
924 p->cursor = p->this->end = s;
925 return 1;
926 }
927 p->this->kind = 0;
928 return 0;
929 }
930 //}}}
931 static int isTable(Parser *p){//{{{
932
933 p->this->start = p->cursor;
934 char *s = cr_skipBlanks(p, p->cursor);
935 if (s[0] != '|') return 0;
936 s +=1;
937 p->this->kind = KIND_TABLE;
938
939
940 //p->cursor = p->this->end = cr_nextLine(p, s);
941 Node *row;
942 Node *tail = NULL;
943
944 while (1) {
945
946 row = pool_new(p);
947 row->kind = KIND_TABLE_ROW;
948
949 if (tail) tail = tail->next = row;
950 else p->this->children = tail = row;
951
952 row->start = s;
953 p->cursor = s = row->end = p->this->end = cr_nextLine(p, s);
954
955 if (row->end[-1] == '\n') row->end -= 1;
956 while(row->end[-1] == ' ' ) row->end -= 1;
957 if (row->end[-1] == '|') row->end -= 1;
958
959 if (!*s) break;
960
961 // blanks *not* normalized
962 s = cr_skipBlanks(p, p->cursor);
963 if (s[0] != '|') break;
964 s++;
965
966 }
967 return 1;
968
969 };
970 //}}}
971 static int isParagraph(Parser *p){//{{{
972
973 char *s = p->cursor;
974 p->this->start = s;
975
976 s = cr_nextLine(p, s);
977 p->cursor = p->this->end = s;
978 p->this->kind = KIND_PARAGRAPH;
979 return 1;
980
981 }
982 //}}}
983 static void cr_parse(Parser *p, char* z){//{{{
984
985 p->previous = pool_new(p);
986 p->previous->kind = KIND_PARA_BREAK;
987
988 p->this = pool_new(p);
989 p->this->kind = KIND_PARA_BREAK;
990
991 p->inLink = 0;
992 p->inTable = 0;
993
994 p->cursor = z;
995 p->list = NULL;
996 p->istack = NULL;
997
998 while (p->cursor[0]) {
999
1000 while (1){
1001
1002 // must be first
1003 if (isNoWikiBlock(p)) break;
1004 if (isParaBreak(p)) break;
1005
1006 // order not important
1007 if (isHeading(p)) break;
1008 if (isHorizontalRule(p)) break;
1009 if (isListItem(p)) break;
1010 if (isTable(p)) break;
1011
1012 // here for efficiency?
1013 if (isEndWikiMarker(p)) break;
1014
1015 // must be last
1016 if (isParagraph(p)); break;
1017
1018 // doh!
1019 assert(0);
1020 }
1021
1022 int kind = p->this->kind;
1023 int prev = p->previous->kind;
1024
1025 if (kind & KIND_END_WIKI_MARKER) return;
1026
1027 if (kind == KIND_PARAGRAPH && prev & KIND_LIST_OR_PARAGRAPH) {
1028 p->previous->end = p->this->end;
1029 p->this = pool_new(p);
1030 continue;
1031 }
1032
1033 if ( !(kind & KIND_LIST && prev & KIND_LIST) )
1034 cr_render(p, p->previous);
1035
1036 p->previous = p->this;
1037 p->this = pool_new(p);
1038
1039 }
1040 }
1041 //}}}
1042
1043 //}}}
1044
1045 char *wiki_render_creole(Renderer *r, char *z){
1046
1047 Parser parser;
1048 Parser *p = &parser;
1049
1050 p->r = r;
1051 p->iblob = r->pOut;
1052
1053 p->nFree = 0;
1054 p->pool = NULL;
1055
1056 cr_parse(p, z);
1057
1058 cr_render(p, p->previous);
1059
1060 pool_free(p);
1061
1062 return p->cursor;
1063
1064 }
1065
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1066
+94 -1
--- src/doc.c
+++ src/doc.c
@@ -316,10 +316,11 @@
316316
}
317317
318318
/*
319319
** WEBPAGE: doc
320320
** URL: /doc?name=BASELINE/PATH
321
+** URL: /doc/BASELINE/PATH
321322
**
322323
** BASELINE can be either a baseline uuid prefix or magic words "tip"
323324
** to me the most recently checked in baseline or "ckout" to mean the
324325
** content of the local checkout, if any. PATH is the relative pathname
325326
** of some file. This method returns the file content.
@@ -438,11 +439,14 @@
438439
}
439440
440441
/* The file is now contained in the filebody blob. Deliver the
441442
** file to the user
442443
*/
443
- zMime = mimetype_from_name(zName);
444
+ zMime = P("mimetype");
445
+ if( zMime==0 ){
446
+ zMime = mimetype_from_name(zName);
447
+ }
444448
if( strcmp(zMime, "application/x-fossil-wiki")==0 ){
445449
Blob title, tail;
446450
if( wiki_find_title(&filebody, &title, &tail) ){
447451
style_header(blob_str(&title));
448452
wiki_convert(&tail, 0, 0);
@@ -469,5 +473,94 @@
469473
style_header("Document Not Found");
470474
@ <p>No such document: %h(PD("name","tip/index.wiki"))</p>
471475
style_footer();
472476
return;
473477
}
478
+
479
+/*
480
+** The default logo.
481
+*/
482
+static const unsigned char aLogo[] = {
483
+ 71, 73, 70, 56, 55, 97, 62, 0, 71, 0, 244, 0, 0, 85,
484
+ 129, 149, 95, 136, 155, 99, 139, 157, 106, 144, 162, 113, 150, 166,
485
+ 116, 152, 168, 127, 160, 175, 138, 168, 182, 148, 176, 188, 159, 184,
486
+ 195, 170, 192, 202, 180, 199, 208, 184, 202, 210, 191, 207, 215, 201,
487
+ 215, 221, 212, 223, 228, 223, 231, 235, 226, 227, 226, 226, 234, 237,
488
+ 233, 239, 241, 240, 244, 246, 244, 247, 248, 255, 255, 255, 0, 0,
489
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
490
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0,
491
+ 0, 0, 62, 0, 71, 0, 0, 5, 255, 96, 100, 141, 100, 105,
492
+ 158, 168, 37, 41, 132, 192, 164, 112, 44, 207, 102, 99, 0, 56,
493
+ 16, 84, 116, 239, 199, 141, 65, 110, 232, 248, 25, 141, 193, 161,
494
+ 82, 113, 108, 202, 32, 55, 229, 210, 73, 61, 41, 164, 88, 102,
495
+ 181, 10, 41, 96, 179, 91, 106, 35, 240, 5, 135, 143, 137, 242,
496
+ 87, 123, 246, 33, 190, 81, 108, 163, 237, 198, 14, 30, 113, 233,
497
+ 131, 78, 115, 72, 11, 115, 87, 101, 19, 124, 51, 66, 74, 8,
498
+ 19, 16, 67, 100, 74, 133, 50, 15, 101, 135, 56, 11, 74, 6,
499
+ 143, 49, 126, 106, 56, 8, 145, 67, 9, 152, 48, 139, 155, 5,
500
+ 22, 13, 74, 115, 161, 41, 147, 101, 13, 130, 57, 132, 170, 40,
501
+ 167, 155, 0, 94, 57, 3, 178, 48, 183, 181, 57, 160, 186, 40,
502
+ 19, 141, 189, 0, 69, 192, 40, 16, 195, 155, 185, 199, 41, 201,
503
+ 189, 191, 205, 193, 188, 131, 210, 49, 175, 88, 209, 214, 38, 19,
504
+ 3, 11, 19, 111, 127, 60, 219, 39, 55, 204, 19, 11, 6, 100,
505
+ 5, 10, 227, 228, 37, 163, 0, 239, 117, 56, 238, 243, 49, 195,
506
+ 177, 247, 48, 158, 56, 251, 50, 216, 254, 197, 56, 128, 107, 158,
507
+ 2, 125, 171, 114, 92, 218, 246, 96, 66, 3, 4, 50, 134, 176,
508
+ 145, 6, 97, 64, 144, 24, 19, 136, 108, 91, 177, 160, 0, 194,
509
+ 19, 253, 0, 216, 107, 214, 224, 192, 129, 5, 16, 83, 255, 244,
510
+ 43, 213, 195, 24, 159, 27, 169, 64, 230, 88, 208, 227, 129, 182,
511
+ 54, 4, 89, 158, 24, 181, 163, 199, 1, 155, 52, 233, 8, 130,
512
+ 176, 83, 24, 128, 137, 50, 18, 32, 48, 48, 114, 11, 173, 137,
513
+ 19, 110, 4, 64, 105, 1, 194, 30, 140, 68, 15, 24, 24, 224,
514
+ 50, 76, 70, 0, 11, 171, 54, 26, 160, 181, 194, 149, 148, 40,
515
+ 174, 148, 122, 64, 180, 208, 161, 17, 207, 112, 164, 1, 128, 96,
516
+ 148, 78, 18, 21, 194, 33, 229, 51, 247, 65, 133, 97, 5, 250,
517
+ 69, 229, 100, 34, 220, 128, 166, 116, 190, 62, 8, 167, 195, 170,
518
+ 47, 163, 0, 130, 90, 152, 11, 160, 173, 170, 27, 154, 26, 91,
519
+ 232, 151, 171, 18, 14, 162, 253, 98, 170, 18, 70, 171, 64, 219,
520
+ 10, 67, 136, 134, 187, 116, 75, 180, 46, 179, 174, 135, 4, 189,
521
+ 229, 231, 78, 40, 10, 62, 226, 164, 172, 64, 240, 167, 170, 10,
522
+ 18, 124, 188, 10, 107, 65, 193, 94, 11, 93, 171, 28, 248, 17,
523
+ 239, 46, 140, 78, 97, 34, 25, 153, 36, 99, 65, 130, 7, 203,
524
+ 183, 168, 51, 34, 136, 25, 140, 10, 6, 16, 28, 255, 145, 241,
525
+ 230, 140, 10, 66, 178, 167, 112, 48, 192, 128, 129, 9, 31, 141,
526
+ 84, 138, 63, 163, 162, 2, 203, 206, 240, 56, 55, 98, 192, 188,
527
+ 15, 185, 50, 160, 6, 0, 125, 62, 33, 214, 195, 33, 5, 24,
528
+ 184, 25, 231, 14, 201, 245, 144, 23, 126, 104, 228, 0, 145, 2,
529
+ 13, 140, 244, 212, 17, 21, 20, 176, 159, 17, 95, 225, 160, 128,
530
+ 16, 1, 32, 224, 142, 32, 227, 125, 87, 64, 0, 16, 54, 129,
531
+ 205, 2, 141, 76, 53, 130, 103, 37, 166, 64, 144, 107, 78, 196,
532
+ 5, 192, 0, 54, 50, 229, 9, 141, 49, 84, 194, 35, 12, 196,
533
+ 153, 48, 192, 137, 57, 84, 24, 7, 87, 159, 249, 240, 215, 143,
534
+ 105, 241, 118, 149, 9, 139, 4, 64, 203, 141, 35, 140, 129, 131,
535
+ 16, 222, 125, 231, 128, 2, 238, 17, 152, 66, 3, 5, 56, 224,
536
+ 159, 103, 16, 76, 25, 75, 5, 11, 164, 215, 96, 9, 14, 16,
537
+ 36, 225, 15, 11, 40, 144, 192, 156, 41, 10, 178, 199, 3, 66,
538
+ 64, 80, 193, 3, 124, 90, 48, 129, 129, 102, 177, 18, 192, 154,
539
+ 49, 84, 240, 208, 92, 22, 149, 96, 39, 9, 31, 74, 17, 94,
540
+ 3, 8, 177, 199, 72, 59, 85, 76, 25, 216, 8, 139, 194, 197,
541
+ 138, 163, 69, 96, 115, 0, 147, 72, 72, 84, 28, 14, 79, 86,
542
+ 233, 230, 23, 113, 26, 160, 128, 3, 10, 58, 129, 103, 14, 159,
543
+ 214, 163, 146, 117, 238, 213, 154, 128, 151, 109, 84, 64, 217, 13,
544
+ 27, 10, 228, 39, 2, 235, 164, 168, 74, 8, 0, 59,
545
+};
546
+
547
+/*
548
+** WEBPAGE: logo
549
+**
550
+** Return the logo image. This image is available to anybody who can see
551
+** the login page. It is designed for use in the upper left-hand corner
552
+** of the header.
553
+*/
554
+void logo_page(void){
555
+ Blob logo;
556
+ char *zMime;
557
+
558
+ zMime = db_get("logo-mimetype", "image/gif");
559
+ blob_zero(&logo);
560
+ db_blob(&logo, "SELECT value FROM config WHERE name='logo-image'");
561
+ if( blob_size(&logo)==0 ){
562
+ blob_init(&logo, (char*)aLogo, sizeof(aLogo));
563
+ }
564
+ cgi_set_content_type(zMime);
565
+ cgi_set_content(&logo);
566
+}
474567
--- src/doc.c
+++ src/doc.c
@@ -316,10 +316,11 @@
316 }
317
318 /*
319 ** WEBPAGE: doc
320 ** URL: /doc?name=BASELINE/PATH
 
321 **
322 ** BASELINE can be either a baseline uuid prefix or magic words "tip"
323 ** to me the most recently checked in baseline or "ckout" to mean the
324 ** content of the local checkout, if any. PATH is the relative pathname
325 ** of some file. This method returns the file content.
@@ -438,11 +439,14 @@
438 }
439
440 /* The file is now contained in the filebody blob. Deliver the
441 ** file to the user
442 */
443 zMime = mimetype_from_name(zName);
 
 
 
444 if( strcmp(zMime, "application/x-fossil-wiki")==0 ){
445 Blob title, tail;
446 if( wiki_find_title(&filebody, &title, &tail) ){
447 style_header(blob_str(&title));
448 wiki_convert(&tail, 0, 0);
@@ -469,5 +473,94 @@
469 style_header("Document Not Found");
470 @ <p>No such document: %h(PD("name","tip/index.wiki"))</p>
471 style_footer();
472 return;
473 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
474
--- src/doc.c
+++ src/doc.c
@@ -316,10 +316,11 @@
316 }
317
318 /*
319 ** WEBPAGE: doc
320 ** URL: /doc?name=BASELINE/PATH
321 ** URL: /doc/BASELINE/PATH
322 **
323 ** BASELINE can be either a baseline uuid prefix or magic words "tip"
324 ** to me the most recently checked in baseline or "ckout" to mean the
325 ** content of the local checkout, if any. PATH is the relative pathname
326 ** of some file. This method returns the file content.
@@ -438,11 +439,14 @@
439 }
440
441 /* The file is now contained in the filebody blob. Deliver the
442 ** file to the user
443 */
444 zMime = P("mimetype");
445 if( zMime==0 ){
446 zMime = mimetype_from_name(zName);
447 }
448 if( strcmp(zMime, "application/x-fossil-wiki")==0 ){
449 Blob title, tail;
450 if( wiki_find_title(&filebody, &title, &tail) ){
451 style_header(blob_str(&title));
452 wiki_convert(&tail, 0, 0);
@@ -469,5 +473,94 @@
473 style_header("Document Not Found");
474 @ <p>No such document: %h(PD("name","tip/index.wiki"))</p>
475 style_footer();
476 return;
477 }
478
479 /*
480 ** The default logo.
481 */
482 static const unsigned char aLogo[] = {
483 71, 73, 70, 56, 55, 97, 62, 0, 71, 0, 244, 0, 0, 85,
484 129, 149, 95, 136, 155, 99, 139, 157, 106, 144, 162, 113, 150, 166,
485 116, 152, 168, 127, 160, 175, 138, 168, 182, 148, 176, 188, 159, 184,
486 195, 170, 192, 202, 180, 199, 208, 184, 202, 210, 191, 207, 215, 201,
487 215, 221, 212, 223, 228, 223, 231, 235, 226, 227, 226, 226, 234, 237,
488 233, 239, 241, 240, 244, 246, 244, 247, 248, 255, 255, 255, 0, 0,
489 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
490 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0,
491 0, 0, 62, 0, 71, 0, 0, 5, 255, 96, 100, 141, 100, 105,
492 158, 168, 37, 41, 132, 192, 164, 112, 44, 207, 102, 99, 0, 56,
493 16, 84, 116, 239, 199, 141, 65, 110, 232, 248, 25, 141, 193, 161,
494 82, 113, 108, 202, 32, 55, 229, 210, 73, 61, 41, 164, 88, 102,
495 181, 10, 41, 96, 179, 91, 106, 35, 240, 5, 135, 143, 137, 242,
496 87, 123, 246, 33, 190, 81, 108, 163, 237, 198, 14, 30, 113, 233,
497 131, 78, 115, 72, 11, 115, 87, 101, 19, 124, 51, 66, 74, 8,
498 19, 16, 67, 100, 74, 133, 50, 15, 101, 135, 56, 11, 74, 6,
499 143, 49, 126, 106, 56, 8, 145, 67, 9, 152, 48, 139, 155, 5,
500 22, 13, 74, 115, 161, 41, 147, 101, 13, 130, 57, 132, 170, 40,
501 167, 155, 0, 94, 57, 3, 178, 48, 183, 181, 57, 160, 186, 40,
502 19, 141, 189, 0, 69, 192, 40, 16, 195, 155, 185, 199, 41, 201,
503 189, 191, 205, 193, 188, 131, 210, 49, 175, 88, 209, 214, 38, 19,
504 3, 11, 19, 111, 127, 60, 219, 39, 55, 204, 19, 11, 6, 100,
505 5, 10, 227, 228, 37, 163, 0, 239, 117, 56, 238, 243, 49, 195,
506 177, 247, 48, 158, 56, 251, 50, 216, 254, 197, 56, 128, 107, 158,
507 2, 125, 171, 114, 92, 218, 246, 96, 66, 3, 4, 50, 134, 176,
508 145, 6, 97, 64, 144, 24, 19, 136, 108, 91, 177, 160, 0, 194,
509 19, 253, 0, 216, 107, 214, 224, 192, 129, 5, 16, 83, 255, 244,
510 43, 213, 195, 24, 159, 27, 169, 64, 230, 88, 208, 227, 129, 182,
511 54, 4, 89, 158, 24, 181, 163, 199, 1, 155, 52, 233, 8, 130,
512 176, 83, 24, 128, 137, 50, 18, 32, 48, 48, 114, 11, 173, 137,
513 19, 110, 4, 64, 105, 1, 194, 30, 140, 68, 15, 24, 24, 224,
514 50, 76, 70, 0, 11, 171, 54, 26, 160, 181, 194, 149, 148, 40,
515 174, 148, 122, 64, 180, 208, 161, 17, 207, 112, 164, 1, 128, 96,
516 148, 78, 18, 21, 194, 33, 229, 51, 247, 65, 133, 97, 5, 250,
517 69, 229, 100, 34, 220, 128, 166, 116, 190, 62, 8, 167, 195, 170,
518 47, 163, 0, 130, 90, 152, 11, 160, 173, 170, 27, 154, 26, 91,
519 232, 151, 171, 18, 14, 162, 253, 98, 170, 18, 70, 171, 64, 219,
520 10, 67, 136, 134, 187, 116, 75, 180, 46, 179, 174, 135, 4, 189,
521 229, 231, 78, 40, 10, 62, 226, 164, 172, 64, 240, 167, 170, 10,
522 18, 124, 188, 10, 107, 65, 193, 94, 11, 93, 171, 28, 248, 17,
523 239, 46, 140, 78, 97, 34, 25, 153, 36, 99, 65, 130, 7, 203,
524 183, 168, 51, 34, 136, 25, 140, 10, 6, 16, 28, 255, 145, 241,
525 230, 140, 10, 66, 178, 167, 112, 48, 192, 128, 129, 9, 31, 141,
526 84, 138, 63, 163, 162, 2, 203, 206, 240, 56, 55, 98, 192, 188,
527 15, 185, 50, 160, 6, 0, 125, 62, 33, 214, 195, 33, 5, 24,
528 184, 25, 231, 14, 201, 245, 144, 23, 126, 104, 228, 0, 145, 2,
529 13, 140, 244, 212, 17, 21, 20, 176, 159, 17, 95, 225, 160, 128,
530 16, 1, 32, 224, 142, 32, 227, 125, 87, 64, 0, 16, 54, 129,
531 205, 2, 141, 76, 53, 130, 103, 37, 166, 64, 144, 107, 78, 196,
532 5, 192, 0, 54, 50, 229, 9, 141, 49, 84, 194, 35, 12, 196,
533 153, 48, 192, 137, 57, 84, 24, 7, 87, 159, 249, 240, 215, 143,
534 105, 241, 118, 149, 9, 139, 4, 64, 203, 141, 35, 140, 129, 131,
535 16, 222, 125, 231, 128, 2, 238, 17, 152, 66, 3, 5, 56, 224,
536 159, 103, 16, 76, 25, 75, 5, 11, 164, 215, 96, 9, 14, 16,
537 36, 225, 15, 11, 40, 144, 192, 156, 41, 10, 178, 199, 3, 66,
538 64, 80, 193, 3, 124, 90, 48, 129, 129, 102, 177, 18, 192, 154,
539 49, 84, 240, 208, 92, 22, 149, 96, 39, 9, 31, 74, 17, 94,
540 3, 8, 177, 199, 72, 59, 85, 76, 25, 216, 8, 139, 194, 197,
541 138, 163, 69, 96, 115, 0, 147, 72, 72, 84, 28, 14, 79, 86,
542 233, 230, 23, 113, 26, 160, 128, 3, 10, 58, 129, 103, 14, 159,
543 214, 163, 146, 117, 238, 213, 154, 128, 151, 109, 84, 64, 217, 13,
544 27, 10, 228, 39, 2, 235, 164, 168, 74, 8, 0, 59,
545 };
546
547 /*
548 ** WEBPAGE: logo
549 **
550 ** Return the logo image. This image is available to anybody who can see
551 ** the login page. It is designed for use in the upper left-hand corner
552 ** of the header.
553 */
554 void logo_page(void){
555 Blob logo;
556 char *zMime;
557
558 zMime = db_get("logo-mimetype", "image/gif");
559 blob_zero(&logo);
560 db_blob(&logo, "SELECT value FROM config WHERE name='logo-image'");
561 if( blob_size(&logo)==0 ){
562 blob_init(&logo, (char*)aLogo, sizeof(aLogo));
563 }
564 cgi_set_content_type(zMime);
565 cgi_set_content(&logo);
566 }
567
+94 -1
--- src/doc.c
+++ src/doc.c
@@ -316,10 +316,11 @@
316316
}
317317
318318
/*
319319
** WEBPAGE: doc
320320
** URL: /doc?name=BASELINE/PATH
321
+** URL: /doc/BASELINE/PATH
321322
**
322323
** BASELINE can be either a baseline uuid prefix or magic words "tip"
323324
** to me the most recently checked in baseline or "ckout" to mean the
324325
** content of the local checkout, if any. PATH is the relative pathname
325326
** of some file. This method returns the file content.
@@ -438,11 +439,14 @@
438439
}
439440
440441
/* The file is now contained in the filebody blob. Deliver the
441442
** file to the user
442443
*/
443
- zMime = mimetype_from_name(zName);
444
+ zMime = P("mimetype");
445
+ if( zMime==0 ){
446
+ zMime = mimetype_from_name(zName);
447
+ }
444448
if( strcmp(zMime, "application/x-fossil-wiki")==0 ){
445449
Blob title, tail;
446450
if( wiki_find_title(&filebody, &title, &tail) ){
447451
style_header(blob_str(&title));
448452
wiki_convert(&tail, 0, 0);
@@ -469,5 +473,94 @@
469473
style_header("Document Not Found");
470474
@ <p>No such document: %h(PD("name","tip/index.wiki"))</p>
471475
style_footer();
472476
return;
473477
}
478
+
479
+/*
480
+** The default logo.
481
+*/
482
+static const unsigned char aLogo[] = {
483
+ 71, 73, 70, 56, 55, 97, 62, 0, 71, 0, 244, 0, 0, 85,
484
+ 129, 149, 95, 136, 155, 99, 139, 157, 106, 144, 162, 113, 150, 166,
485
+ 116, 152, 168, 127, 160, 175, 138, 168, 182, 148, 176, 188, 159, 184,
486
+ 195, 170, 192, 202, 180, 199, 208, 184, 202, 210, 191, 207, 215, 201,
487
+ 215, 221, 212, 223, 228, 223, 231, 235, 226, 227, 226, 226, 234, 237,
488
+ 233, 239, 241, 240, 244, 246, 244, 247, 248, 255, 255, 255, 0, 0,
489
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
490
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0,
491
+ 0, 0, 62, 0, 71, 0, 0, 5, 255, 96, 100, 141, 100, 105,
492
+ 158, 168, 37, 41, 132, 192, 164, 112, 44, 207, 102, 99, 0, 56,
493
+ 16, 84, 116, 239, 199, 141, 65, 110, 232, 248, 25, 141, 193, 161,
494
+ 82, 113, 108, 202, 32, 55, 229, 210, 73, 61, 41, 164, 88, 102,
495
+ 181, 10, 41, 96, 179, 91, 106, 35, 240, 5, 135, 143, 137, 242,
496
+ 87, 123, 246, 33, 190, 81, 108, 163, 237, 198, 14, 30, 113, 233,
497
+ 131, 78, 115, 72, 11, 115, 87, 101, 19, 124, 51, 66, 74, 8,
498
+ 19, 16, 67, 100, 74, 133, 50, 15, 101, 135, 56, 11, 74, 6,
499
+ 143, 49, 126, 106, 56, 8, 145, 67, 9, 152, 48, 139, 155, 5,
500
+ 22, 13, 74, 115, 161, 41, 147, 101, 13, 130, 57, 132, 170, 40,
501
+ 167, 155, 0, 94, 57, 3, 178, 48, 183, 181, 57, 160, 186, 40,
502
+ 19, 141, 189, 0, 69, 192, 40, 16, 195, 155, 185, 199, 41, 201,
503
+ 189, 191, 205, 193, 188, 131, 210, 49, 175, 88, 209, 214, 38, 19,
504
+ 3, 11, 19, 111, 127, 60, 219, 39, 55, 204, 19, 11, 6, 100,
505
+ 5, 10, 227, 228, 37, 163, 0, 239, 117, 56, 238, 243, 49, 195,
506
+ 177, 247, 48, 158, 56, 251, 50, 216, 254, 197, 56, 128, 107, 158,
507
+ 2, 125, 171, 114, 92, 218, 246, 96, 66, 3, 4, 50, 134, 176,
508
+ 145, 6, 97, 64, 144, 24, 19, 136, 108, 91, 177, 160, 0, 194,
509
+ 19, 253, 0, 216, 107, 214, 224, 192, 129, 5, 16, 83, 255, 244,
510
+ 43, 213, 195, 24, 159, 27, 169, 64, 230, 88, 208, 227, 129, 182,
511
+ 54, 4, 89, 158, 24, 181, 163, 199, 1, 155, 52, 233, 8, 130,
512
+ 176, 83, 24, 128, 137, 50, 18, 32, 48, 48, 114, 11, 173, 137,
513
+ 19, 110, 4, 64, 105, 1, 194, 30, 140, 68, 15, 24, 24, 224,
514
+ 50, 76, 70, 0, 11, 171, 54, 26, 160, 181, 194, 149, 148, 40,
515
+ 174, 148, 122, 64, 180, 208, 161, 17, 207, 112, 164, 1, 128, 96,
516
+ 148, 78, 18, 21, 194, 33, 229, 51, 247, 65, 133, 97, 5, 250,
517
+ 69, 229, 100, 34, 220, 128, 166, 116, 190, 62, 8, 167, 195, 170,
518
+ 47, 163, 0, 130, 90, 152, 11, 160, 173, 170, 27, 154, 26, 91,
519
+ 232, 151, 171, 18, 14, 162, 253, 98, 170, 18, 70, 171, 64, 219,
520
+ 10, 67, 136, 134, 187, 116, 75, 180, 46, 179, 174, 135, 4, 189,
521
+ 229, 231, 78, 40, 10, 62, 226, 164, 172, 64, 240, 167, 170, 10,
522
+ 18, 124, 188, 10, 107, 65, 193, 94, 11, 93, 171, 28, 248, 17,
523
+ 239, 46, 140, 78, 97, 34, 25, 153, 36, 99, 65, 130, 7, 203,
524
+ 183, 168, 51, 34, 136, 25, 140, 10, 6, 16, 28, 255, 145, 241,
525
+ 230, 140, 10, 66, 178, 167, 112, 48, 192, 128, 129, 9, 31, 141,
526
+ 84, 138, 63, 163, 162, 2, 203, 206, 240, 56, 55, 98, 192, 188,
527
+ 15, 185, 50, 160, 6, 0, 125, 62, 33, 214, 195, 33, 5, 24,
528
+ 184, 25, 231, 14, 201, 245, 144, 23, 126, 104, 228, 0, 145, 2,
529
+ 13, 140, 244, 212, 17, 21, 20, 176, 159, 17, 95, 225, 160, 128,
530
+ 16, 1, 32, 224, 142, 32, 227, 125, 87, 64, 0, 16, 54, 129,
531
+ 205, 2, 141, 76, 53, 130, 103, 37, 166, 64, 144, 107, 78, 196,
532
+ 5, 192, 0, 54, 50, 229, 9, 141, 49, 84, 194, 35, 12, 196,
533
+ 153, 48, 192, 137, 57, 84, 24, 7, 87, 159, 249, 240, 215, 143,
534
+ 105, 241, 118, 149, 9, 139, 4, 64, 203, 141, 35, 140, 129, 131,
535
+ 16, 222, 125, 231, 128, 2, 238, 17, 152, 66, 3, 5, 56, 224,
536
+ 159, 103, 16, 76, 25, 75, 5, 11, 164, 215, 96, 9, 14, 16,
537
+ 36, 225, 15, 11, 40, 144, 192, 156, 41, 10, 178, 199, 3, 66,
538
+ 64, 80, 193, 3, 124, 90, 48, 129, 129, 102, 177, 18, 192, 154,
539
+ 49, 84, 240, 208, 92, 22, 149, 96, 39, 9, 31, 74, 17, 94,
540
+ 3, 8, 177, 199, 72, 59, 85, 76, 25, 216, 8, 139, 194, 197,
541
+ 138, 163, 69, 96, 115, 0, 147, 72, 72, 84, 28, 14, 79, 86,
542
+ 233, 230, 23, 113, 26, 160, 128, 3, 10, 58, 129, 103, 14, 159,
543
+ 214, 163, 146, 117, 238, 213, 154, 128, 151, 109, 84, 64, 217, 13,
544
+ 27, 10, 228, 39, 2, 235, 164, 168, 74, 8, 0, 59,
545
+};
546
+
547
+/*
548
+** WEBPAGE: logo
549
+**
550
+** Return the logo image. This image is available to anybody who can see
551
+** the login page. It is designed for use in the upper left-hand corner
552
+** of the header.
553
+*/
554
+void logo_page(void){
555
+ Blob logo;
556
+ char *zMime;
557
+
558
+ zMime = db_get("logo-mimetype", "image/gif");
559
+ blob_zero(&logo);
560
+ db_blob(&logo, "SELECT value FROM config WHERE name='logo-image'");
561
+ if( blob_size(&logo)==0 ){
562
+ blob_init(&logo, (char*)aLogo, sizeof(aLogo));
563
+ }
564
+ cgi_set_content_type(zMime);
565
+ cgi_set_content(&logo);
566
+}
474567
--- src/doc.c
+++ src/doc.c
@@ -316,10 +316,11 @@
316 }
317
318 /*
319 ** WEBPAGE: doc
320 ** URL: /doc?name=BASELINE/PATH
 
321 **
322 ** BASELINE can be either a baseline uuid prefix or magic words "tip"
323 ** to me the most recently checked in baseline or "ckout" to mean the
324 ** content of the local checkout, if any. PATH is the relative pathname
325 ** of some file. This method returns the file content.
@@ -438,11 +439,14 @@
438 }
439
440 /* The file is now contained in the filebody blob. Deliver the
441 ** file to the user
442 */
443 zMime = mimetype_from_name(zName);
 
 
 
444 if( strcmp(zMime, "application/x-fossil-wiki")==0 ){
445 Blob title, tail;
446 if( wiki_find_title(&filebody, &title, &tail) ){
447 style_header(blob_str(&title));
448 wiki_convert(&tail, 0, 0);
@@ -469,5 +473,94 @@
469 style_header("Document Not Found");
470 @ <p>No such document: %h(PD("name","tip/index.wiki"))</p>
471 style_footer();
472 return;
473 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
474
--- src/doc.c
+++ src/doc.c
@@ -316,10 +316,11 @@
316 }
317
318 /*
319 ** WEBPAGE: doc
320 ** URL: /doc?name=BASELINE/PATH
321 ** URL: /doc/BASELINE/PATH
322 **
323 ** BASELINE can be either a baseline uuid prefix or magic words "tip"
324 ** to me the most recently checked in baseline or "ckout" to mean the
325 ** content of the local checkout, if any. PATH is the relative pathname
326 ** of some file. This method returns the file content.
@@ -438,11 +439,14 @@
439 }
440
441 /* The file is now contained in the filebody blob. Deliver the
442 ** file to the user
443 */
444 zMime = P("mimetype");
445 if( zMime==0 ){
446 zMime = mimetype_from_name(zName);
447 }
448 if( strcmp(zMime, "application/x-fossil-wiki")==0 ){
449 Blob title, tail;
450 if( wiki_find_title(&filebody, &title, &tail) ){
451 style_header(blob_str(&title));
452 wiki_convert(&tail, 0, 0);
@@ -469,5 +473,94 @@
473 style_header("Document Not Found");
474 @ <p>No such document: %h(PD("name","tip/index.wiki"))</p>
475 style_footer();
476 return;
477 }
478
479 /*
480 ** The default logo.
481 */
482 static const unsigned char aLogo[] = {
483 71, 73, 70, 56, 55, 97, 62, 0, 71, 0, 244, 0, 0, 85,
484 129, 149, 95, 136, 155, 99, 139, 157, 106, 144, 162, 113, 150, 166,
485 116, 152, 168, 127, 160, 175, 138, 168, 182, 148, 176, 188, 159, 184,
486 195, 170, 192, 202, 180, 199, 208, 184, 202, 210, 191, 207, 215, 201,
487 215, 221, 212, 223, 228, 223, 231, 235, 226, 227, 226, 226, 234, 237,
488 233, 239, 241, 240, 244, 246, 244, 247, 248, 255, 255, 255, 0, 0,
489 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
490 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0,
491 0, 0, 62, 0, 71, 0, 0, 5, 255, 96, 100, 141, 100, 105,
492 158, 168, 37, 41, 132, 192, 164, 112, 44, 207, 102, 99, 0, 56,
493 16, 84, 116, 239, 199, 141, 65, 110, 232, 248, 25, 141, 193, 161,
494 82, 113, 108, 202, 32, 55, 229, 210, 73, 61, 41, 164, 88, 102,
495 181, 10, 41, 96, 179, 91, 106, 35, 240, 5, 135, 143, 137, 242,
496 87, 123, 246, 33, 190, 81, 108, 163, 237, 198, 14, 30, 113, 233,
497 131, 78, 115, 72, 11, 115, 87, 101, 19, 124, 51, 66, 74, 8,
498 19, 16, 67, 100, 74, 133, 50, 15, 101, 135, 56, 11, 74, 6,
499 143, 49, 126, 106, 56, 8, 145, 67, 9, 152, 48, 139, 155, 5,
500 22, 13, 74, 115, 161, 41, 147, 101, 13, 130, 57, 132, 170, 40,
501 167, 155, 0, 94, 57, 3, 178, 48, 183, 181, 57, 160, 186, 40,
502 19, 141, 189, 0, 69, 192, 40, 16, 195, 155, 185, 199, 41, 201,
503 189, 191, 205, 193, 188, 131, 210, 49, 175, 88, 209, 214, 38, 19,
504 3, 11, 19, 111, 127, 60, 219, 39, 55, 204, 19, 11, 6, 100,
505 5, 10, 227, 228, 37, 163, 0, 239, 117, 56, 238, 243, 49, 195,
506 177, 247, 48, 158, 56, 251, 50, 216, 254, 197, 56, 128, 107, 158,
507 2, 125, 171, 114, 92, 218, 246, 96, 66, 3, 4, 50, 134, 176,
508 145, 6, 97, 64, 144, 24, 19, 136, 108, 91, 177, 160, 0, 194,
509 19, 253, 0, 216, 107, 214, 224, 192, 129, 5, 16, 83, 255, 244,
510 43, 213, 195, 24, 159, 27, 169, 64, 230, 88, 208, 227, 129, 182,
511 54, 4, 89, 158, 24, 181, 163, 199, 1, 155, 52, 233, 8, 130,
512 176, 83, 24, 128, 137, 50, 18, 32, 48, 48, 114, 11, 173, 137,
513 19, 110, 4, 64, 105, 1, 194, 30, 140, 68, 15, 24, 24, 224,
514 50, 76, 70, 0, 11, 171, 54, 26, 160, 181, 194, 149, 148, 40,
515 174, 148, 122, 64, 180, 208, 161, 17, 207, 112, 164, 1, 128, 96,
516 148, 78, 18, 21, 194, 33, 229, 51, 247, 65, 133, 97, 5, 250,
517 69, 229, 100, 34, 220, 128, 166, 116, 190, 62, 8, 167, 195, 170,
518 47, 163, 0, 130, 90, 152, 11, 160, 173, 170, 27, 154, 26, 91,
519 232, 151, 171, 18, 14, 162, 253, 98, 170, 18, 70, 171, 64, 219,
520 10, 67, 136, 134, 187, 116, 75, 180, 46, 179, 174, 135, 4, 189,
521 229, 231, 78, 40, 10, 62, 226, 164, 172, 64, 240, 167, 170, 10,
522 18, 124, 188, 10, 107, 65, 193, 94, 11, 93, 171, 28, 248, 17,
523 239, 46, 140, 78, 97, 34, 25, 153, 36, 99, 65, 130, 7, 203,
524 183, 168, 51, 34, 136, 25, 140, 10, 6, 16, 28, 255, 145, 241,
525 230, 140, 10, 66, 178, 167, 112, 48, 192, 128, 129, 9, 31, 141,
526 84, 138, 63, 163, 162, 2, 203, 206, 240, 56, 55, 98, 192, 188,
527 15, 185, 50, 160, 6, 0, 125, 62, 33, 214, 195, 33, 5, 24,
528 184, 25, 231, 14, 201, 245, 144, 23, 126, 104, 228, 0, 145, 2,
529 13, 140, 244, 212, 17, 21, 20, 176, 159, 17, 95, 225, 160, 128,
530 16, 1, 32, 224, 142, 32, 227, 125, 87, 64, 0, 16, 54, 129,
531 205, 2, 141, 76, 53, 130, 103, 37, 166, 64, 144, 107, 78, 196,
532 5, 192, 0, 54, 50, 229, 9, 141, 49, 84, 194, 35, 12, 196,
533 153, 48, 192, 137, 57, 84, 24, 7, 87, 159, 249, 240, 215, 143,
534 105, 241, 118, 149, 9, 139, 4, 64, 203, 141, 35, 140, 129, 131,
535 16, 222, 125, 231, 128, 2, 238, 17, 152, 66, 3, 5, 56, 224,
536 159, 103, 16, 76, 25, 75, 5, 11, 164, 215, 96, 9, 14, 16,
537 36, 225, 15, 11, 40, 144, 192, 156, 41, 10, 178, 199, 3, 66,
538 64, 80, 193, 3, 124, 90, 48, 129, 129, 102, 177, 18, 192, 154,
539 49, 84, 240, 208, 92, 22, 149, 96, 39, 9, 31, 74, 17, 94,
540 3, 8, 177, 199, 72, 59, 85, 76, 25, 216, 8, 139, 194, 197,
541 138, 163, 69, 96, 115, 0, 147, 72, 72, 84, 28, 14, 79, 86,
542 233, 230, 23, 113, 26, 160, 128, 3, 10, 58, 129, 103, 14, 159,
543 214, 163, 146, 117, 238, 213, 154, 128, 151, 109, 84, 64, 217, 13,
544 27, 10, 228, 39, 2, 235, 164, 168, 74, 8, 0, 59,
545 };
546
547 /*
548 ** WEBPAGE: logo
549 **
550 ** Return the logo image. This image is available to anybody who can see
551 ** the login page. It is designed for use in the upper left-hand corner
552 ** of the header.
553 */
554 void logo_page(void){
555 Blob logo;
556 char *zMime;
557
558 zMime = db_get("logo-mimetype", "image/gif");
559 blob_zero(&logo);
560 db_blob(&logo, "SELECT value FROM config WHERE name='logo-image'");
561 if( blob_size(&logo)==0 ){
562 blob_init(&logo, (char*)aLogo, sizeof(aLogo));
563 }
564 cgi_set_content_type(zMime);
565 cgi_set_content(&logo);
566 }
567
+3 -2
--- src/login.c
+++ src/login.c
@@ -218,13 +218,13 @@
218218
}
219219
@ <table align="left" hspace="10">
220220
@ <tr>
221221
@ <td align="right">User ID:</td>
222222
if( anonFlag ){
223
- @ <td><input type="text" name="u" value="anonymous" size=30></td>
223
+ @ <td><input type="text" id="u" name="u" value="anonymous" size=30></td>
224224
}else{
225
- @ <td><input type="text" name="u" value="" size=30></td>
225
+ @ <td><input type="text" id="u" name="u" value="" size=30></td>
226226
}
227227
@ </tr>
228228
@ <tr>
229229
@ <td align="right">Password:</td>
230230
@ <td><input type="password" name="p" value="" size=30></td>
@@ -237,10 +237,11 @@
237237
@ <tr>
238238
@ <td></td>
239239
@ <td><input type="submit" name="in" value="Login"></td>
240240
@ </tr>
241241
@ </table>
242
+ @ <script>document.getElementById('u').focus()</script>
242243
if( g.zLogin==0 ){
243244
@ <p>Enter
244245
}else{
245246
@ <p>You are currently logged in as <b>%h(g.zLogin)</b></p>
246247
@ <p>To change your login to a different user, enter
247248
--- src/login.c
+++ src/login.c
@@ -218,13 +218,13 @@
218 }
219 @ <table align="left" hspace="10">
220 @ <tr>
221 @ <td align="right">User ID:</td>
222 if( anonFlag ){
223 @ <td><input type="text" name="u" value="anonymous" size=30></td>
224 }else{
225 @ <td><input type="text" name="u" value="" size=30></td>
226 }
227 @ </tr>
228 @ <tr>
229 @ <td align="right">Password:</td>
230 @ <td><input type="password" name="p" value="" size=30></td>
@@ -237,10 +237,11 @@
237 @ <tr>
238 @ <td></td>
239 @ <td><input type="submit" name="in" value="Login"></td>
240 @ </tr>
241 @ </table>
 
242 if( g.zLogin==0 ){
243 @ <p>Enter
244 }else{
245 @ <p>You are currently logged in as <b>%h(g.zLogin)</b></p>
246 @ <p>To change your login to a different user, enter
247
--- src/login.c
+++ src/login.c
@@ -218,13 +218,13 @@
218 }
219 @ <table align="left" hspace="10">
220 @ <tr>
221 @ <td align="right">User ID:</td>
222 if( anonFlag ){
223 @ <td><input type="text" id="u" name="u" value="anonymous" size=30></td>
224 }else{
225 @ <td><input type="text" id="u" name="u" value="" size=30></td>
226 }
227 @ </tr>
228 @ <tr>
229 @ <td align="right">Password:</td>
230 @ <td><input type="password" name="p" value="" size=30></td>
@@ -237,10 +237,11 @@
237 @ <tr>
238 @ <td></td>
239 @ <td><input type="submit" name="in" value="Login"></td>
240 @ </tr>
241 @ </table>
242 @ <script>document.getElementById('u').focus()</script>
243 if( g.zLogin==0 ){
244 @ <p>Enter
245 }else{
246 @ <p>You are currently logged in as <b>%h(g.zLogin)</b></p>
247 @ <p>To change your login to a different user, enter
248
+3 -2
--- src/login.c
+++ src/login.c
@@ -218,13 +218,13 @@
218218
}
219219
@ <table align="left" hspace="10">
220220
@ <tr>
221221
@ <td align="right">User ID:</td>
222222
if( anonFlag ){
223
- @ <td><input type="text" name="u" value="anonymous" size=30></td>
223
+ @ <td><input type="text" id="u" name="u" value="anonymous" size=30></td>
224224
}else{
225
- @ <td><input type="text" name="u" value="" size=30></td>
225
+ @ <td><input type="text" id="u" name="u" value="" size=30></td>
226226
}
227227
@ </tr>
228228
@ <tr>
229229
@ <td align="right">Password:</td>
230230
@ <td><input type="password" name="p" value="" size=30></td>
@@ -237,10 +237,11 @@
237237
@ <tr>
238238
@ <td></td>
239239
@ <td><input type="submit" name="in" value="Login"></td>
240240
@ </tr>
241241
@ </table>
242
+ @ <script>document.getElementById('u').focus()</script>
242243
if( g.zLogin==0 ){
243244
@ <p>Enter
244245
}else{
245246
@ <p>You are currently logged in as <b>%h(g.zLogin)</b></p>
246247
@ <p>To change your login to a different user, enter
247248
--- src/login.c
+++ src/login.c
@@ -218,13 +218,13 @@
218 }
219 @ <table align="left" hspace="10">
220 @ <tr>
221 @ <td align="right">User ID:</td>
222 if( anonFlag ){
223 @ <td><input type="text" name="u" value="anonymous" size=30></td>
224 }else{
225 @ <td><input type="text" name="u" value="" size=30></td>
226 }
227 @ </tr>
228 @ <tr>
229 @ <td align="right">Password:</td>
230 @ <td><input type="password" name="p" value="" size=30></td>
@@ -237,10 +237,11 @@
237 @ <tr>
238 @ <td></td>
239 @ <td><input type="submit" name="in" value="Login"></td>
240 @ </tr>
241 @ </table>
 
242 if( g.zLogin==0 ){
243 @ <p>Enter
244 }else{
245 @ <p>You are currently logged in as <b>%h(g.zLogin)</b></p>
246 @ <p>To change your login to a different user, enter
247
--- src/login.c
+++ src/login.c
@@ -218,13 +218,13 @@
218 }
219 @ <table align="left" hspace="10">
220 @ <tr>
221 @ <td align="right">User ID:</td>
222 if( anonFlag ){
223 @ <td><input type="text" id="u" name="u" value="anonymous" size=30></td>
224 }else{
225 @ <td><input type="text" id="u" name="u" value="" size=30></td>
226 }
227 @ </tr>
228 @ <tr>
229 @ <td align="right">Password:</td>
230 @ <td><input type="password" name="p" value="" size=30></td>
@@ -237,10 +237,11 @@
237 @ <tr>
238 @ <td></td>
239 @ <td><input type="submit" name="in" value="Login"></td>
240 @ </tr>
241 @ </table>
242 @ <script>document.getElementById('u').focus()</script>
243 if( g.zLogin==0 ){
244 @ <p>Enter
245 }else{
246 @ <p>You are currently logged in as <b>%h(g.zLogin)</b></p>
247 @ <p>To change your login to a different user, enter
248
+2 -2
--- src/manifest.c
+++ src/manifest.c
@@ -952,11 +952,11 @@
952952
if( strcmp(pManifest->aField[i].zName, zStatusColumn)==0 ){
953953
zNewStatus = pManifest->aField[i].zValue;
954954
}
955955
}
956956
if( zNewStatus ){
957
- blob_appendf(&comment, "%h ticket [%.10s]: <i>%h</i>",
957
+ blob_appendf(&comment, "%h ticket [%.10s]: <i>%s</i>",
958958
zNewStatus, pManifest->zTicketUuid, zTitle
959959
);
960960
if( pManifest->nField>1 ){
961961
blob_appendf(&comment, " plus %d other change%s",
962962
pManifest->nField-1, pManifest->nField==2 ? "" : "s");
@@ -966,11 +966,11 @@
966966
}else{
967967
zNewStatus = db_text("unknown",
968968
"SELECT %s FROM ticket WHERE tkt_uuid='%s'",
969969
zStatusColumn, pManifest->zTicketUuid
970970
);
971
- blob_appendf(&comment, "Ticket [%.10s] <i>%h</i> status still %h with "
971
+ blob_appendf(&comment, "Ticket [%.10s] <i>%s</i> status still %h with "
972972
"%d other change%s",
973973
pManifest->zTicketUuid, zTitle, zNewStatus, pManifest->nField,
974974
pManifest->nField==1 ? "" : "s"
975975
);
976976
free(zNewStatus);
977977
--- src/manifest.c
+++ src/manifest.c
@@ -952,11 +952,11 @@
952 if( strcmp(pManifest->aField[i].zName, zStatusColumn)==0 ){
953 zNewStatus = pManifest->aField[i].zValue;
954 }
955 }
956 if( zNewStatus ){
957 blob_appendf(&comment, "%h ticket [%.10s]: <i>%h</i>",
958 zNewStatus, pManifest->zTicketUuid, zTitle
959 );
960 if( pManifest->nField>1 ){
961 blob_appendf(&comment, " plus %d other change%s",
962 pManifest->nField-1, pManifest->nField==2 ? "" : "s");
@@ -966,11 +966,11 @@
966 }else{
967 zNewStatus = db_text("unknown",
968 "SELECT %s FROM ticket WHERE tkt_uuid='%s'",
969 zStatusColumn, pManifest->zTicketUuid
970 );
971 blob_appendf(&comment, "Ticket [%.10s] <i>%h</i> status still %h with "
972 "%d other change%s",
973 pManifest->zTicketUuid, zTitle, zNewStatus, pManifest->nField,
974 pManifest->nField==1 ? "" : "s"
975 );
976 free(zNewStatus);
977
--- src/manifest.c
+++ src/manifest.c
@@ -952,11 +952,11 @@
952 if( strcmp(pManifest->aField[i].zName, zStatusColumn)==0 ){
953 zNewStatus = pManifest->aField[i].zValue;
954 }
955 }
956 if( zNewStatus ){
957 blob_appendf(&comment, "%h ticket [%.10s]: <i>%s</i>",
958 zNewStatus, pManifest->zTicketUuid, zTitle
959 );
960 if( pManifest->nField>1 ){
961 blob_appendf(&comment, " plus %d other change%s",
962 pManifest->nField-1, pManifest->nField==2 ? "" : "s");
@@ -966,11 +966,11 @@
966 }else{
967 zNewStatus = db_text("unknown",
968 "SELECT %s FROM ticket WHERE tkt_uuid='%s'",
969 zStatusColumn, pManifest->zTicketUuid
970 );
971 blob_appendf(&comment, "Ticket [%.10s] <i>%s</i> status still %h with "
972 "%d other change%s",
973 pManifest->zTicketUuid, zTitle, zNewStatus, pManifest->nField,
974 pManifest->nField==1 ? "" : "s"
975 );
976 free(zNewStatus);
977
+2 -2
--- src/manifest.c
+++ src/manifest.c
@@ -952,11 +952,11 @@
952952
if( strcmp(pManifest->aField[i].zName, zStatusColumn)==0 ){
953953
zNewStatus = pManifest->aField[i].zValue;
954954
}
955955
}
956956
if( zNewStatus ){
957
- blob_appendf(&comment, "%h ticket [%.10s]: <i>%h</i>",
957
+ blob_appendf(&comment, "%h ticket [%.10s]: <i>%s</i>",
958958
zNewStatus, pManifest->zTicketUuid, zTitle
959959
);
960960
if( pManifest->nField>1 ){
961961
blob_appendf(&comment, " plus %d other change%s",
962962
pManifest->nField-1, pManifest->nField==2 ? "" : "s");
@@ -966,11 +966,11 @@
966966
}else{
967967
zNewStatus = db_text("unknown",
968968
"SELECT %s FROM ticket WHERE tkt_uuid='%s'",
969969
zStatusColumn, pManifest->zTicketUuid
970970
);
971
- blob_appendf(&comment, "Ticket [%.10s] <i>%h</i> status still %h with "
971
+ blob_appendf(&comment, "Ticket [%.10s] <i>%s</i> status still %h with "
972972
"%d other change%s",
973973
pManifest->zTicketUuid, zTitle, zNewStatus, pManifest->nField,
974974
pManifest->nField==1 ? "" : "s"
975975
);
976976
free(zNewStatus);
977977
--- src/manifest.c
+++ src/manifest.c
@@ -952,11 +952,11 @@
952 if( strcmp(pManifest->aField[i].zName, zStatusColumn)==0 ){
953 zNewStatus = pManifest->aField[i].zValue;
954 }
955 }
956 if( zNewStatus ){
957 blob_appendf(&comment, "%h ticket [%.10s]: <i>%h</i>",
958 zNewStatus, pManifest->zTicketUuid, zTitle
959 );
960 if( pManifest->nField>1 ){
961 blob_appendf(&comment, " plus %d other change%s",
962 pManifest->nField-1, pManifest->nField==2 ? "" : "s");
@@ -966,11 +966,11 @@
966 }else{
967 zNewStatus = db_text("unknown",
968 "SELECT %s FROM ticket WHERE tkt_uuid='%s'",
969 zStatusColumn, pManifest->zTicketUuid
970 );
971 blob_appendf(&comment, "Ticket [%.10s] <i>%h</i> status still %h with "
972 "%d other change%s",
973 pManifest->zTicketUuid, zTitle, zNewStatus, pManifest->nField,
974 pManifest->nField==1 ? "" : "s"
975 );
976 free(zNewStatus);
977
--- src/manifest.c
+++ src/manifest.c
@@ -952,11 +952,11 @@
952 if( strcmp(pManifest->aField[i].zName, zStatusColumn)==0 ){
953 zNewStatus = pManifest->aField[i].zValue;
954 }
955 }
956 if( zNewStatus ){
957 blob_appendf(&comment, "%h ticket [%.10s]: <i>%s</i>",
958 zNewStatus, pManifest->zTicketUuid, zTitle
959 );
960 if( pManifest->nField>1 ){
961 blob_appendf(&comment, " plus %d other change%s",
962 pManifest->nField-1, pManifest->nField==2 ? "" : "s");
@@ -966,11 +966,11 @@
966 }else{
967 zNewStatus = db_text("unknown",
968 "SELECT %s FROM ticket WHERE tkt_uuid='%s'",
969 zStatusColumn, pManifest->zTicketUuid
970 );
971 blob_appendf(&comment, "Ticket [%.10s] <i>%s</i> status still %h with "
972 "%d other change%s",
973 pManifest->zTicketUuid, zTitle, zNewStatus, pManifest->nField,
974 pManifest->nField==1 ? "" : "s"
975 );
976 free(zNewStatus);
977
+58
--- src/setup.c
+++ src/setup.c
@@ -76,10 +76,12 @@
7676
"Edit the Cascading Style Sheet used by all pages of this repository");
7777
setup_menu_entry("Header", "setup_header",
7878
"Edit HTML text inserted at the top of every page");
7979
setup_menu_entry("Footer", "setup_footer",
8080
"Edit HTML text inserted at the bottom of every page");
81
+ setup_menu_entry("Logo", "setup_logo",
82
+ "Change the logo image for the server");
8183
setup_menu_entry("Shunned", "shun",
8284
"Show artifacts that are shunned by this repository");
8385
setup_menu_entry("Log", "rcvfromlist",
8486
"A record of received artifacts and their sources");
8587
setup_menu_entry("Stats", "stat",
@@ -1012,8 +1014,64 @@
10121014
@ <hr>
10131015
@ Here is the default page footer:
10141016
@ <blockquote><pre>
10151017
@ %h(zDefaultFooter)
10161018
@ </pre></blockquote>
1019
+ style_footer();
1020
+ db_end_transaction(0);
1021
+}
1022
+
1023
+/*
1024
+** WEBPAGE: setup_logo
1025
+*/
1026
+void setup_logo(void){
1027
+ const char *zMime = "image/gif";
1028
+ const char *aImg = P("im");
1029
+ int szImg = atoi(PD("im:bytes","0"));
1030
+ if( szImg>0 ){
1031
+ zMime = PD("im:mimetype","image/gif");
1032
+ }
1033
+ login_check_credentials();
1034
+ if( !g.okSetup ){
1035
+ login_needed();
1036
+ }
1037
+ db_begin_transaction();
1038
+ if( P("set")!=0 && zMime && zMime[0] && szImg>0 ){
1039
+ Blob img;
1040
+ Stmt ins;
1041
+ blob_init(&img, aImg, szImg);
1042
+ db_prepare(&ins,
1043
+ "REPLACE INTO config(name, value)"
1044
+ " VALUES('logo-image',:bytes)"
1045
+ );
1046
+ db_bind_blob(&ins, ":bytes", &img);
1047
+ db_step(&ins);
1048
+ db_finalize(&ins);
1049
+ db_multi_exec(
1050
+ "REPLACE INTO config(name, value) VALUES('logo-mimetype',%Q)",
1051
+ zMime
1052
+ );
1053
+ }else if( P("clr")!=0 ){
1054
+ db_multi_exec(
1055
+ "DELETE FROM config WHERE name GLOB 'logo-*'"
1056
+ );
1057
+ }
1058
+ style_header("Edit Project Logo");
1059
+ @ <p>The current project logo has a MIME-Type of <b>%h(zMime)</b> and looks
1060
+ @ like this:</p>
1061
+ @ <blockquote><img src="%s(g.zTop)/logo" alt="logo"></blockquote>
1062
+ @
1063
+ @ <form action="%s(g.zBaseURL)/setup_logo" method="POST"
1064
+ @ enctype="multipart/form-data">
1065
+ @ <p>The logo is accessible to all users at this URL:
1066
+ @ <a href="%s(g.zBaseURL)/logo">%s(g.zBaseURL)/logo</a>.
1067
+ @ To set a new logo image, select a file to use as the logo using
1068
+ @ the entry box below and then press the "Change Logo" button.</p>
1069
+ login_insert_csrf_secret();
1070
+ @ Logo Image file:
1071
+ @ <input type="file" name="im" size="60" accepts="image/*"><br>
1072
+ @ <input type="submit" name="set" value="Change Logo">
1073
+ @ <input type="submit" name="clr" value="Revert To Default">
1074
+ @ </form>
10171075
style_footer();
10181076
db_end_transaction(0);
10191077
}
10201078
--- src/setup.c
+++ src/setup.c
@@ -76,10 +76,12 @@
76 "Edit the Cascading Style Sheet used by all pages of this repository");
77 setup_menu_entry("Header", "setup_header",
78 "Edit HTML text inserted at the top of every page");
79 setup_menu_entry("Footer", "setup_footer",
80 "Edit HTML text inserted at the bottom of every page");
 
 
81 setup_menu_entry("Shunned", "shun",
82 "Show artifacts that are shunned by this repository");
83 setup_menu_entry("Log", "rcvfromlist",
84 "A record of received artifacts and their sources");
85 setup_menu_entry("Stats", "stat",
@@ -1012,8 +1014,64 @@
1012 @ <hr>
1013 @ Here is the default page footer:
1014 @ <blockquote><pre>
1015 @ %h(zDefaultFooter)
1016 @ </pre></blockquote>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1017 style_footer();
1018 db_end_transaction(0);
1019 }
1020
--- src/setup.c
+++ src/setup.c
@@ -76,10 +76,12 @@
76 "Edit the Cascading Style Sheet used by all pages of this repository");
77 setup_menu_entry("Header", "setup_header",
78 "Edit HTML text inserted at the top of every page");
79 setup_menu_entry("Footer", "setup_footer",
80 "Edit HTML text inserted at the bottom of every page");
81 setup_menu_entry("Logo", "setup_logo",
82 "Change the logo image for the server");
83 setup_menu_entry("Shunned", "shun",
84 "Show artifacts that are shunned by this repository");
85 setup_menu_entry("Log", "rcvfromlist",
86 "A record of received artifacts and their sources");
87 setup_menu_entry("Stats", "stat",
@@ -1012,8 +1014,64 @@
1014 @ <hr>
1015 @ Here is the default page footer:
1016 @ <blockquote><pre>
1017 @ %h(zDefaultFooter)
1018 @ </pre></blockquote>
1019 style_footer();
1020 db_end_transaction(0);
1021 }
1022
1023 /*
1024 ** WEBPAGE: setup_logo
1025 */
1026 void setup_logo(void){
1027 const char *zMime = "image/gif";
1028 const char *aImg = P("im");
1029 int szImg = atoi(PD("im:bytes","0"));
1030 if( szImg>0 ){
1031 zMime = PD("im:mimetype","image/gif");
1032 }
1033 login_check_credentials();
1034 if( !g.okSetup ){
1035 login_needed();
1036 }
1037 db_begin_transaction();
1038 if( P("set")!=0 && zMime && zMime[0] && szImg>0 ){
1039 Blob img;
1040 Stmt ins;
1041 blob_init(&img, aImg, szImg);
1042 db_prepare(&ins,
1043 "REPLACE INTO config(name, value)"
1044 " VALUES('logo-image',:bytes)"
1045 );
1046 db_bind_blob(&ins, ":bytes", &img);
1047 db_step(&ins);
1048 db_finalize(&ins);
1049 db_multi_exec(
1050 "REPLACE INTO config(name, value) VALUES('logo-mimetype',%Q)",
1051 zMime
1052 );
1053 }else if( P("clr")!=0 ){
1054 db_multi_exec(
1055 "DELETE FROM config WHERE name GLOB 'logo-*'"
1056 );
1057 }
1058 style_header("Edit Project Logo");
1059 @ <p>The current project logo has a MIME-Type of <b>%h(zMime)</b> and looks
1060 @ like this:</p>
1061 @ <blockquote><img src="%s(g.zTop)/logo" alt="logo"></blockquote>
1062 @
1063 @ <form action="%s(g.zBaseURL)/setup_logo" method="POST"
1064 @ enctype="multipart/form-data">
1065 @ <p>The logo is accessible to all users at this URL:
1066 @ <a href="%s(g.zBaseURL)/logo">%s(g.zBaseURL)/logo</a>.
1067 @ To set a new logo image, select a file to use as the logo using
1068 @ the entry box below and then press the "Change Logo" button.</p>
1069 login_insert_csrf_secret();
1070 @ Logo Image file:
1071 @ <input type="file" name="im" size="60" accepts="image/*"><br>
1072 @ <input type="submit" name="set" value="Change Logo">
1073 @ <input type="submit" name="clr" value="Revert To Default">
1074 @ </form>
1075 style_footer();
1076 db_end_transaction(0);
1077 }
1078
+58
--- src/setup.c
+++ src/setup.c
@@ -76,10 +76,12 @@
7676
"Edit the Cascading Style Sheet used by all pages of this repository");
7777
setup_menu_entry("Header", "setup_header",
7878
"Edit HTML text inserted at the top of every page");
7979
setup_menu_entry("Footer", "setup_footer",
8080
"Edit HTML text inserted at the bottom of every page");
81
+ setup_menu_entry("Logo", "setup_logo",
82
+ "Change the logo image for the server");
8183
setup_menu_entry("Shunned", "shun",
8284
"Show artifacts that are shunned by this repository");
8385
setup_menu_entry("Log", "rcvfromlist",
8486
"A record of received artifacts and their sources");
8587
setup_menu_entry("Stats", "stat",
@@ -1012,8 +1014,64 @@
10121014
@ <hr>
10131015
@ Here is the default page footer:
10141016
@ <blockquote><pre>
10151017
@ %h(zDefaultFooter)
10161018
@ </pre></blockquote>
1019
+ style_footer();
1020
+ db_end_transaction(0);
1021
+}
1022
+
1023
+/*
1024
+** WEBPAGE: setup_logo
1025
+*/
1026
+void setup_logo(void){
1027
+ const char *zMime = "image/gif";
1028
+ const char *aImg = P("im");
1029
+ int szImg = atoi(PD("im:bytes","0"));
1030
+ if( szImg>0 ){
1031
+ zMime = PD("im:mimetype","image/gif");
1032
+ }
1033
+ login_check_credentials();
1034
+ if( !g.okSetup ){
1035
+ login_needed();
1036
+ }
1037
+ db_begin_transaction();
1038
+ if( P("set")!=0 && zMime && zMime[0] && szImg>0 ){
1039
+ Blob img;
1040
+ Stmt ins;
1041
+ blob_init(&img, aImg, szImg);
1042
+ db_prepare(&ins,
1043
+ "REPLACE INTO config(name, value)"
1044
+ " VALUES('logo-image',:bytes)"
1045
+ );
1046
+ db_bind_blob(&ins, ":bytes", &img);
1047
+ db_step(&ins);
1048
+ db_finalize(&ins);
1049
+ db_multi_exec(
1050
+ "REPLACE INTO config(name, value) VALUES('logo-mimetype',%Q)",
1051
+ zMime
1052
+ );
1053
+ }else if( P("clr")!=0 ){
1054
+ db_multi_exec(
1055
+ "DELETE FROM config WHERE name GLOB 'logo-*'"
1056
+ );
1057
+ }
1058
+ style_header("Edit Project Logo");
1059
+ @ <p>The current project logo has a MIME-Type of <b>%h(zMime)</b> and looks
1060
+ @ like this:</p>
1061
+ @ <blockquote><img src="%s(g.zTop)/logo" alt="logo"></blockquote>
1062
+ @
1063
+ @ <form action="%s(g.zBaseURL)/setup_logo" method="POST"
1064
+ @ enctype="multipart/form-data">
1065
+ @ <p>The logo is accessible to all users at this URL:
1066
+ @ <a href="%s(g.zBaseURL)/logo">%s(g.zBaseURL)/logo</a>.
1067
+ @ To set a new logo image, select a file to use as the logo using
1068
+ @ the entry box below and then press the "Change Logo" button.</p>
1069
+ login_insert_csrf_secret();
1070
+ @ Logo Image file:
1071
+ @ <input type="file" name="im" size="60" accepts="image/*"><br>
1072
+ @ <input type="submit" name="set" value="Change Logo">
1073
+ @ <input type="submit" name="clr" value="Revert To Default">
1074
+ @ </form>
10171075
style_footer();
10181076
db_end_transaction(0);
10191077
}
10201078
--- src/setup.c
+++ src/setup.c
@@ -76,10 +76,12 @@
76 "Edit the Cascading Style Sheet used by all pages of this repository");
77 setup_menu_entry("Header", "setup_header",
78 "Edit HTML text inserted at the top of every page");
79 setup_menu_entry("Footer", "setup_footer",
80 "Edit HTML text inserted at the bottom of every page");
 
 
81 setup_menu_entry("Shunned", "shun",
82 "Show artifacts that are shunned by this repository");
83 setup_menu_entry("Log", "rcvfromlist",
84 "A record of received artifacts and their sources");
85 setup_menu_entry("Stats", "stat",
@@ -1012,8 +1014,64 @@
1012 @ <hr>
1013 @ Here is the default page footer:
1014 @ <blockquote><pre>
1015 @ %h(zDefaultFooter)
1016 @ </pre></blockquote>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1017 style_footer();
1018 db_end_transaction(0);
1019 }
1020
--- src/setup.c
+++ src/setup.c
@@ -76,10 +76,12 @@
76 "Edit the Cascading Style Sheet used by all pages of this repository");
77 setup_menu_entry("Header", "setup_header",
78 "Edit HTML text inserted at the top of every page");
79 setup_menu_entry("Footer", "setup_footer",
80 "Edit HTML text inserted at the bottom of every page");
81 setup_menu_entry("Logo", "setup_logo",
82 "Change the logo image for the server");
83 setup_menu_entry("Shunned", "shun",
84 "Show artifacts that are shunned by this repository");
85 setup_menu_entry("Log", "rcvfromlist",
86 "A record of received artifacts and their sources");
87 setup_menu_entry("Stats", "stat",
@@ -1012,8 +1014,64 @@
1014 @ <hr>
1015 @ Here is the default page footer:
1016 @ <blockquote><pre>
1017 @ %h(zDefaultFooter)
1018 @ </pre></blockquote>
1019 style_footer();
1020 db_end_transaction(0);
1021 }
1022
1023 /*
1024 ** WEBPAGE: setup_logo
1025 */
1026 void setup_logo(void){
1027 const char *zMime = "image/gif";
1028 const char *aImg = P("im");
1029 int szImg = atoi(PD("im:bytes","0"));
1030 if( szImg>0 ){
1031 zMime = PD("im:mimetype","image/gif");
1032 }
1033 login_check_credentials();
1034 if( !g.okSetup ){
1035 login_needed();
1036 }
1037 db_begin_transaction();
1038 if( P("set")!=0 && zMime && zMime[0] && szImg>0 ){
1039 Blob img;
1040 Stmt ins;
1041 blob_init(&img, aImg, szImg);
1042 db_prepare(&ins,
1043 "REPLACE INTO config(name, value)"
1044 " VALUES('logo-image',:bytes)"
1045 );
1046 db_bind_blob(&ins, ":bytes", &img);
1047 db_step(&ins);
1048 db_finalize(&ins);
1049 db_multi_exec(
1050 "REPLACE INTO config(name, value) VALUES('logo-mimetype',%Q)",
1051 zMime
1052 );
1053 }else if( P("clr")!=0 ){
1054 db_multi_exec(
1055 "DELETE FROM config WHERE name GLOB 'logo-*'"
1056 );
1057 }
1058 style_header("Edit Project Logo");
1059 @ <p>The current project logo has a MIME-Type of <b>%h(zMime)</b> and looks
1060 @ like this:</p>
1061 @ <blockquote><img src="%s(g.zTop)/logo" alt="logo"></blockquote>
1062 @
1063 @ <form action="%s(g.zBaseURL)/setup_logo" method="POST"
1064 @ enctype="multipart/form-data">
1065 @ <p>The logo is accessible to all users at this URL:
1066 @ <a href="%s(g.zBaseURL)/logo">%s(g.zBaseURL)/logo</a>.
1067 @ To set a new logo image, select a file to use as the logo using
1068 @ the entry box below and then press the "Change Logo" button.</p>
1069 login_insert_csrf_secret();
1070 @ Logo Image file:
1071 @ <input type="file" name="im" size="60" accepts="image/*"><br>
1072 @ <input type="submit" name="set" value="Change Logo">
1073 @ <input type="submit" name="clr" value="Revert To Default">
1074 @ </form>
1075 style_footer();
1076 db_end_transaction(0);
1077 }
1078
+20 -26
--- src/style.c
+++ src/style.c
@@ -143,11 +143,11 @@
143143
@ <div class="content">
144144
cgi_destination(CGI_BODY);
145145
146146
/* Put the footer at the bottom of the page.
147147
*/
148
- @ </div>
148
+ @ </div><br clear="both"></br>
149149
zFooter = db_get("footer", (char*)zDefaultFooter);
150150
if( g.thTrace ) Th_Trace("BEGIN_FOOTER<br />\n", -1);
151151
Th_Render(zFooter);
152152
if( g.thTrace ) Th_Trace("END_FOOTER<br />\n", -1);
153153
@@ -191,12 +191,12 @@
191191
@ media="screen">
192192
@ </head>
193193
@ <body>
194194
@ <div class="header">
195195
@ <div class="logo">
196
-@ <!-- <img src="logo.gif" alt="logo"><br></br> -->
197
-@ <nobr>$<project_name></nobr>
196
+@ <img src="/logo" alt="logo">
197
+@ <br><nobr>$<project_name></nobr>
198198
@ </div>
199199
@ <div class="title">$<title></div>
200200
@ <div class="status"><nobr><th1>
201201
@ if {[info exists login]} {
202202
@ puts "Logged in as $login"
@@ -269,11 +269,12 @@
269269
@ /* The page title centered at the top of each page */
270270
@ div.title {
271271
@ display: table-cell;
272272
@ font-size: 2em;
273273
@ font-weight: bold;
274
-@ text-align: center;
274
+@ text-align: left;
275
+@ padding: 0 0 0 1em;
275276
@ color: #558195;
276277
@ vertical-align: bottom;
277278
@ width: 100%;
278279
@ }
279280
@
@@ -392,32 +393,11 @@
392393
@
393394
@ div.miniform {
394395
@ font-size: smaller;
395396
@ margin: 8px;
396397
@ }
397
-@ table.fossil_db_generic_query_view {
398
-@ border-spacing: 0px;
399
-@ border: 1px solid black;
400
-@ }
401
-@ table.fossil_db_generic_query_view td {
402
-@ padding: 2px 1em 2px 1em;
403
-@ }
404
-@ table.fossil_db_generic_query_view tr {
405
-@ }
406
-@ table.fossil_db_generic_query_view tr.even {
407
-@ background: #ffffff;
408
-@ }
409
-@ table.fossil_db_generic_query_view tr.odd {
410
-@ background: #e5e5e5;
411
-@ }
412
-@ table.fossil_db_generic_query_view tr.header {
413
-@ background: #558195;
414
-@ font-size: 1.5em;
415
-@ color: #ffffff;
416
-@ }
417
-@
418
-@ /* addeitions to support creole parser */
398
+@ /* additions to support creole parser */
419399
@
420400
@ .creoletable {
421401
@ border: 1px solid #666666;
422402
@ border-spacing: 0;
423403
@ margin: 1.5em 2em 1.8em 2em;
@@ -436,10 +416,24 @@
436416
@ border-left: 1px solid #D9D9D9;
437417
@ border-top: 1px solid #D9D9D9;
438418
@ vertical-align: center;
439419
@ empty-cells: show;
440420
@ }
421
+@ .creole-nowiki {
422
+@ background: oldlace;
423
+@ }
424
+@ .creole-inline-nowiki {
425
+@ background: oldlace;
426
+@ }
427
+@ .creole-image {
428
+@ color:green;
429
+@ border:1px solid green;
430
+@ }
431
+@ .creole-nomacro {
432
+@ color:red;
433
+@ border:1px solid red;
434
+@ }
441435
;
442436
443437
/*
444438
** WEBPAGE: style.css
445439
*/
446440
--- src/style.c
+++ src/style.c
@@ -143,11 +143,11 @@
143 @ <div class="content">
144 cgi_destination(CGI_BODY);
145
146 /* Put the footer at the bottom of the page.
147 */
148 @ </div>
149 zFooter = db_get("footer", (char*)zDefaultFooter);
150 if( g.thTrace ) Th_Trace("BEGIN_FOOTER<br />\n", -1);
151 Th_Render(zFooter);
152 if( g.thTrace ) Th_Trace("END_FOOTER<br />\n", -1);
153
@@ -191,12 +191,12 @@
191 @ media="screen">
192 @ </head>
193 @ <body>
194 @ <div class="header">
195 @ <div class="logo">
196 @ <!-- <img src="logo.gif" alt="logo"><br></br> -->
197 @ <nobr>$<project_name></nobr>
198 @ </div>
199 @ <div class="title">$<title></div>
200 @ <div class="status"><nobr><th1>
201 @ if {[info exists login]} {
202 @ puts "Logged in as $login"
@@ -269,11 +269,12 @@
269 @ /* The page title centered at the top of each page */
270 @ div.title {
271 @ display: table-cell;
272 @ font-size: 2em;
273 @ font-weight: bold;
274 @ text-align: center;
 
275 @ color: #558195;
276 @ vertical-align: bottom;
277 @ width: 100%;
278 @ }
279 @
@@ -392,32 +393,11 @@
392 @
393 @ div.miniform {
394 @ font-size: smaller;
395 @ margin: 8px;
396 @ }
397 @ table.fossil_db_generic_query_view {
398 @ border-spacing: 0px;
399 @ border: 1px solid black;
400 @ }
401 @ table.fossil_db_generic_query_view td {
402 @ padding: 2px 1em 2px 1em;
403 @ }
404 @ table.fossil_db_generic_query_view tr {
405 @ }
406 @ table.fossil_db_generic_query_view tr.even {
407 @ background: #ffffff;
408 @ }
409 @ table.fossil_db_generic_query_view tr.odd {
410 @ background: #e5e5e5;
411 @ }
412 @ table.fossil_db_generic_query_view tr.header {
413 @ background: #558195;
414 @ font-size: 1.5em;
415 @ color: #ffffff;
416 @ }
417 @
418 @ /* addeitions to support creole parser */
419 @
420 @ .creoletable {
421 @ border: 1px solid #666666;
422 @ border-spacing: 0;
423 @ margin: 1.5em 2em 1.8em 2em;
@@ -436,10 +416,24 @@
436 @ border-left: 1px solid #D9D9D9;
437 @ border-top: 1px solid #D9D9D9;
438 @ vertical-align: center;
439 @ empty-cells: show;
440 @ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
441 ;
442
443 /*
444 ** WEBPAGE: style.css
445 */
446
--- src/style.c
+++ src/style.c
@@ -143,11 +143,11 @@
143 @ <div class="content">
144 cgi_destination(CGI_BODY);
145
146 /* Put the footer at the bottom of the page.
147 */
148 @ </div><br clear="both"></br>
149 zFooter = db_get("footer", (char*)zDefaultFooter);
150 if( g.thTrace ) Th_Trace("BEGIN_FOOTER<br />\n", -1);
151 Th_Render(zFooter);
152 if( g.thTrace ) Th_Trace("END_FOOTER<br />\n", -1);
153
@@ -191,12 +191,12 @@
191 @ media="screen">
192 @ </head>
193 @ <body>
194 @ <div class="header">
195 @ <div class="logo">
196 @ <img src="/logo" alt="logo">
197 @ <br><nobr>$<project_name></nobr>
198 @ </div>
199 @ <div class="title">$<title></div>
200 @ <div class="status"><nobr><th1>
201 @ if {[info exists login]} {
202 @ puts "Logged in as $login"
@@ -269,11 +269,12 @@
269 @ /* The page title centered at the top of each page */
270 @ div.title {
271 @ display: table-cell;
272 @ font-size: 2em;
273 @ font-weight: bold;
274 @ text-align: left;
275 @ padding: 0 0 0 1em;
276 @ color: #558195;
277 @ vertical-align: bottom;
278 @ width: 100%;
279 @ }
280 @
@@ -392,32 +393,11 @@
393 @
394 @ div.miniform {
395 @ font-size: smaller;
396 @ margin: 8px;
397 @ }
398 @ /* additions to support creole parser */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
399 @
400 @ .creoletable {
401 @ border: 1px solid #666666;
402 @ border-spacing: 0;
403 @ margin: 1.5em 2em 1.8em 2em;
@@ -436,10 +416,24 @@
416 @ border-left: 1px solid #D9D9D9;
417 @ border-top: 1px solid #D9D9D9;
418 @ vertical-align: center;
419 @ empty-cells: show;
420 @ }
421 @ .creole-nowiki {
422 @ background: oldlace;
423 @ }
424 @ .creole-inline-nowiki {
425 @ background: oldlace;
426 @ }
427 @ .creole-image {
428 @ color:green;
429 @ border:1px solid green;
430 @ }
431 @ .creole-nomacro {
432 @ color:red;
433 @ border:1px solid red;
434 @ }
435 ;
436
437 /*
438 ** WEBPAGE: style.css
439 */
440
+20 -26
--- src/style.c
+++ src/style.c
@@ -143,11 +143,11 @@
143143
@ <div class="content">
144144
cgi_destination(CGI_BODY);
145145
146146
/* Put the footer at the bottom of the page.
147147
*/
148
- @ </div>
148
+ @ </div><br clear="both"></br>
149149
zFooter = db_get("footer", (char*)zDefaultFooter);
150150
if( g.thTrace ) Th_Trace("BEGIN_FOOTER<br />\n", -1);
151151
Th_Render(zFooter);
152152
if( g.thTrace ) Th_Trace("END_FOOTER<br />\n", -1);
153153
@@ -191,12 +191,12 @@
191191
@ media="screen">
192192
@ </head>
193193
@ <body>
194194
@ <div class="header">
195195
@ <div class="logo">
196
-@ <!-- <img src="logo.gif" alt="logo"><br></br> -->
197
-@ <nobr>$<project_name></nobr>
196
+@ <img src="/logo" alt="logo">
197
+@ <br><nobr>$<project_name></nobr>
198198
@ </div>
199199
@ <div class="title">$<title></div>
200200
@ <div class="status"><nobr><th1>
201201
@ if {[info exists login]} {
202202
@ puts "Logged in as $login"
@@ -269,11 +269,12 @@
269269
@ /* The page title centered at the top of each page */
270270
@ div.title {
271271
@ display: table-cell;
272272
@ font-size: 2em;
273273
@ font-weight: bold;
274
-@ text-align: center;
274
+@ text-align: left;
275
+@ padding: 0 0 0 1em;
275276
@ color: #558195;
276277
@ vertical-align: bottom;
277278
@ width: 100%;
278279
@ }
279280
@
@@ -392,32 +393,11 @@
392393
@
393394
@ div.miniform {
394395
@ font-size: smaller;
395396
@ margin: 8px;
396397
@ }
397
-@ table.fossil_db_generic_query_view {
398
-@ border-spacing: 0px;
399
-@ border: 1px solid black;
400
-@ }
401
-@ table.fossil_db_generic_query_view td {
402
-@ padding: 2px 1em 2px 1em;
403
-@ }
404
-@ table.fossil_db_generic_query_view tr {
405
-@ }
406
-@ table.fossil_db_generic_query_view tr.even {
407
-@ background: #ffffff;
408
-@ }
409
-@ table.fossil_db_generic_query_view tr.odd {
410
-@ background: #e5e5e5;
411
-@ }
412
-@ table.fossil_db_generic_query_view tr.header {
413
-@ background: #558195;
414
-@ font-size: 1.5em;
415
-@ color: #ffffff;
416
-@ }
417
-@
418
-@ /* addeitions to support creole parser */
398
+@ /* additions to support creole parser */
419399
@
420400
@ .creoletable {
421401
@ border: 1px solid #666666;
422402
@ border-spacing: 0;
423403
@ margin: 1.5em 2em 1.8em 2em;
@@ -436,10 +416,24 @@
436416
@ border-left: 1px solid #D9D9D9;
437417
@ border-top: 1px solid #D9D9D9;
438418
@ vertical-align: center;
439419
@ empty-cells: show;
440420
@ }
421
+@ .creole-nowiki {
422
+@ background: oldlace;
423
+@ }
424
+@ .creole-inline-nowiki {
425
+@ background: oldlace;
426
+@ }
427
+@ .creole-image {
428
+@ color:green;
429
+@ border:1px solid green;
430
+@ }
431
+@ .creole-nomacro {
432
+@ color:red;
433
+@ border:1px solid red;
434
+@ }
441435
;
442436
443437
/*
444438
** WEBPAGE: style.css
445439
*/
446440
--- src/style.c
+++ src/style.c
@@ -143,11 +143,11 @@
143 @ <div class="content">
144 cgi_destination(CGI_BODY);
145
146 /* Put the footer at the bottom of the page.
147 */
148 @ </div>
149 zFooter = db_get("footer", (char*)zDefaultFooter);
150 if( g.thTrace ) Th_Trace("BEGIN_FOOTER<br />\n", -1);
151 Th_Render(zFooter);
152 if( g.thTrace ) Th_Trace("END_FOOTER<br />\n", -1);
153
@@ -191,12 +191,12 @@
191 @ media="screen">
192 @ </head>
193 @ <body>
194 @ <div class="header">
195 @ <div class="logo">
196 @ <!-- <img src="logo.gif" alt="logo"><br></br> -->
197 @ <nobr>$<project_name></nobr>
198 @ </div>
199 @ <div class="title">$<title></div>
200 @ <div class="status"><nobr><th1>
201 @ if {[info exists login]} {
202 @ puts "Logged in as $login"
@@ -269,11 +269,12 @@
269 @ /* The page title centered at the top of each page */
270 @ div.title {
271 @ display: table-cell;
272 @ font-size: 2em;
273 @ font-weight: bold;
274 @ text-align: center;
 
275 @ color: #558195;
276 @ vertical-align: bottom;
277 @ width: 100%;
278 @ }
279 @
@@ -392,32 +393,11 @@
392 @
393 @ div.miniform {
394 @ font-size: smaller;
395 @ margin: 8px;
396 @ }
397 @ table.fossil_db_generic_query_view {
398 @ border-spacing: 0px;
399 @ border: 1px solid black;
400 @ }
401 @ table.fossil_db_generic_query_view td {
402 @ padding: 2px 1em 2px 1em;
403 @ }
404 @ table.fossil_db_generic_query_view tr {
405 @ }
406 @ table.fossil_db_generic_query_view tr.even {
407 @ background: #ffffff;
408 @ }
409 @ table.fossil_db_generic_query_view tr.odd {
410 @ background: #e5e5e5;
411 @ }
412 @ table.fossil_db_generic_query_view tr.header {
413 @ background: #558195;
414 @ font-size: 1.5em;
415 @ color: #ffffff;
416 @ }
417 @
418 @ /* addeitions to support creole parser */
419 @
420 @ .creoletable {
421 @ border: 1px solid #666666;
422 @ border-spacing: 0;
423 @ margin: 1.5em 2em 1.8em 2em;
@@ -436,10 +416,24 @@
436 @ border-left: 1px solid #D9D9D9;
437 @ border-top: 1px solid #D9D9D9;
438 @ vertical-align: center;
439 @ empty-cells: show;
440 @ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
441 ;
442
443 /*
444 ** WEBPAGE: style.css
445 */
446
--- src/style.c
+++ src/style.c
@@ -143,11 +143,11 @@
143 @ <div class="content">
144 cgi_destination(CGI_BODY);
145
146 /* Put the footer at the bottom of the page.
147 */
148 @ </div><br clear="both"></br>
149 zFooter = db_get("footer", (char*)zDefaultFooter);
150 if( g.thTrace ) Th_Trace("BEGIN_FOOTER<br />\n", -1);
151 Th_Render(zFooter);
152 if( g.thTrace ) Th_Trace("END_FOOTER<br />\n", -1);
153
@@ -191,12 +191,12 @@
191 @ media="screen">
192 @ </head>
193 @ <body>
194 @ <div class="header">
195 @ <div class="logo">
196 @ <img src="/logo" alt="logo">
197 @ <br><nobr>$<project_name></nobr>
198 @ </div>
199 @ <div class="title">$<title></div>
200 @ <div class="status"><nobr><th1>
201 @ if {[info exists login]} {
202 @ puts "Logged in as $login"
@@ -269,11 +269,12 @@
269 @ /* The page title centered at the top of each page */
270 @ div.title {
271 @ display: table-cell;
272 @ font-size: 2em;
273 @ font-weight: bold;
274 @ text-align: left;
275 @ padding: 0 0 0 1em;
276 @ color: #558195;
277 @ vertical-align: bottom;
278 @ width: 100%;
279 @ }
280 @
@@ -392,32 +393,11 @@
393 @
394 @ div.miniform {
395 @ font-size: smaller;
396 @ margin: 8px;
397 @ }
398 @ /* additions to support creole parser */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
399 @
400 @ .creoletable {
401 @ border: 1px solid #666666;
402 @ border-spacing: 0;
403 @ margin: 1.5em 2em 1.8em 2em;
@@ -436,10 +416,24 @@
416 @ border-left: 1px solid #D9D9D9;
417 @ border-top: 1px solid #D9D9D9;
418 @ vertical-align: center;
419 @ empty-cells: show;
420 @ }
421 @ .creole-nowiki {
422 @ background: oldlace;
423 @ }
424 @ .creole-inline-nowiki {
425 @ background: oldlace;
426 @ }
427 @ .creole-image {
428 @ color:green;
429 @ border:1px solid green;
430 @ }
431 @ .creole-nomacro {
432 @ color:red;
433 @ border:1px solid red;
434 @ }
435 ;
436
437 /*
438 ** WEBPAGE: style.css
439 */
440
+1 -1
--- src/tktsetup.c
+++ src/tktsetup.c
@@ -363,11 +363,11 @@
363363
@ <tr><td align="right">Ticket&nbsp;UUID:</td><td bgcolor="#d0d0d0" colspan="3">
364364
@ $<tkt_uuid>
365365
@ </td></tr>
366366
@ <tr><td align="right">Title:</td>
367367
@ <td bgcolor="#d0d0d0" colspan="3" valign="top">
368
-@ $<title>
368
+@ <th1>wiki $title</th1>
369369
@ </td></tr>
370370
@ <tr><td align="right">Status:</td><td bgcolor="#d0d0d0">
371371
@ $<status>
372372
@ </td>
373373
@ <td align="right">Type:</td><td bgcolor="#d0d0d0">
374374
--- src/tktsetup.c
+++ src/tktsetup.c
@@ -363,11 +363,11 @@
363 @ <tr><td align="right">Ticket&nbsp;UUID:</td><td bgcolor="#d0d0d0" colspan="3">
364 @ $<tkt_uuid>
365 @ </td></tr>
366 @ <tr><td align="right">Title:</td>
367 @ <td bgcolor="#d0d0d0" colspan="3" valign="top">
368 @ $<title>
369 @ </td></tr>
370 @ <tr><td align="right">Status:</td><td bgcolor="#d0d0d0">
371 @ $<status>
372 @ </td>
373 @ <td align="right">Type:</td><td bgcolor="#d0d0d0">
374
--- src/tktsetup.c
+++ src/tktsetup.c
@@ -363,11 +363,11 @@
363 @ <tr><td align="right">Ticket&nbsp;UUID:</td><td bgcolor="#d0d0d0" colspan="3">
364 @ $<tkt_uuid>
365 @ </td></tr>
366 @ <tr><td align="right">Title:</td>
367 @ <td bgcolor="#d0d0d0" colspan="3" valign="top">
368 @ <th1>wiki $title</th1>
369 @ </td></tr>
370 @ <tr><td align="right">Status:</td><td bgcolor="#d0d0d0">
371 @ $<status>
372 @ </td>
373 @ <td align="right">Type:</td><td bgcolor="#d0d0d0">
374
+1 -1
--- src/tktsetup.c
+++ src/tktsetup.c
@@ -363,11 +363,11 @@
363363
@ <tr><td align="right">Ticket&nbsp;UUID:</td><td bgcolor="#d0d0d0" colspan="3">
364364
@ $<tkt_uuid>
365365
@ </td></tr>
366366
@ <tr><td align="right">Title:</td>
367367
@ <td bgcolor="#d0d0d0" colspan="3" valign="top">
368
-@ $<title>
368
+@ <th1>wiki $title</th1>
369369
@ </td></tr>
370370
@ <tr><td align="right">Status:</td><td bgcolor="#d0d0d0">
371371
@ $<status>
372372
@ </td>
373373
@ <td align="right">Type:</td><td bgcolor="#d0d0d0">
374374
--- src/tktsetup.c
+++ src/tktsetup.c
@@ -363,11 +363,11 @@
363 @ <tr><td align="right">Ticket&nbsp;UUID:</td><td bgcolor="#d0d0d0" colspan="3">
364 @ $<tkt_uuid>
365 @ </td></tr>
366 @ <tr><td align="right">Title:</td>
367 @ <td bgcolor="#d0d0d0" colspan="3" valign="top">
368 @ $<title>
369 @ </td></tr>
370 @ <tr><td align="right">Status:</td><td bgcolor="#d0d0d0">
371 @ $<status>
372 @ </td>
373 @ <td align="right">Type:</td><td bgcolor="#d0d0d0">
374
--- src/tktsetup.c
+++ src/tktsetup.c
@@ -363,11 +363,11 @@
363 @ <tr><td align="right">Ticket&nbsp;UUID:</td><td bgcolor="#d0d0d0" colspan="3">
364 @ $<tkt_uuid>
365 @ </td></tr>
366 @ <tr><td align="right">Title:</td>
367 @ <td bgcolor="#d0d0d0" colspan="3" valign="top">
368 @ <th1>wiki $title</th1>
369 @ </td></tr>
370 @ <tr><td align="right">Status:</td><td bgcolor="#d0d0d0">
371 @ $<status>
372 @ </td>
373 @ <td align="right">Type:</td><td bgcolor="#d0d0d0">
374
+2
--- src/url.c
+++ src/url.c
@@ -65,12 +65,14 @@
6565
}
6666
for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!='@'; i++){}
6767
if( c=='@' ){
6868
for(j=iStart; j<i && zUrl[j]!=':'; j++){}
6969
g.urlUser = mprintf("%.*s", j-iStart, &zUrl[iStart]);
70
+ dehttpize(g.urlUser);
7071
if( j<i ){
7172
g.urlPasswd = mprintf("%.*s", i-j-1, &zUrl[j+1]);
73
+ dehttpize(g.urlPasswd);
7274
}
7375
for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){}
7476
g.urlName = mprintf("%.*s", j-i-1, &zUrl[i+1]);
7577
i = j;
7678
}else{
7779
--- src/url.c
+++ src/url.c
@@ -65,12 +65,14 @@
65 }
66 for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!='@'; i++){}
67 if( c=='@' ){
68 for(j=iStart; j<i && zUrl[j]!=':'; j++){}
69 g.urlUser = mprintf("%.*s", j-iStart, &zUrl[iStart]);
 
70 if( j<i ){
71 g.urlPasswd = mprintf("%.*s", i-j-1, &zUrl[j+1]);
 
72 }
73 for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){}
74 g.urlName = mprintf("%.*s", j-i-1, &zUrl[i+1]);
75 i = j;
76 }else{
77
--- src/url.c
+++ src/url.c
@@ -65,12 +65,14 @@
65 }
66 for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!='@'; i++){}
67 if( c=='@' ){
68 for(j=iStart; j<i && zUrl[j]!=':'; j++){}
69 g.urlUser = mprintf("%.*s", j-iStart, &zUrl[iStart]);
70 dehttpize(g.urlUser);
71 if( j<i ){
72 g.urlPasswd = mprintf("%.*s", i-j-1, &zUrl[j+1]);
73 dehttpize(g.urlPasswd);
74 }
75 for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){}
76 g.urlName = mprintf("%.*s", j-i-1, &zUrl[i+1]);
77 i = j;
78 }else{
79
+2
--- src/url.c
+++ src/url.c
@@ -65,12 +65,14 @@
6565
}
6666
for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!='@'; i++){}
6767
if( c=='@' ){
6868
for(j=iStart; j<i && zUrl[j]!=':'; j++){}
6969
g.urlUser = mprintf("%.*s", j-iStart, &zUrl[iStart]);
70
+ dehttpize(g.urlUser);
7071
if( j<i ){
7172
g.urlPasswd = mprintf("%.*s", i-j-1, &zUrl[j+1]);
73
+ dehttpize(g.urlPasswd);
7274
}
7375
for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){}
7476
g.urlName = mprintf("%.*s", j-i-1, &zUrl[i+1]);
7577
i = j;
7678
}else{
7779
--- src/url.c
+++ src/url.c
@@ -65,12 +65,14 @@
65 }
66 for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!='@'; i++){}
67 if( c=='@' ){
68 for(j=iStart; j<i && zUrl[j]!=':'; j++){}
69 g.urlUser = mprintf("%.*s", j-iStart, &zUrl[iStart]);
 
70 if( j<i ){
71 g.urlPasswd = mprintf("%.*s", i-j-1, &zUrl[j+1]);
 
72 }
73 for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){}
74 g.urlName = mprintf("%.*s", j-i-1, &zUrl[i+1]);
75 i = j;
76 }else{
77
--- src/url.c
+++ src/url.c
@@ -65,12 +65,14 @@
65 }
66 for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!='@'; i++){}
67 if( c=='@' ){
68 for(j=iStart; j<i && zUrl[j]!=':'; j++){}
69 g.urlUser = mprintf("%.*s", j-iStart, &zUrl[iStart]);
70 dehttpize(g.urlUser);
71 if( j<i ){
72 g.urlPasswd = mprintf("%.*s", i-j-1, &zUrl[j+1]);
73 dehttpize(g.urlPasswd);
74 }
75 for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){}
76 g.urlName = mprintf("%.*s", j-i-1, &zUrl[i+1]);
77 i = j;
78 }else{
79
+28 -19
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -1022,11 +1022,10 @@
10221022
static int stackTopType(Renderer *p){
10231023
if( p->nStack<=0 ) return 0;
10241024
return aMarkup[p->aStack[p->nStack-1].iCode].iType;
10251025
}
10261026
1027
-
10281027
/*
10291028
** Convert the wiki in z[] into html in the renderer p. The
10301029
** renderer has already been initialized.
10311030
**
10321031
** This routine will probably modify the content of z[].
@@ -1038,24 +1037,22 @@
10381037
int inlineOnly = (p->state & INLINE_MARKUP_ONLY)!=0;
10391038
10401039
while( z[0] ){
10411040
10421041
/*
1043
- ** Additions to support creole parser
1042
+ ** Additions to support macro extensions
10441043
*/
10451044
10461045
if (!p->inVerbatim && z[0]=='<' && z[1] == '<') {
10471046
z = wiki_render_macro(p, z, &tokenType);
10481047
if (tokenType) continue;
10491048
}
1050
- //
1049
+ /* end additions */
10511050
10521051
n = nextToken(z, p, &tokenType);
10531052
p->state &= ~(AT_NEWLINE|AT_PARAGRAPH);
1054
-
10551053
switch( tokenType ){
1056
-
10571054
case TOKEN_PARAGRAPH: {
10581055
if( inlineOnly ){
10591056
/* blob_append(p->pOut, " &para; ", -1); */
10601057
blob_append(p->pOut, " &nbsp;&nbsp; ", -1);
10611058
}else{
@@ -1227,23 +1224,23 @@
12271224
*/
12281225
if( (markup.iType&MUTYPE_FONT)==0 && (p->state & FONT_MARKUP_ONLY)!=0 ){
12291226
/* Do nothing */
12301227
}else
12311228
1232
- /* Ignore block markup for in-line rendering.
1233
- */
1234
- if( inlineOnly && (markup.iType&MUTYPE_INLINE)==0 ){
1235
- /* Do nothing */
1236
- }else
1237
-
12381229
if( markup.iCode==MARKUP_NOWIKI ){
12391230
if( markup.endTag ){
12401231
p->state |= ALLOW_WIKI;
12411232
}else{
12421233
p->state &= ~ALLOW_WIKI;
12431234
}
12441235
}else
1236
+
1237
+ /* Ignore block markup for in-line rendering.
1238
+ */
1239
+ if( inlineOnly && (markup.iType&MUTYPE_INLINE)==0 ){
1240
+ /* Do nothing */
1241
+ }else
12451242
12461243
/* Generate end-tags */
12471244
if( markup.endTag ){
12481245
popStackToTag(p, markup.iCode);
12491246
}else
@@ -1355,11 +1352,10 @@
13551352
}
13561353
blob_append(renderer.pOut, "\n", 1);
13571354
free(renderer.aStack);
13581355
}
13591356
1360
-
13611357
/*
13621358
** COMMAND: test-wiki-render
13631359
*/
13641360
void test_wiki_render(void){
13651361
Blob in, out;
@@ -1394,21 +1390,35 @@
13941390
blob_init(pTitle, &z[iStart], i-iStart);
13951391
blob_init(pTail, &z[i+8], -1);
13961392
return 1;
13971393
}
13981394
1399
-
14001395
/*
1401
-** Additions to support creole parser
1396
+** Additions to support macro extensions
1397
+**
1398
+** This only allows block level macros, not inline macros
1399
+**
1400
+** All macros must recognize '<<fossil>>' in the input
1401
+** stream and return control to fossil.
14021402
*/
14031403
1404
-#ifndef HAVE_MACRO_EXTENSIONS
1405
-char *wiki_render_macro(Renderer *p, char *z, int *tokenType) {
1404
+char *wiki_render_macro(Renderer *p, char *z, int *tokenType){
1405
+ if (!memcmp(z, "<<fossil>>", 10)){
1406
+ *tokenType = 1;
1407
+ return z + 10;
1408
+ }
1409
+
1410
+#ifdef HAVE_CREOLE_MACRO
1411
+ if (!memcmp(z, "<<creole>>", 10)) {
1412
+ *tokenType = 1;
1413
+ return wiki_render_creole(p, z+10);
1414
+ }
1415
+#endif
1416
+
14061417
*tokenType = 0;
14071418
return z;
14081419
}
1409
-#endif
14101420
14111421
int wf_linkLength(const char *z){
14121422
return linkLength(z);
14131423
}
14141424
void wf_openHyperlink(
@@ -1417,7 +1427,6 @@
14171427
char *zClose, /* Write hyperlink closing text here */
14181428
int nClose /* Bytes available in zClose[] */
14191429
){
14201430
return openHyperlink(p, zTarget, zClose, nClose);
14211431
}
1422
-
1423
-
1432
+/* end additions */
14241433
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -1022,11 +1022,10 @@
1022 static int stackTopType(Renderer *p){
1023 if( p->nStack<=0 ) return 0;
1024 return aMarkup[p->aStack[p->nStack-1].iCode].iType;
1025 }
1026
1027
1028 /*
1029 ** Convert the wiki in z[] into html in the renderer p. The
1030 ** renderer has already been initialized.
1031 **
1032 ** This routine will probably modify the content of z[].
@@ -1038,24 +1037,22 @@
1038 int inlineOnly = (p->state & INLINE_MARKUP_ONLY)!=0;
1039
1040 while( z[0] ){
1041
1042 /*
1043 ** Additions to support creole parser
1044 */
1045
1046 if (!p->inVerbatim && z[0]=='<' && z[1] == '<') {
1047 z = wiki_render_macro(p, z, &tokenType);
1048 if (tokenType) continue;
1049 }
1050 //
1051
1052 n = nextToken(z, p, &tokenType);
1053 p->state &= ~(AT_NEWLINE|AT_PARAGRAPH);
1054
1055 switch( tokenType ){
1056
1057 case TOKEN_PARAGRAPH: {
1058 if( inlineOnly ){
1059 /* blob_append(p->pOut, " &para; ", -1); */
1060 blob_append(p->pOut, " &nbsp;&nbsp; ", -1);
1061 }else{
@@ -1227,23 +1224,23 @@
1227 */
1228 if( (markup.iType&MUTYPE_FONT)==0 && (p->state & FONT_MARKUP_ONLY)!=0 ){
1229 /* Do nothing */
1230 }else
1231
1232 /* Ignore block markup for in-line rendering.
1233 */
1234 if( inlineOnly && (markup.iType&MUTYPE_INLINE)==0 ){
1235 /* Do nothing */
1236 }else
1237
1238 if( markup.iCode==MARKUP_NOWIKI ){
1239 if( markup.endTag ){
1240 p->state |= ALLOW_WIKI;
1241 }else{
1242 p->state &= ~ALLOW_WIKI;
1243 }
1244 }else
 
 
 
 
 
 
1245
1246 /* Generate end-tags */
1247 if( markup.endTag ){
1248 popStackToTag(p, markup.iCode);
1249 }else
@@ -1355,11 +1352,10 @@
1355 }
1356 blob_append(renderer.pOut, "\n", 1);
1357 free(renderer.aStack);
1358 }
1359
1360
1361 /*
1362 ** COMMAND: test-wiki-render
1363 */
1364 void test_wiki_render(void){
1365 Blob in, out;
@@ -1394,21 +1390,35 @@
1394 blob_init(pTitle, &z[iStart], i-iStart);
1395 blob_init(pTail, &z[i+8], -1);
1396 return 1;
1397 }
1398
1399
1400 /*
1401 ** Additions to support creole parser
 
 
 
 
 
1402 */
1403
1404 #ifndef HAVE_MACRO_EXTENSIONS
1405 char *wiki_render_macro(Renderer *p, char *z, int *tokenType) {
 
 
 
 
 
 
 
 
 
 
 
1406 *tokenType = 0;
1407 return z;
1408 }
1409 #endif
1410
1411 int wf_linkLength(const char *z){
1412 return linkLength(z);
1413 }
1414 void wf_openHyperlink(
@@ -1417,7 +1427,6 @@
1417 char *zClose, /* Write hyperlink closing text here */
1418 int nClose /* Bytes available in zClose[] */
1419 ){
1420 return openHyperlink(p, zTarget, zClose, nClose);
1421 }
1422
1423
1424
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -1022,11 +1022,10 @@
1022 static int stackTopType(Renderer *p){
1023 if( p->nStack<=0 ) return 0;
1024 return aMarkup[p->aStack[p->nStack-1].iCode].iType;
1025 }
1026
 
1027 /*
1028 ** Convert the wiki in z[] into html in the renderer p. The
1029 ** renderer has already been initialized.
1030 **
1031 ** This routine will probably modify the content of z[].
@@ -1038,24 +1037,22 @@
1037 int inlineOnly = (p->state & INLINE_MARKUP_ONLY)!=0;
1038
1039 while( z[0] ){
1040
1041 /*
1042 ** Additions to support macro extensions
1043 */
1044
1045 if (!p->inVerbatim && z[0]=='<' && z[1] == '<') {
1046 z = wiki_render_macro(p, z, &tokenType);
1047 if (tokenType) continue;
1048 }
1049 /* end additions */
1050
1051 n = nextToken(z, p, &tokenType);
1052 p->state &= ~(AT_NEWLINE|AT_PARAGRAPH);
 
1053 switch( tokenType ){
 
1054 case TOKEN_PARAGRAPH: {
1055 if( inlineOnly ){
1056 /* blob_append(p->pOut, " &para; ", -1); */
1057 blob_append(p->pOut, " &nbsp;&nbsp; ", -1);
1058 }else{
@@ -1227,23 +1224,23 @@
1224 */
1225 if( (markup.iType&MUTYPE_FONT)==0 && (p->state & FONT_MARKUP_ONLY)!=0 ){
1226 /* Do nothing */
1227 }else
1228
 
 
 
 
 
 
1229 if( markup.iCode==MARKUP_NOWIKI ){
1230 if( markup.endTag ){
1231 p->state |= ALLOW_WIKI;
1232 }else{
1233 p->state &= ~ALLOW_WIKI;
1234 }
1235 }else
1236
1237 /* Ignore block markup for in-line rendering.
1238 */
1239 if( inlineOnly && (markup.iType&MUTYPE_INLINE)==0 ){
1240 /* Do nothing */
1241 }else
1242
1243 /* Generate end-tags */
1244 if( markup.endTag ){
1245 popStackToTag(p, markup.iCode);
1246 }else
@@ -1355,11 +1352,10 @@
1352 }
1353 blob_append(renderer.pOut, "\n", 1);
1354 free(renderer.aStack);
1355 }
1356
 
1357 /*
1358 ** COMMAND: test-wiki-render
1359 */
1360 void test_wiki_render(void){
1361 Blob in, out;
@@ -1394,21 +1390,35 @@
1390 blob_init(pTitle, &z[iStart], i-iStart);
1391 blob_init(pTail, &z[i+8], -1);
1392 return 1;
1393 }
1394
 
1395 /*
1396 ** Additions to support macro extensions
1397 **
1398 ** This only allows block level macros, not inline macros
1399 **
1400 ** All macros must recognize '<<fossil>>' in the input
1401 ** stream and return control to fossil.
1402 */
1403
1404 char *wiki_render_macro(Renderer *p, char *z, int *tokenType){
1405 if (!memcmp(z, "<<fossil>>", 10)){
1406 *tokenType = 1;
1407 return z + 10;
1408 }
1409
1410 #ifdef HAVE_CREOLE_MACRO
1411 if (!memcmp(z, "<<creole>>", 10)) {
1412 *tokenType = 1;
1413 return wiki_render_creole(p, z+10);
1414 }
1415 #endif
1416
1417 *tokenType = 0;
1418 return z;
1419 }
 
1420
1421 int wf_linkLength(const char *z){
1422 return linkLength(z);
1423 }
1424 void wf_openHyperlink(
@@ -1417,7 +1427,6 @@
1427 char *zClose, /* Write hyperlink closing text here */
1428 int nClose /* Bytes available in zClose[] */
1429 ){
1430 return openHyperlink(p, zTarget, zClose, nClose);
1431 }
1432 /* end additions */
 
1433
+28 -19
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -1022,11 +1022,10 @@
10221022
static int stackTopType(Renderer *p){
10231023
if( p->nStack<=0 ) return 0;
10241024
return aMarkup[p->aStack[p->nStack-1].iCode].iType;
10251025
}
10261026
1027
-
10281027
/*
10291028
** Convert the wiki in z[] into html in the renderer p. The
10301029
** renderer has already been initialized.
10311030
**
10321031
** This routine will probably modify the content of z[].
@@ -1038,24 +1037,22 @@
10381037
int inlineOnly = (p->state & INLINE_MARKUP_ONLY)!=0;
10391038
10401039
while( z[0] ){
10411040
10421041
/*
1043
- ** Additions to support creole parser
1042
+ ** Additions to support macro extensions
10441043
*/
10451044
10461045
if (!p->inVerbatim && z[0]=='<' && z[1] == '<') {
10471046
z = wiki_render_macro(p, z, &tokenType);
10481047
if (tokenType) continue;
10491048
}
1050
- //
1049
+ /* end additions */
10511050
10521051
n = nextToken(z, p, &tokenType);
10531052
p->state &= ~(AT_NEWLINE|AT_PARAGRAPH);
1054
-
10551053
switch( tokenType ){
1056
-
10571054
case TOKEN_PARAGRAPH: {
10581055
if( inlineOnly ){
10591056
/* blob_append(p->pOut, " &para; ", -1); */
10601057
blob_append(p->pOut, " &nbsp;&nbsp; ", -1);
10611058
}else{
@@ -1227,23 +1224,23 @@
12271224
*/
12281225
if( (markup.iType&MUTYPE_FONT)==0 && (p->state & FONT_MARKUP_ONLY)!=0 ){
12291226
/* Do nothing */
12301227
}else
12311228
1232
- /* Ignore block markup for in-line rendering.
1233
- */
1234
- if( inlineOnly && (markup.iType&MUTYPE_INLINE)==0 ){
1235
- /* Do nothing */
1236
- }else
1237
-
12381229
if( markup.iCode==MARKUP_NOWIKI ){
12391230
if( markup.endTag ){
12401231
p->state |= ALLOW_WIKI;
12411232
}else{
12421233
p->state &= ~ALLOW_WIKI;
12431234
}
12441235
}else
1236
+
1237
+ /* Ignore block markup for in-line rendering.
1238
+ */
1239
+ if( inlineOnly && (markup.iType&MUTYPE_INLINE)==0 ){
1240
+ /* Do nothing */
1241
+ }else
12451242
12461243
/* Generate end-tags */
12471244
if( markup.endTag ){
12481245
popStackToTag(p, markup.iCode);
12491246
}else
@@ -1355,11 +1352,10 @@
13551352
}
13561353
blob_append(renderer.pOut, "\n", 1);
13571354
free(renderer.aStack);
13581355
}
13591356
1360
-
13611357
/*
13621358
** COMMAND: test-wiki-render
13631359
*/
13641360
void test_wiki_render(void){
13651361
Blob in, out;
@@ -1394,21 +1390,35 @@
13941390
blob_init(pTitle, &z[iStart], i-iStart);
13951391
blob_init(pTail, &z[i+8], -1);
13961392
return 1;
13971393
}
13981394
1399
-
14001395
/*
1401
-** Additions to support creole parser
1396
+** Additions to support macro extensions
1397
+**
1398
+** This only allows block level macros, not inline macros
1399
+**
1400
+** All macros must recognize '<<fossil>>' in the input
1401
+** stream and return control to fossil.
14021402
*/
14031403
1404
-#ifndef HAVE_MACRO_EXTENSIONS
1405
-char *wiki_render_macro(Renderer *p, char *z, int *tokenType) {
1404
+char *wiki_render_macro(Renderer *p, char *z, int *tokenType){
1405
+ if (!memcmp(z, "<<fossil>>", 10)){
1406
+ *tokenType = 1;
1407
+ return z + 10;
1408
+ }
1409
+
1410
+#ifdef HAVE_CREOLE_MACRO
1411
+ if (!memcmp(z, "<<creole>>", 10)) {
1412
+ *tokenType = 1;
1413
+ return wiki_render_creole(p, z+10);
1414
+ }
1415
+#endif
1416
+
14061417
*tokenType = 0;
14071418
return z;
14081419
}
1409
-#endif
14101420
14111421
int wf_linkLength(const char *z){
14121422
return linkLength(z);
14131423
}
14141424
void wf_openHyperlink(
@@ -1417,7 +1427,6 @@
14171427
char *zClose, /* Write hyperlink closing text here */
14181428
int nClose /* Bytes available in zClose[] */
14191429
){
14201430
return openHyperlink(p, zTarget, zClose, nClose);
14211431
}
1422
-
1423
-
1432
+/* end additions */
14241433
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -1022,11 +1022,10 @@
1022 static int stackTopType(Renderer *p){
1023 if( p->nStack<=0 ) return 0;
1024 return aMarkup[p->aStack[p->nStack-1].iCode].iType;
1025 }
1026
1027
1028 /*
1029 ** Convert the wiki in z[] into html in the renderer p. The
1030 ** renderer has already been initialized.
1031 **
1032 ** This routine will probably modify the content of z[].
@@ -1038,24 +1037,22 @@
1038 int inlineOnly = (p->state & INLINE_MARKUP_ONLY)!=0;
1039
1040 while( z[0] ){
1041
1042 /*
1043 ** Additions to support creole parser
1044 */
1045
1046 if (!p->inVerbatim && z[0]=='<' && z[1] == '<') {
1047 z = wiki_render_macro(p, z, &tokenType);
1048 if (tokenType) continue;
1049 }
1050 //
1051
1052 n = nextToken(z, p, &tokenType);
1053 p->state &= ~(AT_NEWLINE|AT_PARAGRAPH);
1054
1055 switch( tokenType ){
1056
1057 case TOKEN_PARAGRAPH: {
1058 if( inlineOnly ){
1059 /* blob_append(p->pOut, " &para; ", -1); */
1060 blob_append(p->pOut, " &nbsp;&nbsp; ", -1);
1061 }else{
@@ -1227,23 +1224,23 @@
1227 */
1228 if( (markup.iType&MUTYPE_FONT)==0 && (p->state & FONT_MARKUP_ONLY)!=0 ){
1229 /* Do nothing */
1230 }else
1231
1232 /* Ignore block markup for in-line rendering.
1233 */
1234 if( inlineOnly && (markup.iType&MUTYPE_INLINE)==0 ){
1235 /* Do nothing */
1236 }else
1237
1238 if( markup.iCode==MARKUP_NOWIKI ){
1239 if( markup.endTag ){
1240 p->state |= ALLOW_WIKI;
1241 }else{
1242 p->state &= ~ALLOW_WIKI;
1243 }
1244 }else
 
 
 
 
 
 
1245
1246 /* Generate end-tags */
1247 if( markup.endTag ){
1248 popStackToTag(p, markup.iCode);
1249 }else
@@ -1355,11 +1352,10 @@
1355 }
1356 blob_append(renderer.pOut, "\n", 1);
1357 free(renderer.aStack);
1358 }
1359
1360
1361 /*
1362 ** COMMAND: test-wiki-render
1363 */
1364 void test_wiki_render(void){
1365 Blob in, out;
@@ -1394,21 +1390,35 @@
1394 blob_init(pTitle, &z[iStart], i-iStart);
1395 blob_init(pTail, &z[i+8], -1);
1396 return 1;
1397 }
1398
1399
1400 /*
1401 ** Additions to support creole parser
 
 
 
 
 
1402 */
1403
1404 #ifndef HAVE_MACRO_EXTENSIONS
1405 char *wiki_render_macro(Renderer *p, char *z, int *tokenType) {
 
 
 
 
 
 
 
 
 
 
 
1406 *tokenType = 0;
1407 return z;
1408 }
1409 #endif
1410
1411 int wf_linkLength(const char *z){
1412 return linkLength(z);
1413 }
1414 void wf_openHyperlink(
@@ -1417,7 +1427,6 @@
1417 char *zClose, /* Write hyperlink closing text here */
1418 int nClose /* Bytes available in zClose[] */
1419 ){
1420 return openHyperlink(p, zTarget, zClose, nClose);
1421 }
1422
1423
1424
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -1022,11 +1022,10 @@
1022 static int stackTopType(Renderer *p){
1023 if( p->nStack<=0 ) return 0;
1024 return aMarkup[p->aStack[p->nStack-1].iCode].iType;
1025 }
1026
 
1027 /*
1028 ** Convert the wiki in z[] into html in the renderer p. The
1029 ** renderer has already been initialized.
1030 **
1031 ** This routine will probably modify the content of z[].
@@ -1038,24 +1037,22 @@
1037 int inlineOnly = (p->state & INLINE_MARKUP_ONLY)!=0;
1038
1039 while( z[0] ){
1040
1041 /*
1042 ** Additions to support macro extensions
1043 */
1044
1045 if (!p->inVerbatim && z[0]=='<' && z[1] == '<') {
1046 z = wiki_render_macro(p, z, &tokenType);
1047 if (tokenType) continue;
1048 }
1049 /* end additions */
1050
1051 n = nextToken(z, p, &tokenType);
1052 p->state &= ~(AT_NEWLINE|AT_PARAGRAPH);
 
1053 switch( tokenType ){
 
1054 case TOKEN_PARAGRAPH: {
1055 if( inlineOnly ){
1056 /* blob_append(p->pOut, " &para; ", -1); */
1057 blob_append(p->pOut, " &nbsp;&nbsp; ", -1);
1058 }else{
@@ -1227,23 +1224,23 @@
1224 */
1225 if( (markup.iType&MUTYPE_FONT)==0 && (p->state & FONT_MARKUP_ONLY)!=0 ){
1226 /* Do nothing */
1227 }else
1228
 
 
 
 
 
 
1229 if( markup.iCode==MARKUP_NOWIKI ){
1230 if( markup.endTag ){
1231 p->state |= ALLOW_WIKI;
1232 }else{
1233 p->state &= ~ALLOW_WIKI;
1234 }
1235 }else
1236
1237 /* Ignore block markup for in-line rendering.
1238 */
1239 if( inlineOnly && (markup.iType&MUTYPE_INLINE)==0 ){
1240 /* Do nothing */
1241 }else
1242
1243 /* Generate end-tags */
1244 if( markup.endTag ){
1245 popStackToTag(p, markup.iCode);
1246 }else
@@ -1355,11 +1352,10 @@
1352 }
1353 blob_append(renderer.pOut, "\n", 1);
1354 free(renderer.aStack);
1355 }
1356
 
1357 /*
1358 ** COMMAND: test-wiki-render
1359 */
1360 void test_wiki_render(void){
1361 Blob in, out;
@@ -1394,21 +1390,35 @@
1390 blob_init(pTitle, &z[iStart], i-iStart);
1391 blob_init(pTail, &z[i+8], -1);
1392 return 1;
1393 }
1394
 
1395 /*
1396 ** Additions to support macro extensions
1397 **
1398 ** This only allows block level macros, not inline macros
1399 **
1400 ** All macros must recognize '<<fossil>>' in the input
1401 ** stream and return control to fossil.
1402 */
1403
1404 char *wiki_render_macro(Renderer *p, char *z, int *tokenType){
1405 if (!memcmp(z, "<<fossil>>", 10)){
1406 *tokenType = 1;
1407 return z + 10;
1408 }
1409
1410 #ifdef HAVE_CREOLE_MACRO
1411 if (!memcmp(z, "<<creole>>", 10)) {
1412 *tokenType = 1;
1413 return wiki_render_creole(p, z+10);
1414 }
1415 #endif
1416
1417 *tokenType = 0;
1418 return z;
1419 }
 
1420
1421 int wf_linkLength(const char *z){
1422 return linkLength(z);
1423 }
1424 void wf_openHyperlink(
@@ -1417,7 +1427,6 @@
1427 char *zClose, /* Write hyperlink closing text here */
1428 int nClose /* Bytes available in zClose[] */
1429 ){
1430 return openHyperlink(p, zTarget, zClose, nClose);
1431 }
1432 /* end additions */
 
1433
+42 -15
--- src/xfer.c
+++ src/xfer.c
@@ -383,17 +383,19 @@
383383
** http_exchange() routine.
384384
*/
385385
void check_login(Blob *pLogin, Blob *pNonce, Blob *pSig){
386386
Stmt q;
387387
int rc = -1;
388
+ char *zLogin = blob_terminate(pLogin);
389
+ defossilize(zLogin);
388390
389391
db_prepare(&q,
390392
"SELECT pw, cap, uid FROM user"
391
- " WHERE login=%B"
393
+ " WHERE login=%Q"
392394
" AND login NOT IN ('anonymous','nobody','developer','reader')"
393395
" AND length(pw)>0",
394
- pLogin
396
+ zLogin
395397
);
396398
if( db_step(&q)==SQLITE_ROW ){
397399
Blob pw, combined, hash;
398400
blob_zero(&pw);
399401
db_ephemeral_blob(&q, 0, &pw);
@@ -521,15 +523,18 @@
521523
/*
522524
** Send a single config card for configuration item zName
523525
*/
524526
static void send_config_card(Xfer *pXfer, const char *zName){
525527
if( zName[0]!='@' ){
526
- char *zValue = db_get(zName, 0);
527
- if( zValue ){
528
- blob_appendf(pXfer->pOut, "config %s %d\n%s\n",
529
- zName, strlen(zValue), zValue);
530
- free(zValue);
528
+ Blob val;
529
+ blob_zero(&val);
530
+ db_blob(&val, "SELECT value FROM config WHERE name=%Q", zName);
531
+ if( blob_size(&val)>0 ){
532
+ blob_appendf(pXfer->pOut, "config %s %d\n", zName, blob_size(&val));
533
+ blob_append(pXfer->pOut, blob_buffer(&val), blob_size(&val));
534
+ blob_reset(&val);
535
+ blob_append(pXfer->pOut, "\n", 1);
531536
}
532537
}else{
533538
Blob content;
534539
blob_zero(&content);
535540
configure_render_special_name(zName, &content);
@@ -766,14 +771,25 @@
766771
@ error not\sauthorized\sto\spush\sconfiguration
767772
nErr++;
768773
break;
769774
}
770775
if( zName[0]!='@' ){
771
- db_multi_exec(
772
- "REPLACE INTO config(name,value) VALUES(%Q,%Q)",
773
- zName, blob_str(&content)
774
- );
776
+ if( strcmp(zName, "logo-image")==0 ){
777
+ Stmt ins;
778
+ db_prepare(&ins,
779
+ "REPLACE INTO config(name, value) VALUES(:name, :value)"
780
+ );
781
+ db_bind_text(&ins, ":name", zName);
782
+ db_bind_blob(&ins, ":value", &content);
783
+ db_step(&ins);
784
+ db_finalize(&ins);
785
+ }else{
786
+ db_multi_exec(
787
+ "REPLACE INTO config(name,value) VALUES(%Q,%Q)",
788
+ zName, blob_str(&content)
789
+ );
790
+ }
775791
}else{
776792
/* Notice that we are evaluating arbitrary SQL received from the
777793
** client. But this can only happen if the client has authenticated
778794
** as an administrator, so presumably we trust the client at this
779795
** point.
@@ -1128,14 +1144,25 @@
11281144
blob_zero(&content);
11291145
blob_extract(xfer.pIn, size, &content);
11301146
g.okAdmin = g.okRdAddr = 1;
11311147
if( configure_is_exportable(zName) & origConfigRcvMask ){
11321148
if( zName[0]!='@' ){
1133
- db_multi_exec(
1134
- "REPLACE INTO config(name,value) VALUES(%Q,%Q)",
1135
- zName, blob_str(&content)
1136
- );
1149
+ if( strcmp(zName, "logo-image")==0 ){
1150
+ Stmt ins;
1151
+ db_prepare(&ins,
1152
+ "REPLACE INTO config(name, value) VALUES(:name, :value)"
1153
+ );
1154
+ db_bind_text(&ins, ":name", zName);
1155
+ db_bind_blob(&ins, ":value", &content);
1156
+ db_step(&ins);
1157
+ db_finalize(&ins);
1158
+ }else{
1159
+ db_multi_exec(
1160
+ "REPLACE INTO config(name,value) VALUES(%Q,%Q)",
1161
+ zName, blob_str(&content)
1162
+ );
1163
+ }
11371164
}else{
11381165
/* Notice that we are evaluating arbitrary SQL received from the
11391166
** server. But this can only happen if we have specifically
11401167
** requested configuration information from the server, so
11411168
** presumably the operator trusts the server.
11421169
--- src/xfer.c
+++ src/xfer.c
@@ -383,17 +383,19 @@
383 ** http_exchange() routine.
384 */
385 void check_login(Blob *pLogin, Blob *pNonce, Blob *pSig){
386 Stmt q;
387 int rc = -1;
 
 
388
389 db_prepare(&q,
390 "SELECT pw, cap, uid FROM user"
391 " WHERE login=%B"
392 " AND login NOT IN ('anonymous','nobody','developer','reader')"
393 " AND length(pw)>0",
394 pLogin
395 );
396 if( db_step(&q)==SQLITE_ROW ){
397 Blob pw, combined, hash;
398 blob_zero(&pw);
399 db_ephemeral_blob(&q, 0, &pw);
@@ -521,15 +523,18 @@
521 /*
522 ** Send a single config card for configuration item zName
523 */
524 static void send_config_card(Xfer *pXfer, const char *zName){
525 if( zName[0]!='@' ){
526 char *zValue = db_get(zName, 0);
527 if( zValue ){
528 blob_appendf(pXfer->pOut, "config %s %d\n%s\n",
529 zName, strlen(zValue), zValue);
530 free(zValue);
 
 
 
531 }
532 }else{
533 Blob content;
534 blob_zero(&content);
535 configure_render_special_name(zName, &content);
@@ -766,14 +771,25 @@
766 @ error not\sauthorized\sto\spush\sconfiguration
767 nErr++;
768 break;
769 }
770 if( zName[0]!='@' ){
771 db_multi_exec(
772 "REPLACE INTO config(name,value) VALUES(%Q,%Q)",
773 zName, blob_str(&content)
774 );
 
 
 
 
 
 
 
 
 
 
 
775 }else{
776 /* Notice that we are evaluating arbitrary SQL received from the
777 ** client. But this can only happen if the client has authenticated
778 ** as an administrator, so presumably we trust the client at this
779 ** point.
@@ -1128,14 +1144,25 @@
1128 blob_zero(&content);
1129 blob_extract(xfer.pIn, size, &content);
1130 g.okAdmin = g.okRdAddr = 1;
1131 if( configure_is_exportable(zName) & origConfigRcvMask ){
1132 if( zName[0]!='@' ){
1133 db_multi_exec(
1134 "REPLACE INTO config(name,value) VALUES(%Q,%Q)",
1135 zName, blob_str(&content)
1136 );
 
 
 
 
 
 
 
 
 
 
 
1137 }else{
1138 /* Notice that we are evaluating arbitrary SQL received from the
1139 ** server. But this can only happen if we have specifically
1140 ** requested configuration information from the server, so
1141 ** presumably the operator trusts the server.
1142
--- src/xfer.c
+++ src/xfer.c
@@ -383,17 +383,19 @@
383 ** http_exchange() routine.
384 */
385 void check_login(Blob *pLogin, Blob *pNonce, Blob *pSig){
386 Stmt q;
387 int rc = -1;
388 char *zLogin = blob_terminate(pLogin);
389 defossilize(zLogin);
390
391 db_prepare(&q,
392 "SELECT pw, cap, uid FROM user"
393 " WHERE login=%Q"
394 " AND login NOT IN ('anonymous','nobody','developer','reader')"
395 " AND length(pw)>0",
396 zLogin
397 );
398 if( db_step(&q)==SQLITE_ROW ){
399 Blob pw, combined, hash;
400 blob_zero(&pw);
401 db_ephemeral_blob(&q, 0, &pw);
@@ -521,15 +523,18 @@
523 /*
524 ** Send a single config card for configuration item zName
525 */
526 static void send_config_card(Xfer *pXfer, const char *zName){
527 if( zName[0]!='@' ){
528 Blob val;
529 blob_zero(&val);
530 db_blob(&val, "SELECT value FROM config WHERE name=%Q", zName);
531 if( blob_size(&val)>0 ){
532 blob_appendf(pXfer->pOut, "config %s %d\n", zName, blob_size(&val));
533 blob_append(pXfer->pOut, blob_buffer(&val), blob_size(&val));
534 blob_reset(&val);
535 blob_append(pXfer->pOut, "\n", 1);
536 }
537 }else{
538 Blob content;
539 blob_zero(&content);
540 configure_render_special_name(zName, &content);
@@ -766,14 +771,25 @@
771 @ error not\sauthorized\sto\spush\sconfiguration
772 nErr++;
773 break;
774 }
775 if( zName[0]!='@' ){
776 if( strcmp(zName, "logo-image")==0 ){
777 Stmt ins;
778 db_prepare(&ins,
779 "REPLACE INTO config(name, value) VALUES(:name, :value)"
780 );
781 db_bind_text(&ins, ":name", zName);
782 db_bind_blob(&ins, ":value", &content);
783 db_step(&ins);
784 db_finalize(&ins);
785 }else{
786 db_multi_exec(
787 "REPLACE INTO config(name,value) VALUES(%Q,%Q)",
788 zName, blob_str(&content)
789 );
790 }
791 }else{
792 /* Notice that we are evaluating arbitrary SQL received from the
793 ** client. But this can only happen if the client has authenticated
794 ** as an administrator, so presumably we trust the client at this
795 ** point.
@@ -1128,14 +1144,25 @@
1144 blob_zero(&content);
1145 blob_extract(xfer.pIn, size, &content);
1146 g.okAdmin = g.okRdAddr = 1;
1147 if( configure_is_exportable(zName) & origConfigRcvMask ){
1148 if( zName[0]!='@' ){
1149 if( strcmp(zName, "logo-image")==0 ){
1150 Stmt ins;
1151 db_prepare(&ins,
1152 "REPLACE INTO config(name, value) VALUES(:name, :value)"
1153 );
1154 db_bind_text(&ins, ":name", zName);
1155 db_bind_blob(&ins, ":value", &content);
1156 db_step(&ins);
1157 db_finalize(&ins);
1158 }else{
1159 db_multi_exec(
1160 "REPLACE INTO config(name,value) VALUES(%Q,%Q)",
1161 zName, blob_str(&content)
1162 );
1163 }
1164 }else{
1165 /* Notice that we are evaluating arbitrary SQL received from the
1166 ** server. But this can only happen if we have specifically
1167 ** requested configuration information from the server, so
1168 ** presumably the operator trusts the server.
1169
+42 -15
--- src/xfer.c
+++ src/xfer.c
@@ -383,17 +383,19 @@
383383
** http_exchange() routine.
384384
*/
385385
void check_login(Blob *pLogin, Blob *pNonce, Blob *pSig){
386386
Stmt q;
387387
int rc = -1;
388
+ char *zLogin = blob_terminate(pLogin);
389
+ defossilize(zLogin);
388390
389391
db_prepare(&q,
390392
"SELECT pw, cap, uid FROM user"
391
- " WHERE login=%B"
393
+ " WHERE login=%Q"
392394
" AND login NOT IN ('anonymous','nobody','developer','reader')"
393395
" AND length(pw)>0",
394
- pLogin
396
+ zLogin
395397
);
396398
if( db_step(&q)==SQLITE_ROW ){
397399
Blob pw, combined, hash;
398400
blob_zero(&pw);
399401
db_ephemeral_blob(&q, 0, &pw);
@@ -521,15 +523,18 @@
521523
/*
522524
** Send a single config card for configuration item zName
523525
*/
524526
static void send_config_card(Xfer *pXfer, const char *zName){
525527
if( zName[0]!='@' ){
526
- char *zValue = db_get(zName, 0);
527
- if( zValue ){
528
- blob_appendf(pXfer->pOut, "config %s %d\n%s\n",
529
- zName, strlen(zValue), zValue);
530
- free(zValue);
528
+ Blob val;
529
+ blob_zero(&val);
530
+ db_blob(&val, "SELECT value FROM config WHERE name=%Q", zName);
531
+ if( blob_size(&val)>0 ){
532
+ blob_appendf(pXfer->pOut, "config %s %d\n", zName, blob_size(&val));
533
+ blob_append(pXfer->pOut, blob_buffer(&val), blob_size(&val));
534
+ blob_reset(&val);
535
+ blob_append(pXfer->pOut, "\n", 1);
531536
}
532537
}else{
533538
Blob content;
534539
blob_zero(&content);
535540
configure_render_special_name(zName, &content);
@@ -766,14 +771,25 @@
766771
@ error not\sauthorized\sto\spush\sconfiguration
767772
nErr++;
768773
break;
769774
}
770775
if( zName[0]!='@' ){
771
- db_multi_exec(
772
- "REPLACE INTO config(name,value) VALUES(%Q,%Q)",
773
- zName, blob_str(&content)
774
- );
776
+ if( strcmp(zName, "logo-image")==0 ){
777
+ Stmt ins;
778
+ db_prepare(&ins,
779
+ "REPLACE INTO config(name, value) VALUES(:name, :value)"
780
+ );
781
+ db_bind_text(&ins, ":name", zName);
782
+ db_bind_blob(&ins, ":value", &content);
783
+ db_step(&ins);
784
+ db_finalize(&ins);
785
+ }else{
786
+ db_multi_exec(
787
+ "REPLACE INTO config(name,value) VALUES(%Q,%Q)",
788
+ zName, blob_str(&content)
789
+ );
790
+ }
775791
}else{
776792
/* Notice that we are evaluating arbitrary SQL received from the
777793
** client. But this can only happen if the client has authenticated
778794
** as an administrator, so presumably we trust the client at this
779795
** point.
@@ -1128,14 +1144,25 @@
11281144
blob_zero(&content);
11291145
blob_extract(xfer.pIn, size, &content);
11301146
g.okAdmin = g.okRdAddr = 1;
11311147
if( configure_is_exportable(zName) & origConfigRcvMask ){
11321148
if( zName[0]!='@' ){
1133
- db_multi_exec(
1134
- "REPLACE INTO config(name,value) VALUES(%Q,%Q)",
1135
- zName, blob_str(&content)
1136
- );
1149
+ if( strcmp(zName, "logo-image")==0 ){
1150
+ Stmt ins;
1151
+ db_prepare(&ins,
1152
+ "REPLACE INTO config(name, value) VALUES(:name, :value)"
1153
+ );
1154
+ db_bind_text(&ins, ":name", zName);
1155
+ db_bind_blob(&ins, ":value", &content);
1156
+ db_step(&ins);
1157
+ db_finalize(&ins);
1158
+ }else{
1159
+ db_multi_exec(
1160
+ "REPLACE INTO config(name,value) VALUES(%Q,%Q)",
1161
+ zName, blob_str(&content)
1162
+ );
1163
+ }
11371164
}else{
11381165
/* Notice that we are evaluating arbitrary SQL received from the
11391166
** server. But this can only happen if we have specifically
11401167
** requested configuration information from the server, so
11411168
** presumably the operator trusts the server.
11421169
--- src/xfer.c
+++ src/xfer.c
@@ -383,17 +383,19 @@
383 ** http_exchange() routine.
384 */
385 void check_login(Blob *pLogin, Blob *pNonce, Blob *pSig){
386 Stmt q;
387 int rc = -1;
 
 
388
389 db_prepare(&q,
390 "SELECT pw, cap, uid FROM user"
391 " WHERE login=%B"
392 " AND login NOT IN ('anonymous','nobody','developer','reader')"
393 " AND length(pw)>0",
394 pLogin
395 );
396 if( db_step(&q)==SQLITE_ROW ){
397 Blob pw, combined, hash;
398 blob_zero(&pw);
399 db_ephemeral_blob(&q, 0, &pw);
@@ -521,15 +523,18 @@
521 /*
522 ** Send a single config card for configuration item zName
523 */
524 static void send_config_card(Xfer *pXfer, const char *zName){
525 if( zName[0]!='@' ){
526 char *zValue = db_get(zName, 0);
527 if( zValue ){
528 blob_appendf(pXfer->pOut, "config %s %d\n%s\n",
529 zName, strlen(zValue), zValue);
530 free(zValue);
 
 
 
531 }
532 }else{
533 Blob content;
534 blob_zero(&content);
535 configure_render_special_name(zName, &content);
@@ -766,14 +771,25 @@
766 @ error not\sauthorized\sto\spush\sconfiguration
767 nErr++;
768 break;
769 }
770 if( zName[0]!='@' ){
771 db_multi_exec(
772 "REPLACE INTO config(name,value) VALUES(%Q,%Q)",
773 zName, blob_str(&content)
774 );
 
 
 
 
 
 
 
 
 
 
 
775 }else{
776 /* Notice that we are evaluating arbitrary SQL received from the
777 ** client. But this can only happen if the client has authenticated
778 ** as an administrator, so presumably we trust the client at this
779 ** point.
@@ -1128,14 +1144,25 @@
1128 blob_zero(&content);
1129 blob_extract(xfer.pIn, size, &content);
1130 g.okAdmin = g.okRdAddr = 1;
1131 if( configure_is_exportable(zName) & origConfigRcvMask ){
1132 if( zName[0]!='@' ){
1133 db_multi_exec(
1134 "REPLACE INTO config(name,value) VALUES(%Q,%Q)",
1135 zName, blob_str(&content)
1136 );
 
 
 
 
 
 
 
 
 
 
 
1137 }else{
1138 /* Notice that we are evaluating arbitrary SQL received from the
1139 ** server. But this can only happen if we have specifically
1140 ** requested configuration information from the server, so
1141 ** presumably the operator trusts the server.
1142
--- src/xfer.c
+++ src/xfer.c
@@ -383,17 +383,19 @@
383 ** http_exchange() routine.
384 */
385 void check_login(Blob *pLogin, Blob *pNonce, Blob *pSig){
386 Stmt q;
387 int rc = -1;
388 char *zLogin = blob_terminate(pLogin);
389 defossilize(zLogin);
390
391 db_prepare(&q,
392 "SELECT pw, cap, uid FROM user"
393 " WHERE login=%Q"
394 " AND login NOT IN ('anonymous','nobody','developer','reader')"
395 " AND length(pw)>0",
396 zLogin
397 );
398 if( db_step(&q)==SQLITE_ROW ){
399 Blob pw, combined, hash;
400 blob_zero(&pw);
401 db_ephemeral_blob(&q, 0, &pw);
@@ -521,15 +523,18 @@
523 /*
524 ** Send a single config card for configuration item zName
525 */
526 static void send_config_card(Xfer *pXfer, const char *zName){
527 if( zName[0]!='@' ){
528 Blob val;
529 blob_zero(&val);
530 db_blob(&val, "SELECT value FROM config WHERE name=%Q", zName);
531 if( blob_size(&val)>0 ){
532 blob_appendf(pXfer->pOut, "config %s %d\n", zName, blob_size(&val));
533 blob_append(pXfer->pOut, blob_buffer(&val), blob_size(&val));
534 blob_reset(&val);
535 blob_append(pXfer->pOut, "\n", 1);
536 }
537 }else{
538 Blob content;
539 blob_zero(&content);
540 configure_render_special_name(zName, &content);
@@ -766,14 +771,25 @@
771 @ error not\sauthorized\sto\spush\sconfiguration
772 nErr++;
773 break;
774 }
775 if( zName[0]!='@' ){
776 if( strcmp(zName, "logo-image")==0 ){
777 Stmt ins;
778 db_prepare(&ins,
779 "REPLACE INTO config(name, value) VALUES(:name, :value)"
780 );
781 db_bind_text(&ins, ":name", zName);
782 db_bind_blob(&ins, ":value", &content);
783 db_step(&ins);
784 db_finalize(&ins);
785 }else{
786 db_multi_exec(
787 "REPLACE INTO config(name,value) VALUES(%Q,%Q)",
788 zName, blob_str(&content)
789 );
790 }
791 }else{
792 /* Notice that we are evaluating arbitrary SQL received from the
793 ** client. But this can only happen if the client has authenticated
794 ** as an administrator, so presumably we trust the client at this
795 ** point.
@@ -1128,14 +1144,25 @@
1144 blob_zero(&content);
1145 blob_extract(xfer.pIn, size, &content);
1146 g.okAdmin = g.okRdAddr = 1;
1147 if( configure_is_exportable(zName) & origConfigRcvMask ){
1148 if( zName[0]!='@' ){
1149 if( strcmp(zName, "logo-image")==0 ){
1150 Stmt ins;
1151 db_prepare(&ins,
1152 "REPLACE INTO config(name, value) VALUES(:name, :value)"
1153 );
1154 db_bind_text(&ins, ":name", zName);
1155 db_bind_blob(&ins, ":value", &content);
1156 db_step(&ins);
1157 db_finalize(&ins);
1158 }else{
1159 db_multi_exec(
1160 "REPLACE INTO config(name,value) VALUES(%Q,%Q)",
1161 zName, blob_str(&content)
1162 );
1163 }
1164 }else{
1165 /* Notice that we are evaluating arbitrary SQL received from the
1166 ** server. But this can only happen if we have specifically
1167 ** requested configuration information from the server, so
1168 ** presumably the operator trusts the server.
1169
--- www/bugtheory.wiki
+++ www/bugtheory.wiki
@@ -113,12 +113,13 @@
113113
114114
Each repository also defines scripts used to generate web pages for
115115
creating new tickets, viewing existing tickets, and modifying an
116116
existing ticket. These scripts consist of HTML with an embedded
117117
scripts written an a Tcl-like language called "TH1". Every new fossil
118
-repository is created with default scripts. There is currently no
119
-documentation on the TH1 language. Administrators wishing to
118
+repository is created with default scripts. Paul Ruizendaal has written
119
+documentation on the TH1 language that is available at
120
+[http://www.sqliteconcepts.org/THManual.pdf]. Administrators wishing to
120121
customize their ticket entry, viewing, and editing screens should
121122
modify the default scripts to suit their needs. These screen generator
122123
scripts are part of the local state of a repository and are not shared
123124
with other repositories during a sync, push, or pull.
124125
125126
--- www/bugtheory.wiki
+++ www/bugtheory.wiki
@@ -113,12 +113,13 @@
113
114 Each repository also defines scripts used to generate web pages for
115 creating new tickets, viewing existing tickets, and modifying an
116 existing ticket. These scripts consist of HTML with an embedded
117 scripts written an a Tcl-like language called "TH1". Every new fossil
118 repository is created with default scripts. There is currently no
119 documentation on the TH1 language. Administrators wishing to
 
120 customize their ticket entry, viewing, and editing screens should
121 modify the default scripts to suit their needs. These screen generator
122 scripts are part of the local state of a repository and are not shared
123 with other repositories during a sync, push, or pull.
124
125
--- www/bugtheory.wiki
+++ www/bugtheory.wiki
@@ -113,12 +113,13 @@
113
114 Each repository also defines scripts used to generate web pages for
115 creating new tickets, viewing existing tickets, and modifying an
116 existing ticket. These scripts consist of HTML with an embedded
117 scripts written an a Tcl-like language called "TH1". Every new fossil
118 repository is created with default scripts. Paul Ruizendaal has written
119 documentation on the TH1 language that is available at
120 [http://www.sqliteconcepts.org/THManual.pdf]. Administrators wishing to
121 customize their ticket entry, viewing, and editing screens should
122 modify the default scripts to suit their needs. These screen generator
123 scripts are part of the local state of a repository and are not shared
124 with other repositories during a sync, push, or pull.
125
126
+10 -1
--- www/index.wiki
+++ www/index.wiki
@@ -21,10 +21,15 @@
2121
<li> [http://www.fossil-scm.org/download.html | Download]
2222
<li> [./build.wiki | Install]
2323
<li> [../COPYRIGHT-GPL2.txt | License]
2424
<li> [/timeline | Recent changes]
2525
<li> [./faq.wiki | FAQ]
26
+<li> Mailing list
27
+ <ul>
28
+ <li> [http://lists.fossil-scm.org:8080/cgi-bin/mailman/listinfo/fossil-users | sign-up]
29
+ <li> [http://www.mail-archive.com/[email protected] | archives]
30
+ <ul>
2631
</ul>
2732
</td></tr>
2833
<tr><td>
2934
<center><img src="fossil3.gif"></center>
3035
</td></tr>
@@ -106,17 +111,21 @@
106111
to do it using fossil.
107112
* The [./selfcheck.wiki | automatic self-check] mechanism
108113
helps insure project integrity.
109114
* Fossil contains a [./wikitheory.wiki | built-in wiki].
110115
* There is a
111
- [http://lists.fossil-scm.org:8080/cgi-bin/mailman/listinfo/fossil-users | mailing list]
116
+ [http://lists.fossil-scm.org:8080/cgi-bin/mailman/listinfo/fossil-users | mailing list] (with publically readable
117
+ [http://www.mail-archive.com/[email protected] | archives]
112118
available for discussing fossil issues.
113119
* [./stats.wiki | Performance statistics] taken from real-world projects
114120
hosted on fossil.
115121
* How to [./shunning.wiki | delete content] from a fossil repository.
116122
* Some (unfinished but expanding) extended
117123
[./reference.wiki | reference documentation] for the fossil command line.
124
+ * Documentation on the
125
+ [http://www.sqliteconcepts.org/THManual.pdf | TH1 Script Language] used
126
+ to configure the ticketing subsystem.
118127
119128
<h3>Links For Fossil Developer:</h3>
120129
121130
* [./pop.wiki | Principles Of Operation]
122131
* The [./fileformat.wiki | file format] used by every content
123132
--- www/index.wiki
+++ www/index.wiki
@@ -21,10 +21,15 @@
21 <li> [http://www.fossil-scm.org/download.html | Download]
22 <li> [./build.wiki | Install]
23 <li> [../COPYRIGHT-GPL2.txt | License]
24 <li> [/timeline | Recent changes]
25 <li> [./faq.wiki | FAQ]
 
 
 
 
 
26 </ul>
27 </td></tr>
28 <tr><td>
29 <center><img src="fossil3.gif"></center>
30 </td></tr>
@@ -106,17 +111,21 @@
106 to do it using fossil.
107 * The [./selfcheck.wiki | automatic self-check] mechanism
108 helps insure project integrity.
109 * Fossil contains a [./wikitheory.wiki | built-in wiki].
110 * There is a
111 [http://lists.fossil-scm.org:8080/cgi-bin/mailman/listinfo/fossil-users | mailing list]
 
112 available for discussing fossil issues.
113 * [./stats.wiki | Performance statistics] taken from real-world projects
114 hosted on fossil.
115 * How to [./shunning.wiki | delete content] from a fossil repository.
116 * Some (unfinished but expanding) extended
117 [./reference.wiki | reference documentation] for the fossil command line.
 
 
 
118
119 <h3>Links For Fossil Developer:</h3>
120
121 * [./pop.wiki | Principles Of Operation]
122 * The [./fileformat.wiki | file format] used by every content
123
--- www/index.wiki
+++ www/index.wiki
@@ -21,10 +21,15 @@
21 <li> [http://www.fossil-scm.org/download.html | Download]
22 <li> [./build.wiki | Install]
23 <li> [../COPYRIGHT-GPL2.txt | License]
24 <li> [/timeline | Recent changes]
25 <li> [./faq.wiki | FAQ]
26 <li> Mailing list
27 <ul>
28 <li> [http://lists.fossil-scm.org:8080/cgi-bin/mailman/listinfo/fossil-users | sign-up]
29 <li> [http://www.mail-archive.com/[email protected] | archives]
30 <ul>
31 </ul>
32 </td></tr>
33 <tr><td>
34 <center><img src="fossil3.gif"></center>
35 </td></tr>
@@ -106,17 +111,21 @@
111 to do it using fossil.
112 * The [./selfcheck.wiki | automatic self-check] mechanism
113 helps insure project integrity.
114 * Fossil contains a [./wikitheory.wiki | built-in wiki].
115 * There is a
116 [http://lists.fossil-scm.org:8080/cgi-bin/mailman/listinfo/fossil-users | mailing list] (with publically readable
117 [http://www.mail-archive.com/[email protected] | archives]
118 available for discussing fossil issues.
119 * [./stats.wiki | Performance statistics] taken from real-world projects
120 hosted on fossil.
121 * How to [./shunning.wiki | delete content] from a fossil repository.
122 * Some (unfinished but expanding) extended
123 [./reference.wiki | reference documentation] for the fossil command line.
124 * Documentation on the
125 [http://www.sqliteconcepts.org/THManual.pdf | TH1 Script Language] used
126 to configure the ticketing subsystem.
127
128 <h3>Links For Fossil Developer:</h3>
129
130 * [./pop.wiki | Principles Of Operation]
131 * The [./fileformat.wiki | file format] used by every content
132

Keyboard Shortcuts

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