1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 The PHP Group |
6 : +----------------------------------------------------------------------+
7 : | This source file is subject to version 3.01 of the PHP license, |
8 : | that is bundled with this package in the file LICENSE, and is |
9 : | available through the world-wide-web at the following url: |
10 : | http://www.php.net/license/3_01.txt |
11 : | If you did not receive a copy of the PHP license and are unable to |
12 : | obtain it through the world-wide-web, please send a note to |
13 : | license@php.net so we can mail you a copy immediately. |
14 : +----------------------------------------------------------------------+
15 : | Author: Andi Gutmans <andi@zend.com> |
16 : +----------------------------------------------------------------------+
17 : */
18 :
19 : /* $Id: bcmath.c 272370 2008-12-31 11:15:49Z sebastian $ */
20 :
21 : #ifdef HAVE_CONFIG_H
22 : #include "config.h"
23 : #endif
24 :
25 : #include "php.h"
26 :
27 : #if HAVE_BCMATH
28 :
29 : #include "php_ini.h"
30 : #include "ext/standard/info.h"
31 : #include "php_bcmath.h"
32 : #include "libbcmath/src/bcmath.h"
33 :
34 : ZEND_DECLARE_MODULE_GLOBALS(bcmath)
35 : static PHP_GINIT_FUNCTION(bcmath);
36 : static PHP_GSHUTDOWN_FUNCTION(bcmath);
37 :
38 : /* {{{ arginfo */
39 : ZEND_BEGIN_ARG_INFO_EX(arginfo_bcadd, 0, 0, 2)
40 : ZEND_ARG_INFO(0, left_operand)
41 : ZEND_ARG_INFO(0, right_operand)
42 : ZEND_ARG_INFO(0, scale)
43 : ZEND_END_ARG_INFO()
44 :
45 : ZEND_BEGIN_ARG_INFO_EX(arginfo_bcsub, 0, 0, 2)
46 : ZEND_ARG_INFO(0, left_operand)
47 : ZEND_ARG_INFO(0, right_operand)
48 : ZEND_ARG_INFO(0, scale)
49 : ZEND_END_ARG_INFO()
50 :
51 : ZEND_BEGIN_ARG_INFO_EX(arginfo_bcmul, 0, 0, 2)
52 : ZEND_ARG_INFO(0, left_operand)
53 : ZEND_ARG_INFO(0, right_operand)
54 : ZEND_ARG_INFO(0, scale)
55 : ZEND_END_ARG_INFO()
56 :
57 : ZEND_BEGIN_ARG_INFO_EX(arginfo_bcdiv, 0, 0, 2)
58 : ZEND_ARG_INFO(0, left_operand)
59 : ZEND_ARG_INFO(0, right_operand)
60 : ZEND_ARG_INFO(0, scale)
61 : ZEND_END_ARG_INFO()
62 :
63 : ZEND_BEGIN_ARG_INFO(arginfo_bcmod, 0)
64 : ZEND_ARG_INFO(0, left_operand)
65 : ZEND_ARG_INFO(0, right_operand)
66 : ZEND_END_ARG_INFO()
67 :
68 : ZEND_BEGIN_ARG_INFO_EX(arginfo_bcpowmod, 0, 0, 3)
69 : ZEND_ARG_INFO(0, x)
70 : ZEND_ARG_INFO(0, y)
71 : ZEND_ARG_INFO(0, mod)
72 : ZEND_ARG_INFO(0, scale)
73 : ZEND_END_ARG_INFO()
74 :
75 : ZEND_BEGIN_ARG_INFO_EX(arginfo_bcpow, 0, 0, 2)
76 : ZEND_ARG_INFO(0, x)
77 : ZEND_ARG_INFO(0, y)
78 : ZEND_ARG_INFO(0, scale)
79 : ZEND_END_ARG_INFO()
80 :
81 : ZEND_BEGIN_ARG_INFO_EX(arginfo_bcsqrt, 0, 0, 1)
82 : ZEND_ARG_INFO(0, operand)
83 : ZEND_ARG_INFO(0, scale)
84 : ZEND_END_ARG_INFO()
85 :
86 : ZEND_BEGIN_ARG_INFO_EX(arginfo_bccomp, 0, 0, 2)
87 : ZEND_ARG_INFO(0, left_operand)
88 : ZEND_ARG_INFO(0, right_operand)
89 : ZEND_ARG_INFO(0, scale)
90 : ZEND_END_ARG_INFO()
91 :
92 : ZEND_BEGIN_ARG_INFO(arginfo_bcscale, 0)
93 : ZEND_ARG_INFO(0, scale)
94 : ZEND_END_ARG_INFO()
95 :
96 : /* }}} */
97 :
98 : const zend_function_entry bcmath_functions[] = {
99 : PHP_FE(bcadd, arginfo_bcadd)
100 : PHP_FE(bcsub, arginfo_bcsub)
101 : PHP_FE(bcmul, arginfo_bcmul)
102 : PHP_FE(bcdiv, arginfo_bcdiv)
103 : PHP_FE(bcmod, arginfo_bcmod)
104 : PHP_FE(bcpow, arginfo_bcpow)
105 : PHP_FE(bcsqrt, arginfo_bcsqrt)
106 : PHP_FE(bcscale, arginfo_bcscale)
107 : PHP_FE(bccomp, arginfo_bccomp)
108 : PHP_FE(bcpowmod, arginfo_bcpowmod)
109 : {NULL, NULL, NULL}
110 : };
111 :
112 : zend_module_entry bcmath_module_entry = {
113 : STANDARD_MODULE_HEADER,
114 : "bcmath",
115 : bcmath_functions,
116 : PHP_MINIT(bcmath),
117 : PHP_MSHUTDOWN(bcmath),
118 : NULL,
119 : NULL,
120 : PHP_MINFO(bcmath),
121 : NO_VERSION_YET,
122 : PHP_MODULE_GLOBALS(bcmath),
123 : PHP_GINIT(bcmath),
124 : PHP_GSHUTDOWN(bcmath),
125 : NULL,
126 : STANDARD_MODULE_PROPERTIES_EX
127 : };
128 :
129 : #ifdef COMPILE_DL_BCMATH
130 : ZEND_GET_MODULE(bcmath)
131 : #endif
132 :
133 : /* {{{ PHP_INI */
134 : PHP_INI_BEGIN()
135 : STD_PHP_INI_ENTRY("bcmath.scale", "0", PHP_INI_ALL, OnUpdateLongGEZero, bc_precision, zend_bcmath_globals, bcmath_globals)
136 : PHP_INI_END()
137 : /* }}} */
138 :
139 : /* {{{ PHP_GINIT_FUNCTION
140 : */
141 : static PHP_GINIT_FUNCTION(bcmath)
142 17633 : {
143 17633 : bcmath_globals->bc_precision = 0;
144 17633 : bc_init_numbers(TSRMLS_C);
145 17633 : }
146 : /* }}} */
147 :
148 : /* {{{ PHP_GSHUTDOWN_FUNCTION
149 : */
150 : static PHP_GSHUTDOWN_FUNCTION(bcmath)
151 17665 : {
152 17665 : _bc_free_num_ex(&bcmath_globals->_zero_, 1);
153 17665 : _bc_free_num_ex(&bcmath_globals->_one_, 1);
154 17665 : _bc_free_num_ex(&bcmath_globals->_two_, 1);
155 17665 : }
156 : /* }}} */
157 :
158 : /* {{{ PHP_MINIT_FUNCTION
159 : */
160 : PHP_MINIT_FUNCTION(bcmath)
161 17633 : {
162 17633 : REGISTER_INI_ENTRIES();
163 :
164 17633 : return SUCCESS;
165 : }
166 : /* }}} */
167 :
168 : /* {{{ PHP_MSHUTDOWN_FUNCTION
169 : */
170 : PHP_MSHUTDOWN_FUNCTION(bcmath)
171 17665 : {
172 17665 : UNREGISTER_INI_ENTRIES();
173 :
174 17665 : return SUCCESS;
175 : }
176 : /* }}} */
177 :
178 : /* {{{ PHP_MINFO_FUNCTION
179 : */
180 : PHP_MINFO_FUNCTION(bcmath)
181 42 : {
182 42 : php_info_print_table_start();
183 42 : php_info_print_table_row(2, "BCMath support", "enabled");
184 42 : php_info_print_table_end();
185 42 : DISPLAY_INI_ENTRIES();
186 42 : }
187 : /* }}} */
188 :
189 : /* {{{ php_str2num
190 : Convert to bc_num detecting scale */
191 : static void php_str2num(bc_num *num, char *str TSRMLS_DC)
192 47 : {
193 : char *p;
194 :
195 47 : if (!(p = strchr(str, '.'))) {
196 44 : bc_str2num(num, str, 0 TSRMLS_CC);
197 44 : return;
198 : }
199 :
200 3 : bc_str2num(num, str, strlen(p+1) TSRMLS_CC);
201 : }
202 : /* }}} */
203 :
204 : /* {{{ proto string bcadd(string left_operand, string right_operand [, int scale])
205 : Returns the sum of two arbitrary precision numbers */
206 : PHP_FUNCTION(bcadd)
207 7 : {
208 : char *left, *right;
209 7 : long scale_param = 0;
210 : bc_num first, second, result;
211 : int left_len, right_len;
212 7 : int scale = BCG(bc_precision), argc = ZEND_NUM_ARGS();
213 :
214 7 : if (zend_parse_parameters(argc TSRMLS_CC, "ss|l", &left, &left_len, &right, &right_len, &scale_param) == FAILURE) {
215 0 : return;
216 : }
217 :
218 7 : if (argc == 3) {
219 2 : scale = (int) ((int)scale_param < 0) ? 0 : scale_param;
220 : }
221 :
222 7 : bc_init_num(&first TSRMLS_CC);
223 7 : bc_init_num(&second TSRMLS_CC);
224 7 : bc_init_num(&result TSRMLS_CC);
225 7 : php_str2num(&first, left TSRMLS_CC);
226 7 : php_str2num(&second, right TSRMLS_CC);
227 7 : bc_add (first, second, &result, scale);
228 :
229 7 : if (result->n_scale > scale) {
230 0 : result->n_scale = scale;
231 : }
232 :
233 7 : Z_STRVAL_P(return_value) = bc_num2str(result);
234 7 : Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
235 7 : Z_TYPE_P(return_value) = IS_STRING;
236 7 : bc_free_num(&first);
237 7 : bc_free_num(&second);
238 7 : bc_free_num(&result);
239 7 : return;
240 : }
241 : /* }}} */
242 :
243 : /* {{{ proto string bcsub(string left_operand, string right_operand [, int scale])
244 : Returns the difference between two arbitrary precision numbers */
245 : PHP_FUNCTION(bcsub)
246 3 : {
247 : char *left, *right;
248 : int left_len, right_len;
249 3 : long scale_param = 0;
250 : bc_num first, second, result;
251 3 : int scale = BCG(bc_precision), argc = ZEND_NUM_ARGS();
252 :
253 3 : if (zend_parse_parameters(argc TSRMLS_CC, "ss|l", &left, &left_len, &right, &right_len, &scale_param) == FAILURE) {
254 0 : return;
255 : }
256 :
257 3 : if (argc == 3) {
258 2 : scale = (int) ((int)scale_param < 0) ? 0 : scale_param;
259 : }
260 :
261 3 : bc_init_num(&first TSRMLS_CC);
262 3 : bc_init_num(&second TSRMLS_CC);
263 3 : bc_init_num(&result TSRMLS_CC);
264 3 : php_str2num(&first, left TSRMLS_CC);
265 3 : php_str2num(&second, right TSRMLS_CC);
266 3 : bc_sub (first, second, &result, scale);
267 :
268 3 : if (result->n_scale > scale) {
269 0 : result->n_scale = scale;
270 : }
271 :
272 3 : Z_STRVAL_P(return_value) = bc_num2str(result);
273 3 : Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
274 3 : Z_TYPE_P(return_value) = IS_STRING;
275 3 : bc_free_num(&first);
276 3 : bc_free_num(&second);
277 3 : bc_free_num(&result);
278 3 : return;
279 : }
280 : /* }}} */
281 :
282 : /* {{{ proto string bcmul(string left_operand, string right_operand [, int scale])
283 : Returns the multiplication of two arbitrary precision numbers */
284 : PHP_FUNCTION(bcmul)
285 4 : {
286 : char *left, *right;
287 : int left_len, right_len;
288 4 : long scale_param = 0;
289 : bc_num first, second, result;
290 4 : int scale = BCG(bc_precision), argc = ZEND_NUM_ARGS();
291 :
292 4 : if (zend_parse_parameters(argc TSRMLS_CC, "ss|l", &left, &left_len, &right, &right_len, &scale_param) == FAILURE) {
293 0 : return;
294 : }
295 :
296 4 : if (argc == 3) {
297 1 : scale = (int) ((int)scale_param < 0) ? 0 : scale_param;
298 : }
299 :
300 4 : bc_init_num(&first TSRMLS_CC);
301 4 : bc_init_num(&second TSRMLS_CC);
302 4 : bc_init_num(&result TSRMLS_CC);
303 4 : php_str2num(&first, left TSRMLS_CC);
304 4 : php_str2num(&second, right TSRMLS_CC);
305 4 : bc_multiply (first, second, &result, scale TSRMLS_CC);
306 :
307 4 : if (result->n_scale > scale) {
308 0 : result->n_scale = scale;
309 : }
310 :
311 4 : Z_STRVAL_P(return_value) = bc_num2str(result);
312 4 : Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
313 4 : Z_TYPE_P(return_value) = IS_STRING;
314 4 : bc_free_num(&first);
315 4 : bc_free_num(&second);
316 4 : bc_free_num(&result);
317 4 : return;
318 : }
319 : /* }}} */
320 :
321 : /* {{{ proto string bcdiv(string left_operand, string right_operand [, int scale])
322 : Returns the quotient of two arbitrary precision numbers (division) */
323 : PHP_FUNCTION(bcdiv)
324 6 : {
325 : char *left, *right;
326 : int left_len, right_len;
327 6 : long scale_param = 0;
328 : bc_num first, second, result;
329 6 : int scale = BCG(bc_precision), argc = ZEND_NUM_ARGS();
330 :
331 6 : if (zend_parse_parameters(argc TSRMLS_CC, "ss|l", &left, &left_len, &right, &right_len, &scale_param) == FAILURE) {
332 1 : return;
333 : }
334 :
335 5 : if (argc == 3) {
336 3 : scale = (int) ((int)scale_param < 0) ? 0 : scale_param;
337 : }
338 :
339 5 : bc_init_num(&first TSRMLS_CC);
340 5 : bc_init_num(&second TSRMLS_CC);
341 5 : bc_init_num(&result TSRMLS_CC);
342 5 : php_str2num(&first, left TSRMLS_CC);
343 5 : php_str2num(&second, right TSRMLS_CC);
344 :
345 5 : switch (bc_divide(first, second, &result, scale TSRMLS_CC)) {
346 : case 0: /* OK */
347 4 : if (result->n_scale > scale) {
348 0 : result->n_scale = scale;
349 : }
350 4 : Z_STRVAL_P(return_value) = bc_num2str(result);
351 4 : Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
352 4 : Z_TYPE_P(return_value) = IS_STRING;
353 4 : break;
354 : case -1: /* division by zero */
355 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Division by zero");
356 : break;
357 : }
358 :
359 5 : bc_free_num(&first);
360 5 : bc_free_num(&second);
361 5 : bc_free_num(&result);
362 5 : return;
363 : }
364 : /* }}} */
365 :
366 : /* {{{ proto string bcmod(string left_operand, string right_operand)
367 : Returns the modulus of the two arbitrary precision operands */
368 : PHP_FUNCTION(bcmod)
369 4 : {
370 : char *left, *right;
371 : int left_len, right_len;
372 : bc_num first, second, result;
373 :
374 4 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &left, &left_len, &right, &right_len) == FAILURE) {
375 1 : return;
376 : }
377 :
378 3 : bc_init_num(&first TSRMLS_CC);
379 3 : bc_init_num(&second TSRMLS_CC);
380 3 : bc_init_num(&result TSRMLS_CC);
381 3 : bc_str2num(&first, left, 0 TSRMLS_CC);
382 3 : bc_str2num(&second, right, 0 TSRMLS_CC);
383 :
384 3 : switch (bc_modulo(first, second, &result, 0 TSRMLS_CC)) {
385 : case 0:
386 3 : Z_STRVAL_P(return_value) = bc_num2str(result);
387 3 : Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
388 3 : Z_TYPE_P(return_value) = IS_STRING;
389 3 : break;
390 : case -1:
391 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Division by zero");
392 : break;
393 : }
394 :
395 3 : bc_free_num(&first);
396 3 : bc_free_num(&second);
397 3 : bc_free_num(&result);
398 3 : return;
399 : }
400 : /* }}} */
401 :
402 : /* {{{ proto string bcpowmod(string x, string y, string mod [, int scale])
403 : Returns the value of an arbitrary precision number raised to the power of another reduced by a modulous */
404 : PHP_FUNCTION(bcpowmod)
405 3 : {
406 : char *left, *right, *modulous;
407 : int left_len, right_len, modulous_len;
408 : bc_num first, second, mod, result;
409 3 : long scale = BCG(bc_precision);
410 : int scale_int;
411 :
412 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|l", &left, &left_len, &right, &right_len, &modulous, &modulous_len, &scale) == FAILURE) {
413 3 : return;
414 : }
415 :
416 0 : bc_init_num(&first TSRMLS_CC);
417 0 : bc_init_num(&second TSRMLS_CC);
418 0 : bc_init_num(&mod TSRMLS_CC);
419 0 : bc_init_num(&result TSRMLS_CC);
420 0 : php_str2num(&first, left TSRMLS_CC);
421 0 : php_str2num(&second, right TSRMLS_CC);
422 0 : php_str2num(&mod, modulous TSRMLS_CC);
423 :
424 0 : scale_int = (int) ((int)scale < 0) ? 0 : scale;
425 :
426 0 : if (bc_raisemod(first, second, mod, &result, scale_int TSRMLS_CC) != -1) {
427 0 : if (result->n_scale > scale) {
428 0 : result->n_scale = scale;
429 : }
430 0 : Z_STRVAL_P(return_value) = bc_num2str(result);
431 0 : Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
432 0 : Z_TYPE_P(return_value) = IS_STRING;
433 : } else {
434 0 : RETVAL_FALSE;
435 : }
436 :
437 0 : bc_free_num(&first);
438 0 : bc_free_num(&second);
439 0 : bc_free_num(&mod);
440 0 : bc_free_num(&result);
441 0 : return;
442 : }
443 : /* }}} */
444 :
445 : /* {{{ proto string bcpow(string x, string y [, int scale])
446 : Returns the value of an arbitrary precision number raised to the power of another */
447 : PHP_FUNCTION(bcpow)
448 3 : {
449 : char *left, *right;
450 : int left_len, right_len;
451 3 : long scale_param = 0;
452 : bc_num first, second, result;
453 3 : int scale = BCG(bc_precision), argc = ZEND_NUM_ARGS();
454 :
455 3 : if (zend_parse_parameters(argc TSRMLS_CC, "ss|l", &left, &left_len, &right, &right_len, &scale_param) == FAILURE) {
456 0 : return;
457 : }
458 :
459 3 : if (argc == 3) {
460 1 : scale = (int) ((int)scale_param < 0) ? 0 : scale_param;
461 : }
462 :
463 3 : bc_init_num(&first TSRMLS_CC);
464 3 : bc_init_num(&second TSRMLS_CC);
465 3 : bc_init_num(&result TSRMLS_CC);
466 3 : php_str2num(&first, left TSRMLS_CC);
467 3 : php_str2num(&second, right TSRMLS_CC);
468 3 : bc_raise (first, second, &result, scale TSRMLS_CC);
469 :
470 3 : if (result->n_scale > scale) {
471 0 : result->n_scale = scale;
472 : }
473 :
474 3 : Z_STRVAL_P(return_value) = bc_num2str(result);
475 3 : Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
476 3 : Z_TYPE_P(return_value) = IS_STRING;
477 3 : bc_free_num(&first);
478 3 : bc_free_num(&second);
479 3 : bc_free_num(&result);
480 3 : return;
481 : }
482 : /* }}} */
483 :
484 : /* {{{ proto string bcsqrt(string operand [, int scale])
485 : Returns the square root of an arbitray precision number */
486 : PHP_FUNCTION(bcsqrt)
487 3 : {
488 : char *left;
489 : int left_len;
490 3 : long scale_param = 0;
491 : bc_num result;
492 3 : int scale = BCG(bc_precision), argc = ZEND_NUM_ARGS();
493 :
494 3 : if (zend_parse_parameters(argc TSRMLS_CC, "s|l", &left, &left_len, &scale_param) == FAILURE) {
495 0 : return;
496 : }
497 :
498 3 : if (argc == 2) {
499 1 : scale = (int) ((int)scale_param < 0) ? 0 : scale_param;
500 : }
501 :
502 3 : bc_init_num(&result TSRMLS_CC);
503 3 : php_str2num(&result, left TSRMLS_CC);
504 :
505 3 : if (bc_sqrt (&result, scale TSRMLS_CC) != 0) {
506 2 : if (result->n_scale > scale) {
507 0 : result->n_scale = scale;
508 : }
509 2 : Z_STRVAL_P(return_value) = bc_num2str(result);
510 2 : Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
511 2 : Z_TYPE_P(return_value) = IS_STRING;
512 : } else {
513 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Square root of negative number");
514 : }
515 :
516 3 : bc_free_num(&result);
517 3 : return;
518 : }
519 : /* }}} */
520 :
521 : /* {{{ proto int bccomp(string left_operand, string right_operand [, int scale])
522 : Compares two arbitrary precision numbers */
523 : PHP_FUNCTION(bccomp)
524 4 : {
525 : char *left, *right;
526 : int left_len, right_len;
527 4 : long scale_param = 0;
528 : bc_num first, second;
529 4 : int scale = BCG(bc_precision), argc = ZEND_NUM_ARGS();
530 :
531 4 : if (zend_parse_parameters(argc TSRMLS_CC, "ss|l", &left, &left_len, &right, &right_len, &scale_param) == FAILURE) {
532 0 : return;
533 : }
534 :
535 4 : if (argc == 3) {
536 2 : scale = (int) ((int)scale_param < 0) ? 0 : scale_param;
537 : }
538 :
539 4 : bc_init_num(&first TSRMLS_CC);
540 4 : bc_init_num(&second TSRMLS_CC);
541 :
542 4 : bc_str2num(&first, left, scale TSRMLS_CC);
543 4 : bc_str2num(&second, right, scale TSRMLS_CC);
544 4 : Z_LVAL_P(return_value) = bc_compare(first, second);
545 4 : Z_TYPE_P(return_value) = IS_LONG;
546 :
547 4 : bc_free_num(&first);
548 4 : bc_free_num(&second);
549 4 : return;
550 : }
551 : /* }}} */
552 :
553 : /* {{{ proto bool bcscale(int scale)
554 : Sets default scale parameter for all bc math functions */
555 : PHP_FUNCTION(bcscale)
556 3 : {
557 : long new_scale;
558 :
559 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &new_scale) == FAILURE) {
560 0 : return;
561 : }
562 :
563 3 : BCG(bc_precision) = (new_scale < 0) ? 0 : new_scale;
564 :
565 3 : RETURN_TRUE;
566 : }
567 : /* }}} */
568 :
569 :
570 : #endif
571 :
572 : /*
573 : * Local variables:
574 : * tab-width: 4
575 : * c-basic-offset: 4
576 : * End:
577 : * vim600: sw=4 ts=4 fdm=marker
578 : * vim<600: sw=4 ts=4
579 : */
|