Blame


1 5127fd58 2021-12-17 jrmu <?php if (!defined('PmWiki')) exit();
2 fc91d0f1 2023-03-07 jrmu /* Copyright 2007-2021 Patrick R. Michaud (pmichaud@pobox.com)
3 5127fd58 2021-12-17 jrmu This file is part of PmWiki; you can redistribute it and/or modify
4 5127fd58 2021-12-17 jrmu it under the terms of the GNU General Public License as published
5 5127fd58 2021-12-17 jrmu by the Free Software Foundation; either version 2 of the License, or
6 5127fd58 2021-12-17 jrmu (at your option) any later version. See pmwiki.php for full details.
7 5127fd58 2021-12-17 jrmu
8 5127fd58 2021-12-17 jrmu This script implements "markup expressions" -- a method to
9 5127fd58 2021-12-17 jrmu do simple computations and manipulations from markup. The
10 5127fd58 2021-12-17 jrmu generic form of a markup expression is "{(func arg1 arg2)}",
11 5127fd58 2021-12-17 jrmu where the named function (held in the $MarkupExpr array)
12 5127fd58 2021-12-17 jrmu is called with arg1 and arg2 as arguments.
13 5127fd58 2021-12-17 jrmu
14 5127fd58 2021-12-17 jrmu Markup expressions can be nested. For example, to strip
15 5127fd58 2021-12-17 jrmu off the first five characters and convert the remainder to
16 5127fd58 2021-12-17 jrmu lowercase, an author can write:
17 5127fd58 2021-12-17 jrmu
18 5127fd58 2021-12-17 jrmu {(tolower (substr "HELLOWORLD" 5))} # produces "world"
19 5127fd58 2021-12-17 jrmu
20 5127fd58 2021-12-17 jrmu Some "built-in" expressions defined by this recipe include:
21 5127fd58 2021-12-17 jrmu substr - extract a portion of a string
22 5127fd58 2021-12-17 jrmu ftime - date/time formatting
23 5127fd58 2021-12-17 jrmu strlen - length of a string
24 5127fd58 2021-12-17 jrmu rand - generate a random number
25 5127fd58 2021-12-17 jrmu pagename - build a pagename from a string
26 5127fd58 2021-12-17 jrmu toupper - convert string to uppercase
27 5127fd58 2021-12-17 jrmu tolower - convert string to lowercase
28 5127fd58 2021-12-17 jrmu ucfirst - convert first character to uppercase
29 5127fd58 2021-12-17 jrmu ucwords - convert first character of each word to uppercase
30 5127fd58 2021-12-17 jrmu asspaced - spaceformatting of wikiwords
31 5127fd58 2021-12-17 jrmu
32 5127fd58 2021-12-17 jrmu Custom expressions may be added by other recipes by adding
33 5127fd58 2021-12-17 jrmu entries into the $MarkupExpr array. Each entry's key is
34 5127fd58 2021-12-17 jrmu the name of the function, the value is the code to be evaluated
35 5127fd58 2021-12-17 jrmu for that function (similar to the way $FmtPV works). By default,
36 5127fd58 2021-12-17 jrmu any arguments for the expression are placed into the $args array:
37 5127fd58 2021-12-17 jrmu
38 5127fd58 2021-12-17 jrmu ## expressions like {(myfunc foo bar)}
39 5127fd58 2021-12-17 jrmu $MarkupExpr['myfunc'] = 'myfunc($args[0], $args[1])';
40 5127fd58 2021-12-17 jrmu
41 5127fd58 2021-12-17 jrmu The expression arguments are parsed using ParseArgs(), and the
42 5127fd58 2021-12-17 jrmu result of this parsing is available through the $argp array:
43 5127fd58 2021-12-17 jrmu
44 5127fd58 2021-12-17 jrmu ## expressions like {(myfunc fmt=foo output=bar)}
45 5127fd58 2021-12-17 jrmu $MarkupExpr['myfunc'] = 'myfunc($argp["fmt"], $argp["output"])';
46 5127fd58 2021-12-17 jrmu
47 5127fd58 2021-12-17 jrmu Finally, if the code in $MarkupExpr contains '$params', then
48 5127fd58 2021-12-17 jrmu it is executed directly without any preprocessing into arguments,
49 5127fd58 2021-12-17 jrmu and $params contains the entire argument string. Note that $params
50 5127fd58 2021-12-17 jrmu may contain escaped values representing quoted arguments and
51 5127fd58 2021-12-17 jrmu results of other expressions; these values may be un-escaped
52 5127fd58 2021-12-17 jrmu by using "preg_replace_callback($rpat, 'cb_expandkpv', $params)".
53 5127fd58 2021-12-17 jrmu
54 5127fd58 2021-12-17 jrmu Script maintained by Petko YOTOV www.pmwiki.org/petko
55 5127fd58 2021-12-17 jrmu */
56 5127fd58 2021-12-17 jrmu Markup('{(', '>{$var}',
57 5127fd58 2021-12-17 jrmu '/\\{(\\(\\w+\\b.*?\\))\\}/',
58 5127fd58 2021-12-17 jrmu "MarkupMarkupExpression");
59 5127fd58 2021-12-17 jrmu
60 5127fd58 2021-12-17 jrmu function MarkupMarkupExpression($m) {
61 5127fd58 2021-12-17 jrmu extract($GLOBALS["MarkupToHTML"]); # get $pagename
62 5127fd58 2021-12-17 jrmu return MarkupExpression($pagename, $m[1]);
63 5127fd58 2021-12-17 jrmu }
64 5127fd58 2021-12-17 jrmu
65 5127fd58 2021-12-17 jrmu SDVA($MarkupExpr, array(
66 5127fd58 2021-12-17 jrmu 'substr' => 'call_user_func_array("substr", $args)',
67 5127fd58 2021-12-17 jrmu 'strlen' => 'strlen($args[0])',
68 5127fd58 2021-12-17 jrmu 'ftime' => 'ME_ftime(@$args[0], @$args[1], $argp)',
69 5127fd58 2021-12-17 jrmu 'rand' => '($args) ? rand($args[0], $args[1]) : rand()',
70 5127fd58 2021-12-17 jrmu 'ucfirst' => 'ucfirst($args[0])',
71 5127fd58 2021-12-17 jrmu 'ucwords' => 'ucwords($args[0])',
72 5127fd58 2021-12-17 jrmu 'tolower' => 'strtolower($args[0])',
73 5127fd58 2021-12-17 jrmu 'toupper' => 'strtoupper($args[0])',
74 5127fd58 2021-12-17 jrmu 'mod' => '0 + (intval($args[0]) % intval($args[1]))',
75 5127fd58 2021-12-17 jrmu 'asspaced' => '$GLOBALS["AsSpacedFunction"]($args[0])',
76 5127fd58 2021-12-17 jrmu 'pagename' => 'MakePageName($pagename, preg_replace_callback($rpat, "cb_expandkpv", $params))',
77 5127fd58 2021-12-17 jrmu ));
78 5127fd58 2021-12-17 jrmu
79 5127fd58 2021-12-17 jrmu function cb_keep_m0_p($m) { return Keep($m[0],'P'); }
80 5127fd58 2021-12-17 jrmu function cb_keep_m2_p($m) { return Keep($m[2],'P'); }
81 5127fd58 2021-12-17 jrmu
82 5127fd58 2021-12-17 jrmu function MarkupExpression($pagename, $expr) {
83 5127fd58 2021-12-17 jrmu global $KeepToken, $KPV, $MarkupExpr;
84 5127fd58 2021-12-17 jrmu $rpat = "/$KeepToken(\\d+P)$KeepToken/";
85 5127fd58 2021-12-17 jrmu
86 5127fd58 2021-12-17 jrmu $expr = preg_replace_callback('/([\'"])(.*?)\\1/','cb_keep_m2_p', $expr);
87 5127fd58 2021-12-17 jrmu $expr = preg_replace_callback('/\\(\\W/', 'cb_keep_m0_p', $expr);
88 5127fd58 2021-12-17 jrmu while (preg_match('/\\((\\w+)(\\s[^()]*)?\\)/', $expr, $match)) {
89 fc91d0f1 2023-03-07 jrmu @list($repl, $func, $params) = $match;
90 5127fd58 2021-12-17 jrmu $code = @$MarkupExpr[$func];
91 5127fd58 2021-12-17 jrmu ## if not a valid function, save this string as-is and exit
92 5127fd58 2021-12-17 jrmu if (!$code) break;
93 5127fd58 2021-12-17 jrmu ## if the code uses '$params', we just evaluate directly
94 5127fd58 2021-12-17 jrmu if (strpos($code, '$params') !== false) {
95 5127fd58 2021-12-17 jrmu $out = eval("return ({$code});");
96 5127fd58 2021-12-17 jrmu if ($expr == $repl) { $expr = $out; break; }
97 5127fd58 2021-12-17 jrmu $expr = str_replace($repl, $out, $expr);
98 5127fd58 2021-12-17 jrmu continue;
99 5127fd58 2021-12-17 jrmu }
100 5127fd58 2021-12-17 jrmu ## otherwise, we parse arguments into $args before evaluating
101 5127fd58 2021-12-17 jrmu $argp = ParseArgs($params);
102 fc91d0f1 2023-03-07 jrmu $x = @$argp['#']; $args = array();
103 5127fd58 2021-12-17 jrmu while ($x) {
104 5127fd58 2021-12-17 jrmu list($k, $v) = array_splice($x, 0, 2);
105 5127fd58 2021-12-17 jrmu if ($k == '' || $k == '+' || $k == '-')
106 5127fd58 2021-12-17 jrmu $args[] = $k.preg_replace_callback($rpat, 'cb_expandkpv', $v);
107 5127fd58 2021-12-17 jrmu }
108 5127fd58 2021-12-17 jrmu ## fix any quoted arguments
109 5127fd58 2021-12-17 jrmu foreach ($argp as $k => $v)
110 5127fd58 2021-12-17 jrmu if (!is_array($v)) $argp[$k] = preg_replace_callback($rpat, 'cb_expandkpv', $v);
111 5127fd58 2021-12-17 jrmu $out = eval("return ({$code});");
112 5127fd58 2021-12-17 jrmu if ($expr == $repl) { $expr = $out; break; }
113 5127fd58 2021-12-17 jrmu $expr = str_replace($repl, Keep($out, 'P'), $expr);
114 5127fd58 2021-12-17 jrmu }
115 5127fd58 2021-12-17 jrmu return preg_replace_callback($rpat, 'cb_expandkpv', $expr);
116 5127fd58 2021-12-17 jrmu }
117 5127fd58 2021-12-17 jrmu
118 5127fd58 2021-12-17 jrmu ## ME_ftime handles {(ftime ...)} expressions.
119 5127fd58 2021-12-17 jrmu ##
120 5127fd58 2021-12-17 jrmu function ME_ftime($arg0 = '', $arg1 = '', $argp = NULL) {
121 5127fd58 2021-12-17 jrmu global $TimeFmt, $Now, $FTimeFmt;
122 5127fd58 2021-12-17 jrmu if (@$argp['fmt']) $fmt = $argp['fmt'];
123 fc91d0f1 2023-03-07 jrmu elseif ($arg0 && strpos($arg0, '%') !== false) { $fmt = $arg0; $arg0 = $arg1; }
124 fc91d0f1 2023-03-07 jrmu elseif ($arg1 && strpos($arg1, '%') !== false) $fmt = $arg1;
125 fc91d0f1 2023-03-07 jrmu else $fmt = '';
126 5127fd58 2021-12-17 jrmu ## determine the timestamp
127 5127fd58 2021-12-17 jrmu if (isset($argp['when'])) list($time, $x) = DRange($argp['when']);
128 fc91d0f1 2023-03-07 jrmu elseif ($arg0 > '') list($time, $x) = DRange($arg0);
129 5127fd58 2021-12-17 jrmu else $time = $Now;
130 fc91d0f1 2023-03-07 jrmu return PSFT($fmt, $time, @$argp['locale'], @$argp['tz']);
131 5127fd58 2021-12-17 jrmu }
132 5127fd58 2021-12-17 jrmu