OSDN Git Service

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