OSDN Git Service

fix for FreeBSD 11.1.
[hmh/hhml.git] / wiki / wikiformat.cc
index 2d6870f..18b5f88 100644 (file)
@@ -19,7 +19,7 @@
 /*
   WIKIMOTORPRE: セットすると,フォーマット済みテキストブロックの中でインライン要素の解釈を行う。
   UTF8JP: セットすると,条件によりパラグラフ内の改行を空白に置き換えない。
-  TABLECOMPATFLAG: セットすると,旧形式の表の継続記号もゆるす。
+  WIKITABLECOMPATFLAG: セットすると,旧形式の表の継続記号もゆるす。
 */
 
 #define  kComment      "//"
 #define  kWikiQUOTE    '>'
 #define  kWikiQUOTE_e  '<'
 #define  kWikiDIV      '{'
+#define  uWikiDIV      "{div:"
+#define  uWikiFORM     "{form:"
+#define  uWikiELEMENT  "{element:"
 #define  kWikiDIV_e    '}'
 #define  kWikiHR       '-'
 #define  kWikiCmd      '$'
+#define  uWikiCmd      "$"
 
 #define  uP    "<p>"
 #define  uPe   "</p>\n"
@@ -61,6 +65,7 @@ ustring  uWiki (CharConst ("wiki_"));
 ustring  uAWiki (CharConst ("@wiki_"));
 
 /*DOC:
+$premode:1
 ==テキストの整形ルール==
 
 */
@@ -127,6 +132,19 @@ void  WikiBlockComplex::outputBlock (MotorOutput* out) {
  ^行頭が他のマークアップ文字になるときは,行頭に^を書く。
  
  空行は,段落を分ける。
+ 段落と段落の間に空行を2行以上入れると、「<div class="pggap"></div>」を出力する。
+
+{div:greenbox
+マークアップ文字以外の文字で書き出すと,段落になる。
+^行頭が他のマークアップ文字になるときは,行頭に^を書く。
+
+空行は,段落を分ける。
+
+
+段落と段落の間に空行を2行以上入れると、「<div class="pggap"></div>」を出力する。
+}
 
 */
 bool  WikiBlockParagraph::nextLine (uiterator b, uiterator e) {
@@ -210,11 +228,16 @@ void  WikiBlockParagraph::output (MotorOutput* out) {
 /* ============================================================ */
 /*DOC:
 ===タイトル===
+行頭に=を書くと,タイトルになる。行末の=は,省略可。
+
  =タイトル1=
  ==タイトル2==
  ===タイトル3===#anchor1
-
-行頭に=を書くと,タイトルになる。行末の=は,省略可。
+{div:greenbox
+=タイトル1=
+==タイトル2==
+===タイトル3===#anchor1
+}
 
 */
 
@@ -271,8 +294,10 @@ WikiBlock::closeType  WikiBlockH::closeLine (uiterator b, uiterator e) {
                            wiki->cur->close ();
                        wiki->cur = NULL;
                        return CloseTrue;
+                   default:;
                    }
                }
+           default:;
            }
        }
        // no opening point.
