Projet

Général

Profil

Révision 219d19c4

Ajouté par Assos Assos il y a plus de 3 ans

Weekly update of contrib modules

Voir les différences:

drupal7/sites/all/modules/ctools/README.txt
1
CONTENTS OF THIS FILE
2
---------------------
3

  
4
 * Introduction
5
 * Requirements
6
 * Recommended Modules
7
 * Installation
8
 * Configuration
9

  
10

  
11
INTRODUCTION
12
------------
13

  
14
The Chaos tool suite (ctools) module is primarily a set of APIs and tools to
15
improve the developer experience. It also contains a module called the Page
16
Manager whose job is to manage pages. In particular it manages panel pages, but
17
as it grows it will be able to manage far more than just Panels.
18

  
19
The Chaos Tool Suite (ctools) is a series of tools that makes code readily
20
available for developers and creates libraries for other modules to use. Modules
21
that use ctools include Views and Panels.
22

  
23
End users will use ctools as underlying user interface libraries when operating
24
Views and Panels modules and will not need to explore further (ctools is geared
25
more toward developer usage). Developers will use the module differently and
26
work more with the tools provided.
27

  
28
For the moment, it includes the following tools:
29

  
30
 * Plugins -- tools to make it easy for modules to let other modules implement
31
   plugins from .inc files.
32
 * Exportables -- tools to make it easier for modules to have objects that live
33
   in database or live in code, such as 'default views'.
34
 * AJAX responder -- tools to make it easier for the server to handle AJAX
35
   requests and tell the client what to do with them.
36
 * Form tools -- tools to make it easier for forms to deal with AJAX.
37
 * Object caching -- tool to make it easier to edit an object across multiple
38
   page requests and cache the editing work.
39
 * Contexts -- the notion of wrapping objects in a unified wrapper and providing
40
   an API to create and accept these contexts as input.
41
 * Modal dialog -- tool to make it simple to put a form in a modal dialog.
42
 * Dependent -- a simple form widget to make form items appear and disappear
43
   based upon the selections in another item.
44
 * Content -- pluggable content types used as panes in Panels and other modules
45
   like Dashboard.
46
 * Form wizard -- an API to make multi-step forms much easier.
47
 * CSS tools -- tools to cache and sanitize CSS easily to make user-input CSS
48
   safe.
49

  
50
 * For a full description of the module visit:
51
   https://www.drupal.org/project/ctools
52

  
53
 * To submit bug reports and feature suggestions, or to track changes visit:
54
   https://www.drupal.org/project/issues/ctools
55

  
56

  
57
REQUIREMENTS
58
------------
59

  
60
This module requires no modules outside of Drupal core.
61

  
62

  
63
RECOMMENDED MODULES
64
-------------------
65

  
66
The Advanced help module provides extended documentation. Once enabled,
67
navigate to Administration > Advanced Help and select the Chaos tools link to
68
view documentation.
69

  
70
 * Advanced help - https://www.drupal.org/project/advanced_help
71

  
72

  
73
INSTALLATION
74
------------
75

  
76
 * Install the Chaos tool suite module as you would normally install a
77
   contributed Drupal module. Visit https://www.drupal.org/node/895232 for
78
   further information.
drupal7/sites/all/modules/ctools/bulk_export/bulk_export.info
4 4
dependencies[] = ctools
5 5
package = Chaos tool suite
6 6

  
7
; Information added by Drupal.org packaging script on 2019-02-08
8
version = "7.x-1.15"
7
; Information added by Drupal.org packaging script on 2020-10-23
8
version = "7.x-1.17"
9 9
core = "7.x"
10 10
project = "ctools"
11
datestamp = "1549603691"
11
datestamp = "1603490551"
drupal7/sites/all/modules/ctools/ctools.api.php
30 30
}
31 31

  
32 32
/**
33
 * Tells CTools where to find module-defined plugins.
34
 *
33 35
 * This hook is used to inform the CTools plugin system about the location of a
34 36
 * directory that should be searched for files containing plugins of a
35 37
 * particular type. CTools invokes this same hook for all plugins, using the
......
104 106
 * This hook is useful for altering flags or other information that will be
105 107
 * used or possibly overriden by the process hook if defined.
106 108
 *
107
 * @param $plugin
109
 * @param array $plugin
108 110
 *   An associative array defining a plugin.
109
 * @param $info
111
 * @param array $info
110 112
 *   An associative array of plugin type info.
111 113
 */
