OSDN Git Service

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