OSDN Git Service

date-format function.
[hmh/hhml.git] / wiki / wikiformat.cc
1 #include "wikiformat.h"
2 #include "wikiline.h"
3 #include "wikitable.h"
4 #include "wikicmd.h"
5 #include "wikienv.h"
6 #include "ml.h"
7 #include "expr.h"
8 #include "motorconst.h"
9 #include "motorenv.h"
10 #include "motoroutput.h"
11 #include "util_const.h"
12 #include "util_check.h"
13 #include "util_string.h"
14 #include "utf8.h"
15 #include "ustring.h"
16 #include <boost/ptr_container/ptr_vector.hpp>
17
18 #define  kComment       "//"
19 #define  kWikiP         '^'
20 #define  kWikiH         '='
21 #define  kWikiPRE       ' '
22 #define  kWikiPRE2      '\t'
23 #define  kWikiUL        '*'
24 #define  kWikiOL        '#'
25 //#define  kWikiNL      ']'
26 #define  kWikiNL        '+'
27 #define  kWikiDL        ';'
28 #define  kWikiTABLE     '|'
29 #define  kWikiQUOTE     '>'
30 #define  kWikiQUOTE_e   '<'
31 #define  kWikiDIV       '{'
32 #define  kWikiDIV_e     '}'
33 #define  kWikiHR        '-'
34 #define  kWikiCmd       '$'
35
36 #define  uP     "<p>"
37 #define  uPe    "</p>\n"
38 #define  uH1    "<h1>"
39 #define  uH2    "<h2>"
40 #define  uH3    "<h3>"
41 #define  uH4    "<h4>"
42 #define  uH5    "<h5>"
43 #define  uH6    "<h6>"
44 #define  uH1e   "</h1>\n"
45 #define  uH2e   "</h2>\n"
46 #define  uH3e   "</h3>\n"
47 #define  uH4e   "</h4>\n"
48 #define  uH5e   "</h5>\n"
49 #define  uH6e   "</h6>\n"
50 #define  uHR    "<hr />\n"
51 //#define  unbsp        "&nbsp;"
52
53 ustring  uWiki (CharConst ("wiki_"));
54
55 /*DOC:
56 ==テキストの整形ルール==
57
58 */
59 /* ============================================================ */
60 void  WikiMlEnv::setVar (const ustring& name, MNode* val) {
61     ustring  na (uWiki);
62     na.append (name);
63     parent->setVar (na, val);
64 }
65
66 void  WikiMlEnv::setAry (const ustring& name, size_t i, MNode* val) {
67     ustring  na (uWiki);
68     na.append (name);
69     parent->setAry (na, i, val);
70 }
71
72 void  WikiMlEnv::setArySize (const ustring& name, size_t n) {
73     ustring  na (uWiki);
74     na.append (name);
75     parent->setArySize (na, n);
76 }
77
78 void  WikiMlEnv::setAry (const ustring& name, MNode* list) {
79     ustring  na (uWiki);
80     na.append (name);
81     parent->setAry (na, list);
82 }
83
84 MNode*  WikiMlEnv::getVar (const ustring& name) {
85     ustring  na (uWiki);
86     na.append (name);
87     return parent->getVar (na);
88 }
89
90 MNode*  WikiMlEnv::getAry (const ustring& name, size_t i) {
91     ustring  na (uWiki);
92     na.append (name);
93     return parent->getAry (na, i);
94 }
95
96 size_t  WikiMlEnv::getArySize (const ustring& name) {
97     ustring  na (uWiki);
98     na.append (name);
99     return parent->getArySize (na);
100 }
101
102 /* ============================================================ */
103 bool  WikiAttrib1::readAttrib1 (WikiMotorObjVec* cell, bool& rc) {
104     ustring  key;
105     WikiMotorObjVec  vval;
106     bool  ferr = false;
107
108     if (cell->size () == 0) {
109         if (fwhole)
110             return true;
111         else
112             return false;
113     }
114     if (cell->splitChar_keyword ('=', key, vval)) {
115         if (wiki->paramID (key, vval, id, ferr)) {
116         } else if (wiki->paramClass (key, vval, classlist, ferr)) {
117         } else if (wiki->paramOnClickCheck (key)) {
118             if (! checkScript (vval, onclick, ferr)) {
119                 wiki->errorMsg.append (cell->dump ()).append (CharConst (": link script error.\n"));
120                 ferr = true;
121             }
122         } else if ((selector & SEL_TARGET) && wiki->paramTargetCheck (key)) {
123             wiki->paramTargetBody (key, vval.textOut (wiki), target, ferr);
124         } else if (readAttribMore (key, vval, ferr)) {
125         } else {
126             if (fwhole) {
127                 wiki->errorMsg.append (cell->dump ()).append (CharConst (": bad attribute.\n"));
128                 rc = false;
129             }
130             return false;
131         }
132     } else {
133         if (selector & SEL_CLASS2) {
134             wiki->paramClassValue (*cell, classlist, ferr);
135         } else if (selector & SEL_TARGET2) {
136             wiki->paramTargetBody (uEmpty, cell->textOut (wiki), target, ferr);
137         } else if ((selector & SEL_ONCLICK2) && checkScript (*cell, onclick, ferr)) {
138         } else if ((selector & SEL_MULTIPLE2) && match (key, CharConst ("multiple"))) {
139             fmultiple = true;
140         } else if ((selector & SEL_DEFAULT2) && match (key, CharConst ("default"))) {
141             fdefault = true;
142         } else if ((selector & SEL_SCRIPT2) && checkScript (*cell, script, ferr)) {
143         } else if (readAttribMore2 (key, *cell, ferr)) {
144         } else {
145             if (fwhole) {
146                 wiki->errorMsg.append (cell->dump ()).append (CharConst (": bad attribute.\n"));
147                 rc = false;
148             }
149             return false;
150         }
151     }
152     if (ferr) {
153         rc = false;
154         return false;
155     } else {
156         return true;
157     }
158 }
159
160 bool  WikiAttrib1::shiftAttrib (WikiMotorObjVecPtr& vec) {
161     bool  rc = true;
162     WikiMotorObjVecPtr  v2;
163
164     while (vec->size () > 0) {
165         WikiMotorObjVec  cell;
166
167         v2 = WikiMotorObjVecPtr (new WikiMotorObjVec);
168         if (vec->splitChar (':', cell, *v2) || fwhole) {
169             if (! readAttrib1 (&cell, rc))
170                 return rc;
171             vec = v2;
172         } else {
173             return true;
174         }
175     }
176     return true;
177 }
178
179 bool  WikiAttrib1::readAttrib (WikiMotorObjVecVec::const_iterator&b, const WikiMotorObjVecVec::const_iterator& e) {
180     bool  rc = true;
181
182     while (b < e) {
183         WikiMotorObjVec*  cell = b->get ();
184         if (! readAttrib1 (cell, rc))
185             return rc;
186         b ++;
187     }
188     return true;
189 }
190
191 bool  WikiAttrib1::checkScript (WikiMotorObjVec& vec, ustring& scr, bool& ferr) {
192     bool  f = false;
193     int  i;
194     ustring  u;
195     for (i = 0; i < vec.size () && vec[i]->type == WikiMotorObj::wiki_funcLink; i ++) {
196         WikiMotorObjFuncLink*  fn = WikiMotorObjFuncLink_type (&*vec[i]);
197         u = fn->execDefunArgs (wiki);
198         // XXX: 末尾の空白を除去し,セミコロンを確認する。
199         scr.append (u);
200         f = true;
201     }
202     if (f)
203         return true;
204
205     return false;
206 }
207
208 bool  WikiAttrib1::shiftLink (WikiMotorObjVecPtr& vec, ustring& url, bool& fscript) {
209     bool  ferr = false;
210     bool  rc;
211     WikiMotorObjVec  cell;
212     WikiMotorObjVecPtr  v2 (new WikiMotorObjVec);
213
214     rc = vec->splitChar (':', cell, *v2);
215     if (checkScript (cell, url, ferr)) {
216         fscript = true;
217         vec = v2;
218         return true;
219     } else if (rc && cell.match (CharConst ("http"), CharConst ("https"))) {
220         ustring  proto = cell.dump ();
221         vec = v2;
222         cell.clear ();
223         v2 = WikiMotorObjVecPtr (new WikiMotorObjVec);
224         rc = vec->splitChar (':', cell, *v2);
225         if (! cell.splitURL_2 (wiki, proto, url)) {
226             vec = v2;
227             return false;
228         }
229         vec = v2;
230         if (vec->size () > 0) {
231             cell.clear ();
232             v2 = WikiMotorObjVecPtr (new WikiMotorObjVec);
233             rc = vec->splitChar (':', cell, *v2);
234             if (cell.splitURL_3 (wiki, url, url))
235                 vec = v2;
236         }
237         return true;
238     } else if (cell.splitURLPath (wiki, url)) {
239         vec = v2;
240         return true;
241     } else {
242         return false;
243     }
244     return false;
245 }
246
247 bool  WikiAttrib1::readLink (WikiMotorObjVecVec::const_iterator& b, const WikiMotorObjVecVec::const_iterator& e, ustring& url, bool& fscript, bool noscript) {
248     bool  ferr = false;
249     bool  rc;
250     WikiMotorObjVec*  cell;
251
252     if (b == e)
253         return false;
254     cell = b->get ();
255     rc = (b + 1 < e);
256     if (! noscript && checkScript (*cell, url, ferr)) {
257         fscript = true;
258         b ++;
259         return true;
260     } else if (rc && cell->match (CharConst ("http"), CharConst ("https"))) {
261         ustring  proto = cell->dump ();
262         b ++;
263         cell = b->get ();
264         if (! cell->splitURL_2 (wiki, proto, url)) {
265             b ++;
266             return false;
267         }
268         b ++;
269         if (b < e) {
270             cell = b->get ();
271             if (cell->splitURL_3 (wiki, url, url))
272                 b ++;
273         }
274         return true;
275     } else if (cell->splitURLPath (wiki, url)) {
276         b ++;
277         return true;
278     } else {
279         return false;
280     }
281     return false;
282 }
283
284 bool  WikiAttrib1::shiftName (WikiMotorObjVecPtr& vec, ustring& name) {
285     if (vec->size () > 0) {
286         WikiMotorObjVec  cell;
287         WikiMotorObjVecPtr  v2 (new WikiMotorObjVec);
288
289         vec->splitChar (':', cell, *v2);
290         name = cell.textOut (wiki);
291         vec = v2;
292         return true;
293     } else {
294         return false;
295     }
296 }
297
298 void  WikiAttrib1::output (MotorOutput* out) {
299     wiki->outputID (out, id);
300     wiki->outputClass (out, classlist);
301     wiki->outputSubmitScript (out, CharConst ("onClick"), onclick);
302     wiki->outputName (out, CharConst ("target"), target);
303 //    wiki->outputName (out, CharConst ("size"), elsize);
304     wiki->outputFlag (out, CharConst ("multiple"), fmultiple);
305     // no fdefault
306     outputMore (out);
307 }
308
309 /* ============================================================ */
310 void  WikiAttribTable::init () {
311     fheader = false;
312     halign = HAlignNone;
313     valign = VAlignNone;
314     fnowrap = false;
315     fnoborder = false;
316     cellspacing = -1;
317     cellpadding = -1;
318     fpadding = false;
319 //      halign = HAlignNone;
320     fnowhite = false;
321     fturn = false;
322
323     id.resize (0);
324     while (! classlist.empty ())
325         classlist.pop_back ();
326     width.resize (0);
327     height.resize (0);
328     bgcolor.resize (0);
329     onclick.resize (0);
330 }
331
332 void  WikiAttribTable::copyFrom (WikiAttribTable& b) {
333     int  i;
334
335     id = b.id;
336     for (i = 0; i < b.classlist.size (); i ++)
337         classlist.push_back (b.classlist[i]);
338     onclick = b.onclick;
339     fheader = b.fheader;
340     halign = b.halign;
341     valign = b.valign;
342     width = b.width;
343     height = b.height;
344     bgcolor = b.bgcolor;
345     fnowrap = b.fnowrap;
346 }
347
348 bool  WikiAttribTable::readAttribMore (const ustring& key, WikiMotorObjVec& vval, bool& ferr) {
349     if (wiki->paramWidth (key, vval, width, ferr)) {
350     } else if (wiki->paramHeight (key, vval, height, ferr)) {
351     } else if (match (key, CharConst ("bgcolor"), CharConst ("bg"))) {
352         wiki->paramColor (vval.textOut (wiki), bgcolor, key);
353     } else {
354         switch (selector2) {
355         case SEL_TABLE:
356             if (match (key, CharConst ("cellspacing"), CharConst ("spc"))) {
357                 wiki->paramUNum (vval.textOut (wiki), cellspacing, key);
358             } else if (match (key, CharConst ("cellpadding"))) {
359                 wiki->paramUNum (vval.textOut (wiki), cellpadding, key);
360             } else {
361                 return false;
362             }
363             break;
364         case SEL_TD:
365             return false;
366         default:
367             assert (0);
368         }
369     }
370     return true;
371 }
372
373 bool  WikiAttribTable::readAttribMore2 (const ustring& key, WikiMotorObjVec& cell, bool& ferr) {
374     if (match (key, CharConst ("left"), CharConst ("l"))) {
375         halign = HAlignLeft;
376     } else if (match (key, CharConst ("right"), CharConst ("r"))) {
377         halign = HAlignRight;
378     } else if (match (key, CharConst ("center"), CharConst ("c"))) {
379         halign = HAlignCenter;
380     } else {
381         switch (selector2) {
382         case SEL_TABLE:
383             if (match (key, CharConst ("noborder"), CharConst ("nb"))) {
384                 fnoborder = true;
385             } else if (match (key, CharConst ("padding"), CharConst ("pad"))) {
386                 fpadding = true;
387             } else if (match (key, CharConst ("expanding"), CharConst ("expand"))) {
388                 fpadding = false;
389             } else if (match (key, CharConst ("nowhite"), CharConst ("nw"))) {
390                 fnowhite = true;
391             } else if (match (key, CharConst ("turn"))) {
392                 fturn = true;
393             } else {
394                 return false;
395             }
396             break;
397         case SEL_TD:
398             if (match (key, CharConst ("header"), CharConst ("h"))) {
399                 fheader = true;
400             } else if (match (key, CharConst ("top"), CharConst ("t"))) {
401                 valign = VAlignTop;
402             } else if (match (key, CharConst ("middle"), CharConst ("m"))) {
403                 valign = VAlignMiddle;
404             } else if (match (key, CharConst ("bottom"), CharConst ("b"))) {
405                 valign = VAlignBottom;
406             } else if (match (key, CharConst ("nowrap"), CharConst ("nw"))) {
407                 fnowrap = true;
408             } else if (match (key, CharConst ("*"))) {
409                 init ();
410             } else {
411                 return false;
412             }
413             break;
414         default:
415             assert (0);
416         }
417     }
418
419     return true;
420 }
421
422 void  WikiAttribTable::outputMore (MotorOutput* out) {
423     switch (halign) {
424     case HAlignLeft:
425         out->out_raw (CharConst (" align=\"left\""));
426         break;
427     case HAlignCenter:
428         out->out_raw (CharConst (" align=\"center\""));
429         break;
430     case HAlignRight:
431         out->out_raw (CharConst (" align=\"right\""));
432         break;
433     }
434     wiki->outputName (out, CharConst ("width"), width);
435     wiki->outputName (out, CharConst ("height"), height);
436     wiki->outputName (out, CharConst ("bgcolor"), bgcolor);
437
438     switch (selector2) {
439     case SEL_TABLE:
440         wiki->outputName (out, CharConst ("border"), fnoborder ? 0 : 1, false);
441         wiki->outputName (out, CharConst ("cellspacing"), cellspacing, false);
442         wiki->outputName (out, CharConst ("cellpadding"), cellpadding, false);
443         break;
444     case SEL_TD:
445         switch (valign) {
446         case VAlignTop:
447             out->out_raw (CharConst (" valign=\"top\""));
448             break;
449         case VAlignMiddle:
450             out->out_raw (CharConst (" valign=\"middle\""));
451             break;
452         case VAlignBottom:
453             out->out_raw (CharConst (" valign=\"bottom\""));
454             break;
455         }
456         wiki->outputFlag (out, CharConst ("nowrap"), fnowrap);
457         break;
458     default:
459         assert (0);
460     }
461 }
462
463 /* ============================================================ */
464 bool  WikiAttribImg::readAttribMore (const ustring& key, WikiMotorObjVec& vval, bool& ferr) {
465     if (wiki->paramWidth (key, vval, width, ferr)) {
466     } else if (wiki->paramHeight (key, vval, height, ferr)) {
467     } else if (match (key, CharConst ("alt"))) {
468         alt = vval.textOut (wiki);
469     } else {
470         return false;
471     }
472     return true;
473 }
474
475 void  WikiAttribImg::outputMore (MotorOutput* out) {
476     wiki->outputName (out, CharConst ("width"), width);
477     wiki->outputName (out, CharConst ("height"), height);
478     // longdesc
479 }
480
481 /* ============================================================ */
482 bool  WikiAttribInput::readAttribMore (const ustring& key, WikiMotorObjVec& vval, bool& ferr) {
483     if ((selector2 & SEL_INPUT) && wiki->paramSize (CharConst ("size"), key, vval, psize, ferr)) {
484     } else if ((selector2 & SEL_ELSIZE) && match (key, CharConst ("size"))) {
485         ustring  v = vval.textOut (wiki);
486         if (match (v, CharConst ("*"))) {
487             elsize = 1;
488         } else if (checkNum (v)) {
489             elsize = to_int32 (v);
490             if (elsize < 0 || elsize > 999) {
491                 elsize = 1;
492             }
493         } else {
494             elsize = 1;
495         }
496     } else if (wiki->paramWidth (key, vval, pwidth, ferr)) {
497     } else if ((selector2 & SEL_TEXTAREA) && wiki->paramSize (CharConst ("cols"), key, vval, pcols, ferr)) {
498     } else if ((selector2 & SEL_TEXTAREA) && wiki->paramSize (CharConst ("rows"), key, vval, prows, ferr)) {
499     } else if ((selector2 & SEL_TEXTAREA) && match (key, CharConst ("wrap"))) {
500         ustring  value (vval.textOut (wiki));
501         if (match (value, CharConst ("off"))) {
502             pwrap = W_OFF;
503         } else if (match (value, CharConst ("soft"))) {
504             pwrap = W_SOFT;
505         } else if (match (value, CharConst ("hard"))) {
506             pwrap = W_HARD;
507         } else if (wiki->paramWidth (key, vval, pwidth, ferr)) {
508         } else {
509             wiki->errorMsg.append (key).append (CharConst ("=")).append (vval.dump ()).append (CharConst (": link script error.\n"));
510             ferr = true;
511             return false;
512         }
513     } else {
514         return false;
515     }
516     return true;
517 }
518
519 bool  WikiAttribInput::readAttribMore2 (const ustring& key, WikiMotorObjVec& cell, bool& ferr) {
520     if (key == uDefault) {
521         pdefault = true;
522     } else if ((selector2 & SEL_CHECK) && match (key, CharConst ("checked"))) {
523         pchecked = true;
524     } else {
525         return false;
526     }
527     return true;
528 }
529
530 void  WikiAttribInput::outputMore (MotorOutput* out) {
531     wiki->outputName (out, CharConst ("size"), psize);
532     wiki->outputName (out, CharConst ("size"), elsize);
533     if (pwidth.size () > 0)
534         out->out_raw (CharConst (" style=\"width: "))->out_toHTML_noCtrl (pwidth)->out_raw (CharConst (";\""));
535     if (selector2 & SEL_CHECK) {
536         wiki->outputFlag (out, CharConst ("checked"), pchecked);
537     }
538     if (selector2 & SEL_TEXTAREA) {
539         wiki->outputName (out, CharConst ("cols"), pcols, false);
540         wiki->outputName (out, CharConst ("rows"), prows);
541         switch (pwrap) {
542         case W_OFF:
543             out->out_raw (CharConst (" wrap=\"off\""));
544             break;
545         case W_SOFT:
546             out->out_raw (CharConst (" wrap=\"soft\""));
547             //  out->out_raw (CharConst (" wrap=\"virtual\""));
548             break;
549         case W_HARD:
550             out->out_raw (CharConst (" wrap=\"hard\""));
551             //  out->out_raw (CharConst (" wrap=\"physical\""));
552             break;
553         }
554     }
555 }
556
557 /* ============================================================ */
558 bool  WikiAttribButton::readAttrib (WikiMotorObjVecVec::const_iterator& b, const WikiMotorObjVecVec::const_iterator& e) {
559     bool  rc = true;
560
561     if (b < e) {
562         WikiMotorObjVec*  cell = b->get ();
563         bool  bf = fwhole;
564         fwhole = false;
565         if (! readAttrib1 (cell, rc)) {
566             name = cell->textOut (wiki);
567         }
568         fwhole = bf;
569         b ++;
570     }
571     while (b < e) {
572         WikiMotorObjVec*  cell = b->get ();
573         if (! readAttrib1 (cell, rc))
574             return rc;
575         b ++;
576     }
577     return true;
578 }
579
580 /* ============================================================ */
581 void  WikiBlockComplex::outputBlock (MotorOutput* out) {
582     for (int i = 0; i < block.size (); i ++) {
583         block[i].output (out);
584     }
585 }
586
587 /* ============================================================ */
588 /*DOC:
589 ===段落===
590  マークアップ文字以外の文字で書き出すと,段落になる。
591  ^行頭が他のマークアップ文字になるときは,行頭に^を書く。
592  
593  空行は,段落を分ける。
594
595 */
596 bool  WikiBlockParagraph::nextLine (uiterator b, uiterator e) {
597     if (*b == kWikiP) {
598         addLine (b, e);
599         return true;
600     } else {
601         return false;
602     }
603 }
604
605 void  WikiBlockParagraph::addLine (uiterator b, uiterator e) {
606     uiterator  it;
607     int  n;
608
609     if (b[0] == kWikiP)
610         b ++;
611     if (b == e)
612         return;
613     if (html.size () == 0) {
614     } else {
615         lastChar (html, it);
616         n = html.end () - it;
617         it = b;
618         nextChar (it, e);
619 #ifdef UTF8JP
620         if (n == 3 && it - b == 3) {
621         } else {
622             html.append (uSPC);
623         }
624 #else
625         html.append (uSPC);
626 #endif
627     }
628     html.append (wiki->wikiMotor (b, e));
629 }
630
631 void  WikiBlockParagraph::addHtml (const ustring& ht) {
632     html.append (ht);
633 }
634
635 void  WikiBlockParagraph::output (MotorOutput* out) {
636     out->out_raw (CharConst (uP))->out_toText (html)->out_raw (CharConst (uPe));
637 }
638
639 /* ============================================================ */
640 /*DOC:
641 ===タイトル===
642  =タイトル1=
643  ==タイトル2==
644  ===タイトル3===#anchor1
645
646 行頭に=を書くと,タイトルになる。行末の=は,省略可。
647
648 */
649
650 bool  WikiBlockH::nextLine (uiterator b, uiterator e) {
651     return false;
652 }
653
654 void  WikiBlockH::addLine (uiterator b, uiterator e) {
655     uiterator  u;
656     umatch  m;
657     int  n, cn;
658     static uregex  re ("(=+)#([a-zA-Z0-9_-]+)$");
659
660     cn = wiki->countWikiH (b, e);
661     level = cn + wiki->headbase;
662     if (level > 6)
663         level = 6;
664     level0 = wiki->hlevel;
665
666     for (; b < e && *b == ' '; b ++) {}
667     if (usearch (b, e, m, re)) {
668         u = m[0].first;
669         n = m[1].second - m[1].first - cn;
670         if (n > 0) {
671             u += n;
672         }
673         for (; b < u && u[-1] == ' '; u --) {}
674         title = wiki->wikiMotor (b, u);
675         anchor = ustring (m[2].first, m[2].second);
676     } else {
677         u = e;
678         for (n = cn; n > 0 && b < u && u[-1] == '='; u --, n --) {}
679         for (; b < u && u[-1] == ' '; u --) {}
680         title = wiki->wikiMotor (b, u);
681     }
682     wiki->hlevel = level;
683 }
684
685 WikiBlock::closeType  WikiBlockH::closeLine (uiterator b, uiterator e) {
686     if (e - b == 1 && *b == kWikiDIV_e) {
687         int  i;
688         for (i = wiki->bstack.size () - 1; i >= 0; i --) {
689             switch (wiki->bstack[i]->type) {
690             case BlockDiv:
691             case BlockForm:
692                 for (i = wiki->bstack.size () - 1; i >= 0; i --) {
693                     wiki->pop_block ();
694                     switch (wiki->bstack[i]->type) {
695                     case BlockDiv:
696                     case BlockForm:
697                         if (wiki->cur)
698                             wiki->cur->close ();
699                         wiki->cur = NULL;
700                         return CloseTrue;
701                     }
702                 }
703             }
704         }
705         return CloseFalse;
706     } else if (b != e && *b == kWikiH) {
707         int  l = wiki->countWikiH (b, e) + wiki->headbase;
708         int  i;
709         if (l > 6)
710             l = 6;
711         WikiBlockH*  obj;
712         for (i = wiki->bstack.size () - 1; i >= 0; i --) {
713             if (wiki->bstack[i]->type == BlockH) {
714                 obj = (WikiBlockH*)wiki->bstack[i];
715                 if (obj->level >= l) {
716                     wiki->pop_block ();
717                 } else {
718                     break;
719                 }
720             } else {
721                 break;
722             }
723         }
724         if (wiki->cur)
725             wiki->cur->close ();
726         wiki->cur = NULL;
727         return CloseFalse;
728     } else {
729         return CloseFalse;
730     }
731 }
732
733 void  WikiBlockH::close () {
734     wiki->hlevel = level0;
735 }
736
737 void  WikiBlockH::output (MotorOutput* out) {
738     int  i;
739
740     assert (0 < level && level <= 6);
741     for (i = level0 + 1; i <= level; i ++) {
742         outputBeginDiv (i, out);
743     }
744     switch (level) {
745     case 1: out->out_raw (CharConst (uH1)); break;
746     case 2: out->out_raw (CharConst (uH2)); break;
747     case 3: out->out_raw (CharConst (uH3)); break;
748     case 4: out->out_raw (CharConst (uH4)); break;
749     case 5: out->out_raw (CharConst (uH5)); break;
750     case 6: out->out_raw (CharConst (uH6)); break;
751     }
752     if (anchor.size () > 0) {
753         out->out_raw (CharConst ("<a name=\""))->out_toHTML_noCtrl (anchor)->out_raw (CharConst ("\">"))->out_toText (title)->out_raw (CharConst ("</a>"));
754     } else {
755         out->out_noCtrl (title);
756     }
757     switch (level) {
758     case 1: out->out_raw (CharConst (uH1e)); break;
759     case 2: out->out_raw (CharConst (uH2e)); break;
760     case 3: out->out_raw (CharConst (uH3e)); break;
761     case 4: out->out_raw (CharConst (uH4e)); break;
762     case 5: out->out_raw (CharConst (uH5e)); break;
763     case 6: out->out_raw (CharConst (uH6e)); break;
764     }
765     outputBlock (out);
766     for (i = level; i > level0; i --) {
767 #ifdef DEBUG
768         out->out_raw (CharConst ("</div><!-- hh"))->out_raw (to_ustring (i))->out_raw (CharConst (" -->\n"));
769 #else
770         outputEndDiv (out);
771 #endif /* DEBUG */
772     }
773 }
774
775 void  WikiBlockH::outputBeginDiv (int lv, MotorOutput* out) {
776     switch (lv) {
777     case 1: out->out_raw (CharConst ("<div class=\"hh1\">\n")); break;
778     case 2: out->out_raw (CharConst ("<div class=\"hh2\">\n")); break;
779     case 3: out->out_raw (CharConst ("<div class=\"hh3\">\n")); break;
780     case 4: out->out_raw (CharConst ("<div class=\"hh4\">\n")); break;
781     case 5: out->out_raw (CharConst ("<div class=\"hh5\">\n")); break;
782     case 6: out->out_raw (CharConst ("<div class=\"hh6\">\n")); break;
783     }
784 }
785
786 void  WikiBlockH::outputEndDiv (MotorOutput* out) {
787     out->out_raw (CharConst ("</div>\n"));
788 }
789
790 /* ============================================================ */
791 /*DOC:
792 ===フォーマット済みテキストブロック===
793   行頭に空白文字を書くと,<pre>〜</pre>タグで囲まれます。
794 インライン要素の解釈は行われない。
795
796 */
797 bool  WikiBlockPreformat::nextLine (uiterator b, uiterator e) {
798     if (*b == markup) {
799         addLine (b, e);
800         return true;
801     } else {
802         return false;
803     }
804 }
805
806 void  WikiBlockPreformat::addLine (uiterator b, uiterator e) {
807     markup = *b;
808     if (markup == ' ') {
809 //      html.append (wiki->wikiMotor (b + 1, e));
810         text.append (b + 1, e);
811     } else {
812 //      html.append (wiki->wikiMotor (b, e));
813         text.append (b, e);
814     }
815 //    html.append (uLF);
816     text.append (uLF);
817 }
818
819 void  WikiBlockPreformat::output (MotorOutput* out) {
820 //    out->out_raw (CharConst ("<pre>"))->out_toText (html)->out_raw (CharConst ("</pre>\n"));
821     out->out_raw (CharConst ("<pre>"))->out_toHTML (text)->out_raw (CharConst ("</pre>\n"));
822 }
823
824 /* ============================================================ */
825 bool  WikiBlockItemText::nextLine (uiterator b, uiterator e) {
826     return false;
827 }
828
829 void  WikiBlockItemText::addLine (uiterator b, uiterator e) {
830     WikiMotor  motor (b, e, wiki);
831     WikiMotorObjVecPtr  v1 (new WikiMotorObjVec);
832
833     motor.compile (*v1);
834     if (! attrib.shiftAttrib (v1))
835         return;
836     html.append (v1->htmlOut (wiki));
837 }
838
839 bool  WikiBlockItemText::checkAddLine (uiterator b, uiterator e) {
840     int  ch;
841     WikiBlock*  obj;
842     WikiBlockItem*  wbi;
843
844     if (b == e) {
845     } else {
846         ch = *b;
847         if (block.size () > 0) {
848             obj = &block.back ();
849             switch (obj->type) {
850             case BlockItemUL:
851             case BlockItemOL:
852             case BlockItemNL:
853                 wbi = (WikiBlockItem*)obj;
854                 if (wbi->ch == ch) {
855                     wbi->addLine (b, e);
856                     return true;
857                 }
858                 break;
859             default:;
860             }
861         }
862     }
863     return false;
864 }
865
866 void  WikiBlockItemText::output (MotorOutput* out) {
867     if (indentHack) {
868         outputBlock (out);
869     } else {
870         out->out_raw (CharConst ("<li"));
871         attrib.output (out);
872         out->out_raw (CharConst (">"));
873         out->out_toText (html);
874         outputBlock (out);
875         out->out_raw (CharConst ("</li>\n"));
876     }
877 }
878
879 /* ============================================================ */
880 /*DOC:
881 ===箇条書き===
882 {div:pre
883 +&*;項目1
884 +&*;*項目1-1
885 +&#;ナンバリング1
886 +&#;#ナンバリング1-2
887 +&+;インデント1
888 +&+;+インデント1-1
889 +&*;''[OPTION1:OPTION2:...:]''TEXT
890 }
891 行頭に「*」を書くと,<UL>タグによるリスト,「#」を書くと<NL>タグによる番号付きリスト,「+」を書くとnobullクラス指定の<UL>タグによるリスト。
892
893 |h:オプション|
894 |id=''ID''|
895 |class=''CLASS,...''|
896 |onclick=''LINK-FUNCTION:PARAM1:...::''|
897
898 */
899 bool  WikiBlockItem::nextLine (uiterator b, uiterator e) {
900     if (*b == ch) {
901         addLine (b, e);
902         return true;
903     } else {
904         return false;
905     }
906 }
907
908 void  WikiBlockItem::setChar (char c) {
909     assert (ch == 0);
910     ch = c;
911 }
912
913 void  WikiBlockItem::addLine (uiterator b, uiterator e) {
914     WikiBlock*  wb;
915     WikiBlockItem*  wbi;
916     WikiBlockItemText*  wbt;
917     int  c;
918
919     if (ch == 0)
920         setChar (b[0]);
921     assert (b != e && b[0] == ch);
922     b ++;
923     if (b == e) {
924         wbt = new WikiBlockItemText (wiki);
925         block.push_back (wbt);
926         wbt->addLine (b, e);
927     } else {
928         c = *b;
929         if (block.size () > 0 && block.back ().checkAddLine (b, e)) {
930         } else {
931             switch (c) {
932             case kWikiUL:       // *
933                 wbi = new WikiBlockItem (WikiBlock::BlockItemUL, wiki);
934                 break;
935             case kWikiOL:       // #
936                 wbi = new WikiBlockItem (WikiBlock::BlockItemOL, wiki);
937                 break;
938             case kWikiNL:       // ]
939                 wbi = new WikiBlockItem (WikiBlock::BlockItemNL, wiki);
940                 break;
941             default:
942                 wbi = NULL;
943             }
944             if (wbi) {
945                 if (block.size () > 0) {
946                     wbt = &block.back ();
947                     wbi->addLine (b, e);
948                     wbt->block.push_back (wbi);
949                 } else {
950                     wbt = new WikiBlockItemText (wiki);
951                     block.push_back (wbt);
952                     wbi->addLine (b, e);
953                     wbt->block.push_back (wbi);
954                     wbt->indentHack = true;
955                 }
956             } else {
957                 wbt = new WikiBlockItemText (wiki);
958                 block.push_back (wbt);
959                 wbt->addLine (b, e);
960             }
961         }
962     }
963 }
964
965 void  WikiBlockItem::output (MotorOutput* out) {
966     int  i;
967
968     switch (type) {
969     case BlockItemUL:
970         out->out_raw (CharConst ("<ul>\n"));
971         outputBlock (out);
972         out->out_raw (CharConst ("</ul>\n"));
973         break;
974     case BlockItemOL:
975         out->out_raw (CharConst ("<ol>\n"));
976         outputBlock (out);
977         out->out_raw (CharConst ("</ol>\n"));
978         break;
979     case BlockItemNL:
980         out->out_raw (CharConst ("<ul class=\"nobull\">\n"));
981         outputBlock (out);
982         out->out_raw (CharConst ("</ul>\n"));
983         break;
984     default:
985         std::cerr << "type:" << type << uLF;
986         assert (0);
987     }
988 }
989
990 void  WikiBlockItem::outputBlock (MotorOutput* out) {
991     for (int i = 0; i < block.size (); i ++) {
992         block[i].output (out);
993     }
994 }
995
996 /* ============================================================ */
997 /*DOC:
998 ===定義リスト===
999  ;見出し:説明文
1000
1001 */
1002 bool  WikiBlockItemDL::nextLine (uiterator b, uiterator e) {
1003     if (*b == kWikiDL) {
1004         addLine (b, e);
1005         return true;
1006     } else {
1007         return false;
1008     }
1009 }
1010
1011 void  WikiBlockItemDL::addLine (uiterator b, uiterator e) {
1012     WikiMotor  motor (b + 1, e, wiki);
1013     WikiMotorObjVec  objs;
1014     ustring  def, desc;
1015
1016     motor.compile (objs);
1017     objs.splitChar (wiki, ':', def, desc);
1018     html1.push_back (def);
1019     html2.push_back (desc);
1020 }
1021
1022 void  WikiBlockItemDL::output (MotorOutput* out) {
1023     int  i;
1024
1025     out->out_raw (CharConst ("<dl>\n"));
1026     for (i = 0; i < html1.size (); i ++) {
1027         out->out_raw (CharConst ("<dt>"))->out_toText (html1[i])->out_raw (CharConst ("</dt>\n"));
1028         out->out_raw (CharConst ("<dd>"))->out_toText (html2[i])->out_raw (CharConst ("</dd>\n"));
1029     }
1030     out->out_raw (CharConst ("</dl>\n"));
1031 }
1032
1033 /* ============================================================ */
1034 /*DOC:
1035 ===表===
1036  |table:w=100%|head:right:||right:|
1037  |*:|head:品名|head:数量|
1038  |1|テレビ|2|
1039  |2|空気清浄機|3|
1040
1041 +・テーブルセルオプション
1042 表定義の最初の行の最初のカラムに「table:」を書くと,この行はテーブルオプション指定行になる。2番目以降のカラムは,デフォルトのカラムオプション指定になる。
1043
1044 |table:||c:||
1045 |h:名前|h:省略形|h:意味|
1046 |noborder|nb|border="0"を出力する。|
1047 |cellspacing=''integer''|spc=|cellspacing属性を出力する。|
1048 |cellpadding=''integer''||cellpadding属性を出力する。|
1049 |padding|pad|テーブルの最大のカラム数よりカラムが少ない行に,空のカラムを追加する。|
1050 |expanding|expand|テーブルの最大のカラム数よりカラムが少ない行の最後のカラムを引き延ばす。|
1051 |center|c|テーブルをセンタリングする。|
1052 |left|l|テーブルを左寄せする。|
1053 |right|r|テーブルを右寄せする。|
1054 |id=''name''||id属性を出力する。|
1055 |class=''name,name,...''||class属性を出力する。|
1056 |width=''number'', width=''number''%|w=|width属性を出力する。|
1057 |bgcolor=#''color''|bg=|bgcolor属性を出力する。|
1058 |onclick=''fn(arg1,arg2,...)''||onClick属性を出力する。''name''はdefun-wiki-linkで定義したもの。|
1059 |nowhite|nw||
1060 |turn||セルの並びの横方向と縦方向を交換する。|
1061
1062 +・セルオプション
1063  |header:名前|class=big:東武|
1064  |header:
1065 |table:||c:||
1066 |h:名前|h:省略形|h:意味|
1067 |header|h|ヘッダタグ(<th>)を出力する。|
1068 |left|l|セル内で左寄せする。|
1069 |right|r|右寄せする。|
1070 |center|c|横方向で中央あわせする。|
1071 |top|t|セル内で上寄せする。|
1072 |middle|m|縦方向で中央あわせする。|
1073 |bottom|b|下寄せする。|
1074 |nowrap|nw|セル内での折り返しを禁止する。|
1075 |*||デフォルトのセルオプションを含め,全てのセルオプションを破棄する。|
1076 |id=''name''||セルタグにid属性を付加する。|
1077 |class=''name,name,...''||セルタグにclass属性を付加する。|
1078 |width=''number''&|;''number''%||セルタグにwidth属性を付加する。|
1079 |height=''number''&|;''number''%||セルタグにheight属性を付加する。|
1080 |bgcolor=#''hex''|bg=|セルタグにbg属性を付加する。|
1081 |onclick=''fn(arg1,arg2,...)''||onClick属性を出力する。''name''はdefun-wiki-linkで定義したもの。|
1082
1083 |h:結合記号|h:意味|
1084 |&<;|左のセルと結合する。|
1085 |&<;''text''|左のセルと内容が一致するとき,結合する。|
1086 |&<;^''text''|左のセルと内容が一致し,左のセルが上のセルと結合しているとき,結合する。|
1087 |&^;|上のセルと結合する。|
1088 |&^;''text''|上のセルと内容が一致するとき,結合する。|
1089 |&^;<''text''|上のセルと内容が一致し,上のセルが左のセルと結合しているとき,結合する。|
1090
1091 +・継続オプション
1092 行末に「\」を指定すると,次のテーブル記述を1行として継続する。数値指定を付加し「!''NUM''\」と指定するとカラム数が''NUM''に達したところで継続をやめる。
1093
1094 */
1095 void  WikiBlockTable::TableCell::cellBody (WikiMotorObjVec* vtext, WikiBlockTable* table, int idx) {
1096     int  i;
1097     CellList_t*  col;
1098
1099     if (vtext->size () > 0 && (*vtext)[0].get ()->type == WikiMotorObj::wiki_text) {
1100         WikiMotorObjText*  w = WikiMotorObjText_type ((*vtext)[0].get ());
1101         uiterator  b = w->text.begin ();
1102         uiterator  e = w->text.end ();
1103         
1104         if (b < e && *b == '<') {
1105             fcolspan = true;
1106             b ++;
1107             if (b < e && *b == '^') {
1108                 b ++;
1109                 spanmatch = true;
1110             }
1111         } else if (b < e && *b == '^') {
1112             frowspan = true;
1113             b ++;
1114             if (b < e && *b == '<') {
1115                 b ++;
1116                 spanmatch = true;
1117             }
1118         }
1119         (*vtext)[0].reset (new WikiMotorObjText (b, e));
1120     }
1121
1122     html = vtext->htmlOut (table->wiki);
1123     if (fcolspan) {
1124         if (! spanmatch || table->ary.size () <= 1 || table->ary[table->ary.size () - 2][idx].colspan == 0) {
1125             col = &table->ary.back ();
1126             for (i = idx - 1; i >= 0; i --) {
1127                 if ((*col)[i].colspan > 0) {
1128                     if (html.length () == 0 || (*col)[i].html == html) {
1129                         colspan = 0;
1130                         (*col)[i].colspan ++;
1131                     }
1132                     break;
1133                 }
1134             }
1135         }
1136     }
1137     if (frowspan) {
1138         if (! spanmatch || idx == 0 || table->ary.back ()[idx - 1].rowspan == 0) {
1139             for (i = table->ary.size () - 2; i >= 0; i --) {
1140                 col = &table->ary[i];
1141                 if (idx < col->size () && (*col)[idx].rowspan > 0) {
1142                     if (html.length () == 0 || (*col)[idx].html == html) {
1143                         rowspan = 0;
1144                         (*col)[idx].rowspan ++;
1145                     }
1146                     break;
1147                 }
1148             }
1149         }
1150     }
1151 }
1152
1153 void  WikiBlockTable::TableCell::outputTD (WikiFormat* wiki, MotorOutput* out, bool fturn) {
1154     int  i;
1155
1156     if (attrib.fheader)
1157         out->out_raw (CharConst ("<th"));
1158     else
1159         out->out_raw (CharConst ("<td"));
1160     attrib.output (out);
1161     if (attrib.fturn) {
1162         if (colspan > 1)
1163             wiki->outputName (out, CharConst ("rowspan"), colspan, false);
1164         if (rowspan > 1)
1165             wiki->outputName (out, CharConst ("colspan"), rowspan, false);
1166     } else {
1167         if (colspan > 1)
1168             wiki->outputName (out, CharConst ("colspan"), colspan, false);
1169         if (rowspan > 1)
1170             wiki->outputName (out, CharConst ("rowspan"), rowspan, false);
1171     }
1172     out->out_raw (CharConst (">"));
1173 }
1174
1175 void  WikiBlockTable::TableCell::outputTDe (MotorOutput* out) {
1176     if (attrib.fheader)
1177         out->out_raw (CharConst ("</th>\n"));
1178     else
1179         out->out_raw (CharConst ("</td>\n"));
1180 }
1181
1182 /* ============================================================ */
1183 bool  WikiBlockTable::nextLine (uiterator b, uiterator e) {
1184     if (*b == kWikiTABLE) {
1185         addLine (b, e);
1186         return true;
1187     } else {
1188         return false;
1189     }
1190 }
1191
1192 void  WikiBlockTable::addLine (uiterator b, uiterator e) {
1193     assert (b[0] == '|');
1194     b ++;
1195     if (n == 0 && matchSkip (b, e, CharConst ("table:"))) {
1196         addLine_head (b, e);
1197     } else {
1198         addLine_body (b, e);
1199     }
1200     n ++;
1201 }
1202
1203 WikiBlock::closeType  WikiBlockTable::closeLine (uiterator b, uiterator e) {
1204     static uregex  re ("^\\}\\}(($)|(\\|)|((!([1-9][0-9]*))?\\\\$))");
1205     umatch  m;
1206
1207     if (usearch (b, e, m, re)) {
1208         if (m[2].matched) {     // }}
1209             wiki->pop_block ();
1210             return CloseTrue;
1211         } else if (m[3].matched) { // }}|...
1212             wiki->pop_block ();
1213             if (wiki->cur && wiki->cur->type == BlockTable) {
1214                 WikiBlockTable*  obj = (WikiBlockTable*)wiki->cur;
1215                 obj->cont = true;
1216                 addLine_body (m[3].second, e);
1217             } else {
1218                 assert (0);
1219             }
1220             return CloseTrue;
1221         } else if (m[4].matched) {              // }}\     .
1222             wiki->pop_block ();
1223             if (wiki->cur && wiki->cur->type == BlockTable) {
1224                 WikiBlockTable*  obj = (WikiBlockTable*)wiki->cur;
1225                 obj->cont = true;
1226                 addLine_body (m[4].first, e);
1227             } else {
1228                 assert (0);
1229             }
1230             return CloseTrue;
1231         }
1232     }
1233     return CloseFalse;
1234 }
1235
1236 void  WikiBlockTable::output (MotorOutput* out) {
1237     normalize ();
1238     outputTableTag (out);
1239     outputTBody (out);
1240     out->out_raw (CharConst ("</table>\n"));
1241 }
1242
1243 void  WikiBlockTable::addLine_head (uiterator b, uiterator e) {
1244     WikiMotor  motor (b, e, wiki);
1245     WikiMotorObjVec  objv;
1246     WikiMotorObjVecVec  objvv;
1247     int  i;
1248     TableCell*  cell;
1249
1250     motor.compile (objv);
1251     objv.splitCharA ('|', objvv);
1252     if (objvv.size () > 0 && objvv.back ()->size () == 0)
1253         objvv.pop_back ();
1254     attrib.shiftAttrib (objvv[0]);
1255     for (i = 1; i < objvv.size (); i ++) {
1256         cell = new TableCell (wiki, true);
1257         cell->attrib.shiftAttrib (objvv[i]);
1258         defaultList.push_back (cell);
1259     }
1260 }
1261
1262 void  WikiBlockTable::addLine_body (uiterator b, uiterator e) {
1263     CellList_t*  cols;
1264     bool  fmorecell = false;
1265     umatch  m;
1266     static uregex  re ("(!([1-9][0-9]*))?\\\\$");
1267
1268     if (cont) {
1269         cont = false;
1270         cols = &ary.back ();
1271     } else {
1272         cols = new CellList_t;
1273         ary.push_back (cols);
1274     }
1275
1276     if (usearch (b, e, m, re)) { // 
1277         e = m[0].first;
1278         if (m[2].matched) {     // ...!NUM\         .
1279             int  v = strtoul (m[2].first);
1280             ccont ++;
1281             if (ccont >= v) {
1282                 cont = false;
1283                 ccont = 0;
1284             } else {
1285                 cont = true;
1286             }
1287         } else {                // ...\             .
1288             cont = true;
1289         }
1290         if (b < e && e[-1] == '|') { // ...|\       .
1291             fmorecell = true;
1292         }
1293     } else {
1294         ccont = 0;
1295     }
1296
1297     {
1298         WikiMotor  motor (b, e, wiki);
1299         WikiMotorObjVec  objv;
1300         WikiMotorObjVecVec  objvv;
1301         TableCell*  cell;
1302         int  i, n;
1303         bool  fop;
1304         static const ustring  brabra (CharConst ("{{"));
1305
1306         motor.compile (objv);
1307         objv.splitCharA ('|', objvv);
1308         if (objvv.size () > 0 && objvv.back ()->size () == 0) {
1309             objvv.pop_back ();
1310             fop = false;
1311         } else {
1312             fop = true;
1313         }
1314         n = objvv.size () - 1;
1315         for (i = 0; i <= n; i ++) {
1316             cell = newCell (cols->size ());
1317             if (! cell->attrib.shiftAttrib (objvv[i]))
1318                 return;
1319             if (i == n && fop && objvv[i]->match (brabra)) {
1320                 cols->push_back (cell);
1321                 wiki->push_block (&cell->block);
1322                 return;
1323             } else {
1324                 cell->cellBody (objvv[i].get (), this, cols->size ());
1325                 cols->push_back (cell);
1326             }
1327         }
1328         if (fmorecell) {
1329             cell = newCell (cols->size ());
1330             cols->push_back (cell);
1331         }
1332     }
1333 }
1334
1335 WikiBlockTable::TableCell*  WikiBlockTable::newCell (int idx) {
1336     TableCell*  ans = new TableCell (wiki, false);
1337
1338     if (idx < defaultList.size ())
1339         ans->attrib.copyFrom (defaultList[idx].attrib);
1340     return ans;
1341 }
1342
1343 void  WikiBlockTable::normalize () {
1344     int  maxcol = 0;
1345     int  i, j;
1346     CellList_t*  col;
1347     TableCell*  cell;
1348
1349     for (i = 0; i < ary.size (); i ++) {
1350         col = &ary[i];
1351         if (col->size () > maxcol)
1352             maxcol = col->size ();
1353     }
1354     if (attrib.fpadding) {
1355         for (i = 0; i < ary.size (); i ++) {
1356             col = &ary[i];
1357             if (col->size () < maxcol) {
1358                 cell = newCell (col->size ());
1359                 cell->colspan = maxcol - col->size ();
1360                 col->push_back (cell);
1361                 while (col->size () < maxcol) {
1362                     cell = newCell (col->size ());
1363                     cell->colspan = 0;
1364                     col->push_back (cell);
1365                 }
1366             }
1367         }
1368     } else {                    // expand
1369         for (i = 0; i < ary.size (); i ++) {
1370             col = &ary[i];
1371             for (j = col->size () - 1; j >= 0; j --) {
1372                 cell = &(*col)[j];
1373                 if (cell->colspan > 0) {
1374                     cell->colspan += maxcol - col->size ();
1375                     while (col->size () < maxcol) {
1376                         cell = newCell (col->size ());
1377                         cell->colspan = 0;
1378                         col->push_back (cell);
1379                     }
1380                     break;
1381                 }
1382             }
1383         }
1384     }
1385 }
1386
1387 void  WikiBlockTable::outputTableTag (MotorOutput* out) {
1388     int  i;
1389
1390     if (attrib.cellspacing < 0)
1391         attrib.cellspacing = 0;
1392     if (attrib.cellpadding < 0)
1393         attrib.cellpadding = 0;
1394     out->out_raw (CharConst ("<table"));
1395     attrib.output (out);
1396     out->out_raw (CharConst (">\n"));
1397 }
1398
1399 void  WikiBlockTable::outputTBody (MotorOutput* out) {
1400     int  i, j, n;
1401     CellList_t*  col;
1402     TableCell*  cell;
1403
1404     if (attrib.fturn) {
1405         if (ary.size () > 0) {
1406             n = ary[0].size ();
1407             for (j = 0; j < n; j ++) {
1408                 out->out_raw (CharConst ("<tr>\n"));
1409                 for (i = 0; i < ary.size (); i ++) {
1410                     col = &ary[i];
1411                     cell = &(*col)[j];
1412                     outputTBodyCell (wiki, out, cell);
1413                 }
1414                 out->out_raw (CharConst ("</tr>\n"));
1415             }
1416         }
1417     } else {
1418         for (i = 0; i < ary.size (); i ++) {
1419             col = &ary[i];
1420             out->out_raw (CharConst ("<tr>\n"));
1421             for (j = 0; j < col->size (); j ++) {
1422                 cell = &(*col)[j];
1423                 outputTBodyCell (wiki, out, cell);
1424             }
1425             out->out_raw (CharConst ("</tr>\n"));
1426         }
1427     }
1428 }
1429
1430 void  WikiBlockTable::outputTBodyCell (WikiFormat* wiki, MotorOutput* out, TableCell* cell) {
1431     if (cell->colspan > 0 && cell->rowspan > 0) {
1432         cell->outputTD (wiki, out, attrib.fturn);
1433         if (cell->block.size () > 0) {
1434             wiki->output (cell->block);
1435         } else {
1436             if (cell->html.size () > 0) {
1437                 out->out_toText (cell->html);
1438             } else {
1439                 if (! attrib.fnowhite)
1440                     out->out_raw (uNbsp);
1441             }
1442         }
1443         cell->outputTDe (out);
1444     }
1445 }
1446
1447 /* ============================================================ */
1448 /*DOC:
1449 ===selectタグ===
1450  |select:NAME:function:default:size=NUM:multiple|
1451  |VALUE|
1452  |LABEL|VALUE|selected|
1453
1454 */
1455 bool  WikiBlockSelect::nextLine (uiterator b, uiterator e) {
1456     if (*b == kWikiTABLE) {
1457         addLine (b, e);
1458         return true;
1459     } else {
1460         close ();
1461         return false;
1462     }
1463 }
1464
1465 void  WikiBlockSelect::addLine (uiterator b, uiterator e) {
1466     assert (b[0] == '|');
1467     b ++;
1468     if (n == 0 && matchSkip (b, e, CharConst ("select:"))) {
1469         addLine_head (b, e);
1470     } else {
1471         addLine_body (b, e);
1472     }
1473     n ++;
1474 }
1475
1476 void  WikiBlockSelect::addLine_head (uiterator b, uiterator e) {
1477     WikiMotor  motor (b, e, wiki);
1478     WikiMotorObjVec  objv;
1479     WikiMotorObjVecVec  objvv;
1480     WikiMotorObjVec*  vcell;
1481     bool  ferr;
1482
1483     motor.compile (objv);
1484     objv.splitCharA ('|', objvv);
1485     if (objvv.size () > 0 && objvv.back ()->size () == 0)
1486         objvv.pop_back ();
1487     if (objvv.size () > 0)
1488         attrib.shiftName (objvv[0], name);
1489     if (objvv.size () > 0) {
1490         attrib.shiftAttrib (objvv[0]);
1491     }
1492     if (attrib.fmultiple && attrib.elsize == 0) {
1493         attrib.elsize = 1;
1494     }
1495 }
1496
1497 void  WikiBlockSelect::addLine_body (uiterator b, uiterator e) {
1498     WikiMotor  motor (b, e, wiki);
1499     WikiMotorObjVec  objv;
1500     WikiMotorObjVecVec  objvv;
1501     SelectItem  v;
1502
1503     motor.compile (objv);
1504     objv.splitCharA ('|', objvv);
1505     if (objvv.size () > 0 && objvv.back ()->size () == 0)
1506         objvv.pop_back ();
1507     if (objvv.size () > 0) {
1508         v.label = omitCtrl (objvv[0].get ()->textOut (wiki));
1509     } else {
1510         v.label.resize (0);
1511     }
1512     if (objvv.size () > 1) {
1513         v.value = omitCtrl (objvv[1].get ()->textOut (wiki));
1514         v.fvalue = true;
1515     } else {
1516         v.value.resize (0);
1517         v.fvalue = false;
1518     }
1519     v.fselect = false;
1520     if (objvv.size () > 2) {
1521         if (objvv[2].get ()->match (CharConst ("selected"), CharConst ("sel"))) {
1522             v.fselect = true;
1523         }
1524     }
1525     item.push_back (v);
1526 }
1527
1528 void  WikiBlockSelect::close () {
1529     wiki->cur = NULL;
1530     wiki->pop_block ();
1531     assert (wiki->cur->type == BlockParagraph);
1532
1533     MotorOutputString  out;
1534     output (&out);
1535     wiki->cur->addHtml (out.ans);
1536     delete this;
1537 }
1538
1539 void  WikiBlockSelect::output (MotorOutput* out) {
1540     int  i;
1541     ustring  u;
1542
1543     if (attrib.elsize == 1)
1544         attrib.elsize = item.size ();
1545     out->out_raw (CharConst ("<select"));
1546     wiki->outputName (out, CharConst ("name"), name, false);
1547     attrib.output (out);
1548     if (attrib.script.length () > 0)
1549         wiki->outputName (out, CharConst ("onChange"), attrib.script);
1550     out->out_raw (CharConst (">\n"));
1551
1552     if (attrib.fdefault)
1553         u = wiki->getVar (name);
1554 #ifdef DEBUG2
1555     std::cerr << "u:" << u << uLF;
1556 #endif /* DEBUG */
1557
1558     for (i = 0; i < item.size (); i ++) {
1559         SelectItem*  v = &item[i];
1560         out->out_raw (CharConst ("<option"));
1561         if (v->fvalue) {
1562             wiki->outputName (out, CharConst ("value"), v->value, false);
1563             if (v->fselect || (attrib.fdefault && u == v->value))
1564                 out->out_raw (CharConst (" selected=\"selected\""));
1565         } else {
1566             if (v->fselect || (attrib.fdefault && u == v->label))
1567                 out->out_raw (CharConst (" selected=\"selected\""));
1568         }
1569         out->out_raw (CharConst (">"));
1570         out->out_toHTML (v->label)->out_raw (CharConst ("</option>\n"));
1571     }
1572     out->out_raw (CharConst ("</select>\n"));
1573 }
1574
1575 /* ============================================================ */
1576 /*DOC:
1577 ===引用===
1578  >
1579  この部分は,引用です。
1580  <
1581
1582 */
1583 bool  WikiBlockQuote::nextLine (uiterator b, uiterator e) {
1584     return false;
1585 }
1586
1587 WikiBlock::closeType  WikiBlockQuote::closeLine (uiterator b, uiterator e) {
1588     if (e - b == 1 && *b == kWikiQUOTE_e) {
1589         wiki->pop_block ();
1590         wiki->cur = NULL;
1591         return CloseTrue;
1592     } else {
1593         return CloseFalse;
1594     }
1595 }
1596
1597 void  WikiBlockQuote::addLine (uiterator b, uiterator e) {
1598     // do nothing
1599 }
1600
1601 void  WikiBlockQuote::output (MotorOutput* out) {
1602     out->out_raw (CharConst ("<blockquote>\n"));
1603     outputBlock (out);
1604     out->out_raw (CharConst ("</blockquote>\n"));
1605 }
1606
1607 /* ============================================================ */
1608 /*DOC:
1609 ===DIVタグ===
1610  {div:SideMenu
1611  ...
1612  }
1613  {div:id=Name:SideMenu:onclick=fn()
1614  ...
1615  }
1616
1617 */
1618 bool  WikiBlockDiv::nextLine (uiterator b, uiterator e) {
1619     return false;
1620 }
1621
1622 void  WikiBlockDiv::addLine (uiterator b, uiterator e) {
1623     bool  rc = matchSkip (b, e, CharConst ("{div:"));
1624     assert (rc);
1625     WikiMotor  motor (b, e, wiki);
1626     WikiMotorObjVecPtr  vec (new WikiMotorObjVec);
1627
1628     motor.compile (*vec);
1629     attrib.shiftAttrib (vec);
1630 }
1631
1632 WikiBlock::closeType  WikiBlockDiv::closeLine (uiterator b, uiterator e) {
1633     if (e - b == 1 && *b == kWikiDIV_e) {
1634         wiki->pop_block ();
1635         wiki->cur = NULL;
1636         return CloseTrue;
1637     } else {
1638         return CloseFalse;
1639     }
1640 }
1641
1642 void  WikiBlockDiv::output (MotorOutput* out) {
1643     out->out_raw (CharConst ("<div"));
1644     attrib.output (out);
1645     out->out_raw (CharConst (">\n"));
1646     outputBlock (out);
1647     out->out_raw (CharConst ("</div>\n"));
1648 }
1649
1650 /* ============================================================ */
1651 /*DOC:
1652 ===FORMタグ===
1653  {form:POST:post.hml
1654  ...
1655  }
1656 // {form:POST:id=form1:class=formclass:post.hml
1657 // {form:POST:post.hml:id=form1:class=formclass
1658  {form:POST:post.hml:target=target_window:id=form1:class=formclass
1659  ...
1660  }
1661
1662 */
1663 bool  WikiBlockForm::nextLine (uiterator b, uiterator e) {
1664     return false;
1665 }
1666
1667 void  WikiBlockForm::addLine (uiterator b, uiterator e) {
1668     bool  rc = matchSkip (b, e, CharConst ("{form:"));
1669     assert (rc);
1670
1671     WikiMotor  motor (b, e, wiki);
1672     WikiMotorObjVecPtr  vec (new WikiMotorObjVec);
1673     ustring  key;
1674     WikiMotorObjVecPtr  v2 (new WikiMotorObjVec);
1675
1676     motor.compile (*vec);
1677     vec->splitChar_keyword (':', key, *v2);
1678     if (match (key, CharConst ("get"), CharConst ("GET"))) {
1679         method = M_GET;
1680         vec = v2;
1681     } else if (match (key, CharConst ("post"), CharConst ("POST"))) {
1682         method = M_POST;
1683         vec = v2;
1684     }
1685     if (vec->size () > 0) {
1686         attrib.shiftLink (vec, url, fscript);
1687     }
1688     attrib.shiftAttrib (vec);
1689 }
1690
1691 WikiBlock::closeType  WikiBlockForm::closeLine (uiterator b, uiterator e) {
1692     if (e - b == 1 && *b == kWikiDIV_e) {
1693         wiki->pop_block ();
1694         wiki->cur = NULL;
1695         wiki->curform = NULL;
1696         return CloseTrue;
1697     } else {
1698         return CloseFalse;
1699     }
1700 }
1701
1702 void  WikiBlockForm::output (MotorOutput* out) {
1703     out->out_raw (CharConst ("<form"));
1704     switch (method) {
1705     case M_GET:
1706         out->out_raw (CharConst (" method=\"get\""));
1707         break;
1708     case M_NONE:
1709     case M_POST:
1710         out->out_raw (CharConst (" method=\"post\""));
1711         break;
1712     default:
1713         assert (0);
1714     }
1715     if (fscript) {
1716         wiki->outputName (out, CharConst ("action"), ustring (CharConst ("#")), false);
1717         wiki->outputSubmitScript (out, CharConst ("onSubmit"), url);
1718     } else {
1719         wiki->outputName (out, CharConst ("action"), url, false);
1720     }
1721     if (qfileform)
1722         out->out_raw (CharConst (" enctype=\"multipart/form-data\""));
1723     attrib.output (out);
1724     out->out_raw (CharConst (">\n"));
1725     outputBlock (out);
1726     out->out_raw (CharConst ("</form>\n"));
1727 }
1728
1729 /* ============================================================ */
1730 /*DOC:
1731 ===水平線===
1732  ----
1733
1734 */
1735 bool  WikiBlockHR::nextLine (uiterator b, uiterator e) {
1736     return false;
1737 }
1738
1739 void  WikiBlockHR::addLine (uiterator b, uiterator e) {
1740     // do nothing
1741 }
1742
1743 void  WikiBlockHR::output (MotorOutput* out) {
1744     out->out_raw (CharConst (uHR));
1745 }
1746
1747 /* ============================================================ */
1748 void  WikiFormat::pass1 (const ustring& text, WikiLine::linevec* block, bool fsuper) {
1749     Splitter  sp (text, re_nl);
1750
1751     pass1_1 (sp, NULL, NULL, block, NULL, NULL, NULL, fsuper);
1752 }
1753
1754 int  WikiFormat::pass1_1 (Splitter& sp, ustring* elseword, ustring* endword, WikiLine::linevec* block, uiterator* elsebegin0, uiterator* elsebegin, uiterator* elseend, bool fsuper) {
1755     uiterator  b, e, t, u, v;
1756     umatch  m;
1757
1758     while (sp.next ()) {
1759         b = sp.begin ();
1760         e = sp.end ();
1761         while (b < e && b[0] == '\t')
1762             b ++;
1763         if (matchSkip (b, e, CharConst (kComment))) {
1764             // comment
1765         } else if (b != e && b[0] == kWikiCmd) {
1766             if (usearch (b, e, m, re_wikicmdsep)) {
1767                 t = b;
1768                 u = m[0].first;
1769                 v = m[0].second;
1770             } else {
1771                 t = b;
1772                 u = e;
1773                 v = e;
1774             }
1775             if (endword && match (t, u, *endword)) { 
1776                 return 2;       // endword
1777             } else if (elseword && match (t, u, *elseword)) {
1778                 if (elsebegin0)
1779                     *elsebegin0 = t;
1780                 if (elsebegin)
1781                     *elsebegin = v;
1782                 if (elseend)
1783                     *elseend = e;
1784                 return 1;       // elseword
1785             } else if (pass1_2 (sp, b, e, t, u, v, block, fsuper)) {
1786             } else {
1787                 WikiLine*  wl;
1788                 block->push_back (wl = new WikiLine (b, e, fsuper));
1789                 wl->fn = wc_call_defun;
1790             }
1791         } else {
1792             block->push_back (new WikiLine (b, e, fsuper));
1793         }
1794     }
1795     return 0;                   // end of line
1796 }
1797
1798 bool  WikiFormat::pass1_2 (Splitter& sp, uiterator& b, uiterator& e, uiterator& t, uiterator& u, uiterator& v, WikiLine::linevec* block, bool fsuper) {
1799     WikiCmdTable::iterator  it;
1800     ustring  elseword, endword;
1801     WikiLine*  wl;
1802     WikiLine*  wl2;
1803     int  rc;
1804
1805     if ((it = GWikiCmdTable.find (ustring (t, u))) != GWikiCmdTable.end ()) {
1806         block->push_back (wl = new WikiLine (b, v, e, fsuper));
1807         wl->fn = it->second->fn;
1808         if (it->second->endname) {
1809             endword.assign (it->second->endname, it->second->endnamelen);
1810             if (it->second->elsename) {
1811                 elseword.assign (it->second->elsename, it->second->elsenamelen);
1812                 // if-then-else block
1813                 wl->block = new WikiLine::linevec;
1814                 rc = pass1_1 (sp, &elseword, &endword, wl->block, &b, &v, &e, fsuper);
1815                 switch (rc) {
1816                 case 0: // eot
1817                         // no end line
1818                     if (endword.length () > 0) {
1819                         errorMsg.append (CharConst ("no matcing \"")).append (endword).append (CharConst ("\".\n"));
1820                     }
1821                     break;
1822                 case 1: // else
1823                     do {
1824                         wl2 = new WikiLine (b, v, e, fsuper);
1825                         wl2->fn = wl->fn;
1826                         wl->block2 = wl2;
1827                         wl = wl2;
1828                         wl->block = new WikiLine::linevec;
1829                         rc = pass1_1 (sp, &elseword, &endword, wl->block, &b, &v, &e, fsuper);
1830                         if (rc == 0) {
1831                             // no end line
1832                             if (endword.length () > 0) {
1833                                 errorMsg.append (CharConst ("no matcing \"")).append (endword).append (CharConst ("\".\n"));
1834                             }
1835                         } else if (rc == 2) {
1836                             assert (wl->block2 == NULL);
1837                             wl->block2 = new WikiLine (sp.begin (), sp.end (), false);
1838                         }
1839                     } while (rc == 1);
1840                     break;
1841                 case 2: // end
1842                     assert (wl->block2 == NULL);
1843                     wl->block2 = new WikiLine (sp.begin (), sp.end (), false);
1844                     break;
1845                 default:
1846                     assert (0);
1847                 }
1848             } else {
1849                 // block
1850                 wl->block = new WikiLine::linevec;
1851                 rc = pass1_1 (sp, NULL, &endword, wl->block, NULL, NULL, NULL, fsuper);
1852                 if (rc == 0) {
1853                     // no end line error
1854                     if (endword.length () > 0) {
1855                         errorMsg.append (CharConst ("no matcing \"")).append (endword).append (CharConst ("\".\n"));
1856                     }
1857                 } else if (rc == 2) {
1858                     assert (wl->block2 == NULL);
1859                     wl->block2 = new WikiLine (sp.begin (), sp.end (), false);
1860                 }
1861             }
1862         } else {
1863             // nonblock
1864         }
1865         return true;
1866     }
1867
1868     return false;
1869 }
1870
1871 #ifdef DEBUG2
1872 static void  dump (WikiLine::linevec* block, int indent = 0) {
1873     int  i, j;
1874     if (! block) {
1875         for (j = 0; j < indent; j ++) std::cerr << "    ";
1876         std::cerr << "(NULL)\n";
1877         return;
1878     }
1879     for (i = 0; i < block->size (); i ++) {
1880         WikiLine*  wl = &(*block)[i];
1881         for (j = 0; j < indent; j ++) std::cerr << "    ";
1882         if (wl->fn)
1883             std::cerr << (void*)wl->fn << ":";
1884         std::cerr << ustring (wl->begin, wl->end) << uLF;
1885         while (1) {
1886             if (wl->block) {
1887                 dump (wl->block, indent + 1);
1888             }
1889             if (wl->block2) {
1890                 wl = wl->block2;
1891                 for (j = 0; j < indent; j ++) std::cerr << "    ";
1892                 std::cerr << "else:" << (void*)wl->fn << ":" << ustring (wl->begin, wl->end) << uLF;
1893                 //          dump (wl->block, indent + 1);
1894             } else {
1895                 break;
1896             }
1897         }
1898     }
1899 }
1900 #endif /* DEBUG */
1901
1902 void  WikiFormat::compile (const ustring& text, bool fsuper) {
1903     try {
1904         WikiLine::linevec  block;
1905         pass1 (text, &block, fsuper);
1906 #ifdef DEBUG2
1907         dump (&block);
1908 #endif /* DEBUG */
1909
1910         {
1911             WikiLineScanner  scanner (&block);
1912             compileLines (scanner);
1913             while (1) {
1914                 if (cur)
1915                     cur->close ();
1916                 cur = NULL;
1917                 if (bstack.size () > 0)
1918                     pop_block ();
1919                 else
1920                     break;
1921             }
1922             cur = NULL;
1923         }
1924     } catch (ustring& msg) {
1925         logLispFunctionError (msg, uEmpty);
1926     }
1927 }
1928
1929 void  WikiFormat::output (boost::ptr_vector<WikiBlock>& ary) {
1930     int  i;
1931
1932     for (i = 0; i < ary.size (); i ++) {
1933         ary[i].output (env->output);
1934     }
1935     errorOutput ();
1936 }
1937
1938 void  WikiFormat::errorOutput () {
1939     if (errorMsg.size () > 0) {
1940         env->output->out_raw (CharConst (uP));
1941         env->output->out_toHTML_br (errorMsg);
1942         env->output->out_raw (CharConst (uPe));
1943         errorMsg.resize (0);
1944     }
1945 }
1946
1947 bool  WikiFormat::checkClose (uiterator b, uiterator e) {
1948     int  n = bstack.size ();
1949     WikiBlock::closeType  rc;
1950
1951     while (n > 0) {
1952         n --;
1953         rc = bstack[n]->closeLine (b, e);
1954         switch (rc) {
1955         case WikiBlock::CloseTrue:
1956             return true;
1957         case WikiBlock::CloseFalse:
1958             return false;
1959         }
1960     }
1961     return false;
1962 }
1963
1964 void  WikiFormat::compileLine (WikiLineScanner& scanner) {
1965     WikiLine*  wl = scanner.cur ();
1966     if (! wl)
1967         return;
1968
1969     uiterator  b = wl->begin;
1970     uiterator  e = wl->end;
1971
1972     if (wl->fn) {
1973         wl->fn (wl, this);
1974     } else {
1975         if (b == e) {           // empty line
1976             if (cur) {
1977                 cur->close ();
1978                 cur = NULL;
1979             }
1980         } else if (matchSkip (b, e, CharConst ("//"))) {        // comment
1981         } else if (checkClose (b, e)) {
1982         } else if (cur && cur->nextLine (b, e)) {
1983         } else if (b[0] == kWikiP) { // ^
1984             if (cur)
1985                 cur->close ();
1986             cur = new WikiBlockParagraph (this);
1987             blockp->push_back (cur);
1988             cur->addLine (b, e);
1989         } else if (b[0] == kWikiH) {    // =
1990             WikiBlockH*  obj;
1991             if (cur)
1992                 cur->close ();
1993             cur = obj = new WikiBlockH (this);
1994             blockp->push_back (cur);
1995             cur->addLine (b, e);
1996             push_block (&obj->block);
1997         } else if (b[0] == kWikiPRE     // SPC
1998                    || b[0] == kWikiPRE2) {      // TAB
1999             if (cur)
2000                 cur->close ();
2001             cur = new WikiBlockPreformat (this);
2002             blockp->push_back (cur);
2003             cur->addLine (b, e);
2004         } else if (b[0] == kWikiUL) {   // *
2005             WikiBlockItem*  obj;
2006             if (cur)
2007                 cur->close ();
2008             cur = obj = new WikiBlockItem (WikiBlock::BlockItemUL, this);
2009             blockp->push_back (cur);
2010             obj->addLine (b, e);
2011         } else if (b[0] == kWikiOL) {   // #
2012             WikiBlockItem*  obj;
2013             if (cur)
2014                 cur->close ();
2015             cur = obj = new WikiBlockItem (WikiBlock::BlockItemOL, this);
2016             blockp->push_back (cur);
2017             obj->addLine (b, e);
2018         } else if (b[0] == kWikiNL) {   // ]
2019             WikiBlockItem*  obj;
2020             if (cur)
2021                 cur->close ();
2022             cur = obj = new WikiBlockItem (WikiBlock::BlockItemNL, this);
2023             blockp->push_back (cur);
2024             obj->addLine (b, e);
2025         } else if (b[0] == kWikiDL) {   // ;
2026             if (cur)
2027                 cur->close ();
2028             cur = new WikiBlockItemDL (this);
2029             blockp->push_back (cur);
2030             cur->addLine (b, e);
2031         } else if (matchHead (b, e, CharConst ("|select:"))) {  // |select:
2032             if (cur && cur->type == WikiBlock::BlockParagraph) {
2033             } else {
2034                 if (cur)
2035                     cur->close ();
2036                 cur = new WikiBlockParagraph (this);
2037                 blockp->push_back (cur);
2038             }
2039             push_block (NULL);
2040             cur = new WikiBlockSelect (this);
2041             cur->addLine (b, e);
2042         } else if (b[0] == kWikiTABLE) {        // |
2043             WikiBlockTable*  obj;
2044             if (cur)
2045                 cur->close ();
2046             cur = obj = new WikiBlockTable (this);
2047             blockp->push_back (cur);
2048             cur->addLine (b, e);
2049         } else if (b[0] == kWikiQUOTE && e - b == 1) {  // >
2050             WikiBlockQuote*  obj;
2051             if (cur)
2052                 cur->close ();
2053             cur = obj = new WikiBlockQuote (this);
2054             blockp->push_back (cur);
2055             push_block (&obj->block);
2056         } else if (matchHead (b, e, CharConst ("{div:"))) {
2057             WikiBlockComplex*  obj;
2058             if (cur)
2059                 cur->close ();
2060             cur = obj = new WikiBlockDiv (this);
2061             blockp->push_back (cur);
2062             cur->addLine (b, e);
2063             push_block (&obj->block);
2064         } else if (curform == NULL && matchHead (b, e, CharConst ("{form:"))) {
2065             WikiBlockComplex*  obj;
2066             if (cur)
2067                 cur->close ();
2068             cur = obj = curform = new WikiBlockForm (this);
2069             blockp->push_back (cur);
2070             cur->addLine (b, e);
2071             push_block (&obj->block);
2072         } else if (matchHead (b, e, CharConst ("----"))) { // ----
2073             if (cur)
2074                 cur->close ();
2075             cur = new WikiBlockHR (this);
2076             blockp->push_back (cur);
2077             cur->addLine (b, e);
2078         } else {
2079         Bp1:
2080             if (cur && cur->type != WikiBlock::BlockParagraph) {
2081                 cur->close ();
2082                 cur = NULL;
2083             }
2084             if (! cur) {
2085                 cur = new WikiBlockParagraph (this);
2086                 blockp->push_back (cur);
2087             }
2088             cur->addLine (b, e);
2089         }
2090     }
2091 }
2092
2093 void  WikiFormat::compileLines (WikiLineScanner& scanner, bool (*fn)(WikiLine& spp, WikiLineScanner& scanner, WikiFormat* wiki, void* par), void* par) {
2094     WikiLine*  wl;
2095
2096     while (wl = scanner.next ()) {
2097         if (fn && fn (*scanner.cur (), scanner, this, par)) {
2098             break;
2099         } else {
2100             compileLine (scanner);
2101         }
2102     }
2103 }
2104
2105 int  WikiFormat::countWikiH (uiterator& b, uiterator e) {
2106     int  ans = 0;
2107
2108     while (b != e && *b == kWikiH) {
2109         ans ++;
2110         b ++;
2111     }
2112     if (ans > 6)
2113         ans = 6;
2114     return ans;
2115 }
2116
2117 bool  WikiFormat::paramID (const ustring& key, WikiMotorObjVec& vval, ustring& var_id, bool& ferr) {
2118     if (match (key, CharConst ("id"))) {
2119         ustring  value (vval.textOut (this));
2120         if (value.length () > 0) {
2121             if (checkWikiID (value)) {
2122                 var_id = value;
2123                 ferr = false;
2124             } else {
2125                 errorMsg.append (key).append (uEq).append (value).append (CharConst (": bad id\n"));
2126                 ferr = true;
2127             }
2128         }
2129         return true;
2130     } else {
2131         return false;
2132     }
2133 }
2134
2135 bool  WikiFormat::paramClass (const ustring& key, WikiMotorObjVec& vval, std::vector<ustring>& classes, bool& ferr) {
2136     if (match (key, CharConst ("class"))) {
2137         paramClassValue (vval, classes, ferr);
2138         return true;
2139     } else {
2140         return false;
2141     }
2142 }
2143
2144 void  WikiFormat::paramClassValue (WikiMotorObjVec& vval, std::vector<ustring>& classes, bool& ferr) {
2145     WikiMotorObjVecVec  args;
2146     ferr = false;
2147     vval.splitCharA (',', args);
2148     for (int i = 0; i < args.size (); i ++) {
2149         ustring  value (args[i]->textOut (this));
2150         if (value.length () > 0) {
2151             if (checkWikiID (value)) {
2152                 classes.push_back (value);
2153             } else {
2154                 errorMsg.append (value).append (CharConst (": bad class name\n"));
2155                 ferr = true;
2156             }
2157         }
2158     }
2159 }
2160
2161 bool  WikiFormat::paramName (const ustring& key, WikiMotorObjVec& vval, ustring& var, bool& ferr) {
2162     if (match (key, CharConst ("name"))) {
2163         ustring  value (vval.textOut (this));
2164         if (checkWikiID (value)) {
2165             var = value;
2166             ferr = false;
2167         } else {
2168             ferr = true;
2169         }
2170         return true;
2171     } else {
2172         return false;
2173     }
2174 }
2175
2176 bool  WikiFormat::paramWidth (const ustring& key, WikiMotorObjVec& vval, ustring& var, bool& ferr) {
2177     if (match (key, CharConst ("width"), CharConst ("w"))) {
2178         ustring  value (vval.textOut (this));
2179         if (checkWidth (value)) {
2180             var = value;
2181             if (checkNum (value))
2182                 var.append (CharConst ("px"));
2183             ferr = false;
2184         } else {
2185             ferr = true;
2186         }
2187         return true;
2188     } else {
2189         return false;
2190     }
2191 }
2192
2193 bool  WikiFormat::paramHeight (const ustring& key, WikiMotorObjVec& vval, ustring& var, bool& ferr) {
2194     if (match (key, CharConst ("height"), CharConst ("h"))) {
2195         ustring  value (vval.textOut (this));
2196         if (checkWidth (value)) {
2197             var = value;
2198             ferr = false;
2199         } else {
2200             errorMsg.append (key).append (uEq).append (value).append (CharConst (": bad value\n"));
2201             ferr = true;
2202         }
2203         return true;
2204     } else {
2205         return false;
2206     }
2207 }
2208
2209 bool  WikiFormat::paramSize (const char* name, size_t namelen, const ustring& key, WikiMotorObjVec& vval, ustring& var, bool& ferr) {
2210     if (match (key, name, namelen)) {
2211         ustring  value (vval.textOut (this));
2212         if (checkNum (value)) {
2213             var = value;
2214             ferr = false;
2215         } else {
2216             ferr = true;
2217         }
2218         return true;
2219     }
2220     return false;
2221 }
2222
2223 void  WikiFormat::paramUNum (const ustring& value, int& var, const ustring& name) {
2224     if (checkNum (value)) {
2225         var = strtoul (value);
2226     } else {
2227         errorMsg.append (name).append (uEq).append (value).append (uErrorBadValue).append (uLF);
2228     }
2229 }
2230
2231 void  WikiFormat::paramColor (const ustring& value, ustring& var, const ustring& name) {
2232     if (checkColor (value)) {
2233         var = value;
2234     } else {
2235         errorMsg.append (name).append (uEq).append (value).append (uErrorBadValue).append (uLF);
2236     }
2237 }
2238
2239 bool  WikiFormat::paramTargetCheck (const ustring& key) {
2240     return match (key, CharConst ("target"));
2241 }
2242
2243 void  WikiFormat::paramTargetBody (const ustring& key, const ustring& value, ustring& var, bool& ferr) {
2244     if (value.length () == 0 || checkWikiID (value)) {
2245         var = value;
2246     } else {
2247         if (key.length () > 0)
2248             errorMsg.append (key).append (uEq).append (value).append (CharConst (": bad target name.\n"));
2249         else
2250             errorMsg.append (value).append (CharConst (": bad target name.\n"));
2251         ferr = true;
2252     }
2253 }
2254
2255 bool  WikiFormat::paramOnClickCheck (const ustring& name) {
2256     return match (name, CharConst ("onclick"));
2257 }
2258
2259 void  WikiFormat::outputName (MotorOutput* out, const char* name, size_t len, const ustring& val, bool cond) {
2260     if (! cond || val.length () > 0)
2261         out->out_raw (uSPC)
2262             ->out_raw (name, len)
2263             ->out_raw (CharConst ("=\""))
2264             ->out_toHTML_noCtrl (val)
2265             ->out_raw (uQ2);
2266 }
2267
2268 void  WikiFormat::outputName (MotorOutput* out, const char* name, size_t len, long val, bool cond) {
2269     if (! cond || val > 0)
2270         out->out_raw (uSPC)
2271             ->out_raw (name, len)
2272             ->out_raw (CharConst ("=\""))
2273             ->out_raw (to_ustring (val))
2274             ->out_raw (uQ2);
2275 }
2276
2277 void  WikiFormat::outputFlag (MotorOutput* out, const char* name, size_t len, bool flag) {
2278     if (flag)
2279         out->out_raw (uSPC)
2280             ->out_raw (name, len)
2281             ->out_raw (CharConst ("=\""))
2282             ->out_raw (name, len)
2283             ->out_raw (uQ2);
2284 }
2285
2286 void  WikiFormat::outputID (MotorOutput* out, const ustring& id) {
2287     if (id.length () > 0)
2288         out->out_raw (CharConst (" id=\""))
2289             ->out_toHTML_noCtrl (id)
2290             ->out_raw (uQ2);
2291 }
2292
2293 void  WikiFormat::outputClass (MotorOutput* out, std::vector<ustring>& classes) {
2294     if (classes.size () > 0) {
2295         out->out_raw (CharConst (" class=\""));
2296         for (int i = 0; i < classes.size (); i ++) {
2297             if (i > 0)
2298                 out->out_raw (uSPC);
2299             out->out_toHTML_noCtrl (classes[i]);
2300         }
2301         out->out_raw (uQ2);
2302     }
2303 }
2304
2305 void  WikiFormat::outputSubmitScript (MotorOutput* out, const char* name, size_t len, const ustring& onclick) {
2306     if (onclick.length () > 0)
2307         out->out_raw (uSPC)
2308             ->out_raw (name, len)
2309             ->out_raw (CharConst ("=\""))
2310             ->out_toHTML_noCtrl (onclick)
2311             ->out_raw ("return false;\"");
2312 //          ->out_raw ("\"");
2313 }
2314
2315 void  WikiFormat::wikiMotor (uiterator b, uiterator e, WikiMotorObjVec& ans) {
2316     WikiMotor  motor (b, e, this);
2317
2318     motor.compile (ans, WikiMotor::TMATCH_NONE);
2319 }
2320
2321 ustring  WikiFormat::wikiMotor (uiterator b, uiterator e) {
2322     WikiMotorObjVec  objv;
2323
2324     wikiMotor (b, e, objv);
2325     return objv.htmlOut (this);
2326 }
2327
2328 MNode*  WikiFormat::buildArgs (WikiMotorObjVecVec::const_iterator b, WikiMotorObjVecVec::const_iterator e, bool dumpmode) {
2329     MNodeList  ans;
2330
2331     if (dumpmode) {
2332         for (; b < e; b ++) {
2333             ans.append (newMNode_str (new ustring ((*b)->dump ())));
2334         }
2335     } else {
2336         for (; b < e; b ++) {
2337             ans.append (newMNode_str (new ustring ((*b)->textOut (this))));
2338         }
2339     }
2340     
2341     return ans.release ();
2342 #if 0
2343     MNode*  ans = NULL;
2344     MNode*  a;
2345
2346     if (b < e) {
2347         ans = a = new MNode;
2348         a->set_car (newMNode_str (new ustring ((*b)->textOut (this))));
2349         for (b ++; b < e; b ++) {
2350             newMNodeCdr (a);
2351             a->set_car (newMNode_str (new ustring ((*b)->textOut (this))));
2352         }
2353     }
2354     return ans;
2355 #endif
2356 }
2357
2358 void  WikiFormat::logLispFunctionError (const ustring& msg, const ustring& cmd) {
2359     if (cmd.length () > 0)
2360         errorMsg.append (cmd).append (CharConst (": "));
2361     errorMsg.append (CharConst ("lisp function error.\n"));
2362     if (mlenv->env->mlenv->currentCell ()) {
2363         if (mlenv->env->log)
2364             *mlenv->env->log << mlenv->env->mlenv->currentCell ()->dump_string_short () << ": ";
2365         *mlenv->env->log << msg << uLF;
2366     }
2367 }
2368
2369 /* ============================================================ */