112
function hook_ctools_plugin_pre_alter(&$plugin, &$info) {
114
function hook_ctools_plugin_pre_alter(array &$plugin, array &$info) {
113 115
  // Override a function defined by the plugin.
114 116
  if ($info['type'] == 'my_type') {
115 117
    $plugin['my_flag'] = 'new_value';
......
122 124
 * This hook is useful for overriding the final values for a plugin after it
123 125
 * has been processed.
124 126
 *
125
 * @param $plugin
127
 * @param array $plugin
126 128
 *   An associative array defining a plugin.
127
 * @param $info
129
 * @param array $info
128 130
 *   An associative array of plugin type info.
129 131
 */
130
function hook_ctools_plugin_post_alter(&$plugin, &$info) {
132
function hook_ctools_plugin_post_alter(array &$plugin, array &$info) {
131 133
  // Override a function defined by the plugin.
132 134
  if ($info['type'] == 'my_type') {
133 135
    $plugin['my_function'] = 'new_function';
......
144 146
 *   An array of informations about the implementors of a certain api.
145 147
 *   The key of this array are the module names/theme names.
146 148
 */
147
function hook_ctools_api_hook_alter(&$list) {
149
function hook_ctools_api_hook_alter(array &$list) {
148 150
  // Alter the path of the node implementation.
149 151
  $list['node']['path'] = drupal_get_path('module', 'node');
150 152
}
......
152 154
/**
153 155
 * Alter the available functions to be used in ctools math expression api.
154 156
 *
155
 * One usecase would be to create your own function in your module and
157
 * One use case would be to create your own function in your module and
156 158
 * allow to use it in the math expression api.
157 159
 *
158
 * @param $functions
160
 * @param array $functions
159 161
 *   An array which has the functions as value.
162
 * @param array $context
163
 *   An array containing an item 'final' whose value is a reference to the
164
 *   definitions for multiple-arg functions. Use this to add in functions that
165
 *   require more than one arg.
160 166
 */
161
function hook_ctools_math_expression_functions_alter(&$functions) {
162
  // Allow to convert from degrees to radiant.
167
function hook_ctools_math_expression_functions_alter(array &$functions, array $context) {
168
  // Allow to convert from degrees to radians.
163 169
  $functions[] = 'deg2rad';
170

  
171
  $multiarg = $context['final'];
172
  $multiarg['pow'] = array(
173
    'function' => 'pow',
174
    'arguments' => 2,
175
  );
176
}
177

  
178
/**
179
 * Alter the available functions to be used in ctools math expression api.
180
 *
181
 * One usecase would be to create your own function in your module and
182
 * allow to use it in the math expression api.
183
 *
184
 * @param array $constants
185
 *   An array of name:value pairs, one for each named constant. Values added
186
 *   to this array become read-only variables with the value assigned here.
187
 */
188
function hook_ctools_math_expression_constants_alter(array &$constants) {
189
  // Add the speed of light as constant 'c':
190
  $constants['c'] = 299792458;
164 191
}
165 192

  
166 193
/**
167 194
 * Alter everything.
168 195
 *
169
 * @param $info
196
 * @param array $info
170 197
 *   An associative array containing the following keys:
171 198
 *   - content: The rendered content.
172 199
 *   - title: The content's title.
173 200
 *   - no_blocks: A boolean to decide if blocks should be displayed.
174
 * @param $page
201
 * @param bool $page
175 202
 *   If TRUE then this renderer owns the page and can use theme('page')
176 203
 *   for no blocks; if false, output is returned regardless of any no
177 204
 *   blocks settings.
178
 * @param $context
205
 * @param array $context
179 206
 *   An associative array containing the following keys:
180 207
 *   - args: The raw arguments behind the contexts.
181 208
 *   - contexts: The context objects in use.
......
183 210
 *   - subtask: The subtask object in use.
184 211
 *   - handler: The handler object in use.
185 212
 */
186
function hook_ctools_render_alter(&$info, &$page, &$context) {
213
function hook_ctools_render_alter(array &$info, &$page, array &$context) {
187 214
  if ($context['handler']->name == 'my_handler') {
188 215
    ctools_add_css('my_module.theme', 'my_module');
189 216
  }
......
219 246
 * @param string $plugin_id
220 247
 *   The plugin ID, in the format NAME:KEY.
221 248
 */
222
function hook_ctools_entity_context_alter(&$plugin, &$entity, $plugin_id) {
249
function hook_ctools_entity_context_alter(array &$plugin, array &$entity, $plugin_id) {
223 250
  ctools_include('context');
224 251
  switch ($plugin_id) {
225 252
    case 'entity_id:taxonomy_term':
......
242 269
 *   A string associated with the plugin type, identifying the operation.
243 270
 * @param string $value
244 271
 *   The value being converted; this is the only return from the function.
245
 * @param $converter_options
272
 * @param array $converter_options
246 273
 *   Array of key-value pairs to pass to a converter function from higher
247 274
 *   levels.
248 275
 *
249 276
 * @see ctools_context_convert_context()
250 277
 */
251
function hook_ctools_context_converter_alter($context, $converter, &$value, $converter_options) {
278
function hook_ctools_context_converter_alter(ctools_context $context, $converter, &$value, array $converter_options) {
252 279
  if ($converter === 'mystring') {
253 280
    $value = 'fixed';
254 281
  }
......
262 289
 *
263 290
 * @see hook_ctools_entity_context_alter()
264 291
 */
265
function hook_ctools_entity_contexts_alter(&$plugins) {
292
function hook_ctools_entity_contexts_alter(array &$plugins) {
266 293
  $plugins['entity_id:taxonomy_term']['no ui'] = TRUE;
267 294
}
268 295

  
......
274 301
 *
275 302
 * @see ctools_cleanstring()
276 303
 */
277
function hook_ctools_cleanstring_alter(&$settings) {
304
function hook_ctools_cleanstring_alter(array &$settings) {
278 305
  // Convert all strings to lower case.
279 306
  $settings['lower case'] = TRUE;
280 307
}
......
287 314
 *
288 315
 * @see ctools_cleanstring()
289 316
 */
290
function hook_ctools_cleanstring_CLEAN_ID_alter(&$settings) {
317
function hook_ctools_cleanstring_CLEAN_ID_alter(array &$settings) {
291 318
  // Convert all strings to lower case.
292 319
  $settings['lower case'] = TRUE;
293 320
}
......
304 331
 *
305 332
 * @see ctools_context_handler_pre_render()
306 333
 */
307
function ctools_context_handler_pre_render($handler, $contexts, $args) {
334
function ctools_context_handler_pre_render($handler, array $contexts, array $args) {
308 335
  $handler->conf['css_id'] = 'my-id';
309 336
}
310 337

  
drupal7/sites/all/modules/ctools/ctools.info
19 19
files[] = tests/object_cache_unit.test
20 20
files[] = tests/page_tokens.test
21 21

  
22
; Information added by Drupal.org packaging script on 2019-02-08
23
version = "7.x-1.15"
22
; Information added by Drupal.org packaging script on 2020-10-23
23
version = "7.x-1.17"
24 24
core = "7.x"
25 25
project = "ctools"
26
datestamp = "1549603691"
26
datestamp = "1603490551"
drupal7/sites/all/modules/ctools/ctools.module
479 479
  if (!module_exists('uuid')) {
480 480
    ctools_include('uuid');
481 481

  
482
    $callback = drupal_static(__FUNCTION__);
482
    $callback = &drupal_static(__FUNCTION__);
483 483

  
484 484
    if (empty($callback)) {
485 485
      if (function_exists('uuid_create') && !function_exists('uuid_make')) {
......
903 903
 */
904 904

  
905 905
function ctools_access_menu($access) {
906
  $func_args = func_get_args();
906 907
  // Short circuit everything if there are no access tests.
907 908
  if (empty($access['plugins'])) {
908 909
    return TRUE;
909 910
  }
910 911

  
911 912
  $contexts = array();
912
  foreach (func_get_args() as $arg) {
913
  foreach ($func_args as $arg) {
913 914
    if (is_object($arg) && get_class($arg) == 'ctools_context') {
914 915
      $contexts[$arg->id] = $arg;
915 916
    }
drupal7/sites/all/modules/ctools/ctools_access_ruleset/ctools_access_ruleset.info
4 4
package = Chaos tool suite
5 5
dependencies[] = ctools
6 6

  
7
; Information added by Drupal.org packaging script on 2019-02-08
8
version = "7.x-1.15"
7
; Information added by Drupal.org packaging script on 2020-10-23
8
version = "7.x-1.17"
9 9
core = "7.x"
10 10
project = "ctools"
11
datestamp = "1549603691"
11
datestamp = "1603490551"
drupal7/sites/all/modules/ctools/ctools_ajax_sample/ctools_ajax_sample.info
4 4
dependencies[] = ctools
5 5
core = 7.x
6 6

  
7
; Information added by Drupal.org packaging script on 2019-02-08
8
version = "7.x-1.15"
7
; Information added by Drupal.org packaging script on 2020-10-23
8
version = "7.x-1.17"
9 9
core = "7.x"
10 10
project = "ctools"
11
datestamp = "1549603691"
11
datestamp = "1603490551"
drupal7/sites/all/modules/ctools/ctools_ajax_sample/ctools_ajax_sample.module
187 187
    );
188 188
  }
189 189

  
190
  $output .= theme('table', array('header' => $header, 'rows' => $rows, array('class' => array('ajax-sample-table'))));
190
  $output .= theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('class' => array('ajax-sample-table'))));
191 191

  
192 192
  // Show examples of ctools javascript widgets.
193 193
  $output .= '<h2>' . t('CTools Javascript Widgets') . '</h2>';
drupal7/sites/all/modules/ctools/ctools_custom_content/ctools_custom_content.info
4 4
package = Chaos tool suite
5 5
dependencies[] = ctools
6 6

  
7
; Information added by Drupal.org packaging script on 2019-02-08
8
version = "7.x-1.15"
7
; Information added by Drupal.org packaging script on 2020-10-23
8
version = "7.x-1.17"
9 9
core = "7.x"
10 10
project = "ctools"
11
datestamp = "1549603691"
11
datestamp = "1603490551"
drupal7/sites/all/modules/ctools/ctools_plugin_example/ctools_plugin_example.info
7 7
dependencies[] = advanced_help
8 8
core = 7.x
9 9

  
10
; Information added by Drupal.org packaging script on 2019-02-08
11
version = "7.x-1.15"
10
; Information added by Drupal.org packaging script on 2020-10-23
11
version = "7.x-1.17"
12 12
core = "7.x"
13 13
project = "ctools"
14
datestamp = "1549603691"
14
datestamp = "1603490551"
drupal7/sites/all/modules/ctools/includes/math-expr.inc
1 1
<?php
2 2

  
3
/*
4
================================================================================
5

  
6
ctools_math_expr - PHP Class to safely evaluate math expressions
7
Copyright (C) 2005 Miles Kaufmann <http://www.twmagic.com/>
8

  
9
================================================================================
10

  
11
NAME
12
    ctools_math_expr - safely evaluate math expressions
13

  
14
SYNOPSIS
15
      include('ctools_math_expr.class.php');
16
      $m = new ctools_math_expr;
17
      // basic evaluation:
18
      $result = $m->evaluate('2+2');
19
      // supports: order of operation; parentheses; negation; built-in functions
20
      $result = $m->evaluate('-8(5/2)^2*(1-sqrt(4))-8');
21
      // create your own variables
22
      $m->evaluate('a = e^(ln(pi))');
23
      // or functions
24
      $m->evaluate('f(x,y) = x^2 + y^2 - 2x*y + 1');
25
      // and then use them
26
      $result = $m->evaluate('3*f(42,a)');
27

  
28
DESCRIPTION
29
    Use the ctools_math_expr class when you want to evaluate mathematical expressions
30
    from untrusted sources.  You can define your own variables and functions,
31
    which are stored in the object.  Try it, it's fun!
32

  
33
METHODS
34
    $m->evalute($expr)
35
        Evaluates the expression and returns the result.  If an error occurs,
36
        prints a warning and returns false.  If $expr is a function assignment,
37
        returns true on success.
38

  
39
    $m->e($expr)
40
        A synonym for $m->evaluate().
41

  
42
    $m->vars()
43
        Returns an associative array of all user-defined variables and values.
44

  
45
    $m->funcs()
46
        Returns an array of all user-defined functions.
47

  
48
PARAMETERS
49
    $m->suppress_errors
50
        Set to true to turn off warnings when evaluating expressions
51

  
52
    $m->last_error
53
        If the last evaluation failed, contains a string describing the error.
54
        (Useful when suppress_errors is on).
55

  
56
AUTHOR INFORMATION
57
    Copyright 2005, Miles Kaufmann.
58

  
59
LICENSE
60
    Redistribution and use in source and binary forms, with or without
61
    modification, are permitted provided that the following conditions are
62
    met:
63

  
64
    1   Redistributions of source code must retain the above copyright
65
        notice, this list of conditions and the following disclaimer.
66
    2.  Redistributions in binary form must reproduce the above copyright
67
        notice, this list of conditions and the following disclaimer in the
68
        documentation and/or other materials provided with the distribution.
69
    3.  The name of the author may not be used to endorse or promote
70
        products derived from this software without specific prior written
71
        permission.
72

  
73
    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
74
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
75
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
76
    DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
77
    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
78
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
79
    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
80
    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
81
    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
82
    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
83
    POSSIBILITY OF SUCH DAMAGE.
84

  
85
*/
86

  
3
/**
4
 * @file
5
 * =============================================================================.
6
 *
7
 * ctools_math_expr - PHP Class to safely evaluate math expressions
8
 * Copyright (C) 2005 Miles Kaufmann <http://www.twmagic.com/>
9
 *
10
 * =============================================================================
11
 *
12
 * NAME
13
 *     ctools_math_expr - safely evaluate math expressions
14
 *
15
 * SYNOPSIS
16
 *     $m = new ctools_math_expr();
17
 *     // basic evaluation:
18
 *     $result = $m->evaluate('2+2');
19
 *     // supports: order of operation; parentheses; negation; built-in
20
 *     // functions.
21
 *     $result = $m->evaluate('-8(5/2)^2*(1-sqrt(4))-8');
22
 *     // create your own variables
23
 *     $m->evaluate('a = e^(ln(pi))');
24
 *     // or functions
25
 *     $m->evaluate('f(x,y) = x^2 + y^2 - 2x*y + 1');
26
 *     // and then use them
27
 *     $result = $m->evaluate('3*f(42,a)');
28
 *
29
 * DESCRIPTION
30
 *     Use the ctools_math_expr class when you want to evaluate mathematical
31
 *     expressions from untrusted sources.  You can define your own variables
32
 *     and functions, which are stored in the object.  Try it, it's fun!
33
 *
34
 * AUTHOR INFORMATION
35
 *     Copyright 2005, Miles Kaufmann.
36
 *     Enhancements, 2005 onwards, Drupal Community.
37
 *
38
 * LICENSE
39
 *     Redistribution and use in source and binary forms, with or without
40
 *     modification, are permitted provided that the following conditions are
41
 *     met:
42
 *
43
 *     1   Redistributions of source code must retain the above copyright
44
 *         notice, this list of conditions and the following disclaimer.
45
 *     2.  Redistributions in binary form must reproduce the above copyright
46
 *         notice, this list of conditions and the following disclaimer in the
47
 *         documentation and/or other materials provided with the distribution.
48
 *     3.  The name of the author may not be used to endorse or promote
49
 *         products derived from this software without specific prior written
50
 *         permission.
51
 *
52
 *     THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
53
 *     IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
54
 *     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
55
 *     DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
56
 *     INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
57
 *     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
58
 *     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59
 *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
60
 *     STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
61
 *     ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
62
 *     POSSIBILITY OF SUCH DAMAGE.
63
 */
64

  
65
/**
66
 * ctools_math_expr Class.
67
 */
87 68
class ctools_math_expr {
88
    var $suppress_errors = false;
89
    var $last_error = null;
90

  
91
    var $v = array('e'=>2.71,'pi'=>3.14); // variables (and constants)
92
    var $f = array(); // user-defined functions
93
    var $vb = array('e', 'pi'); // constants
94
    var $fb = array(  // built-in functions
95
        'sin','sinh','arcsin','asin','arcsinh','asinh',
96
        'cos','cosh','arccos','acos','arccosh','acosh',
97
        'tan','tanh','arctan','atan','arctanh','atanh',
98
        'pow', 'exp',
99
        'sqrt','abs','ln','log',
100
        'time', 'ceil', 'floor', 'min', 'max', 'round');
101 69

  
102 70
  /**
103
   * ctools_math_expr constructor.
71
   * If TRUE do not call trigger_error on error other wise do.
72
   *
73
   * @var bool
104 74
   */
105
  function __construct() {
106
        // make the variables a little more accurate
107
        $this->v['pi'] = pi();
108
        $this->v['e'] = exp(1);
109
        drupal_alter('ctools_math_expression_functions', $this->fb);
110
    }
75
  public $suppress_errors = FALSE;
76

  
77
  /**
78
   * The last error message reported.
79
   *
80
   * @var string
81
   */
82
  public $last_error = NULL;
83

  
84
  /**
85
   * List of all errors reported.
86
   *
87
   * @var array
88
   */
89
  public $errors = array();
90

  
91
  /**
92
   * Variable and constant values.
93
   *
94
   * @var array
95
   */
96
  protected $vars;
97

  
98
  /**
99
   * User defined functions.
100
   *
101
   * @var array
102
   */
103
  protected $userfuncs;
104

  
105
  /**
106
   * The names of constants, used to make constants read-only.
107
   *
108
   * @var array
109
   */
110
  protected $constvars;
111

  
112
  /**
113
   * Built in simple (one arg) functions.
114
   * Merged into $this->funcs in constructor.
115
   *
116
   * @var array
117
   */
118
  protected $simplefuncs;
119

  
120
  /**
121
   * Definitions of all built-in functions.
122
   *
123
   * @var array
124
   */
125
  protected $funcs;
126

  
127
  /**
128
   * Operators and their precedence.
129
   *
130
   * @var array
131
   */
132
  protected $ops;
133

  
134
  /**
135
   * The set of operators using two arguments.
136
   *
137
   * @var array
138
   */
139
  protected $binaryops;
111 140

  
112
    function e($expr) {
113
        return $this->evaluate($expr);
141
  /**
142
   * Public constructor.
143
   */
144
  public function __construct() {
145
    $this->userfuncs = array();
146
    $this->simplefuncs = array(
147
      'sin',
148
      'sinh',
149
      'asin',
150
      'asinh',
151
      'cos',
152
      'cosh',
153
      'acos',
154
      'acosh',
155
      'tan',
156
      'tanh',
157
      'atan',
158
      'atanh',
159
      'exp',
160
      'sqrt',
161
      'abs',
162
      'log',
163
      'ceil',
164
      'floor',
165
      'round',
166
    );
167

  
168
    $this->ops = array(
169
      '+' => array('precedence' => 0),
170
      '-' => array('precedence' => 0),
171
      '*' => array('precedence' => 1),
172
      '/' => array('precedence' => 1),
173
      '^' => array('precedence' => 2, 'right' => TRUE),
174
      '_' => array('precedence' => 1),
175
      '==' => array('precedence' => -1),
176
      '!=' => array('precedence' => -1),
177
      '>=' => array('precedence' => -1),
178
      '<=' => array('precedence' => -1),
179
      '>' => array('precedence' => -1),
180
      '<' => array('precedence' => -1),
181
    );
182

  
183
    $this->binaryops = array(
184
      '+', '-', '*', '/', '^', '==', '!=', '<', '<=', '>=', '>',
185
    );
186

  
187
    $this->funcs = array(
188
      'ln' => array(
189
        'function' => 'log',
190
        'arguments' => 1,
191
      ),
192
      'arcsin' => array(
193
        'function' => 'asin',
194
        'arguments' => 1,
195
      ),
196
      'arcsinh' => array(
197
        'function' => 'asinh',
198
        'arguments' => 1,
199
      ),
200
      'arccos' => array(
201
        'function' => 'acos',
202
        'arguments' => 1,
203
      ),
204
      'arccosh' => array(
205
        'function' => 'acosh',
206
        'arguments' => 1,
207
      ),
208
      'arctan' => array(
209
        'function' => 'atan',
210
        'arguments' => 1,
211
      ),
212
      'arctanh' => array(
213
        'function' => 'atanh',
214
        'arguments' => 1,
215
      ),
216
      'min' => array(
217
        'function' => 'min',
218
        'arguments' => 2,
219
        'max arguments' => 99,
220
      ),
221
      'max' => array(
222
        'function' => 'max',
223
        'arguments' => 2,
224
        'max arguments' => 99,
225
      ),
226
      'pow' => array(
227
        'function' => 'pow',
228
        'arguments' => 2,
229
      ),
230
      'if' => array(
231
        'function' => 'ctools_math_expr_if',
232
        'arguments' => 2,
233
        'max arguments' => 3,
234
      ),
235
      'number' => array(
236
        'function' => 'ctools_math_expr_number',
237
        'arguments' => 1,
238
      ),
239
      'time' => array(
240
        'function' => 'time',
241
        'arguments' => 0,
242
      ),
243
    );
244

  
245
    // Allow modules to add custom functions.
246
    $context = array('final' => &$this->funcs);
247
    drupal_alter('ctools_math_expression_functions', $this->simplefuncs, $context);
248

  
249
    // Set up the initial constants and mark them read-only.
250
    $this->vars = array('e' => exp(1), 'pi' => pi());
251
    drupal_alter('ctools_math_expression_constants', $this->vars);
252
    $this->constvars = array_keys($this->vars);
253

  
254
    // Translate the older, simpler style into the newer, richer style.
255
    foreach ($this->simplefuncs as $function) {
256
      $this->funcs[$function] = array(
257
        'function' => $function,
258
        'arguments' => 1,
259
      );
114 260
    }
261
  }
115 262

  
116
    function evaluate($expr) {
117
        $this->last_error = null;
118
        $expr = trim($expr);
119
        if (substr($expr, -1, 1) == ';') $expr = substr($expr, 0, strlen($expr)-1); // strip semicolons at the end
120
        //===============
121
        // is it a variable assignment?
122
        if (preg_match('/^\s*([a-z]\w*)\s*=\s*(.+)$/', $expr, $matches)) {
123
            if (in_array($matches[1], $this->vb)) { // make sure we're not assigning to a constant
124
                return $this->trigger("cannot assign to constant '$matches[1]'");
125
            }
126
            if (($tmp = $this->pfx($this->nfx($matches[2]))) === false) return false; // get the result and make sure it's good
127
            $this->v[$matches[1]] = $tmp; // if so, stick it in the variable array
128
            return $this->v[$matches[1]]; // and return the resulting value
129
        //===============
130
        // is it a function assignment?
131
        } elseif (preg_match('/^\s*([a-z]\w*)\s*\(\s*([a-z]\w*(?:\s*,\s*[a-z]\w*)*)\s*\)\s*=\s*(.+)$/', $expr, $matches)) {
132
            $fnn = $matches[1]; // get the function name
133
            if (in_array($matches[1], $this->fb)) { // make sure it isn't built in
134
                return $this->trigger("cannot redefine built-in function '$matches[1]()'");
135
            }
136
            $args = explode(",", preg_replace("/\s+/", "", $matches[2])); // get the arguments
137
            if (($stack = $this->nfx($matches[3])) === false) return false; // see if it can be converted to postfix
138
            for ($i = 0; $i<count($stack); $i++) { // freeze the state of the non-argument variables
139
                $token = $stack[$i];
140
                if (preg_match('/^[a-z]\w*$/', $token) and !in_array($token, $args)) {
141
                    if (array_key_exists($token, $this->v)) {
142
                        $stack[$i] = $this->v[$token];
143
                    } else {
144
                        return $this->trigger("undefined variable '$token' in function definition");
145
                    }
146
                }
147
            }
148
            $this->f[$fnn] = array('args'=>$args, 'func'=>$stack);
149
            return true;
150
        //===============
151
        } else {
152
            return $this->pfx($this->nfx($expr)); // straight up evaluation, woo
153
        }
263
  /**
264
   * Change the suppress errors flag.
265
   *
266
   * When errors are not suppressed, trigger_error is used to cause a PHP error
267
   * when an evaluation error occurs, as a result of calling trigger(). With
268
   * errors suppressed this doesn't happen.
269
   *
270
   * @param bool $enable
271
   *   If FALSE, enable triggering of php errors when expression errors occurs.
272
   *   otherwise, suppress triggering the errors.
273
   *
274
   * @return bool
275
   *   The new (current) state of the flag.
276
   *
277
   * @see ctools_math_expr::trigger()
278
   */
279
  public function set_suppress_errors($enable) {
280
    return $this->suppress_errors = (bool) $enable;
281
  }
282

  
283
  /**
284
   * Backwards compatible wrapper for evaluate().
285
   *
286
   * @see ctools_math_expr::evaluate()
287
   */
288
  public function e($expr) {
289
    return $this->evaluate($expr);
290
  }
291

  
292
  /**
293
   * Evaluate the expression.
294
   *
295
   * @param string $expr
296
   *   The expression to evaluate.
297
   *
298
   * @return string|bool
299
   *   The result of the expression, or FALSE if an error occurred, or TRUE if
300
   *   an user-defined function was created.
301
   */
302
  public function evaluate($expr) {
303
    $this->last_error = NULL;
304
    $expr = trim($expr);
305

  
306
    // Strip possible semicolons at the end.
307
    if (substr($expr, -1, 1) == ';') {
308
      $expr = substr($expr, 0, -1);
154 309
    }
155 310

  
156
    function vars() {
157
        $output = $this->v;
158
        unset($output['pi']);
159
        unset($output['e']);
160
        return $output;
311
    // Is it a variable assignment?
312
    if (preg_match('/^\s*([a-z]\w*)\s*=\s*(.+)$/', $expr, $matches)) {
313

  
314
      // Make sure we're not assigning to a constant.
315
      if (in_array($matches[1], $this->constvars)) {
316
        return $this->trigger("cannot assign to constant '$matches[1]'");
317
      }
318

  
319
      // Get the result and make sure it's good:
320
      if (($tmp = $this->pfx($this->nfx($matches[2]))) === FALSE) {
321
        return FALSE;
322
      }
323
      // If so, stick it in the variable array...
324
      $this->vars[$matches[1]] = $tmp;
325
      // ...and return the resulting value:
326
      return $this->vars[$matches[1]];
327

  
161 328
    }
329
    // Is it a function assignment?
330
    elseif (preg_match('/^\s*([a-z]\w*)\s*\(\s*([a-z]\w*(?:\s*,\s*[a-z]\w*)*)\s*\)\s*=\s*(.+)$/', $expr, $matches)) {
331
      // Get the function name.
332
      $fnn = $matches[1];
333
      // Make sure it isn't built in:
334
      if (isset($this->funcs[$matches[1]])) {
335
        return $this->trigger("cannot redefine built-in function '$matches[1]()'");
336
      }
337

  
338
      // Get the arguments.
339
      $args = explode(",", preg_replace("/\s+/", "", $matches[2]));
340
      // See if it can be converted to postfix.
341
      $stack = $this->nfx($matches[3]);
342
      if ($stack === FALSE) {
343
        return FALSE;
344
      }
345

  
346
      // Freeze the state of the non-argument variables.
347
      for ($i = 0; $i < count($stack); $i++) {
348
        $token = $stack[$i];
349
        if (preg_match('/^[a-z]\w*$/', $token) and !in_array($token, $args)) {
350
          if (array_key_exists($token, $this->vars)) {
351
            $stack[$i] = $this->vars[$token];
352
          }
353
          else {
354
            return $this->trigger("undefined variable '$token' in function definition");
355
          }
356
        }
357
      }
358
      $this->userfuncs[$fnn] = array('args' => $args, 'func' => $stack);
162 359

  
163
    function funcs() {
164
        $output = array();
165
        foreach ($this->f as $fnn=>$dat)
166
            $output[] = $fnn . '(' . implode(',', $dat['args']) . ')';
167
        return $output;
360
      return TRUE;
168 361
    }
362
    else {
363
      // Straight up evaluation.
364
      return trim($this->pfx($this->nfx($expr)), '"');
365
    }
366
  }
169 367

  
170
    //===================== HERE BE INTERNAL METHODS ====================\\
368
  /**
369
   * Fetch an array of variables used in the expression.
370
   *
371
   * @return array
372
   *   Array of name : value pairs, one for each variable defined.
373
   */
374
  public function vars() {
375
    $output = $this->vars;
171 376

  
172
    // Convert infix to postfix notation
173
    function nfx($expr) {
377
    // @todo: Is this supposed to remove all constants? we should remove all
378
    // those in $this->constvars!
379
    unset($output['pi']);
380
    unset($output['e']);
174 381

  
175
        $index = 0;
176
        $stack = new ctools_math_expr_stack;
177
        $output = array(); // postfix form of expression, to be passed to pfx()
178
        $expr = trim(strtolower($expr));
382
    return $output;
383
  }
179 384

  
180
        $ops   = array('+', '-', '*', '/', '^', '_');
181
        $ops_r = array('+'=>0,'-'=>0,'*'=>0,'/'=>0,'^'=>1); // right-associative operator?
182
        $ops_p = array('+'=>0,'-'=>0,'*'=>1,'/'=>1,'_'=>1,'^'=>2); // operator precedence
385
  /**
386
   * Fetch all user defined functions in the expression.
387
   *
388
   * @return array
389
   *   Array of name : string pairs, one for each function defined. The string
390
   *   will be of the form fname(arg1,arg2). The function body is not returned.
391
   */
392
  public function funcs() {
393
    $output = array();
394
    foreach ($this->userfuncs as $fnn => $dat) {
395
      $output[] = $fnn . '(' . implode(',', $dat['args']) . ')';
396
    }
183 397

  
184
        $expecting_op = false; // we use this in syntax-checking the expression
185
                               // and determining when a - is a negation
398
    return $output;
399
  }
186 400

  
187
        if (preg_match("/[^\w\s+*^\/()\.,-]/", $expr, $matches)) { // make sure the characters are all good
188
            return $this->trigger("illegal character '{$matches[0]}'");
401
  /**
402
   * Convert infix to postfix notation.
403
   *
404
   * @param string $expr
405
   *   The expression to convert.
406
   *
407
   * @return array|bool
408
   *   The expression as an ordered list of postfix action tokens.
409
   */
410
  private function nfx($expr) {
411

  
412
    $index = 0;
413
    $stack = new ctools_math_expr_stack();
414
    // Postfix form of expression, to be passed to pfx().
415
    $output = array();
416

  
417
    // @todo: Because the expr can contain string operands, using strtolower here is a bug.
418
    $expr = trim(strtolower($expr));
419

  
420
    // We use this in syntax-checking the expression and determining when
421
    // '-' is a negation.
422
    $expecting_op = FALSE;
423

  
424
    while (TRUE) {
425
      $op = substr($expr, $index, 1);
426
      // Get the first character at the current index, and if the second
427
      // character is an =, add it to our op as well (accounts for <=).
428
      if (substr($expr, $index + 1, 1) === '=') {
429
        $op = substr($expr, $index, 2);
430
        $index++;
431
      }
432

  
433
      // Find out if we're currently at the beginning of a number/variable/
434
      // function/parenthesis/operand.
435
      $ex = preg_match('/^([a-z]\w*\(?|\d+(?:\.\d*)?|\.\d+|\()/', substr($expr, $index), $match);
436

  
437
      // Is it a negation instead of a minus?
438
      if ($op === '-' and !$expecting_op) {
439
        // Put a negation on the stack.
440
        $stack->push('_');
441
        $index++;
442
      }
443
      // We have to explicitly deny this, because it's legal on the stack but
444
      // not in the input expression.
445
      elseif ($op == '_') {
446
        return $this->trigger("illegal character '_'");
447

  
448
      }
449
      // Are we putting an operator on the stack?
450
      elseif ((isset($this->ops[$op]) || $ex) && $expecting_op) {
451
        // Are we expecting an operator but have a num, var, func, or
452
        // open-paren?
453
        if ($ex) {
454
          $op = '*';
455
          // It's an implicit multiplication.
456
          $index--;
457
        }
458
        // Heart of the algorithm:
459
        while ($stack->count() > 0 &&
460
          ($o2 = $stack->last()) &&
461
          isset($this->ops[$o2]) &&
462
          (!empty($this->ops[$op]['right']) ?
463
            $this->ops[$op]['precedence'] < $this->ops[$o2]['precedence'] :
464
            $this->ops[$op]['precedence'] <= $this->ops[$o2]['precedence'])) {
465

  
466
          // Pop stuff off the stack into the output.
467
          $output[] = $stack->pop();
468
        }
469
        // Many thanks: http://en.wikipedia.org/wiki/Reverse_Polish_notation#The_algorithm_in_detail
470
        // finally put OUR operator onto the stack.
471
        $stack->push($op);
472
        $index++;
473
        $expecting_op = FALSE;
474

  
475
      }
476
      // Ready to close a parenthesis?
477
      elseif ($op === ')') {
478

  
479
        // Pop off the stack back to the last '('.
480
        while (($o2 = $stack->pop()) !== '(') {
481
          if (is_null($o2)) {
482
            return $this->trigger("unexpected ')'");
483
          }
484
          else {
485
            $output[] = $o2;
486
          }
189 487
        }
190 488

  
191
        while(1) { // 1 Infinite Loop ;)
192
            $op = substr($expr, $index, 1); // get the first character at the current index
193
            // find out if we're currently at the beginning of a number/variable/function/parenthesis/operand
194
            $ex = preg_match('/^([a-z]\w*\(?|\d+(?:\.\d*)?|\.\d+|\()/', substr($expr, $index), $match);
195
            //===============
196
            if ($op == '-' and !$expecting_op) { // is it a negation instead of a minus?
197
                $stack->push('_'); // put a negation on the stack
198
                $index++;
199
            } elseif ($op == '_') { // we have to explicitly deny this, because it's legal on the stack
200
                return $this->trigger("illegal character '_'"); // but not in the input expression
201
            //===============
202
            } elseif ((in_array($op, $ops) or $ex) and $expecting_op) { // are we putting an operator on the stack?
203
                if ($ex) { // are we expecting an operator but have a number/variable/function/opening parethesis?
204
                    $op = '*'; $index--; // it's an implicit multiplication
205
                }
206
                // heart of the algorithm:
207
                while($stack->count > 0 and ($o2 = $stack->last()) and in_array($o2, $ops) and ($ops_r[$op] ? $ops_p[$op] < $ops_p[$o2] : $ops_p[$op] <= $ops_p[$o2])) {
208
                    $output[] = $stack->pop(); // pop stuff off the stack into the output
209
                }
210
                // many thanks: http://en.wikipedia.org/wiki/Reverse_Polish_notation#The_algorithm_in_detail
211
                $stack->push($op); // finally put OUR operator onto the stack
212
                $index++;
213
                $expecting_op = false;
214
            //===============
215
            } elseif ($op == ')' and $expecting_op) { // ready to close a parenthesis?
216
                while (($o2 = $stack->pop()) != '(') { // pop off the stack back to the last (
217
                    if (is_null($o2)) return $this->trigger("unexpected ')'");
218
                    else $output[] = $o2;
219
                }
220
                if (preg_match("/^([a-z]\w*)\($/", $stack->last(2), $matches)) { // did we just close a function?
221
                    $fnn = $matches[1]; // get the function name
222
                    $arg_count = $stack->pop(); // see how many arguments there were (cleverly stored on the stack, thank you)
223
                    $output[] = $stack->pop(); // pop the function and push onto the output
224
                    if (in_array($fnn, $this->fb)) { // check the argument count
225
                        if($arg_count > 1)
226
                            return $this->trigger("too many arguments ($arg_count given, 1 expected)");
227
                    } elseif (array_key_exists($fnn, $this->f)) {
228
                        if ($arg_count != count($this->f[$fnn]['args']))
229
                            return $this->trigger("wrong number of arguments ($arg_count given, " . count($this->f[$fnn]['args']) . " expected)");
230
                    } else { // did we somehow push a non-function on the stack? this should never happen
231
                        return $this->trigger("internal error");
232
                    }
233
                }
234
                $index++;
235
            //===============
236
            } elseif ($op == ',' and $expecting_op) { // did we just finish a function argument?
237
                while (($o2 = $stack->pop()) != '(') {
238
                    if (is_null($o2)) return $this->trigger("unexpected ','"); // oops, never had a (
239
                    else $output[] = $o2; // pop the argument expression stuff and push onto the output
240
                }
241
                // make sure there was a function
242
                if (!preg_match("/^([a-z]\w*)\($/", $stack->last(2), $matches))
243
                    return $this->trigger("unexpected ','");
244
                $stack->push($stack->pop()+1); // increment the argument count
245
                $stack->push('('); // put the ( back on, we'll need to pop back to it again
246
                $index++;
247
                $expecting_op = false;
248
            //===============
249
            } elseif ($op == '(' and !$expecting_op) {
250
                $stack->push('('); // that was easy
251
                $index++;
252
                $allow_neg = true;
253
            //===============
254
            } elseif ($ex and !$expecting_op) { // do we now have a function/variable/number?
255
                $expecting_op = true;
256
                $val = $match[1];
257
                if (preg_match("/^([a-z]\w*)\($/", $val, $matches)) { // may be func, or variable w/ implicit multiplication against parentheses...
258
                    if (in_array($matches[1], $this->fb) or array_key_exists($matches[1], $this->f)) { // it's a func
259
                        $stack->push($val);
260
                        $stack->push(1);
261
                        $stack->push('(');
262
                        $expecting_op = false;
263
                    } else { // it's a var w/ implicit multiplication
264
                        $val = $matches[1];
265
                        $output[] = $val;
266
                    }
267
                } else { // it's a plain old var or num
268
                    $output[] = $val;
269
                }
270
                $index += strlen($val);
271
            //===============
272
            } elseif ($op == ')') { // miscellaneous error checking
273
                return $this->trigger("unexpected ')'");
274
            } elseif (in_array($op, $ops) and !$expecting_op) {
275
                return $this->trigger("unexpected operator '$op'");
276
            } else { // I don't even want to know what you did to get here
277
                return $this->trigger("an unexpected error occurred");
489
        // Did we just close a function?
490
        if (preg_match("/^([a-z]\w*)\($/", $stack->last(2), $matches)) {
491

  
492
          // Get the function name.
493
          $fnn = $matches[1];
494
          // See how many arguments there were (cleverly stored on the stack,
495
          // thank you).
496
          $arg_count = $stack->pop();
497
          // Pop the function and push onto the output.
498
          $output[] = $stack->pop();
499

  
500
          // Check the argument count:
501
          if (isset($this->funcs[$fnn])) {
502
            $fdef = $this->funcs[$fnn];
503
            $max_arguments = isset($fdef['max arguments']) ? $fdef['max arguments'] : $fdef['arguments'];
504
            if ($arg_count > $max_arguments) {
505
              return $this->trigger("too many arguments ($arg_count given, $max_arguments expected)");
278 506
            }
279
            if ($index == strlen($expr)) {
280
                if (in_array($op, $ops)) { // did we end with an operator? bad.
281
                    return $this->trigger("operator '$op' lacks operand");
282
                } else {
283
                    break;
284
                }
507
          }
508
          elseif (array_key_exists($fnn, $this->userfuncs)) {
509
            $fdef = $this->userfuncs[$fnn];
510
            if ($arg_count !== count($fdef['args'])) {
511
              return $this->trigger("wrong number of arguments ($arg_count given, " . count($fdef['args']) . ' expected)');
512
            }
513
          }
514
          else {
515
            // Did we somehow push a non-function on the stack? this should
516
            // never happen.
517
            return $this->trigger('internal error');
518
          }
519
        }
520
        $index++;
521

  
522
      }
523
      // Did we just finish a function argument?
524
      elseif ($op === ',' && $expecting_op) {
525
        $index++;
526
        $expecting_op = FALSE;
527
      }
528
      elseif ($op === '(' && !$expecting_op) {
529
        $stack->push('(');
530
        $index++;
531

  
532
      }
533
      elseif ($ex && !$expecting_op) {
534
        // Make sure there was a function.
535
        if (preg_match("/^([a-z]\w*)\($/", $stack->last(3), $matches)) {
536
          // Pop the argument expression stuff and push onto the output:
537
          while (($o2 = $stack->pop()) !== '(') {
538
            // Oops, never had a '('.
539
            if (is_null($o2)) {
540
              return $this->trigger("unexpected argument in $expr $o2");
285 541
            }
286
            while (substr($expr, $index, 1) == ' ') { // step the index past whitespace (pretty much turns whitespace
287
                $index++;                             // into implicit multiplication if no operator is there)
542
            else {
543
              $output[] = $o2;
288 544
            }
545
          }
289 546

  
547
          // Increment the argument count.
548
          $stack->push($stack->pop() + 1);
549
          // Put the ( back on, we'll need to pop back to it again.
550
          $stack->push('(');
551
        }
552

  
553
        // Do we now have a function/variable/number?
554
        $expecting_op = TRUE;
555
        $val = $match[1];
556
        if (preg_match("/^([a-z]\w*)\($/", $val, $matches)) {
557
          // May be func, or variable w/ implicit multiplication against
558
          // parentheses...
559
          if (isset($this->funcs[$matches[1]]) or array_key_exists($matches[1], $this->userfuncs)) {
560
            $stack->push($val);
561
            $stack->push(0);
562
            $stack->push('(');
563
            $expecting_op = FALSE;
564
          }
565
          // it's a var w/ implicit multiplication.
566
          else {
567
            $val = $matches[1];
568
            $output[] = $val;
569
          }
570
        }
571
        // it's a plain old var or num.
572
        else {
573
          $output[] = $val;
290 574
        }
291
        while (!is_null($op = $stack->pop())) { // pop everything off the stack and push onto output
292
            if ($op == '(') return $this->trigger("expecting ')'"); // if there are (s on the stack, ()s were unbalanced
293
            $output[] = $op;
575
        $index += strlen($val);
576

  
577
      }
578
      elseif ($op === ')') {
579
        // Miscellaneous error checking.
580
        return $this->trigger("unexpected ')'");
581
      }
582
      elseif (isset($this->ops[$op]) and !$expecting_op) {
583
        return $this->trigger("unexpected operator '$op'");
584
      }
585
      elseif ($op === '"') {
586
        // Fetch a quoted string.
587
        $string = substr($expr, $index);
588
        if (preg_match('/"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"/s', $string, $matches)) {
589
          $string = $matches[0];
590
          // Trim the quotes off:
591
          $output[] = $string;
592
          $index += strlen($string);
593
          $expecting_op = TRUE;
294 594
        }
295
        return $output;
595
        else {
596
          return $this->trigger('open quote without close quote.');
597
        }
598
      }
599
      else {
600
        // I don't even want to know what you did to get here.
601
        return $this->trigger("an unexpected error occurred at $op");
602
      }
603
      if ($index === strlen($expr)) {
604
        if (isset($this->ops[$op])) {
605
          // Did we end with an operator? bad.
606
          return $this->trigger("operator '$op' lacks operand");
607
        }
608
        else {
609
          break;
610
        }
611
      }
612

  
613
      // Step the index past whitespace (pretty much turns whitespace into
614
      // implicit multiplication if no operator is there).
615
      while (substr($expr, $index, 1) === ' ') {
616
        $index++;
617
      }
618
    }
619

  
620
    // Pop everything off the stack and push onto output:
621
    while (!is_null($op = $stack->pop())) {
622

  
623
      // If there are (s on the stack, ()s were unbalanced.
624
      if ($op === '(') {
625
        return $this->trigger("expecting ')'");
626
      }
627
      $output[] = $op;
628
    }
629

  
630
    return $output;
631
  }
632

  
633
  /**
634
   * Evaluate a prefix-operator stack expression.
635
   *
636
   * @param array $tokens
637
   *   The array of token values to evaluate. A token is a string value
638
   *   representing either an operation to perform, a variable, or a value.
639
   *   Literal values are checked using is_numeric(), or a value that starts
640
   *   with a double-quote; functions and variables by existence in the
641
   *   appropriate tables.
642
   *   If FALSE is passed in the function terminates immediately, returning
643
   *   FALSE.
644
   * @param array $vars
645
   *   Additional variable values to use when evaluating the expression. These
646
   *   variables do not override internal variables with the same name.
647
   *
648
   * @return bool|mixed
649
   *   The expression's value, otherwise FALSE is returned if there is an error
650
   *   detected unless php error handling intervenes: see suppress_error.
651
   */
652
  public function pfx(array $tokens, array $vars = array()) {
653

  
654
    if ($tokens == FALSE) {
655
      return FALSE;
296 656
    }
297 657

  
298
    // evaluate postfix notation
299
    function pfx($tokens, $vars = array()) {
300

  
301
        if ($tokens == false) return false;
302

  
303
        $stack = new ctools_math_expr_stack;
304

  
305
        foreach ($tokens as $token) { // nice and easy
306
            // if the token is a binary operator, pop two values off the stack, do the operation, and push the result back on
307
            if (in_array($token, array('+', '-', '*', '/', '^'))) {
308
                if (is_null($op2 = $stack->pop())) return $this->trigger("internal error");
309
                if (is_null($op1 = $stack->pop())) return $this->trigger("internal error");
310
                switch ($token) {
311
                    case '+':
312
                        $stack->push($op1+$op2); break;
313
                    case '-':
314
                        $stack->push($op1-$op2); break;
315
                    case '*':
316
                        $stack->push($op1*$op2); break;
317
                    case '/':
318
                        if ($op2 == 0) return $this->trigger("division by zero");
319
                        $stack->push($op1/$op2); break;
320
                    case '^':
321
                        $stack->push(pow($op1, $op2)); break;
322
                }
323
            // if the token is a unary operator, pop one value off the stack, do the operation, and push it back on
324
            } elseif ($token == "_") {
325
                $stack->push(-1*$stack->pop());
326
            // if the token is a function, pop arguments off the stack, hand them to the function, and push the result back on
327
            } elseif (preg_match("/^([a-z]\w*)\($/", $token, $matches)) { // it's a function!
328
                $fnn = $matches[1];
329
                if (in_array($fnn, $this->fb)) { // built-in function:
330
                    if (is_null($op1 = $stack->pop())) return $this->trigger("internal error");
331
                    $fnn = preg_replace("/^arc/", "a", $fnn); // for the 'arc' trig synonyms
332
                    if ($fnn == 'ln') $fnn = 'log';
333
                    eval('$stack->push(' . $fnn . '($op1));'); // perfectly safe eval()
334
                } elseif (array_key_exists($fnn, $this->f)) { // user function
335
                    // get args
336
                    $args = array();
337
                    for ($i = count($this->f[$fnn]['args'])-1; $i >= 0; $i--) {
338
                        if (is_null($args[$this->f[$fnn]['args'][$i]] = $stack->pop())) return $this->trigger("internal error");
339
                    }
340
                    $stack->push($this->pfx($this->f[$fnn]['func'], $args)); // yay... recursion!!!!
341
                }
342
            // if the token is a number or variable, push it on the stack
343
            } else {
344
                if (is_numeric($token)) {
345
                    $stack->push($token);
346
                } elseif (array_key_exists($token, $this->v)) {
347
                    $stack->push($this->v[$token]);
348
                } elseif (array_key_exists($token, $vars)) {
349
                    $stack->push($vars[$token]);
350
                } else {
351
                    return $this->trigger("undefined variable '$token'");
352
                }
658
    $stack = new ctools_math_expr_stack();
659

  
660
    foreach ($tokens as $token) {
661
      // If the token is a binary operator, pop two values off the stack, do
662
      // the operation, and push the result back on again.
663
      if (in_array($token, $this->binaryops)) {
664
        if (is_null($op2 = $stack->pop())) {
665
          return $this->trigger('internal error');
666
        }
667
        if (is_null($op1 = $stack->pop())) {
668
          return $this->trigger('internal error');
669
        }
670
        switch ($token) {
671
          case '+':
672
            $stack->push($op1 + $op2);
673
            break;
674

  
675
          case '-':
676
            $stack->push($op1 - $op2);
677
            break;
678

  
679
          case '*':
680
            $stack->push($op1 * $op2);
681
            break;
682

  
683
          case '/':
684
            if ($op2 == 0) {
685
              return $this->trigger('division by zero');
686
            }
687
            $stack->push($op1 / $op2);
688
            break;
689

  
690
          case '^':
691
            $stack->push(pow($op1, $op2));
692
            break;
693

  
694
          case '==':
695
            $stack->push((int) ($op1 == $op2));
696
            break;
697

  
698
          case '!=':
699
            $stack->push((int) ($op1 != $op2));
700
            break;
701

  
702
          case '<=':
703
            $stack->push((int) ($op1 <= $op2));
704
            break;
705

  
706
          case '<':
707
            $stack->push((int) ($op1 < $op2));
708
            break;
709

  
710
          case '>=':
711
            $stack->push((int) ($op1 >= $op2));
712
            break;
713

  
714
          case '>':
715
            $stack->push((int) ($op1 > $op2));
716
            break;
717
        }
718
      }
719
      // If the token is a unary operator, pop one value off the stack, do the
720
      // operation, and push it back on again.
721
      elseif ($token === "_") {
722
        $stack->push(-1 * $stack->pop());
723
      }
724
      // If the token is a function, pop arguments off the stack, hand them to
725
      // the function, and push the result back on again.
726
      elseif (preg_match("/^([a-z]\w*)\($/", $token, $matches)) {
727
        $fnn = $matches[1];
728

  
729
        // Check for a built-in function.
730
        if (isset($this->funcs[$fnn])) {
731
          $args = array();
732
          // Collect all required args from the stack.
733
          for ($i = 0; $i < $this->funcs[$fnn]['arguments']; $i++) {
734
            if (is_null($op1 = $stack->pop())) {
735
              return $this->trigger("function $fnn missing argument $i");
736
            }
737
            $args[] = $op1;
738
          }
739
          // If func allows additional args, collect them too, stopping on a
740
          // NULL arg.
741
          if (!empty($this->funcs[$fnn]['max arguments'])) {
742
            for (; $i < $this->funcs[$fnn]['max arguments']; $i++) {
743
              $arg = $stack->pop();
744
              if (!isset($arg)) {
745
                break;
746
              }
747
              $args[] = $arg;
748
            }
749
          }
750
          $stack->push(
751
            call_user_func_array($this->funcs[$fnn]['function'], array_reverse($args))
752
          );
753
        }
754

  
755
        // Check for a user function.
756
        elseif (isset($fnn, $this->userfuncs)) {
757
          $args = array();
758
          for ($i = count($this->userfuncs[$fnn]['args']) - 1; $i >= 0; $i--) {
759
            $value = $stack->pop();
... Ce différentiel a été tronqué car il excède la taille maximale pouvant être affichée.

Formats disponibles : Unified diff