3 #include "wikiformat.h"
6 #include "ml-formvar.h"
10 #include "motoroutput.h"
11 #include "util_const.h"
12 #include "util_check.h"
13 #include "util_string.h"
15 #include <boost/ptr_container/ptr_vector.hpp>
19 //#define WIKIREPEATPROTECT 1
20 //#define WIKIEVALPROTECT 1
23 WIKICOMPAT: 1をセットすると,defun-wiki-commandで定義した関数の中で,motor-output, motor-output-rawで出力したテキストをWikiテキストとして解釈する。
30 /* ============================================================ */
31 static void do_linevec (WikiLine::linevec* block, WikiFormat* wiki) {
33 WikiLineScanner scanner (block);
34 wiki->compileLines (scanner);
38 /* ============================================================ */
41 $repeat:''VAR'':''FROM'':''TO''[:''STEP'']
44 変数''VAR''に,数値''FROM''から''TO''までの値を1づつ加算しながら代入し,$endrepeatまでの間のブロックを繰り返し実行する。
47 //#WIKICMD $repeat $endrepeat wc_repeat
48 void wc_repeat (WikiLine* wl, WikiFormat* wiki) {
49 WikiMotor motor (wl->begin, wl->end, wiki);
51 WikiMotorObjVecVec args;
59 #ifdef WIKIREPEATPROTECT
60 if (wiki->protectMode && ! wl->fsuper) {
62 std::cerr << "(wiki):(protected)\n";
69 std::cerr << "(wiki):" << ustring (wl->begin0, wl->end) << "\n";
72 objv.splitCharA (':', args);
73 if (args.size () == 3 || args.size () == 4) {
74 iv = clipWhite (args[0]->textOut (wiki));
75 from = strtod (args[1]->textOut (wiki));
76 to = strtod (args[2]->textOut (wiki));
77 if (args.size () == 4)
78 step = strtod (args[3]->textOut (wiki));
80 wiki->errorMsg.append (CharConst ("$repeat: wrong number of parameters.\n"));
84 for (i = from; i <= to; i += step) {
86 wiki->mlenv->setVar (iv, h ());
87 do_linevec (wl->block, wiki);
88 // if (mlenv->qtimeup ())
91 } else if (step < 0.) {
92 for (i = from; i >= to; i += step) {
94 wiki->mlenv->setVar (iv, h ());
95 do_linevec (wl->block, wiki);
96 // if (wiki->mlenv->qtimeup ())
102 /* ============================================================ */
105 $doarray:''VAR1'',''VAR2'',...[:''INDEX_VAR'']
109 配列''VAR1'', ''VAR2'', ...の各要素をそれぞれ変数''VAR1'', ''VAR2'', ...に代入しながら,$enddoarrayまでのブロックを繰り返し実行する。
110 ブロックの中で変数''VAR1'', ...に代入した値は,配列に書き戻される。
111 配列の長さが異なる場合は,配列''VAR1''の長さに揃えられる。
112 ''INDEX_VAR''を指定すると,配列のインデックス番号を変数''INDEX_VAR''に代入して,ブロックを実行する。
115 //#WIKICMD $doarray $enddoarray wc_doarray
116 void wc_doarray (WikiLine* wl, WikiFormat* wiki) {
117 WikiMotor motor (wl->begin, wl->end, wiki);
118 WikiMotorObjVec objv;
119 WikiMotorObjVecVec args;
120 std::vector<ustring> lv;
125 #ifdef WIKIREPEATPROTECT
126 if (wiki->protectMode && ! wl->fsuper) {
128 std::cerr << "(wiki):(protected)\n";
135 std::cerr << "(wiki):" << ustring (wl->begin0, wl->end) << "\n";
137 motor.compile (objv);
138 objv.splitCharA (':', args);
139 if (args.size () == 1 || args.size () == 2) {
140 WikiMotorObjVecVec v;
141 args[0]->splitCharA (',', v);
142 for (int i = 0; i < v.size (); i ++)
143 lv.push_back (clipWhite (v[i]->textOut (wiki)));
144 if (args.size () == 2) {
145 iv = clipWhite (args[1]->textOut (wiki));
148 wiki->errorMsg.append (CharConst ("$repeat: wrong number of parameters.\n"));
152 n = wiki->mlenv->getArySize (lv[0]);
153 for (i = 1; i <= n; i ++) {
154 for (it = 0; it < iu; it ++) {
155 wiki->mlenv->setVar (lv[it], wiki->mlenv->getAry (lv[it], i));
157 if (iv.size () > 0) {
158 h = newMNode_num (i);
159 wiki->mlenv->setVar (iv, h ());
161 do_linevec (wl->block, wiki);
162 for (it = 0; it < iu; it ++) {
163 wiki->mlenv->setAry (lv[it], i, wiki->mlenv->getVar (lv[it]));
166 for (it = 0; it < iu; it ++) {
167 wiki->mlenv->setArySize (lv[it], n);
172 /* ============================================================ */
183 LISPセル''EXPR''が真のとき,$elseblockまたは$endblockまでのブロックを実行する。
184 $elseblockに条件を書かないとき,それ以前のすべての条件が真でないときに次のブロックを実行する。
187 //#WIKICMD $block $elseblock $endblock wc_block
188 void wc_block (WikiLine* wl, WikiFormat* wiki) {
189 MotorSexp ml (wiki->mlenv);
190 ustring sexp (wl->begin, wl->end);
194 #ifdef WIKIEVALPROTECT
195 if (wiki->protectMode && ! wl->fsuper) {
197 std::cerr << "(wiki):(protected)\n";
204 std::cerr << "(wiki):" << ustring (wl->begin0, wl->end) << "\n";
210 if (ml.top.isCons ()) {
211 MNode* arg = ml.top.cdr ();
212 if (arg && arg->isCons ()) {
214 v = eval (arg->car (), wiki->mlenv);
215 } catch (ustring& msg) {
216 if (wiki->mlenv->currentCell ()) {
217 wiki->errorMsg.append (wiki->mlenv->currentCell ()->dump_string_short ()).append (CharConst (": "));
219 wiki->errorMsg.append (msg).append (uLF);
223 q = v ()->to_bool ();
232 do_linevec (wl->block, wiki);
234 std::cerr << "(wiki):" << "$endblock" << "\n";
237 WikiLine* w2 = wl->block2;
242 std::cerr << "(wiki):" << "$endblock" << "\n";
248 /* ============================================================ */
249 //#WIKICMD $setvar wc_setvar
250 void wc_setvar (WikiLine* wl, WikiFormat* wiki) {
251 MotorSexp ml (wiki->mlenv);
252 ustring sexp (wl->begin, wl->end);
258 if (wiki->protectMode && ! wl->fsuper) {
260 std::cerr << "(wiki):(protected)\n";
267 std::cerr << "(wiki):" << ustring (wl->begin0, wl->end) << "\n";
269 if (! sexp.empty ()) {
271 if (ml.top.isCons ()) {
273 if (arg && arg->isCons ()) {
274 var = to_string (arg->car ());
278 wiki->errorMsg.append (CharConst ("$setvar: wrong number of parameters.\n"));
282 v = eval (arg->car (), wiki->mlenv);
283 } catch (ustring& msg) {
284 if (wiki->mlenv->currentCell ()) {
285 wiki->errorMsg.append (wiki->mlenv->currentCell ()->dump_string_short ()).append (CharConst (": "));
287 wiki->errorMsg.append (msg).append (uLF);
290 if (var.size () > 0) {
291 if (checkAry (var, var)) {
292 wiki->mlenv->setAry (var, v ());
294 wiki->mlenv->setVar (var, v ());
300 /* ============================================================ */
308 //#WIKICMD $eval wc_eval
309 void wc_eval (WikiLine* wl, WikiFormat* wiki) {
310 MotorSexp ml (wiki->mlenv);
311 ustring sexp (wl->begin, wl->end);
314 #ifdef WIKIEVALPROTECT
315 if (wiki->protectMode && ! wl->fsuper) {
317 std::cerr << "(wiki):(protected)\n";
324 std::cerr << "(wiki):" << ustring (wl->begin0, wl->end) << "\n";
326 if (! sexp.empty ()) {
328 if (ml.top.isCons ()) {
329 MNode* arg = ml.top.cdr ();
330 if (arg && arg->isCons ()) {
332 v = eval (arg->car (), wiki->mlenv);
333 } catch (ustring& msg) {
334 if (wiki->mlenv->currentCell ()) {
335 wiki->errorMsg.append (wiki->mlenv->currentCell ()->dump_string_short ()).append (CharConst (": "));
337 wiki->errorMsg.append (msg).append (uLF);
344 /* ============================================================ */
351 ブロック内部に記述されたLISPファンクションを実行する。
355 //#WIKICMD $evalblock $endevalblock wc_evalblock
356 void wc_evalblock (WikiLine* wl, WikiFormat* wiki) {
357 MotorSexp ml (wiki->mlenv);
358 // ustring sexp (wl->begin, wl->end);
360 #ifdef WIKIEVALPROTECT
361 if (wiki->protectMode && ! wl->fsuper) {
363 std::cerr << "(wiki):(protected)\n";
370 ustring sexp (wl->end + 1, wl->block->back ().end + 1);
371 // std::cerr << "[" << sexp << "]\n";
373 std::cerr << "(wiki): $evalblock\n";
375 if (! sexp.empty ()) {
377 MNode* arg = &ml.top;
378 if (arg->isCons ()) {
380 progn_ex (arg, wiki->mlenv);
381 } catch (ustring& msg) {
382 if (wiki->mlenv->currentCell ()) {
383 wiki->errorMsg.append (wiki->mlenv->currentCell ()->dump_string_short ()).append (CharConst (": "));
385 wiki->errorMsg.append (msg).append (uLF);
392 /* ============================================================ */
397 $insert:VARIABLE:superuser
398 $insert:VARIABLE:superuser:==
400 変数''VARIABLE''に格納されたWikiテキストを挿入する。
401 オプションの「=」を追加すると,「=」の数だけ挿入されるWikiテキストのタイトルの深さが下げられる。
405 //#WIKICMD $insert wc_insert
406 void wc_insert (WikiLine* wl, WikiFormat* wiki) {
407 WikiMotor motor (wl->begin, wl->end, wiki);
408 WikiMotorObjVec objv;
409 WikiMotorObjVecVec argsv;
410 std::vector<ustring> args;
415 static uregex re_eq ("=+");
419 std::cerr << "(wiki):" << ustring (wl->begin0, wl->end) << "\n";
421 motor.compile (objv);
422 objv.splitCharA (':', argsv);
423 for (i = 0; i < argsv.size (); i ++)
424 args.push_back (argsv[i]->textOut (wiki));
426 protect = wiki->protectMode && ! wl->fsuper;
428 for (i = 1; i < args.size (); i ++) {
429 if (! protect && match (args[i], CharConst ("superuser"))) {
431 } else if (usearch (args[i], m, re_eq)) {
432 hn = m[0].second - m[0].first;
441 if (args.size () >= 1) {
442 AutoInclCount autoIncl (wiki->mlenv);
443 ustring text = wiki->getVar (args[0]);
444 WikiLine::linevec bl;
445 wiki->headbase += hn;
446 wiki->pass1 (text, &bl, super);
448 do_linevec (&bl, wiki);
449 wiki->headbase -= hn;
453 /* ============================================================ */
461 static void wldump (ustring& data, WikiLine::linevec* vwl);
462 static void wldump (ustring& data, WikiLine* wl) {
463 data.append (wl->begin0, wl->end).append (uLF);
465 wldump (data, wl->block);
468 wldump (data, wl->block2);
472 static void wldump (ustring& data, WikiLine::linevec* vwl) {
476 for (i = 0; i < n; i ++) {
477 wldump (data, &(*vwl)[i]);
481 //#WIKICMD $data $enddata wc_data
482 void wc_data (WikiLine* wl, WikiFormat* wiki) {
483 WikiMotor motor (wl->begin, wl->end, wiki);
486 WikiMotorObjVec objv;
487 WikiMotorObjVecVec args;
489 if (wiki->protectMode && ! wl->fsuper) {
491 std::cerr << "(wiki):(protected)\n";
496 motor.compile (objv);
497 objv.splitCharA (':', args);
498 if (args.size () > 0) {
499 name = clipWhite (args[0]->textOut (wiki));
501 wiki->errorMsg.append (CharConst ("$data: missing variable name.\n"));
506 wldump (data, wl->block);
507 wiki->mlenv->setVar (name, newMNode_str (new ustring (data)));
511 /* ============================================================ */
514 $local:''VARIABLE'',...
519 //#WIKICMD $local $endlocal wc_local
520 void wc_local (WikiLine* wl, WikiFormat* wiki) {
521 WikiMotor motor (wl->begin, wl->end, wiki);
522 WikiMotorObjVec objv;
523 WikiMotorObjVecVec args;
524 std::vector<ustring> vars;
527 #ifdef WIKIEVALPROTECT
528 if (wiki->protectMode && ! wl->fsuper) {
530 std::cerr << "(wiki):(protected)\n";
537 std::cerr << "(wiki):" << ustring (wl->begin0, wl->end) << "\n";
540 motor.compile (objv);
541 objv.splitCharA (':', args);
542 if (args.size () == 1) {
543 WikiMotorObjVecVec v;
544 args[0]->splitCharA (',', v);
545 for (i = 0; i < v.size (); i ++)
546 vars.push_back (clipWhite (v[i]->textOut (wiki)));
548 wiki->errorMsg.append (CharConst ("$local: wrong number of parameters.\n"));
552 AutoLocalVariable autoLocal (wiki->mlenv);
553 for (i = 0; i < n; i ++) {
554 wiki->mlenv->setLocalVar (vars[i], NULL);
556 do_linevec (wl->block, wiki);
558 std::cerr << "(endlocal)\n";
561 do_linevec (wl->block, wiki);
564 std::cerr << "(wiki):$endlocal\n";
568 /* ============================================================ */
571 $macro:''NAME'':''VARIABLE'',...
576 マクロは組み込みコマンドをオーバーライドできない。
579 //#WIKICMD $macro $endmacro wc_macro
580 void wc_macro (WikiLine* wl, WikiFormat* wiki) {
581 WikiMotor motor (wl->begin, wl->end, wiki);
582 WikiMotorObjVec objv;
583 WikiMotorObjVecVec args;
585 // std::vector<ustring> vars;
589 assert (0); // メモリ管理問題
591 if (wiki->protectMode && ! wl->fsuper) {
593 std::cerr << "(wiki):(protected)\n";
599 std::cerr << "(wiki):" << ustring (wl->begin0, wl->end) << "\n";
602 motor.compile (objv);
603 objv.splitCharA (':', args);
604 if (args.size () >= 1) {
605 name = clipWhite (args[0]->textOut (wiki));
607 wiki->errorMsg.append (CharConst ("$macro: wrong number of parameters.\n"));
610 if (args.size () == 2) {
611 WikiMotorObjVecVec v;
612 args[1]->splitCharA (',', v);
613 for (i = 0; i < v.size (); i ++) {
614 // vars.push_back (clipWhite (v[i]->textOut (wiki)));
615 vars.append (newMNode_str (new ustring (clipWhite (v[i]->textOut (wiki)))));
617 } else if (args.size () > 2) {
618 wiki->errorMsg.append (CharConst ("$macro: wrong number of parameters.\n"));
622 wiki->env->wikienv->wikiMacro.setVar (name, vars.release (), wl->block);
627 // std::cerr << "(wiki):$endmacro\n";
631 /* ============================================================ */
633 ===$input-text, $input-textarea, $input-int, $input-real, $input-int-or-blank, $input-real-or-blank, $input-ascii, $input-bool===
635 $input-textarea:VARIABLE
638 $input-int-or-blank:VARIABLE
639 $input-real-or-blank:VARIABLE
640 $input-ascii:VARIABLE
644 //#WIKICMD $input-text wc_input_text
645 //#WIKICMD $input-textarea wc_input_textarea
646 //#WIKICMD $input-int wc_input_int
647 //#WIKICMD $input-real wc_input_real
648 //#WIKICMD $input-int-or-blank wc_input_int_or_blank
649 //#WIKICMD $input-real-or-blank wc_input_real_or_blank
650 //#WIKICMD $input-ascii wc_input_ascii
651 //#WIKICMD $input-bool wc_input_bool
652 static void wc_input_sub (WikiLine* wl, WikiFormat* wiki, ustring (*prefn)(const ustring&), MNode* (FormVarOp::*postfn)(const ustring&)) {
653 WikiMotor motor (wl->begin, wl->end, wiki);
654 WikiMotorObjVec objv;
655 WikiMotorObjVecVec args;
658 std::cerr << "(wiki):" << ustring (wl->begin0, wl->end) << "\n";
660 motor.compile (objv);
661 objv.splitCharA (':', args);
666 if (args.size () > 0) {
667 name = args[0]->textOut (wiki);
668 for (i = 1; i < args.size (); i ++) {
669 if (args[i]->matchHead (CharConst ("max="))) {
671 args[i]->splitChar (wiki, '=', x, y);
672 opt.max = to_uint32 (y);
673 } else if (args[i]->match (CharConst ("nowhite"))) {
675 } else if (args[i]->match (CharConst ("nw"))) {
677 } else if (args[i]->matchHead (CharConst ("filter="))) {
679 args[i]->splitChar (wiki, '=', x, y);
681 } else if (args[i]->matchHead (CharConst ("default="))) {
683 args[i]->splitChar (wiki, '=', x, y);
686 wiki->errorMsg.append (args[i]->textOut (wiki) + ustring (CharConst (": bad parameter.\n")));
689 opt.input (wiki->mlenv, name, prefn, postfn);
693 void wc_input_text (WikiLine* wl, WikiFormat* wiki) {
694 wc_input_sub (wl, wiki, omitCtrl, &FormVarOp::stringNode);
697 void wc_input_textarea (WikiLine* wl, WikiFormat* wiki) {
698 wc_input_sub (wl, wiki, omitCtrlX, &FormVarOp::stringNode);
701 void wc_input_int (WikiLine* wl, WikiFormat* wiki) {
702 wc_input_sub (wl, wiki, NULL, &FormVarOp::intNode);
705 void wc_input_real (WikiLine* wl, WikiFormat* wiki) {
706 wc_input_sub (wl, wiki, NULL, &FormVarOp::doubleNode);
709 void wc_input_int_or_blank (WikiLine* wl, WikiFormat* wiki) {
710 wc_input_sub (wl, wiki, NULL, &FormVarOp::intBlankNode);
713 void wc_input_real_or_blank (WikiLine* wl, WikiFormat* wiki) {
714 wc_input_sub (wl, wiki, NULL, &FormVarOp::doubleBlankNode);
717 void wc_input_ascii (WikiLine* wl, WikiFormat* wiki) {
718 wc_input_sub (wl, wiki, omitNonAscii, &FormVarOp::stringNode);
721 void wc_input_bool (WikiLine* wl, WikiFormat* wiki) {
722 wc_input_sub (wl, wiki, NULL, &FormVarOp::boolNode);
725 /* ============================================================ */
730 フォーマット済みブロック内で,インラインファンクションの展開を行うモードの設定。
734 //#WIKICMD $premode wc_premode
735 void wc_premode (WikiLine* wl, WikiFormat* wiki) {
736 WikiMotor motor (wl->begin, wl->end, wiki);
737 WikiMotorObjVec objv;
738 WikiMotorObjVecVec argsv;
742 std::cerr << "(wiki):" << ustring (wl->begin0, wl->end) << "\n";
744 motor.compile (objv);
745 objv.splitCharA (':', argsv);
746 if (argsv.size () > 0) {
747 arg = argsv[0]->textOut (wiki);
749 wiki->motorPre = to_bool (arg);
752 /* ============================================================ */
753 static void call_defun_wikicmd (ustring& name, MNode* wf, WikiMotorObjVec& objv2, WikiLine* wl, WikiFormat* wiki) {
754 WikiMotorObjVecVec argsv;
757 objv2.splitCharA (':', argsv);
758 vargs = wiki->buildArgs (argsv.begin (), argsv.end ());
760 MotorOutputString out;
761 MotorOutput* back = wiki->env->output;
762 WikiMotorOutputString* wikiback = wiki->env->wikioutput;
763 WikiMotorOutputString wikiout (wiki);
767 wiki->env->wikioutput = &wikiout;
768 wiki->env->output = &out;
769 bcell = wiki->env->mlenv->currentCell;
770 wiki->env->mlenv->currentCell = NULL;
772 node = execDefun (wiki->env->mlenv, wf, vargs (), name);
773 } catch (ustring& msg) {
774 wiki->logLispFunctionError (msg, ustring (wl->begin, wl->end));
776 wiki->env->mlenv->currentCell = bcell;
777 if (wikiout.ans.length () > 0) {
778 WikiLine::linevec bl;
779 wiki->pass1 (wikiout.ans, &bl, wl->fsuper);
780 do_linevec (&bl, wiki);
782 wiki->env->wikioutput = wikiback;
783 if (out.ans.length () > 0) {
785 WikiLine::linevec bl;
786 wiki->pass1 (out.ans, &bl, wl->fsuper);
787 do_linevec (&bl, wiki);
789 wiki->pushBlockRaw (out.ans.begin (), out.ans.end ());
792 wiki->env->output = back;
796 static void call_defun_macro (ustring& name, WikiMacro* mf, WikiMotorObjVec& objv2, WikiLine* wl, WikiFormat* wiki) {
797 WikiMotorObjVecVec argsv;
800 objv2.splitCharA (':', argsv);
801 // vargs = wiki->buildArgs (argsv.begin (), argsv.end ());
804 AutoLocalVariable autoLocal (wiki->mlenv);
805 MNode* p = mf->vars ();
811 while (p && (t = p->car ())) {
813 v = newMNode_str (new ustring (argsv[i]->textOut (wiki)));
818 wiki->mlenv->setLocalVar (to_string (t), v);
821 do_linevec (mf->wl, wiki);
825 void wc_call_defun (WikiLine* wl, WikiFormat* wiki) {
826 WikiMotor motor (wl->begin + 1, wl->end, wiki);
827 WikiMotorObjVec objv;
828 WikiMotorObjVec objv2;
835 std::cerr << "(wiki):" << ustring (wl->begin0, wl->end) << "\n";
837 motor.compile (objv);
838 objv.splitChar_keyword (':', name, objv2);
839 if (wiki->protectMode && ! wl->fsuper && ! wiki->env->wikienv->wikiGuestFunc.get (name))
842 if (fx && (wf = wiki->env->wikienv->wikiCmd.getVar (name))) { // Wiki Command
843 call_defun_wikicmd (name, wf, objv2, wl, wiki);
844 } else if (mf = wiki->env->wikienv->wikiMacro.getVar (name)) { // Wiki Macro. macroは誰でも実行できる。
845 // std::cerr << "macro:" << name << "\n";
846 call_defun_macro (name, mf, objv2, wl, wiki);
848 WikiLine::linevec bl;
850 ustring u (CharConst ("^"));
852 u.append (wl->begin, wl->end);
853 wl2 = new WikiLine (u.begin (), u.end (), wl->fsuper);
855 do_linevec (&bl, wiki);
859 void wikiOutput (const ustring& text, bool fsuper, WikiFormat* wiki) {
860 WikiLine::linevec bl;
861 wiki->pass1 (text, &bl, fsuper);
862 do_linevec (&bl, wiki);
868 /* ============================================================ */