@@ -315,9 +340,6 @@ void  WikiBlockH::output (MotorOutput* out) {
     if (checkEmpty ())
        return;
 
-//    for (i = level0 + 1; i <= level; i ++) {
-//     outputBeginDiv (i, out);
-//    }
     outputBeginDiv (level, out);
     switch (level) {
     case 1: out->out_raw (CharConst (uH1)); break;
@@ -341,9 +363,6 @@ void  WikiBlockH::output (MotorOutput* out) {
     case 6: out->out_raw (CharConst (uH6e)); break;
     }
     outputBlock (out);
-//    for (i = level; i > level0; i --) {
-//     outputEndDiv (i, out);
-//    }
     outputEndDiv (level, out);
 }
 
@@ -375,6 +394,9 @@ bool  WikiBlockH::checkEmpty () {
 ===フォーマット済みテキストブロック===
   行頭に空白文字を書くと,<pre>〜</pre>タグで囲まれます。
 インライン要素の解釈は行われない。
+{div:greenbox
+ 行頭に空白文字を書くと,<pre>〜</pre>タグで囲まれます。
+}
 
 */
 bool  WikiBlockPreformatRaw::nextLine (uiterator b, uiterator e) {
@@ -388,29 +410,21 @@ bool  WikiBlockPreformatRaw::nextLine (uiterator b, uiterator e) {
 
 void  WikiBlockPreformatRaw::addLine (uiterator b, uiterator e) {
     markup = *b;
-#ifdef WIKIMOTORPRE
-    if (markup == ' ') {
-       text.append (wiki->wikiMotor (b + 1, e));
-    } else {
+
+    if (markup == ' ')
+       b ++;
+    if (wiki->motorPre) {
        text.append (wiki->wikiMotor (b, e));
-    }
-    text.append (uLF);
-#else
-    if (markup == ' ') {
-       text.append (b + 1, e);
     } else {
-       text.append (b, e);
+       MotorOutputString  o;
+       o.out_toHTML (ustring (b, e));
+       text.append (o.ans);
     }
     text.append (uLF);
-#endif
 }
 
 void  WikiBlockPreformatRaw::output (MotorOutput* out) {
-#ifdef WIKIMOTORPRE
     out->out_raw (CharConst ("<pre>"))->out_toText (text)->out_raw (CharConst ("</pre>\n"));
-#else
-    out->out_raw (CharConst ("<pre>"))->out_toHTML (text)->out_raw (CharConst ("</pre>\n"));
-#endif
 }
 
 /* ============================================================ */
@@ -459,33 +473,54 @@ void  WikiBlockItemText::output (MotorOutput* out) {
     if (indentHack) {
        outputBlock (out);
     } else {
-       out->out_raw (CharConst ("<li"));
-       attrib.output (out);
-       out->out_raw (CharConst (">"));
-       out->out_toText (html);
-       outputBlock (out);
-       out->out_raw (CharConst ("</li>\n"));
+       if (html.length () > 0) {
+           out->out_raw (CharConst ("<li"));
+           attrib.output (out);
+           out->out_raw (CharConst (">"));
+           out->out_toText (html);
+           outputBlock (out);
+           out->out_raw (CharConst ("</li>\n"));
+       } else {
+           outputBlock (out);
+       }
     }
 }
 
 /* ============================================================ */
 /*DOC:
 ===箇条書き===
-{div:pre
-+&*;項目1
-+&*;*項目1-1
-+&#;ナンバリング1
-+&#;#ナンバリング1-2
-+&+;インデント1
-+&+;+インデント1-1
-+&*;''[OPTION1:OPTION2:...:]''TEXT
-}
+ *項目1
+ **項目1-1
+ #ナンバリング1
+ ##ナンバリング1-2
+ +インデント1
+ ++インデント1-1
+ *''[OPTION1:OPTION2:...:]''TEXT
+ *id=item1:class=style1:onclick=[[ignore:]]:TEXT
+
 行頭に「*」を書くと,<UL>タグによるリスト,「#」を書くと<NL>タグによる番号付きリスト,「+」を書くとnobullクラス指定の<UL>タグによるリスト。
 
-|h:オプション|
-|id=''ID''|
-|class=''CLASS,...''|
-|onclick=''LINK-FUNCTION:PARAM1:...::''|
+オプションパラメータ
+|table:w=100%|t:w=20%|c:w=10%|t:|
+|h:オプション|h:省略形|h:説明|
+|'''id='''''ID''||id属性。|
+|'''class='''''ClassList''||class属性。複数のクラスを指定する場合はコンマ区切りで連ねる。|
+//|'''data-'''''name'''''='''''ID''||Bootstrap用属性。|
+|'''onclick='''''Link''||onclick属性。Javascriptリンク。|
+|'''onfocus='''''Link''||onfocus属性。Javascriptリンク。|
+|'''onblur='''''Link''||onblur属性。Javascriptリンク。|
+|'''onchange='''''Link''||onchange属性。Javascriptリンク。|
+|'''start='''''Number''||start属性。OLのみ。|
+
+{div:greenbox
+*項目1
+**項目1-1
+#ナンバリング1
+##ナンバリング1-2
++インデント1
+++インデント1-1
+*id=item1:class=style1:onclick=[[ignore:]]:TEXT
+}
 
 */
 bool  WikiBlockItem::nextLine (uiterator b, uiterator e) {
@@ -513,7 +548,7 @@ void  WikiBlockItem::addLine (uiterator b, uiterator e) {
     assert (b != e && b[0] == ch);
     b ++;
     if (b == e) {
-       wbt = new WikiBlockItemText (wiki);
+       wbt = new WikiBlockItemText (wiki, this);
        block.push_back (wbt);
        wbt->addLine (b, e);
     } else {
@@ -527,7 +562,7 @@ void  WikiBlockItem::addLine (uiterator b, uiterator e) {
            case kWikiOL:       // #
                wbi = new WikiBlockItem (WikiBlock::BlockItemOL, wiki);
                break;
-           case kWikiNL:       // ]
+           case kWikiNL:       // +
                wbi = new WikiBlockItem (WikiBlock::BlockItemNL, wiki);
                break;
            default:
@@ -539,14 +574,14 @@ void  WikiBlockItem::addLine (uiterator b, uiterator e) {
                    wbi->addLine (b, e);
                    wbt->block.push_back (wbi);
                } else {
-                   wbt = new WikiBlockItemText (wiki);
+                   wbt = new WikiBlockItemText (wiki, this);
                    block.push_back (wbt);
                    wbi->addLine (b, e);
                    wbt->block.push_back (wbi);
                    wbt->indentHack = true;
                }
            } else {
-               wbt = new WikiBlockItemText (wiki);
+               wbt = new WikiBlockItemText (wiki, this);
                block.push_back (wbt);
                wbt->addLine (b, e);
            }
@@ -559,17 +594,25 @@ void  WikiBlockItem::output (MotorOutput* out) {
 
     switch (type) {
     case BlockItemUL:
-       out->out_raw (CharConst ("<ul>\n"));
+       out->out_raw (CharConst ("<ul"));
+       attrib.output (out);
+       out->out_raw (CharConst (">\n"));
        outputBlock (out);
        out->out_raw (CharConst ("</ul>\n"));
        break;
     case BlockItemOL:
-       out->out_raw (CharConst ("<ol>\n"));
+       out->out_raw (CharConst ("<ol"));
+       attrib.output (out);
+       out->out_raw (CharConst (">\n"));
        outputBlock (out);
        out->out_raw (CharConst ("</ol>\n"));
        break;
     case BlockItemNL:
-       out->out_raw (CharConst ("<ul class=\"nobull\">\n"));
+       out->out_raw (CharConst ("<ul"));
+       attrib.classlist.push_back (ustring (CharConst ("nobull")));
+       attrib.output (out);
+       attrib.classlist.pop_back ();
+       out->out_raw (CharConst (">\n"));
        outputBlock (out);
        out->out_raw (CharConst ("</ul>\n"));
        break;
@@ -590,6 +633,10 @@ void  WikiBlockItem::outputBlock (MotorOutput* out) {
 ===定義リスト===
  ;見出し:説明文
 
+{div:greenbox
+;見出し:説明文
+}
+
 */
 bool  WikiBlockItemDL::nextLine (uiterator b, uiterator e) {
     if (*b == kWikiDL) {
@@ -636,25 +683,28 @@ void  WikiBlockItemDL::output (MotorOutput* out) {
 表定義の最初の行の最初のカラムに「table:」を書くと,この行はテーブルオプション指定行になる。属性指定の後にテキストを書くと,表のキャプションになる。
 2番目以降のカラムは,デフォルトのカラムオプション指定になる。
 
-|table:||c:||
-|h:名前|h:省略形|h:意味|
-|noborder|nb|border="0"を出力する。|
-|cellspacing=''integer''|spc=|cellspacing属性を出力する。|
-|cellpadding=''integer''||cellpadding属性を出力する。|
-|padding|pad|テーブルの最大のカラム数よりカラムが少ない行に,空のカラムを追加する。|
-|expanding|expand|テーブルの最大のカラム数よりカラムが少ない行の最後のカラムを引き延ばす。|
-|center|c|テーブルをセンタリングする。|
-|left|l|テーブルを左寄せする。|
-|right|r|テーブルを右寄せする。|
-|id=''name''||id属性を出力する。|
-|class=''name,name,...''||class属性を出力する。|
-|width=''number'', width=''number''%|w=|width属性を出力する。|
-|bgcolor=#''color''|bg=|bgcolor属性を出力する。|
-|onclick=''fn(arg1,arg2,...)''||onClick属性を出力する。''name''はdefun-wiki-linkで定義したもの。|
-|nowhite|nw||
-|turn||セルの並びの横方向と縦方向を交換する。|
-|toptitle|tt|class=toptitleと同じ。|
-|bottomtitle|bt|class=bottomtitleと同じ。|
+|table:w=100%:テーブルオプション|t:w=20%|c:w=10%|t:|
+|h:オプション|h:省略形|h:説明|
+|'''id='''''ID''||id属性。|
+|'''class='''''ClassList''||class属性。複数のクラスを指定する場合はコンマ区切りで連ねる。|
+//|'''data-'''''name'''''='''''ID''||Bootstrap用属性。|
+|'''onclick='''''Link''||onclick属性。Javascriptリンク。|
+|'''onfocus='''''Link''||onfocus属性。Javascriptリンク。|
+|'''onblur='''''Link''||onblur属性。Javascriptリンク。|
+|'''onchange='''''Link''||onchange属性。Javascriptリンク。|
+|'''width='''''Size''|'''w='''|width属性。単位はpx, pt, in, mm, cm, em, ex。または%。|
+//|'''height='''''Size''|'''h='''|height属性。単位はpx, pt, in, mm, cm, em, ex。または%。|
+|'''bgcolor='''''Color''|'''bg='''|bgcolor属性。|
+|'''cellspacing='''''Integer''|'''spc='''|cellspacing属性。*コンパイル時設定による。|
+|'''cellpadding='''''Integer''||cellpadding属性。*コンパイル時設定による。|
+|'''left'''|'''l'''|align="left"属性。|
+|'''right'''|'''r'''|align="right"属性。|
+|'''center'''|'''c'''|align="center"属性。|
+|'''noborder'''|''nb''|border="0"属性。|
+|'''padding'''|'''pad'''|行のカラム定義が最大カラム数に満たない時,空のカラムを追加する。|
+|'''expanding'''|'''expand'''|行のカラム定義が最大カラム数に満たない時,最終カラムを伸ばす。|
+|'''nowhite'''|'''nw'''|空セルにnbspを出力する。|
+|'''turn'''||表の行と列を入れ替える。|
 
 +・行オプション
  |row:bgcolor=#ff0|&[;&[;Name]]|&[;&[;Value]]|
@@ -662,25 +712,30 @@ void  WikiBlockItemDL::output (MotorOutput* out) {
 行オプションで指定できる属性はセルオプションと同じものである。
 
 +・セルオプション
- |header:名前|class=big:東武|
- |header:
-|table:||c:||
-|h:名前|h:省略形|h:意味|
-|header|h|ヘッダタグ(<th>)を出力する。|
-|left|l|セル内で左寄せする。|
-|right|r|右寄せする。|
-|center|c|横方向で中央あわせする。|
-|top|t|セル内で上寄せする。|
-|middle|m|縦方向で中央あわせする。|
-|bottom|b|下寄せする。|
-|nowrap|nw|セル内での折り返しを禁止する。|
-|*||デフォルトのセルオプションを含め,全てのセルオプションを破棄する。|
-|id=''name''||セルタグにid属性を付加する。|
-|class=''name,name,...''||セルタグにclass属性を付加する。|
-|width=''number''&|;''number''%||セルタグにwidth属性を付加する。|
-|height=''number''&|;''number''%||セルタグにheight属性を付加する。|
-|bgcolor=#''hex''|bg=|セルタグにbg属性を付加する。|
-|onclick=''fn(arg1,arg2,...)''||onClick属性を出力する。''name''はdefun-wiki-linkで定義したもの。|
+// |header:名前|class=big:東武|
+// |header:
+
+|table:w=100%:行オプション,セルオプション|t:w=20%|c:w=10%|t:|
+|h:オプション|h:省略形|h:説明|
+|'''id='''''ID''||id属性。|
+|'''class='''''ClassList''||class属性。複数のクラスを指定する場合はコンマ区切りで連ねる。|
+//|'''data-'''''name'''''='''''ID''||Bootstrap用属性。|
+|'''onclick='''''Link''||onclick属性。Javascriptリンク。|
+|'''onfocus='''''Link''||onfocus属性。Javascriptリンク。|
+|'''onblur='''''Link''||onblur属性。Javascriptリンク。|
+|'''onchange='''''Link''||onchange属性。Javascriptリンク。|
+|'''width='''''Size''|'''w='''|width属性。単位はpx, pt, in, mm, cm, em, ex。または%。|
+|'''height='''''Size''|'''h='''|height属性。単位はpx, pt, in, mm, cm, em, ex。または%。|
+|'''bgcolor='''''Color''|'''bg='''|bgcolor属性。|
+|'''header'''|'''h'''|thタグを出力する。|
+|'''left'''|'''l'''|align="left"属性。|
+|'''right'''|'''r'''|align="right"属性。|
+|'''center'''|'''c'''|align="center"属性。|
+|'''top'''|'''t'''|valign="top"属性。|
+|'''middle'''|'''m'''|valign="middle"属性。|
+|'''bottom'''|'''b'''|valign="bottom"属性。|
+|'''nowrap'''|'''nw'''|nowrap属性。|
+|'''*'''||オプションのクリア。|
 
 |h:結合記号|h:意味|
 |&<;|左のセルと結合する。|
@@ -759,7 +814,8 @@ void  WikiBlockTable::TableCell::outputTD (WikiFormat* wiki, MotorOutput* out, b
        out->out_raw (CharConst ("<th"));
     else
        out->out_raw (CharConst ("<td"));
-    cellattrib.output (out);
+    bool  foutputwidth = (! fturn && colspan == 1) || (fturn && rowspan == 1);
+    cellattrib.outputCell (out, foutputwidth);
     if (fturn) {
        if (colspan > 1)
            wiki->outputName (out, CharConst ("rowspan"), colspan, false);
@@ -803,7 +859,7 @@ void  WikiBlockTable::addLine (uiterator b, uiterator e) {
 }
 
 WikiBlock::closeType  WikiBlockTable::closeLine (uiterator b, uiterator e) {
-#ifdef TABLECOMPATFLAG
+#ifdef WIKITABLECOMPATFLAG
     static uregex  re ("^\\}\\}(($)|(\\|)|((!([1-9][0-9]*))?(\\\\|&)$))");
 #else
     static uregex  re ("^\\}\\}(($)|(\\|)|((!([1-9][0-9]*))?(&)$))");
@@ -877,7 +933,7 @@ void  WikiBlockTable::addLine_body (uiterator b, uiterator e) {
     CellList_t*  cols;
     bool  fmorecell = false;
     umatch  m;
-#ifdef TABLECOMPATFLAG
+#ifdef WIKITABLECOMPATFLAG
     static uregex  re ("(!([1-9][0-9]*))?(\\\\|&)$");
 #else
     static uregex  re ("(!([1-9][0-9]*))?(&)$");
@@ -1036,10 +1092,12 @@ void  WikiBlockTable::normalize () {
 void  WikiBlockTable::outputTableTag (MotorOutput* out) {
     int  i;
 
+#ifdef WIKITABLEATTRIB
     if (attrib.cellspacing < 0)
        attrib.cellspacing = 0;
     if (attrib.cellpadding < 0)
        attrib.cellpadding = 0;
+#endif
     out->out_raw (CharConst ("<table"));
     attrib.output (out);
     out->out_raw (CharConst (">\n"));
@@ -1115,6 +1173,19 @@ void  WikiBlockTable::outputTBodyCell (WikiFormat* wiki, MotorOutput* out, Table
  |VALUE|
  |LABEL|VALUE|selected|
 
+オプションパラメータ
+|table:w=100%|t:w=20%|c:w=10%|t:|
+|h:オプション|h:省略形|h:説明|
+|'''id='''''ID''||id属性。|
+|'''class='''''ClassList''||class属性。複数のクラスを指定する場合はコンマ区切りで連ねる。|
+//|'''data-'''''name'''''='''''ID''||Bootstrap用属性。|
+|'''onclick='''''Link''||onclick属性。Javascriptリンク。|
+|'''onfocus='''''Link''||onfocus属性。Javascriptリンク。|
+|'''onblur='''''Link''||onblur属性。Javascriptリンク。|
+|'''onchange='''''Link''||onchange属性。Javascriptリンク。|
+|'''size='''''Integer''||size属性。|
+|'''multiple'''||multiple属性。|
+
 */
 bool  WikiBlockSelect::nextLine (uiterator b, uiterator e) {
     if (*b == kWikiTABLE) {
@@ -1214,7 +1285,7 @@ void  WikiBlockSelect::output (MotorOutput* out) {
     out->out_raw (CharConst (">\n"));
 
     if (attrib.fdefault)
-       u = wiki->getVar (name);
+       u = wiki->getVar_string (name);
 #ifdef DEBUG2
     std::cerr << "u:" << u << uLF;
 #endif /* DEBUG */
@@ -1271,26 +1342,50 @@ void  WikiBlockQuote::output (MotorOutput* out) {
 /* ============================================================ */
 /*DOC:
 ===DIVタグ===
- {div:SideMenu
+ {div:''ClassName''
  ...
  }
- {div:id=Name:SideMenu:onclick=fn()
+ {div:id=''ID'':''ClassName'':onclick=''LinkFunction''
  ...
  }
 
+オプションパラメータ
+|table:w=100%|t:w=20%|c:w=10%|t:|
+|h:オプション|h:省略形|h:説明|
+|'''id='''''ID''||id属性。|
+|'''class='''''ClassList''||class属性。複数のクラスを指定する場合はコンマ区切りで連ねる。|
+//|'''data-'''''name'''''='''''ID''||Bootstrap用属性。|
+|'''onclick='''''Link''||onclick属性。Javascriptリンク。|
+|'''onfocus='''''Link''||onfocus属性。Javascriptリンク。|
+|'''onblur='''''Link''||onblur属性。Javascriptリンク。|
+|'''onchange='''''Link''||onchange属性。Javascriptリンク。|
+|''ClassList''||class=は省略できる。|
+|'''#nop'''||divタグを出力しない。pタグを抑制する。|
+
 */
 bool  WikiBlockDiv::nextLine (uiterator b, uiterator e) {
     return false;
 }
 
 void  WikiBlockDiv::addLine (uiterator b, uiterator e) {
-    bool  rc = matchSkip (b, e, CharConst ("{div:"));
+    bool  rc = matchSkip (b, e, CharConst (uWikiDIV)); // {div:
     assert (rc);
     WikiMotor  motor (b, e, wiki);
     WikiMotorObjVecPtr  vec (new WikiMotorObjVec);
 
     motor.compile (*vec);
     attrib.shiftAttrib (vec);
+    {
+       std::vector<ustring>::const_iterator  b = attrib.directlist.begin ();
+       std::vector<ustring>::const_iterator  e = attrib.directlist.end ();
+       for (; b < e; ++ b) {
+           if (match (*b, CharConst ("#nop"))) {
+               nopflag = true;
+           } else {
+               wiki->errorMsg.append (*b).append (CharConst (": bad attribute.\n"));
+           }
+       }
+    }
 }
 
 WikiBlock::closeType  WikiBlockDiv::closeLine (uiterator b, uiterator e) {
@@ -1306,44 +1401,72 @@ WikiBlock::closeType  WikiBlockDiv::closeLine (uiterator b, uiterator e) {
 void  WikiBlockDiv::output (MotorOutput* out) {
     bool  nonl = false;
 
-    if (block.size () == 1 && block[0].type == BlockParagraph) {
-       WikiBlockParagraph*  b = WikiBlockParagraph_type (&block[0]);
-       if (! b->pflag) {
-           b->singleTag = true;
-           nonl = true;
+    if (nopflag) {
+       boost::ptr_vector<WikiBlock>::iterator  b = block.begin ();
+       boost::ptr_vector<WikiBlock>::iterator  e = block.end ();
+       for (; b < e; ++ b) {
+           if (b->type == BlockParagraph) {
+               WikiBlockParagraph*  p = WikiBlockParagraph_type (&(*b));
+               if (! p->pflag) {
+                   p->singleTag = true;
+                   nonl = true;
+               }
+           }
        }
+    } else {
+       if (block.size () == 1 && block[0].type == BlockParagraph) {
+           WikiBlockParagraph*  b = WikiBlockParagraph_type (&block[0]);
+           if (! b->pflag) {
+               b->singleTag = true;
+               nonl = true;
+           }
+       }
+       out->out_raw (CharConst ("<div"));
+       attrib.output (out);
+       if (nonl)
+           out->out_raw (CharConst (">"));
+       else
+           out->out_raw (CharConst (">\n"));
     }
-    out->out_raw (CharConst ("<div"));
-    attrib.output (out);
-    if (nonl)
-       out->out_raw (CharConst (">"));
-    else
-       out->out_raw (CharConst (">\n"));
     outputBlock (out);
-    out->out_raw (CharConst ("</div>\n"));
+    if (! nopflag) {
+       out->out_raw (CharConst ("</div>\n"));
+    } else {
+       out->out_raw (uLF);
+    }
 }
 
 /* ============================================================ */
 /*DOC:
 ===FORMタグ===
- {form:POST:post.hml
+ {form:POST:''URL''
  ...
  }
-// {form:POST:id=form1:class=formclass:post.hml
-// {form:POST:post.hml:id=form1:class=formclass
- {form:POST:post.hml:target=target_window:id=form1:class=formclass
+ {form:POST:''URL'':target=''TargetWindow'':id=''ID'':class=''ClassName''
  ...
  }
 
+オプションパラメータ
+|table:w=100%|t:w=20%|c:w=10%|t:|
+|h:オプション|h:省略形|h:説明|
+|'''id='''''ID''||id属性。|
+|'''class='''''ClassList''||class属性。複数のクラスを指定する場合はコンマ区切りで連ねる。|
+//|'''data-'''''name'''''='''''ID''||Bootstrap用属性。|
+|'''onclick='''''Link''||onclick属性。Javascriptリンク。|
+|'''onfocus='''''Link''||onfocus属性。Javascriptリンク。|
+|'''onblur='''''Link''||onblur属性。Javascriptリンク。|
+|'''onchange='''''Link''||onchange属性。Javascriptリンク。|
+|'''target='''''Window''||target属性。|
+
 */
 bool  WikiBlockForm::nextLine (uiterator b, uiterator e) {
     return false;
 }
 
 void  WikiBlockForm::addLine (uiterator b, uiterator e) {
-    bool  rc = matchSkip (b, e, CharConst ("{form:"));
+//    bool  rc = matchSkip (b, e, CharConst ("{form:"));
+    bool  rc = matchSkip (b, e, CharConst (uWikiFORM));
     assert (rc);
-
     WikiMotor  motor (b, e, wiki);
     WikiMotorObjVecPtr  vec (new WikiMotorObjVec);
     ustring  key;
@@ -1404,6 +1527,54 @@ void  WikiBlockForm::output (MotorOutput* out) {
 
 /* ============================================================ */
 /*DOC:
+===Elementブロック===
+ {element:''Name''
+ ...
+ }
+
+Wikiテキストの名前付きブロック。
+
+*/
+bool  WikiBlockElement::nextLine (uiterator b, uiterator e) {
+    return false;
+}
+
+void  WikiBlockElement::addLine (uiterator b, uiterator e) {
+    bool  rc = matchSkip (b, e, CharConst (uWikiELEMENT));
+    assert (rc);
+    WikiMotor  motor (b, e, wiki);
+    WikiMotorObjVecPtr  vec (new WikiMotorObjVec);
+    WikiMotorObjVecPtr  v2 (new WikiMotorObjVec);
+
+    motor.compile (*vec);
+    vec->splitChar_keyword (':', name, *v2);
+    if (name.size () == 0) {
+       wiki->errorMsg.append (CharConst ("missing name in the element block."));
+    }
+    if (v2->size () > 0) {
+       wiki->errorMsg.append (v2->dump ()).append (CharConst (": bad attribute.\n"));
+    }
+    if (name.size () > 0) {
+       wiki->elementMap.put (name, this);
+    }
+}
+
+WikiBlock::closeType  WikiBlockElement::closeLine (uiterator b, uiterator e) {
+    if (e - b == 1 && *b == kWikiDIV_e) {
+       wiki->pop_block ();
+       wiki->cur = NULL;
+       return CloseTrue;
+    } else {
+       return CloseFalse;
+    }
+}
+
+void  WikiBlockElement::output (MotorOutput* out) {
+//***    outputBlock (out);
+}
+
+/* ============================================================ */
+/*DOC:
 ===水平線===
  ----
 
@@ -1434,30 +1605,93 @@ void  WikiBlockRaw::output (MotorOutput* out) {
 }
 
 /* ============================================================ */
+bool  WikiBlockBlank::nextLine (uiterator b, uiterator e) {
+    if (b == e) {
+       count ++;
+       return true;
+    } else {
+       switch (*b) {           // paragraph以外の全て
+       case kWikiH:
+       case kWikiPRE:
+       case kWikiPRE2:
+       case kWikiUL:
+       case kWikiOL:
+       case kWikiNL:
+       case kWikiDL:
+       case kWikiTABLE:
+           count = 0;
+           break;
+       default:
+           if ((*b == kWikiQUOTE && e - b == 1) ||
+               matchHead (b, e, CharConst (uWikiDIV)) ||
+               (wiki->curform == NULL && matchHead (b, e, CharConst (uWikiFORM))) ||
+               (wiki->curform == NULL && matchHead (b, e, CharConst (uWikiELEMENT))) ||
+               matchHead (b, e, CharConst ("----"))) {
+               count = 0;
+           } else {
+               if (count >= 2)
+                   enable = true;
+           }
+       }
+       return false;
+    }
+}
+
+void  WikiBlockBlank::addLine (uiterator b, uiterator e) {
+    count ++;
+}
+
+void  WikiBlockBlank::output (MotorOutput* out) {
+    if (enable) {
+       out->out_raw (CharConst ("<div class=\"pggap\"></div>\n"));
+    }
+}
+
+/* ============================================================ */
 void  WikiFormat::pass1 (const ustring& text, WikiLine::linevec* block, bool fsuper) {
-    Splitter  sp (text, re_nl);
+    SplitterNL  sp (text);
 
     pass1_1 (sp, NULL, NULL, block, NULL, NULL, NULL, fsuper);
 }
 
+static bool  findCmdSep (uiterator& b, uiterator e, uiterator& u) {
+    int  c;
+    uiterator  p = b;
+    for (; p < e; ++ p) {
+       c = *p;
+       if (c == ':') {
+           b = p;
+           u = b + 1;
+           return true;
+       } else if (c == ' ' || c == '\t') {
+           b = p;
+           u = b;
+           do {
+               ++ u;
+           } while (u < e && ((c = *u) == ' ' || c == '\t'));
+           return true;
+       }
+    }
+    b = p;
+    u = e;
+    return true;
+}
+
 int  WikiFormat::pass1_1 (Splitter& sp, ustring* elseword, ustring* endword, WikiLine::linevec* block, uiterator* elsebegin0, uiterator* elsebegin, uiterator* elseend, bool fsuper) {
     uiterator  b, e, t, u, v;
-    umatch  m;
 
     while (sp.next ()) {
        b = sp.begin ();
        e = sp.end ();
-       while (b < e && b[0] == '\t')
+       while (b < e && b[0] == '\t')   // TABを無視
            b ++;
        if (matchSkip (b, e, CharConst (kComment))) {
            // comment
        } else if (b != e && b[0] == kWikiCmd) {
-           if (usearch (b, e, m, re_wikicmdsep)) {
-               t = b;
-               u = m[0].first;
-               v = m[0].second;
+           t = b;
+           u = b;
+           if (findCmdSep (u, e, v)) {
            } else {
-               t = b;
                u = e;
                v = e;
            }
@@ -1552,6 +1786,30 @@ bool  WikiFormat::pass1_2 (Splitter& sp, uiterator& b, uiterator& e, uiterator&
            // nonblock
        }
        return true;
+    } else if (t < u && *t == kWikiCmd) {
+       bool  fx = true;
+       MNode*  wf;
+       ustring  name (t + 1, u);                       // '$'を取り除く
+       if (protectMode && ! fsuper && ! env->wikienv->wikiGuestFunc.get (name))
+           fx = false;
+       if (fx && (wf = env->wikienv->wikiCmd2.getVar (name))) { // Wiki Command
+           ustring  endword;
+           endword.assign (CharConst (uWikiCmd "end")).append (name);  // $end...
+           block->push_back (wl = new WikiLine (b, e, fsuper));
+           wl->fn = wc_call_defun;
+           wl->block = new WikiLine::linevec;
+           rc = pass1_1 (sp, NULL, &endword, wl->block, NULL, NULL, NULL, fsuper);
+           if (rc == 0) {
+               // no end line error
+               if (endword.length () > 0) {
+                   errorMsg.append (CharConst ("no matcing \"")).append (endword).append (CharConst ("\".\n"));
+               }
+           } else if (rc == 2) {
+               assert (wl->block2 == NULL);
+               wl->block2 = new WikiLine (sp.begin (), sp.end (), false);
+           }
+           return true;
+       }
     }
 
     return false;
@@ -1615,6 +1873,15 @@ void  WikiFormat::compile (const ustring& text, bool fsuper) {
     }
 }
 
+void  WikiFormat::outputElement (const ustring& elementName) {
+    WikiBlockElement*  b;
+    
+    b = elementMap.get (elementName);
+    if (b) {
+       output (b->block);
+    }
+}
+
 void  WikiFormat::output (boost::ptr_vector<WikiBlock>& ary) {
     int  i;
 
@@ -1645,6 +1912,7 @@ bool  WikiFormat::checkClose (uiterator b, uiterator e) {
            return true;
        case WikiBlock::CloseFalse:
            return false;
+       default:;
        }
     }
     return false;
@@ -1654,17 +1922,28 @@ void  WikiFormat::compileLine (WikiLineScanner& scanner) {
     WikiLine*  wl = scanner.cur ();
     if (! wl)
        return;
-
-    uiterator  b = wl->begin;
-    uiterator  e = wl->end;
-
     if (wl->fn) {
        wl->fn (wl, this);
     } else {
+       uiterator  b = wl->begin;
+       uiterator  e = wl->end;
+
        if (b == e) {           // empty line
            if (cur) {
-               cur->close ();
-               cur = NULL;
+               switch (cur->type) {
+               case WikiBlock::BlockParagraph:
+                   cur->close ();
+                   cur = new WikiBlockBlank (this);
+                   blockp->push_back (cur);
+                   cur->addLine (b, e);
+                   break;
+               case WikiBlock::BlockBlank:
+                   cur->addLine (b, e);
+                   break;
+               default:
+                   cur->close ();
+                   cur = NULL;
+               }
            }
        } else if (matchSkip (b, e, CharConst ("//"))) {        // comment
        } else if (checkClose (b, e)) {
@@ -1709,7 +1988,7 @@ void  WikiFormat::compileLine (WikiLineScanner& scanner) {
            cur = obj = new WikiBlockItem (WikiBlock::BlockItemOL, this);
            blockp->push_back (cur);
            obj->addLine (b, e);
-       } else if (b[0] == kWikiNL) {   // ]
+       } else if (b[0] == kWikiNL) {   // +
            WikiBlockItem*  obj;
            if (cur)
                cur->close ();
@@ -1730,7 +2009,7 @@ void  WikiFormat::compileLine (WikiLineScanner& scanner) {
                cur = new WikiBlockParagraph (this);
                blockp->push_back (cur);
            }
-           push_block (NULL);
+           push_block (blockp);
            cur = new WikiBlockSelect (this);
            cur->addLine (b, e);
        } else if (b[0] == kWikiTABLE) {        // |
@@ -1747,7 +2026,8 @@ void  WikiFormat::compileLine (WikiLineScanner& scanner) {
            cur = obj = new WikiBlockQuote (this);
            blockp->push_back (cur);
            push_block (&obj->block);
-       } else if (matchHead (b, e, CharConst ("{div:"))) {
+//     } else if (matchHead (b, e, CharConst ("{div:"))) {
+       } else if (matchHead (b, e, CharConst (uWikiDIV))) {
            WikiBlockComplex*  obj;
            if (cur)
                cur->close ();
@@ -1755,7 +2035,7 @@ void  WikiFormat::compileLine (WikiLineScanner& scanner) {
            blockp->push_back (cur);
            cur->addLine (b, e);
            push_block (&obj->block);
-       } else if (curform == NULL && matchHead (b, e, CharConst ("{form:"))) {
+       } else if (curform == NULL && matchHead (b, e, CharConst (uWikiFORM))) {
            WikiBlockComplex*  obj;
            if (cur)
                cur->close ();
@@ -1763,6 +2043,14 @@ void  WikiFormat::compileLine (WikiLineScanner& scanner) {
            blockp->push_back (cur);
            cur->addLine (b, e);
            push_block (&obj->block);
+       } else if (curform == NULL && matchHead (b, e, CharConst (uWikiELEMENT))) {
+           WikiBlockComplex*  obj;
+           if (cur)
+               cur->close ();
+           cur = obj = new WikiBlockElement (this);
+           blockp->push_back (cur);
+           cur->addLine (b, e);
+           push_block (&obj->block);
        } else if (matchHead (b, e, CharConst ("----"))) { // ----
            if (cur)
                cur->close ();
@@ -1787,7 +2075,7 @@ void  WikiFormat::compileLine (WikiLineScanner& scanner) {
 void  WikiFormat::compileLines (WikiLineScanner& scanner, bool (*fn)(WikiLine& spp, WikiLineScanner& scanner, WikiFormat* wiki, void* par), void* par) {
     WikiLine*  wl;
 
-    while (wl = scanner.next ()) {
+    while ((wl = scanner.next ())) {
        if (fn && fn (*scanner.cur (), scanner, this, par)) {
            break;
        } else {
@@ -1816,160 +2104,6 @@ int  WikiFormat::countWikiH (uiterator& b, uiterator e) {
     return ans;
 }
 
-bool  WikiFormat::paramID (const ustring& key, WikiMotorObjVec& vval, ustring& var_id, bool& ferr) {
-    if (match (key, CharConst ("id"))) {
-       ustring  value (vval.textOut (this));
-       if (value.length () > 0) {
-           if (checkWikiID (value)) {
-               var_id = value;
-               ferr = false;
-           } else {
-               errorMsg.append (key).append (uEq).append (value).append (CharConst (": bad id\n"));
-               ferr = true;
-           }
-       }
-       return true;
-    } else {
-       return false;
-    }
-}
-
-bool  WikiFormat::paramClass (const ustring& key, WikiMotorObjVec& vval, std::vector<ustring>& classes, bool& ferr) {
-    if (match (key, CharConst ("class"))) {
-       paramClassValue (vval, classes, ferr);
-       return true;
-    } else {
-       return false;
-    }
-}
-
-void  WikiFormat::paramClassValue (WikiMotorObjVec& vval, std::vector<ustring>& classes, bool& ferr) {
-    WikiMotorObjVecVec  args;
-    ferr = false;
-    vval.splitCharA (',', args);
-    for (int i = 0; i < args.size (); i ++) {
-       ustring  value (args[i]->textOut (this));
-       if (value.length () > 0) {
-           if (checkWikiID (value)) {
-               classes.push_back (value);
-           } else {
-               errorMsg.append (value).append (CharConst (": bad class name\n"));
-               ferr = true;
-           }
-       }
-    }
-}
-
-bool  WikiFormat::paramName (const ustring& key, WikiMotorObjVec& vval, ustring& var, bool& ferr) {
-    if (match (key, CharConst ("name"))) {
-       ustring  value (vval.textOut (this));
-       if (checkWikiID (value)) {
-           var = value;
-           ferr = false;
-       } else {
-           ferr = true;
-       }
-       return true;
-    } else {
-       return false;
-    }
-}
-
-bool  WikiFormat::paramWidth (const ustring& key, WikiMotorObjVec& vval, ustring& var, bool& ferr) {
-    if (match (key, CharConst ("width"), CharConst ("w"))) {
-       ustring  value (vval.textOut (this));
-       if (checkWidth (value)) {
-           var = value;
-//         if (checkNum (value))
-//             var.append (CharConst ("px"));
-           ferr = false;
-       } else {
-           ferr = true;
-       }
-       return true;
-    } else {
-       return false;
-    }
-}
-
-bool  WikiFormat::paramHeight (const ustring& key, WikiMotorObjVec& vval, ustring& var, bool& ferr) {
-    if (match (key, CharConst ("height"), CharConst ("h"))) {
-       ustring  value (vval.textOut (this));
-       if (checkWidth (value)) {
-           var = value;
-           ferr = false;
-       } else {
-           errorMsg.append (key).append (uEq).append (value).append (CharConst (": bad value\n"));
-           ferr = true;
-       }
-       return true;
-    } else {
-       return false;
-    }
-}
-
-bool  WikiFormat::paramSize (const char* name, size_t namelen, const ustring& key, WikiMotorObjVec& vval, ustring& var, bool& ferr) {
-    if (match (key, name, namelen)) {
-       ustring  value (vval.textOut (this));
-       if (checkNum (value)) {
-           var = value;
-           ferr = false;
-       } else {
-           ferr = true;
-       }
-       return true;
-    }
-    return false;
-}
-
-void  WikiFormat::paramUNum (const ustring& value, int& var, const ustring& name) {
-    if (checkNum (value)) {
-       var = strtoul (value);
-    } else {
-       errorMsg.append (name).append (uEq).append (value).append (uErrorBadValue).append (uLF);
-    }
-}
-
-void  WikiFormat::paramColor (const ustring& value, ustring& var, const ustring& name) {
-    if (checkColor (value)) {
-       var = value;
-    } else {
-       errorMsg.append (name).append (uEq).append (value).append (uErrorBadValue).append (uLF);
-    }
-}
-
-bool  WikiFormat::paramTargetCheck (const ustring& key) {
-    return match (key, CharConst ("target"));
-}
-
-void  WikiFormat::paramTargetBody (const ustring& key, const ustring& value, ustring& var, bool& ferr) {
-    if (value.length () == 0 || checkWikiID (value)) {
-       var = value;
-    } else {
-       if (key.length () > 0)
-           errorMsg.append (key).append (uEq).append (value).append (CharConst (": bad target name.\n"));
-       else
-           errorMsg.append (value).append (CharConst (": bad target name.\n"));
-       ferr = true;
-    }
-}
-
-bool  WikiFormat::paramOnClickCheck (const ustring& name) {
-    return match (name, CharConst ("onclick"));
-}
-
-bool  WikiFormat::paramOnFocusCheck (const ustring& name) {
-    return match (name, CharConst ("onfocus"));
-}
-
-bool  WikiFormat::paramOnBlurCheck (const ustring& name) {
-    return match (name, CharConst ("onblur"));
-}
-
-bool  WikiFormat::paramOnChangeCheck (const ustring& name) {
-    return match (name, CharConst ("onchange"));
-}
-
 void  WikiFormat::outputName (MotorOutput* out, const char* name, size_t len, const ustring& val, bool cond) {
     if (! cond || val.length () > 0)
        out->out_raw (uSPC)
@@ -2029,6 +2163,35 @@ void  WikiFormat::outputSubmitScript (MotorOutput* out, const char* name, size_t
     }
 }
 
+void  WikiFormat::outputNum (MotorOutput* out, const char* name, size_t len, int val) {
+    out->out_raw (uSPC)
+       ->out_raw (name, len)
+       ->out_raw (CharConst ("="))
+       ->out_raw (to_ustring (val));
+}
+
+MNode*  WikiFormat::arrayToTexp (const ustring& name) {
+    size_t  i, n;
+    MNodeList  e;
+
+    n = mlenv->getArySize (name);
+    for (i = 1; i <= n; i ++) {
+       e.append (mlenv->getAry (name, i));
+    }
+    return mlenv->retval = e ();
+}
+
+MNode*  WikiFormat::evalVar (const ustring& name) {
+    // @NAME → getarray
+    // NAME → getvar
+    ustring  sym;
+    if (checkAry (name, sym)) {
+       return arrayToTexp (sym);
+    } else {
+       return mlenv->getVar (name);
+    }
+}
+
 void  WikiFormat::wikiMotor (uiterator b, uiterator e, WikiMotorObjVec& ans) {
     WikiMotor  motor (b, e, this);
     AutoInclCount  autoIncl (env->mlenv);
@@ -2053,23 +2216,11 @@ void  WikiFormat::wikiMotorInline (uiterator b, uiterator e, WikiMotorObjVec& an
     objv.eval (ans, this);
 }
 
-#if 0
-void  WikiFormat::wikiMotorEval (uiterator b, uiterator e, WikiMotorObjVec& ans) {
-    ans.push_back (WikiMotorObjPtr (new WikiMotorObjHtml (wikiMotor (b, e))));
-}
-#endif
-
-MNode*  WikiFormat::buildArgs (WikiMotorObjVecVec::const_iterator b, WikiMotorObjVecVec::const_iterator e, bool dumpmode) {
+MNode*  WikiFormat::buildArgs (WikiMotorObjVecVec::const_iterator b, WikiMotorObjVecVec::const_iterator e) {
     MNodeList  ans;
 
-    if (dumpmode) {
-       for (; b < e; b ++) {
-           ans.append (newMNode_str (new ustring ((*b)->dump ())));
-       }
-    } else {
-       for (; b < e; b ++) {
-           ans.append (newMNode_str (new ustring ((*b)->textOut (this))));
-       }
+    for (; b < e; b ++) {
+       ans.append ((*b)->toMNode (this));
     }
     
     return ans.release ();
@@ -2086,4 +2237,7 @@ void  WikiFormat::logLispFunctionError (const ustring& msg, const ustring& cmd)
     }
 }
 
+/*DOC:
+$premode:
+*/
 /* ============================================================ */