OSDN Git Service

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