OSDN Git Service

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