OSDN Git Service

fix for FreeBSD 11.1.
[hmh/hhml.git] / wiki / wikiline.cc
1 #include "wikiline.h"
2 #include "wikienv.h"
3 #include "wikitable.h"
4 #include "wikiformat.h"
5 #include "wikimotor.h"
6 #include "motorconst.h"
7 #include "motoroutput.h"
8 #include "motorenv.h"
9 #include "ml.h"
10 #include "expr.h"
11 #include "util_const.h"
12 #include "util_check.h"
13 #include "util_string.h"
14 #include "utf8.h"
15 #include "ustring.h"
16 #include <boost/ptr_container/ptr_vector.hpp>
17 #include <vector>
18 #include <assert.h>
19
20 /*DOC:
21 ==インライン要素==
22
23 */
24 /* ============================================================ */
25 static void  errorBadParam (WikiMotorObjVec* param, WikiFormat* wiki) {
26     wiki->errorMsg.append (param->dump()).append (CharConst (": bad parameter.\n"));
27 }
28
29 static bool  outamp_opt (MotorOutputWiki& o, const ustring& opt, const ustring& val) {
30     if (opt.length () == 0) {
31         o.outamp (val);
32     } else if (opt.length () == 1) {
33         switch (opt[0]) {
34         case '/':
35             o.outamp_br (val);
36             break;
37         case '~':
38             o.outamp_nw (val);
39             break;
40         case ',':
41             o.outamp_c3 (val);
42             break;
43 //      case '^':
44 //          o.outamp_wbr (val);
45 //          break;
46         default:
47             return false;
48         }
49     } else {
50         return false;
51     }
52     return true;
53 }
54
55 /* ============================================================ */
56 /*DOC:
57 ===強制改行===
58  <br>
59
60 ===幅なしスペース===
61  <zwsp>
62
63 */
64 /*DOC:
65 ===変数展開===
66  [[VARIABLE]]
67  [[VARIABLE/]]
68  [[VARIABLE~]]
69  [[VARIABLE,]]
70 // [[@array]]
71
72 */
73 /*DOC:
74 ===選択出力===
75  [[VARIABLE?VALUE:true_text]]
76  [[VARIABLE!?VALUE:false_text]]
77  [[VARIABLE?VALUE:true_text||false_text]]
78  [[VARIABLE!?VALUE:false_text||true_text]]
79  [[VARIABLE?VALUE1:text1||?VALUE2:text2||?VALUE3:text3||text4]]
80
81 */
82 /*DOC:
83 ===変数展開===
84  [[getvar:NAME]]
85  [[getvar:NAME:/]]
86  [[getvar:NAME:~]]
87  [[getvar:NAME:,]]
88
89 */
90 //#WIKILINE     getvar  wl_getvar
91 bool  wl_getvar (WikiMotorObjVecVec* args, WikiMotorObjVec& out, WikiFormat* wiki) {
92     MotorOutputWiki  o (out);
93     ustring  var;
94     ustring  val;
95     ustring  opt;
96
97     if (args->size () == 0 || args->size () > 2)
98         return false;
99     var = (*args)[0]->textOut (wiki);
100     if (args->size () >= 2)
101         opt = (*args)[1]->textOut (wiki);
102
103     val = fixUTF8 (wiki->getVar_string (var));
104     return outamp_opt (o, opt, val);
105
106     return true;
107 }
108
109 /*DOC:
110 ===配列展開===
111  [[getarray:NAME]]
112  [[string-join:TEXT:NAME]]
113
114 */
115 //#WIKILINE     getarray        wl_getarray
116 bool  wl_getarray (WikiMotorObjVecVec* args, WikiMotorObjVec& out, WikiFormat* wiki) {
117     MotorOutputWiki  o (out);
118     ustring  var;
119
120     if (args->size () == 0 || args->size () > 1)
121         return false;
122     var = (*args)[0]->textOut (wiki);
123     o.outamp (fixUTF8 (dump_to_texp (wiki->arrayToTexp (var))));
124
125     return true;
126 }
127
128 /*DOC:
129 ===consセル展開
130  [[car:NAME]]
131  [[cdr:NAME]]
132  [[nth:NAME:i]]
133
134 */
135 //#WIKILINE     car     wl_car
136 bool  wl_car (WikiMotorObjVecVec* args, WikiMotorObjVec& out, WikiFormat* wiki) {
137     MotorOutputWiki  o (out);
138     ustring  var;
139     ustring  val;
140     MNodePtr  e;
141     ustring  opt;
142
143     if (args->size () != 1)
144         return false;
145     var = (*args)[0]->textOut (wiki);
146     e = wiki->getVar (var);
147     if (e ()) {
148         e = e ()->car ();
149         val = fixUTF8 (to_string (e ()));
150         return outamp_opt (o, opt, val);
151     }
152     return true;
153 }
154
155 //#WIKILINE     cdr     wl_cdr
156 bool  wl_cdr (WikiMotorObjVecVec* args, WikiMotorObjVec& out, WikiFormat* wiki) {
157     MotorOutputWiki  o (out);
158     ustring  var;
159     ustring  val;
160     MNodePtr  e;
161     ustring  opt;
162
163     if (args->size () != 1)
164         return false;
165     var = (*args)[0]->textOut (wiki);
166     e = wiki->getVar (var);
167     if (e ()) {
168         e = e ()->cdr ();
169         val = fixUTF8 (to_string (e ()));
170         return outamp_opt (o, opt, val);
171     }
172     return true;
173 }
174
175 //#WIKILINE     nth     wl_nth
176 bool  wl_nth (WikiMotorObjVecVec* args, WikiMotorObjVec& out, WikiFormat* wiki) {
177     MotorOutputWiki  o (out);
178     ustring  var;
179     int  idx;
180     ustring  val;
181     MNodePtr  e;
182     ustring  opt;
183
184     if (args->size () != 2)
185         return false;
186     var = (*args)[0]->textOut (wiki);
187     idx = strtol ((*args)[1]->textOut (wiki));
188     e = wiki->getVar (var);
189     if (e ()) {
190         MNode*  a = e ();
191         while (idx > 0 && a && a->isCons ()) {
192             idx --;
193             nextNode (a);
194         }
195         if (a && a->isCons ())
196             val = fixUTF8 (to_string (a->car ()));
197         return outamp_opt (o, opt, val);
198     }
199     return true;
200 }
201
202 /*DOC:
203 ===ベクタ展開===
204  [[vector:NAME:i]]
205  [[vector:NAME:i:/]]
206  [[vector:NAME:i:~]]
207  [[vector:NAME:i:,]]
208
209 */
210 //#WIKILINE     vector  wl_vector
211 bool  wl_vector (WikiMotorObjVecVec* args, WikiMotorObjVec& out, WikiFormat* wiki) {
212     MotorOutputWiki  o (out);
213     ustring  var;
214     ustring  val;
215     size_t  i;
216     ustring  opt;
217     MNodePtr  e;
218
219     if (args->size () < 2 || args->size () > 3)
220         return false;
221     var = (*args)[0]->textOut (wiki);
222     i = to_int32 ((*args)[1]->textOut (wiki));
223     if (args->size () == 3)
224         opt = (*args)[2]->textOut (wiki);
225     e = wiki->getVar (var);
226     if (e ()) {
227         e = e ()->vectorGet (i);
228         val = fixUTF8 (to_string (e ()));
229         return outamp_opt (o, opt, val);
230     }
231
232     return true;
233 }
234
235 /*DOC:
236 ===連結===
237  [[join:SEPARATOR:NAME]]
238 Wiki変数''NAME''に格納されたベクタ、または、リストを連結して出力する。
239
240 */
241 //#WIKILINE     join    wl_join
242 bool  wl_join (WikiMotorObjVecVec* args, WikiMotorObjVec& out, WikiFormat* wiki) {
243     MotorOutputWiki  o (out);
244     ustring  sep;
245     ustring  var;
246     MNodePtr  val;
247     size_t  i, n;
248     ustring  ans;
249
250     if (args->size () != 2)
251         return false;
252     sep = (*args)[0]->textOut (wiki);
253     var = (*args)[1]->textOut (wiki);
254     val = wiki->getVar (var);
255     if (isCons (val ())) {
256         MNode*  a = val ();
257         i = 0;
258         while (isCons (a)) {
259             if (i > 0)
260                 ans.append (sep);
261             ans.append (to_string (a->car ()));
262             nextNode (a);
263             ++ i;
264         }
265         o.outamp (fixUTF8 (ans));
266     } else if (isVector (val ())) {
267         n = val ()->vectorSize ();
268         for (i = 0; i < n; ++ i) {
269             if (i > 0)
270                 ans.append (sep);
271             ans.append (to_string (val ()->vectorGet (i)));
272         }
273         o.outamp (fixUTF8 (ans));
274     }
275     return true;
276 }
277
278 /*DOC:
279 ===テーブル展開===
280  [[table:NAME:i]]
281  [[table:NAME:i:/]]
282  [[table:NAME:i:~]]
283  [[table:NAME:i:,]]
284
285 */
286 //#WIKILINE     table   wl_table
287 bool  wl_table (WikiMotorObjVecVec* args, WikiMotorObjVec& out, WikiFormat* wiki) {
288     MotorOutputWiki  o (out);
289     ustring  var;
290     ustring  val;
291     ustring  key;
292     ustring  opt;
293     MNodePtr  e;
294
295     if (args->size () < 2 || args->size () > 3)
296         return false;
297     var = (*args)[0]->textOut (wiki);
298     key = (*args)[1]->textOut (wiki);
299     if (args->size () == 3)
300         opt = (*args)[2]->textOut (wiki);
301     e = wiki->getVar (var);
302     if (e ()) {
303         e = e ()->tableGet (key);
304         val = fixUTF8 (to_string (e ()));
305         return outamp_opt (o, opt, val);
306     }
307
308     return true;
309 }
310
311 /*DOC:
312 ===Lispファンクション実行===
313  [[eval:FUNC]]
314
315 */
316 //#WIKILINE     eval    wl_eval
317 bool  wl_eval (WikiMotorObjVec* arg2, WikiMotorObjVec& out, WikiFormat* wiki) {
318 #ifdef WIKIEVALPROTECT
319     if (wiki->protectMode && ! wl->fsuper) {
320         return false;
321     }
322 #endif
323
324     MotorTexp  ml (wiki->mlenv);
325     ustring  sexp = arg2->textOut (wiki);
326     MNodePtr  v;
327
328     if (! sexp.empty ()) {
329         ml.scan (sexp);
330         if (ml.top.isCons ()) {
331             MNode*  arg = ml.top.cdr ();
332             if (arg && arg->isCons ()) {
333                 try {
334                     v = eval (arg->car (), wiki->mlenv);
335                     MotorOutputWiki  o (out);
336                     o.outamp (to_string (v ()));
337                 } catch (ustring& msg) {
338                     if (wiki->mlenv->currentCell ()) {
339                         wiki->errorMsg.append (wiki->mlenv->currentCell ()->dump_string_short ()).append (CharConst (": "));
340                     }
341                     wiki->errorMsg.append (msg).append (uLF);
342                 }
343             }
344         }
345     }
346     return true;
347 }
348
349 /* ============================================================ */
350 /*DOC:
351 ===強調===
352  ''これはイタリック''
353  '''これはボールド'''
354  '''''イタリック+ボールド'''''
355  [[i:wiki function形式のイタリック]]
356  [[b:wiki function形式のボールド]]
357  [[bi:ボールド+イタリック]]
358  [[ib:ボールド+イタリック]]
359  [[sup:上付き]]
360  [[sub:下付き]]
361
362 */
363 static bool  wl_em_sub (const char* op, size_t oplen, const char* cl, size_t cllen,
364                         WikiMotorObjVec* arg2, WikiMotorObjVec& out, WikiFormat* wiki) {
365     MotorOutputString  html;
366     html.out_raw (op, oplen)
367         ->out_toText (arg2->htmlOut (wiki))
368         ->out_raw (cl, cllen);
369     out.push_back (WikiMotorObjPtr (new WikiMotorObjHtml (html.ans)));
370     return true;
371 }
372
373 //#WIKILINE     i       wl_italic
374 bool  wl_italic (WikiMotorObjVec* arg2, WikiMotorObjVec& out, WikiFormat* wiki) {
375     return wl_em_sub (CharConst ("<i>"), CharConst ("</i>"), arg2, out, wiki);
376 }
377
378 //#WIKILINE     b       wl_bold
379 bool  wl_bold (WikiMotorObjVec* arg2, WikiMotorObjVec& out, WikiFormat* wiki) {
380     return wl_em_sub (CharConst ("<b>"), CharConst ("</b>"), arg2, out, wiki);
381 }
382
383 //#WIKILINE     bi      wl_bolditalic
384 //#WIKILINE     ib      wl_bolditalic
385 bool  wl_bolditalic (WikiMotorObjVec* arg2, WikiMotorObjVec& out, WikiFormat* wiki) {
386     return wl_em_sub (CharConst ("<b><i>"), CharConst ("</i></b>"), arg2, out, wiki);
387 }
388
389 //#WIKILINE     sup     wl_sup
390 bool  wl_sup (WikiMotorObjVec* arg2, WikiMotorObjVec& out, WikiFormat* wiki) {
391     return wl_em_sub (CharConst ("<sup>"), CharConst ("</sup>"), arg2, out, wiki);
392 }
393
394 //#WIKILINE     sub     wl_sub
395 bool  wl_sub (WikiMotorObjVec* arg2, WikiMotorObjVec& out, WikiFormat* wiki) {
396     return wl_em_sub (CharConst ("<sub>"), CharConst ("</sub>"), arg2, out, wiki);
397 }
398
399 /* ============================================================ */
400 /*DOC:
401 ===リンク===
402  [[http://www.yahoo.co.jp]]
403  [[+http://www.google.co.jp Googleトップ]]
404  [[https://ab.com/ HTTPSリンク]]
405  [[+https://ab.com/ HTTPSリンク]]
406  [[link:new.hml?Name=n2&Value=[[v1]] 次]]
407  [[link:new.hml?Name=n2&Value=[[v1]]:MainFrame 次]]
408  [[+link:profile.hml?ID=[[id]] プロフィール]]
409  [[link:edit([[id]]) 編集]]
410
411 オプションパラメータ
412 |table:w=100%|t:w=20%|c:w=10%|t:|
413 |h:オプション|h:省略形|h:説明|
414 |'''id='''''ID''||id属性。|
415 |'''class='''''ClassList''||class属性。複数のクラスを指定する場合はコンマ区切りで連ねる。|
416 //|'''data-'''''name'''''='''''ID''||Bootstrap用属性。|
417 |'''onclick='''''Link''||onclick属性。Javascriptリンク。|
418 |'''onfocus='''''Link''||onfocus属性。Javascriptリンク。|
419 |'''onblur='''''Link''||onblur属性。Javascriptリンク。|
420 |'''onchange='''''Link''||onchange属性。Javascriptリンク。|
421 |'''target='''''Window''||target属性。|
422 |''Window''||taget=は省略可。|
423
424 */
425 static bool  wl_http_sub (bool newwin, WikiMotorObjVecVec* args, WikiMotorObjVec* arg2, WikiMotorObjVec& out, WikiFormat* wiki) {
426     ustring  url;
427     bool  fscript = false;
428     WikiAttrib1  attrib (wiki, WikiAttrib1::SEL_TARGET | WikiAttrib1::SEL_TARGET2, true, WikiAttrib1::M_ATTRIB);
429     WikiMotorObjVecVec::const_iterator  b = args->begin ();
430     WikiMotorObjVecVec::const_iterator  e = args->end ();
431     MotorOutputString  html;
432
433     if (b < e) {
434         attrib.readLink (b, e, url, fscript);
435         attrib.readAttrib (b, e);
436         html.out_raw (CharConst ("<a"));
437         if (fscript) {
438             attrib.onclick = url + attrib.onclick;
439             html.out_raw (CharConst (" href=\"#\""));
440         } else {
441             wiki->outputName (&html, CharConst ("href"), url, false);
442         }
443         if (newwin) {
444             attrib.target = ustring (CharConst ("_blank"));
445         }
446         attrib.output (&html);
447         html.out_raw (CharConst (">"));
448         if (arg2->size () > 0) {
449             html.out_toText (arg2->htmlOut (wiki));
450         } else if (! fscript) {
451             html.out_toHTML_noCtrl (url);
452         } else {
453         }
454         html.out_raw (CharConst ("</a>"));
455     }
456     out.push_back (WikiMotorObjPtr (new WikiMotorObjHtml (html.ans)));
457     return true;
458 }
459
460 static void  copynargs (WikiMotorObjVecVec& nargs, WikiMotorObjVecVec* args, const ustring& proto) {
461     WikiMotorObjVec*  v = new WikiMotorObjVec;
462     v->push_back (WikiMotorObjPtr (new WikiMotorObjText (proto)));
463     nargs.push_back (WikiMotorObjVecPtr (v));
464     for (int i = 0; i < args->size (); i ++) {
465         nargs.push_back ((*args)[i]);
466     }
467 }
468
469 //#WIKILINE2    http    wl_http
470 bool  wl_http (WikiMotorObjVecVec* args, WikiMotorObjVec* arg2, WikiMotorObjVec& out, WikiFormat* wiki) {
471     WikiMotorObjVecVec  nargs;
472     copynargs (nargs, args, uHttp);
473     return wl_http_sub (false, &nargs, arg2, out, wiki);
474 }
475
476 //#WIKILINE2    +http   wl_http_new
477 bool  wl_http_new (WikiMotorObjVecVec* args, WikiMotorObjVec* arg2, WikiMotorObjVec& out, WikiFormat* wiki) {
478     WikiMotorObjVecVec  nargs;
479     copynargs (nargs, args, uHttp);
480     return wl_http_sub (true, &nargs, arg2, out, wiki);
481 }
482
483 //#WIKILINE2    https   wl_https
484 bool  wl_https (WikiMotorObjVecVec* args, WikiMotorObjVec* arg2, WikiMotorObjVec& out, WikiFormat* wiki) {
485     WikiMotorObjVecVec  nargs;
486     copynargs (nargs, args, uHttps);
487     return wl_http_sub (false, &nargs, arg2, out, wiki);
488 }
489
490 //#WIKILINE2    +https  wl_https_new
491 bool  wl_https_new (WikiMotorObjVecVec* args, WikiMotorObjVec* arg2, WikiMotorObjVec& out, WikiFormat* wiki) {
492     WikiMotorObjVecVec  nargs;
493     copynargs (nargs, args, uHttps);
494     return wl_http_sub (true, &nargs, arg2, out, wiki);
495 }
496
497 //#WIKILINE2    link    wl_link
498 bool  wl_link (WikiMotorObjVecVec* args, WikiMotorObjVec* arg2, WikiMotorObjVec& out, WikiFormat* wiki) {
499     return wl_http_sub (false, args, arg2, out, wiki);
500 }
501
502 //#WIKILINE2    +link   wl_link_new
503 bool  wl_link_new (WikiMotorObjVecVec* args, WikiMotorObjVec* arg2, WikiMotorObjVec& out, WikiFormat* wiki) {
504     return wl_http_sub (true, args, arg2, out, wiki);
505 }
506
507 /* ============================================================ */
508 /*DOC:
509 ===IMGタグ===
510  [[image:images/logo.gif]]
511  [[image:images/logo.gif Logo]]
512  [[image:images/logo.gif:width=120:height=48 Logo]]
513
514 オプションパラメータ
515 |table:w=100%|t:w=20%|c:w=10%|t:|
516 |h:オプション|h:省略形|h:説明|
517 |'''id='''''ID''||id属性。|
518 |'''class='''''ClassList''||class属性。複数のクラスを指定する場合はコンマ区切りで連ねる。|
519 //|'''data-'''''name'''''='''''ID''||Bootstrap用属性。|
520 |'''onclick='''''Link''||onclick属性。Javascriptリンク。|
521 |'''onfocus='''''Link''||onfocus属性。Javascriptリンク。|
522 |'''onblur='''''Link''||onblur属性。Javascriptリンク。|
523 |'''onchange='''''Link''||onchange属性。Javascriptリンク。|
524 |'''width='''''Size''|'''w='''|styleのwidth属性。単位はpx, pt, in, mm, cm, em, ex。または%。|
525 |'''height='''''Size''|'''h='''|styleのheight属性。単位はpx, pt, in, mm, cm, em, ex。または%。|
526 |'''alt='''''Text''||alt属性とlongdesc属性の指定。altオプションを指定すると,第二パラメータがlongdesc属性になる。|
527
528 */
529 //#WIKILINE2    image   wl_image
530 bool  wl_image (WikiMotorObjVecVec* args, WikiMotorObjVec* arg2, WikiMotorObjVec& out, WikiFormat* wiki) {
531     WikiMotorObjVecVec::const_iterator  b = args->begin ();
532     WikiMotorObjVecVec::const_iterator  e = args->end ();
533     ustring  url;
534     WikiAttribImg  attrib (wiki);
535     bool  fscript;
536     MotorOutputString  html;
537
538     if (! attrib.readLink (b, e, url, fscript, true))
539         return false;
540     if (! attrib.readAttrib (b, e))
541         return false;
542     if (b != e) {
543         errorBadParam (b->get (), wiki);
544         return false;
545     }
546
547     html.out_raw (CharConst ("<img"));
548     wiki->outputName (&html, CharConst ("src"), url);
549     attrib.output (&html);
550     if (attrib.alt.length () > 0) {
551         wiki->outputName (&html, CharConst ("alt"), attrib.alt);
552         wiki->outputName (&html, CharConst ("longdesc"), arg2->textOut (wiki));
553     } else {
554         wiki->outputName (&html, CharConst ("alt"), arg2->textOut (wiki));
555     }
556     html.out_raw (CharConst (" />"));
557     out.push_back (WikiMotorObjPtr (new WikiMotorObjHtml (html.ans)));
558
559     return true;
560 }
561
562 /*DOC:
563 ===テキストカラー===
564  [[color:#ff0000 赤色]]
565
566 オプションパラメータ
567 |table:w=100%|t:w=20%|c:w=10%|t:|
568 |h:オプション|h:省略形|h:説明|
569 |'''#'''''RRGGBB''||color属性。|
570
571 */
572 //#WIKILINE     color   wl_color
573 bool  wl_color (WikiMotorObjVecVec* args, WikiMotorObjVec* arg2, WikiMotorObjVec& out, WikiFormat* wiki) {
574     ustring  color, v;
575     MotorOutputString  html;
576
577     if (args->size () == 1) {
578         color = (*args)[0]->textOut (wiki);
579         if (! checkColor (color))
580             return false;
581     } else {
582         return false;
583     }
584
585     html.out_raw (CharConst ("<span style=\"color:"))
586         ->out_toHTML_noCtrl (color)
587         ->out_raw (CharConst (";\">"))
588         ->out_toText (arg2->htmlOut (wiki))
589         ->out_raw (CharConst ("</span>"));
590     out.push_back (WikiMotorObjPtr (new WikiMotorObjHtml (html.ans)));
591
592     return true;
593 }
594
595 static bool  matchAnchor (uiterator b, uiterator e) {
596     int  c;
597     static char  table_anchor[] = {     // [a-zA-Z0-9_\-]
598         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
599         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
600         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 
601         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 
602         0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
603         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 
604         0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
605         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 
606     };
607     for (; b < e; ++ b) {
608         c = *b;
609         if (0 <= c && c < 128 && table_anchor[c]) {
610         } else {
611             return false;
612         }
613     }
614     return true;
615 }
616
617 /*DOC:
618 ===アンカー===
619  [[anchor:Fig1]]
620
621 */
622 //#WIKILINE     anchor  wl_anchor
623 bool  wl_anchor (WikiMotorObjVec* arg, WikiMotorObjVec& out, WikiFormat* wiki) {
624     ustring  name (arg->textOut (wiki));
625     MotorOutputString  html;
626
627     if (! matchAnchor (name.begin (), name.end ()))
628         return false;
629     html.out_raw (CharConst ("<a"));
630     wiki->outputName (&html, CharConst ("name"), name, false);
631     html.out_raw (CharConst ("></a>"));
632     out.push_back (WikiMotorObjPtr (new WikiMotorObjHtml (html.ans)));
633
634     return true;
635 }
636
637 /*DOC:
638 ===SPANタグ===
639  [[span:red,top クラス指定]]
640  [[span:id=Field1 ID指定]]
641
642 オプションパラメータ
643 |table:w=100%|t:w=20%|c:w=10%|t:|
644 |h:オプション|h:省略形|h:説明|
645 |'''id='''''ID''||id属性。|
646 |'''class='''''ClassList''||class属性。複数のクラスを指定する場合はコンマ区切りで連ねる。|
647 //|'''data-'''''name'''''='''''ID''||Bootstrap用属性。|
648 |'''onclick='''''Link''||onclick属性。Javascriptリンク。|
649 |'''onfocus='''''Link''||onfocus属性。Javascriptリンク。|
650 |'''onblur='''''Link''||onblur属性。Javascriptリンク。|
651 |'''onchange='''''Link''||onchange属性。Javascriptリンク。|
652 |''ClassList''||class=は省略可。|
653
654 */
655 //#WIKILINE2    span    wl_span
656 bool  wl_span (WikiMotorObjVecVec* args, WikiMotorObjVec* arg2, WikiMotorObjVec& out, WikiFormat* wiki) {
657     WikiMotorObjVecVec::const_iterator  b = args->begin ();
658     WikiMotorObjVecVec::const_iterator  e = args->end ();
659     WikiAttrib1  attrib (wiki, WikiAttrib1::SEL_CLASS2, false, WikiAttrib1::M_ATTRIB);
660     MotorOutputString  html;
661
662     if (! attrib.readAttrib (b, e))
663         return false;
664     if (b != e) {
665         errorBadParam (b->get (), wiki);
666         return false;
667     }
668
669     html.out_raw (CharConst ("<span"));
670     attrib.output (&html);
671     html.out_raw (CharConst (">"))
672         ->out_toText (arg2->htmlOut (wiki))
673         ->out_raw (CharConst ("</span>"));
674     out.push_back (WikiMotorObjPtr (new WikiMotorObjHtml (html.ans)));
675
676     return true;
677 }
678
679 /* ============================================================ */
680 /*DOC:
681 ===フォームエレメント===
682  [[input:Name:size=24 初期値]]
683  [[input:Name:default]]
684  [[password:PW]]
685  [[hidden:Name 値]]
686  [[file:Name]]
687  [[submit 送信]]
688  [[button ボタン]]
689  [[radio:Name:Value:id=Radio1 ラベル]]
690  [[checkbox:Name:Value ラベル]]
691  [[textarea:Text:cols=40:rows=6:wrap=soft テキストを入力してください。]]
692  [[input-number:Name]]
693
694 オプションパラメータ
695 |table:w=100%|t:w=15%|t:w=20%|t:c:w=10%|t:|
696 |h:フォームタグ|h:オプション|h:省略形|h:説明|
697 |共通|'''id='''''ID''||id属性。|
698 |^|'''class='''''ClassList''||class属性。複数のクラスを指定する場合はコンマ区切りで連ねる。|
699 //|^|'''data-'''''name'''''='''''ID''||Bootstrap用属性。|
700 |^|'''onclick='''''Link''||onclick属性。Javascriptリンク。|
701 |^|'''onfocus='''''Link''||onfocus属性。Javascriptリンク。|
702 |^|'''onblur='''''Link''||onblur属性。Javascriptリンク。|
703 |^|'''onchange='''''Link''||onchange属性。Javascriptリンク。|
704 |^|'''size='''''Integer''||size属性。|
705 |^|'''width='''''Size''|'''w='''|width属性。単位はpx, pt, in, mm, cm, em, ex。または%。|
706 |^|'''accept='''''Type''||accept属性。値は「camera」または,Mime Type。|
707 |^|'''default'''||FORM変数の値をプリセットする。|
708 |^radio, check|'''checked'''||checked属性。|
709 |^radio, check|''WikiLink''||Javascriptリンクを直接指定できる。|
710 |^textarea|'''cols='''''Integer''||cols属性。|
711 |^textarea|'''rows='''''Integer''||rows属性。|
712 |^textarea|'''wrap='''''Value''||wrap属性。値は,off, soft, hard。|
713 |^textarea|'''tab'''||tab入力させるJavascript出力。|
714
715 */
716 static bool  wl_input_sub (const char* type, size_t typelen, WikiMotorObjVecVec* args, WikiMotorObjVec* arg2, WikiMotorObjVec& out, WikiFormat* wiki, bool novalue = false) {
717     WikiMotorObjVecVec::const_iterator  b = args->begin ();
718     WikiMotorObjVecVec::const_iterator  e = args->end ();
719     WikiAttribInput  attrib (wiki, WikiAttribInput::SEL_INPUT);
720     ustring  name;
721     bool  ferr;
722     MotorOutputString  html;
723
724     if (b < e) {
725         name = (*b)->textOut (wiki);
726         b ++;
727     }
728     if (! attrib.readAttrib (b, e))
729         return false;
730     if (b != e) {
731         errorBadParam (b->get (), wiki);
732         return false;
733     }
734
735     html.out_raw (CharConst ("<input"));
736     wiki->outputName (&html, CharConst ("type"), ustring (type, typelen), false);
737     wiki->outputName (&html, CharConst ("name"), name, false);
738     attrib.output (&html);
739     if (! novalue) {
740         if (attrib.pdefault) {
741 //          wiki->outputName (&html, CharConst ("value"), wiki->getVar (name), false);
742             wiki->outputName (&html, CharConst ("value"), wiki->getVar_string (name), false);
743         } else {
744             wiki->outputName (&html, CharConst ("value"), arg2->textOut (wiki), false);
745         }
746     }
747     html.out_raw (CharConst (" />"));
748     out.push_back (WikiMotorObjPtr (new WikiMotorObjHtml (html.ans)));
749
750     return true;
751 }
752
753 bool  wl_input_radiocheck (const char* type, size_t typelen, WikiMotorObjVecVec* args, WikiMotorObjVec* arg2, WikiMotorObjVec& out, WikiFormat* wiki) {
754     WikiMotorObjVecVec::const_iterator  b = args->begin ();
755     WikiMotorObjVecVec::const_iterator  e = args->end ();
756     WikiAttribInput  attrib (wiki, WikiAttribInput::SEL_CHECK);
757     ustring  name;
758     ustring  value;
759     ustring  text;
760     MotorOutputString  html;
761
762     if (b < e) {
763         name = (*b)->textOut (wiki);
764         b ++;
765     }
766     if (b < e) {
767         value = (*b)->textOut (wiki);
768         b ++;
769     }
770     attrib.selector |= WikiAttrib1::SEL_SCRIPT2; // XXX
771     if (! attrib.readAttrib (b, e))
772         return false;
773     attrib.onclick.append (attrib.script);
774     text = arg2->htmlOut (wiki);
775
776     if (attrib.pdefault && wiki->getVar_string (name) == value)
777         attrib.pchecked = true;
778     if (text.length () > 0)
779         html.out_raw (CharConst ("<label>"));
780     html.out_raw (CharConst ("<input"));
781     wiki->outputName (&html, CharConst ("type"), ustring (type, typelen), false);
782     wiki->outputName (&html, CharConst ("name"), name, false);
783     wiki->outputName (&html, CharConst ("value"), value, false);
784     attrib.output (&html);
785     html.out_raw (CharConst (" />"));
786     if (text.length () > 0)
787         html.out_toText (text)
788             ->out_raw (CharConst ("</label>"));
789     out.push_back (WikiMotorObjPtr (new WikiMotorObjHtml (html.ans)));
790
791     return true;
792 }
793
794 //#WIKILINE2    input   wl_input
795 bool  wl_input (WikiMotorObjVecVec* args, WikiMotorObjVec* arg2, WikiMotorObjVec& out, WikiFormat* wiki) {
796     return wl_input_sub (CharConst ("text"), args, arg2, out, wiki);
797 }
798
799 //#WIKILINE2    input-number    wl_input_number
800 bool  wl_input_number (WikiMotorObjVecVec* args, WikiMotorObjVec* arg2, WikiMotorObjVec& out, WikiFormat* wiki) {
801     return wl_input_sub (CharConst ("number"), args, arg2, out, wiki);
802 }
803
804 //#WIKILINE2    password        wl_password
805 bool  wl_password (WikiMotorObjVecVec* args, WikiMotorObjVec* arg2, WikiMotorObjVec& out, WikiFormat* wiki) {
806     return wl_input_sub (CharConst ("password"), args, arg2, out, wiki);
807 }
808
809 //#WIKILINE2    hidden  wl_hidden
810 bool  wl_hidden (WikiMotorObjVecVec* args, WikiMotorObjVec* arg2, WikiMotorObjVec& out, WikiFormat* wiki) {
811     return wl_input_sub (CharConst ("hidden"), args, arg2, out, wiki);
812 }
813
814 //#WIKILINE2    file    wl_file
815 bool  wl_file (WikiMotorObjVecVec* args, WikiMotorObjVec& out, WikiFormat* wiki) {
816     WikiMotorObjVec  arg2;
817
818     if (wl_input_sub (CharConst ("file"), args, &arg2, out, wiki, true)) {
819         if (wiki->curform)
820             wiki->curform->qfileform = true;
821         return true;
822     } else {
823         return false;
824     }
825 }
826
827 bool  wl_button_sub (const char* name, size_t len, WikiMotorObjVecVec* args, WikiMotorObjVec* arg2, WikiMotorObjVec& out, WikiFormat* wiki) {
828     WikiMotorObjVecVec::const_iterator  b = args->begin ();
829     WikiMotorObjVecVec::const_iterator  e = args->end ();
830     WikiAttribButton  attrib (wiki, true);
831     MotorOutputString  html;
832
833     if (! attrib.readAttrib (b, e))
834         return false;
835     attrib.onclick.append (attrib.script);
836     html.out_raw (CharConst ("<input type=\""))
837         ->out_raw (name, len)
838         ->out_raw ("\"");
839     wiki->outputName (&html, CharConst ("name"), attrib.name);
840     attrib.output (&html);
841     wiki->outputName (&html, CharConst ("value"), arg2->textOut (wiki), false);
842     html.out_raw (CharConst (" />"));
843     out.push_back (WikiMotorObjPtr (new WikiMotorObjHtml (html.ans)));
844
845     return true;
846 }
847
848 //#WIKILINE2    submit  wl_submit
849 bool  wl_submit (WikiMotorObjVecVec* args, WikiMotorObjVec* arg2, WikiMotorObjVec& out, WikiFormat* wiki) {
850     return wl_button_sub (CharConst ("submit"), args, arg2, out, wiki);
851 }
852
853 //#WIKILINE2    button  wl_button
854 bool  wl_button (WikiMotorObjVecVec* args, WikiMotorObjVec* arg2, WikiMotorObjVec& out, WikiFormat* wiki) {
855     return wl_button_sub (CharConst ("button"), args, arg2, out, wiki);
856 }
857
858 //#WIKILINE2    radio   wl_radio
859 bool  wl_radio (WikiMotorObjVecVec* args, WikiMotorObjVec* arg2, WikiMotorObjVec& out, WikiFormat* wiki) {
860 //      <input name="radio" type="radio" value="radio" checked="checked" />
861     return wl_input_radiocheck (CharConst ("radio"), args, arg2, out, wiki);
862 }
863
864 //#WIKILINE2    checkbox        wl_checkbox
865 bool  wl_checkbox (WikiMotorObjVecVec* args, WikiMotorObjVec* arg2, WikiMotorObjVec& out, WikiFormat* wiki) {
866 //      <input name="checkbox" type="checkbox" value="1" checked="checked" />
867     return wl_input_radiocheck (CharConst ("checkbox"), args, arg2, out, wiki);
868 }
869
870 //#WIKILINE2    textarea        wl_textarea
871 bool  wl_textarea (WikiMotorObjVecVec* args, WikiMotorObjVec* arg2, WikiMotorObjVec& out, WikiFormat* wiki) {
872     WikiMotorObjVecVec::const_iterator  b = args->begin ();
873     WikiMotorObjVecVec::const_iterator  e = args->end ();
874     ustring  name;
875     WikiAttribInput  attrib (wiki, WikiAttribInput::SEL_TEXTAREA);
876     MotorOutputString  html;
877
878     if (b < e) {
879         name = (*b)->textOut (wiki);
880         b ++;
881     }
882     if (! attrib.readAttrib (b, e))
883         return false;
884     
885     if (attrib.pcols.size () == 0)
886         attrib.pcols = ustring (CharConst ("80"));
887
888     html.out_raw (CharConst ("<textarea"));
889     wiki->outputName (&html, CharConst ("name"), name);
890     attrib.output (&html);
891     html.out_raw (CharConst (">"));
892     if (attrib.pdefault) {
893         html.out_toHTML (wiki->getVar_string (name));
894     } else {
895         html.out_toText (arg2->htmlOut (wiki));
896     }
897     html.out_raw (CharConst ("</textarea>"));
898     out.push_back (WikiMotorObjPtr (new WikiMotorObjHtml (html.ans)));
899     return true;
900 }
901
902 /* ============================================================ */
903 /*DOC:
904 ===数値フォーマット===
905  [[pad0:NUMBER:VALUE]]
906
907 */
908 //#WIKILINE     pad0    wl_pad0
909 bool  wl_pad0 (WikiMotorObjVecVec* args, WikiMotorObjVec& out, WikiFormat* wiki) {
910     WikiMotorObjVecVec::const_iterator  b = args->begin ();
911     WikiMotorObjVecVec::const_iterator  e = args->end ();
912     int  n;
913     ustring  t;
914
915     if (b < e) {
916         n = strtol ((*b)->textOut (wiki));
917         b ++;
918         if (b < e) {
919             t = (*b)->textOut (wiki);
920             out.push_back (WikiMotorObjPtr (new WikiMotorObjText (omitCtrl (zeroPad (n, wiki->getVar_string (t))))));
921             return true;
922         }
923     }
924     return false;
925 }
926
927 /*DOC:
928  [[c3:VALUE]]
929
930 */
931 //#WIKILINE     c3      wl_c3
932 bool  wl_c3 (WikiMotorObjVecVec* args, WikiMotorObjVec& out, WikiFormat* wiki) {
933     WikiMotorObjVecVec::const_iterator  b = args->begin ();
934     WikiMotorObjVecVec::const_iterator  e = args->end ();
935     ustring  t;
936
937     if (b < e) {
938         t = (*b)->textOut (wiki);
939         out.push_back (WikiMotorObjPtr (new WikiMotorObjText (omitCtrl (c3 (t)))));
940         return true;
941     }
942     return false;
943 }
944
945 /*DOC:
946 ===時刻出力===
947  [[date:var_timeval]]
948  [[date:var_timeval format]]
949  [[date:integer]]
950  [[date:integer format]]
951
952  ${Y:4}, ${Y:2}
953  ${M:2}, ${M}
954  ${D:2}, ${D}
955  ${h:2}, ${h}
956  ${m:2}, ${m}
957  ${s:2}, ${s}
958  ${W}, ${w}
959 */
960 //#WIKILINE2    date    wl_date
961 bool  wl_date (WikiMotorObjVecVec* args, WikiMotorObjVec* arg2, WikiMotorObjVec& out, WikiFormat* wiki) {
962     WikiMotorObjVecVec::const_iterator  b = args->begin ();
963     WikiMotorObjVecVec::const_iterator  e = args->end ();
964     ustring  val;
965     time_t  tm;
966     struct tm  tmv;
967     ustring  format;
968
969     if (b < e) {
970         val = (*b)->textOut (wiki);
971         if (matchNum (val)) {
972         } else {
973             val = wiki->getVar_string (val);
974         }
975         if (val.length () > 0) {
976             tm = strtol (val);
977             if (arg2->size () > 0)
978                 format = arg2->textOut (wiki);
979             else
980                 format = uTimeFormat;
981             
982             localtime_r (&tm, &tmv);
983             out.push_back (WikiMotorObjPtr (new WikiMotorObjText (formatDateString (format, tmv))));
984         }
985         return true;
986     }
987
988     return false;
989 }
990
991 /*DOC:
992 ===文字列出力===
993  [[q:TEXT]]
994
995 */
996 //#WIKILINE     q       wl_q
997 bool  wl_q (WikiMotorObjVec* arg2, WikiMotorObjVec& out, WikiFormat* wiki) {
998     arg2->eval (out, wiki);
999     return true;
1000 }
1001
1002 /* ============================================================ */
1003 #if 0
1004 bool  wl_M2 (WikiMotorObjVecVec* args, WikiMotorObjVec* arg2, WikiMotorObjVec& out, WikiFormat* wiki) {
1005     out->out_raw (CharConst ("{{"));
1006     for (int i = 0; i < args.size (); i ++) {
1007         if (i > 0)
1008             out->out_raw (uColon);
1009         out->out_text (args[i]);
1010     }
1011     out->out_raw (uSPC)->out_text (arg2)->out_raw (CharConst ("}}"));
1012     return true;
1013 }
1014 #endif
1015 /* ============================================================ */