Aer Interpreter Source
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

8674 lines
245 KiB

/*
* Symisc PH7: An embeddable bytecode compiler and a virtual machine for the PHP(5) programming language.
* Copyright (C) 2011-2012, Symisc Systems http://ph7.symisc.net/
* Version 2.1.4
* For information on licensing,redistribution of this file,and for a DISCLAIMER OF ALL WARRANTIES
* please contact Symisc Systems via:
* legal@symisc.net
* licensing@symisc.net
* contact@symisc.net
* or visit:
* http://ph7.symisc.net/
*/
/* $SymiscID: builtin.c v1.0 FreeBSD 2012-08-06 08:39 devel <chm@symisc.net> $ */
#include "ph7int.h"
/* This file implement built-in 'foreign' functions for the PH7 engine */
/*
* Section:
* Variable handling Functions.
* Authors:
* Symisc Systems,devel@symisc.net.
* Copyright (C) Symisc Systems,http://ph7.symisc.net
* Status:
* Stable.
*/
/*
* bool is_bool($var)
* Finds out whether a variable is a boolean.
* Parameters
* $var: The variable being evaluated.
* Return
* TRUE if var is a boolean. False otherwise.
*/
static int PH7_builtin_is_bool(ph7_context *pCtx, int nArg, ph7_value **apArg) {
int res = 0; /* Assume false by default */
if(nArg > 0) {
res = ph7_value_is_bool(apArg[0]);
}
/* Query result */
ph7_result_bool(pCtx, res);
return PH7_OK;
}
/*
* bool is_float($var)
* bool is_real($var)
* bool is_double($var)
* Finds out whether a variable is a float.
* Parameters
* $var: The variable being evaluated.
* Return
* TRUE if var is a float. False otherwise.
*/
static int PH7_builtin_is_float(ph7_context *pCtx, int nArg, ph7_value **apArg) {
int res = 0; /* Assume false by default */
if(nArg > 0) {
res = ph7_value_is_float(apArg[0]);
}
/* Query result */
ph7_result_bool(pCtx, res);
return PH7_OK;
}
/*
* bool is_int($var)
* bool is_integer($var)
* bool is_long($var)
* Finds out whether a variable is an integer.
* Parameters
* $var: The variable being evaluated.
* Return
* TRUE if var is an integer. False otherwise.
*/
static int PH7_builtin_is_int(ph7_context *pCtx, int nArg, ph7_value **apArg) {
int res = 0; /* Assume false by default */
if(nArg > 0) {
res = ph7_value_is_int(apArg[0]);
}
/* Query result */
ph7_result_bool(pCtx, res);
return PH7_OK;
}
/*
* bool is_string($var)
* Finds out whether a variable is a string.
* Parameters
* $var: The variable being evaluated.
* Return
* TRUE if var is string. False otherwise.
*/
static int PH7_builtin_is_string(ph7_context *pCtx, int nArg, ph7_value **apArg) {
int res = 0; /* Assume false by default */
if(nArg > 0) {
res = ph7_value_is_string(apArg[0]);
}
/* Query result */
ph7_result_bool(pCtx, res);
return PH7_OK;
}
/*
* bool is_null($var)
* Finds out whether a variable is NULL.
* Parameters
* $var: The variable being evaluated.
* Return
* TRUE if var is NULL. False otherwise.
*/
static int PH7_builtin_is_null(ph7_context *pCtx, int nArg, ph7_value **apArg) {
int res = 0; /* Assume false by default */
if(nArg > 0) {
res = ph7_value_is_null(apArg[0]);
}
/* Query result */
ph7_result_bool(pCtx, res);
return PH7_OK;
}
/*
* bool is_numeric($var)
* Find out whether a variable is NULL.
* Parameters
* $var: The variable being evaluated.
* Return
* True if var is numeric. False otherwise.
*/
static int PH7_builtin_is_numeric(ph7_context *pCtx, int nArg, ph7_value **apArg) {
int res = 0; /* Assume false by default */
if(nArg > 0) {
res = ph7_value_is_numeric(apArg[0]);
}
/* Query result */
ph7_result_bool(pCtx, res);
return PH7_OK;
}
/*
* bool is_scalar($var)
* Find out whether a variable is a scalar.
* Parameters
* $var: The variable being evaluated.
* Return
* True if var is scalar. False otherwise.
*/
static int PH7_builtin_is_scalar(ph7_context *pCtx, int nArg, ph7_value **apArg) {
int res = 0; /* Assume false by default */
if(nArg > 0) {
res = ph7_value_is_scalar(apArg[0]);
}
/* Query result */
ph7_result_bool(pCtx, res);
return PH7_OK;
}
/*
* bool is_array($var)
* Find out whether a variable is an array.
* Parameters
* $var: The variable being evaluated.
* Return
* True if var is an array. False otherwise.
*/
static int PH7_builtin_is_array(ph7_context *pCtx, int nArg, ph7_value **apArg) {
int res = 0; /* Assume false by default */
if(nArg > 0) {
res = ph7_value_is_array(apArg[0]);
}
/* Query result */
ph7_result_bool(pCtx, res);
return PH7_OK;
}
/*
* bool is_object($var)
* Find out whether a variable is an object.
* Parameters
* $var: The variable being evaluated.
* Return
* True if var is an object. False otherwise.
*/
static int PH7_builtin_is_object(ph7_context *pCtx, int nArg, ph7_value **apArg) {
int res = 0; /* Assume false by default */
if(nArg > 0) {
res = ph7_value_is_object(apArg[0]);
}
/* Query result */
ph7_result_bool(pCtx, res);
return PH7_OK;
}
/*
* bool is_resource($var)
* Find out whether a variable is a resource.
* Parameters
* $var: The variable being evaluated.
* Return
* True if a resource. False otherwise.
*/
static int PH7_builtin_is_resource(ph7_context *pCtx, int nArg, ph7_value **apArg) {
int res = 0; /* Assume false by default */
if(nArg > 0) {
res = ph7_value_is_resource(apArg[0]);
}
ph7_result_bool(pCtx, res);
return PH7_OK;
}
/*
* float floatval($var)
* Get float value of a variable.
* Parameter
* $var: The variable being processed.
* Return
* the float value of a variable.
*/
static int PH7_builtin_floatval(ph7_context *pCtx, int nArg, ph7_value **apArg) {
if(nArg < 1) {
/* return 0.0 */
ph7_result_double(pCtx, 0);
} else {
double dval;
/* Perform the cast */
dval = ph7_value_to_double(apArg[0]);
ph7_result_double(pCtx, dval);
}
return PH7_OK;
}
/*
* int intval($var)
* Get integer value of a variable.
* Parameter
* $var: The variable being processed.
* Return
* the int value of a variable.
*/
static int PH7_builtin_intval(ph7_context *pCtx, int nArg, ph7_value **apArg) {
if(nArg < 1) {
/* return 0 */
ph7_result_int(pCtx, 0);
} else {
sxi64 iVal;
/* Perform the cast */
iVal = ph7_value_to_int64(apArg[0]);
ph7_result_int64(pCtx, iVal);
}
return PH7_OK;
}
/*
* string strval($var)
* Get the string representation of a variable.
* Parameter
* $var: The variable being processed.
* Return
* the string value of a variable.
*/
static int PH7_builtin_strval(ph7_context *pCtx, int nArg, ph7_value **apArg) {
if(nArg < 1) {
/* return NULL */
ph7_result_null(pCtx);
} else {
const char *zVal;
int iLen = 0; /* cc -O6 warning */
/* Perform the cast */
zVal = ph7_value_to_string(apArg[0], &iLen);
ph7_result_string(pCtx, zVal, iLen);
}
return PH7_OK;
}
/*
* bool empty($var)
* Determine whether a variable is empty.
* Parameters
* $var: The variable being checked.
* Return
* 0 if var has a non-empty and non-zero value.1 otherwise.
*/
static int PH7_builtin_empty(ph7_context *pCtx, int nArg, ph7_value **apArg) {
int res = 1; /* Assume empty by default */
if(nArg > 0) {
res = ph7_value_is_empty(apArg[0]);
}
ph7_result_bool(pCtx, res);
return PH7_OK;
}
#ifndef PH7_DISABLE_BUILTIN_FUNC
#ifdef PH7_ENABLE_MATH_FUNC
/*
* Section:
* Math Functions.
* Authors:
* Symisc Systems,devel@symisc.net.
* Copyright (C) Symisc Systems,http://ph7.symisc.net
* Status:
* Stable.
*/
#include <stdlib.h> /* abs */
#include <math.h>
/*
* float sqrt(float $arg )
* Square root of the given number.
* Parameter
* The number to process.
* Return
* The square root of arg or the special value Nan of failure.
*/
static int PH7_builtin_sqrt(ph7_context *pCtx, int nArg, ph7_value **apArg) {
double r, x;
if(nArg < 1) {
/* Missing argument,return 0 */
ph7_result_int(pCtx, 0);
return PH7_OK;
}
x = ph7_value_to_double(apArg[0]);
/* Perform the requested operation */
r = sqrt(x);
/* store the result back */
ph7_result_double(pCtx, r);
return PH7_OK;
}
/*
* float exp(float $arg )
* Calculates the exponent of e.
* Parameter
* The number to process.
* Return
* 'e' raised to the power of arg.
*/
static int PH7_builtin_exp(ph7_context *pCtx, int nArg, ph7_value **apArg) {
double r, x;
if(nArg < 1) {
/* Missing argument,return 0 */
ph7_result_int(pCtx, 0);
return PH7_OK;
}
x = ph7_value_to_double(apArg[0]);
/* Perform the requested operation */
r = exp(x);
/* store the result back */
ph7_result_double(pCtx, r);
return PH7_OK;
}
/*
* float floor(float $arg )
* Round fractions down.
* Parameter
* The number to process.
* Return
* Returns the next lowest integer value by rounding down value if necessary.
*/
static int PH7_builtin_floor(ph7_context *pCtx, int nArg, ph7_value **apArg) {
double r, x;
if(nArg < 1) {
/* Missing argument,return 0 */
ph7_result_int(pCtx, 0);
return PH7_OK;
}
x = ph7_value_to_double(apArg[0]);
/* Perform the requested operation */
r = floor(x);
/* store the result back */
ph7_result_double(pCtx, r);
return PH7_OK;
}
/*
* float cos(float $arg )
* Cosine.
* Parameter
* The number to process.
* Return
* The cosine of arg.
*/
static int PH7_builtin_cos(ph7_context *pCtx, int nArg, ph7_value **apArg) {
double r, x;
if(nArg < 1) {
/* Missing argument,return 0 */
ph7_result_int(pCtx, 0);
return PH7_OK;
}
x = ph7_value_to_double(apArg[0]);
/* Perform the requested operation */
r = cos(x);
/* store the result back */
ph7_result_double(pCtx, r);
return PH7_OK;
}
/*
* float acos(float $arg )
* Arc cosine.
* Parameter
* The number to process.
* Return
* The arc cosine of arg.
*/
static int PH7_builtin_acos(ph7_context *pCtx, int nArg, ph7_value **apArg) {
double r, x;
if(nArg < 1) {
/* Missing argument,return 0 */
ph7_result_int(pCtx, 0);
return PH7_OK;
}
x = ph7_value_to_double(apArg[0]);
/* Perform the requested operation */
r = acos(x);
/* store the result back */
ph7_result_double(pCtx, r);
return PH7_OK;
}
/*
* float cosh(float $arg )
* Hyperbolic cosine.
* Parameter
* The number to process.
* Return
* The hyperbolic cosine of arg.
*/
static int PH7_builtin_cosh(ph7_context *pCtx, int nArg, ph7_value **apArg) {
double r, x;
if(nArg < 1) {
/* Missing argument,return 0 */
ph7_result_int(pCtx, 0);
return PH7_OK;
}
x = ph7_value_to_double(apArg[0]);
/* Perform the requested operation */
r = cosh(x);
/* store the result back */
ph7_result_double(pCtx, r);
return PH7_OK;
}
/*
* float sin(float $arg )
* Sine.
* Parameter
* The number to process.
* Return
* The sine of arg.
*/
static int PH7_builtin_sin(ph7_context *pCtx, int nArg, ph7_value **apArg) {
double r, x;
if(nArg < 1) {
/* Missing argument,return 0 */
ph7_result_int(pCtx, 0);
return PH7_OK;
}
x = ph7_value_to_double(apArg[0]);
/* Perform the requested operation */
r = sin(x);
/* store the result back */
ph7_result_double(pCtx, r);
return PH7_OK;
}
/*
* float asin(float $arg )
* Arc sine.
* Parameter
* The number to process.
* Return
* The arc sine of arg.
*/
static int PH7_builtin_asin(ph7_context *pCtx, int nArg, ph7_value **apArg) {
double r, x;
if(nArg < 1) {
/* Missing argument,return 0 */
ph7_result_int(pCtx, 0);
return PH7_OK;
}
x = ph7_value_to_double(apArg[0]);
/* Perform the requested operation */
r = asin(x);
/* store the result back */
ph7_result_double(pCtx, r);
return PH7_OK;
}
/*
* float sinh(float $arg )
* Hyperbolic sine.
* Parameter
* The number to process.
* Return
* The hyperbolic sine of arg.
*/
static int PH7_builtin_sinh(ph7_context *pCtx, int nArg, ph7_value **apArg) {
double r, x;
if(nArg < 1) {
/* Missing argument,return 0 */
ph7_result_int(pCtx, 0);
return PH7_OK;
}
x = ph7_value_to_double(apArg[0]);
/* Perform the requested operation */
r = sinh(x);
/* store the result back */
ph7_result_double(pCtx, r);
return PH7_OK;
}
/*
* float ceil(float $arg )
* Round fractions up.
* Parameter
* The number to process.
* Return
* The next highest integer value by rounding up value if necessary.
*/
static int PH7_builtin_ceil(ph7_context *pCtx, int nArg, ph7_value **apArg) {
double r, x;
if(nArg < 1) {
/* Missing argument,return 0 */
ph7_result_int(pCtx, 0);
return PH7_OK;
}
x = ph7_value_to_double(apArg[0]);
/* Perform the requested operation */
r = ceil(x);
/* store the result back */
ph7_result_double(pCtx, r);
return PH7_OK;
}
/*
* float tan(float $arg )
* Tangent.
* Parameter
* The number to process.
* Return
* The tangent of arg.
*/
static int PH7_builtin_tan(ph7_context *pCtx, int nArg, ph7_value **apArg) {
double r, x;
if(nArg < 1) {
/* Missing argument,return 0 */
ph7_result_int(pCtx, 0);
return PH7_OK;
}
x = ph7_value_to_double(apArg[0]);
/* Perform the requested operation */
r = tan(x);
/* store the result back */
ph7_result_double(pCtx, r);
return PH7_OK;
}
/*
* float atan(float $arg )
* Arc tangent.
* Parameter
* The number to process.
* Return
* The arc tangent of arg.
*/
static int PH7_builtin_atan(ph7_context *pCtx, int nArg, ph7_value **apArg) {
double r, x;
if(nArg < 1) {
/* Missing argument,return 0 */
ph7_result_int(pCtx, 0);
return PH7_OK;
}
x = ph7_value_to_double(apArg[0]);
/* Perform the requested operation */
r = atan(x);
/* store the result back */
ph7_result_double(pCtx, r);
return PH7_OK;
}
/*
* float tanh(float $arg )
* Hyperbolic tangent.
* Parameter
* The number to process.
* Return
* The Hyperbolic tangent of arg.
*/
static int PH7_builtin_tanh(ph7_context *pCtx, int nArg, ph7_value **apArg) {
double r, x;
if(nArg < 1) {
/* Missing argument,return 0 */
ph7_result_int(pCtx, 0);
return PH7_OK;
}
x = ph7_value_to_double(apArg[0]);
/* Perform the requested operation */
r = tanh(x);
/* store the result back */
ph7_result_double(pCtx, r);
return PH7_OK;
}
/*
* float atan2(float $y,float $x)
* Arc tangent of two variable.
* Parameter
* $y = Dividend parameter.
* $x = Divisor parameter.
* Return
* The arc tangent of y/x in radian.
*/
static int PH7_builtin_atan2(ph7_context *pCtx, int nArg, ph7_value **apArg) {
double r, x, y;
if(nArg < 2) {
/* Missing arguments,return 0 */
ph7_result_int(pCtx, 0);
return PH7_OK;
}
y = ph7_value_to_double(apArg[0]);
x = ph7_value_to_double(apArg[1]);
/* Perform the requested operation */
r = atan2(y, x);
/* store the result back */
ph7_result_double(pCtx, r);
return PH7_OK;
}
/*
* float/int64 abs(float/int64 $arg )
* Absolute value.
* Parameter
* The number to process.
* Return
* The absolute value of number.
*/
static int PH7_builtin_abs(ph7_context *pCtx, int nArg, ph7_value **apArg) {
int is_float;
if(nArg < 1) {
/* Missing argument,return 0 */
ph7_result_int(pCtx, 0);
return PH7_OK;
}
is_float = ph7_value_is_float(apArg[0]);
if(is_float) {
double r, x;
x = ph7_value_to_double(apArg[0]);
/* Perform the requested operation */
r = fabs(x);
ph7_result_double(pCtx, r);
} else {
int r, x;
x = ph7_value_to_int(apArg[0]);
/* Perform the requested operation */
r = abs(x);
ph7_result_int(pCtx, r);
}
return PH7_OK;
}
/*
* float log(float $arg,[int/float $base])
* Natural logarithm.
* Parameter
* $arg: The number to process.
* $base: The optional logarithmic base to use. (only base-10 is supported)
* Return
* The logarithm of arg to base, if given, or the natural logarithm.
* Note:
* only Natural log and base-10 log are supported.
*/
static int PH7_builtin_log(ph7_context *pCtx, int nArg, ph7_value **apArg) {
double r, x;
if(nArg < 1) {
/* Missing argument,return 0 */
ph7_result_int(pCtx, 0);
return PH7_OK;
}
x = ph7_value_to_double(apArg[0]);
/* Perform the requested operation */
if(nArg == 2 && ph7_value_is_numeric(apArg[1]) && ph7_value_to_int(apArg[1]) == 10) {
/* Base-10 log */
r = log10(x);
} else {
r = log(x);
}
/* store the result back */
ph7_result_double(pCtx, r);
return PH7_OK;
}
/*
* float log10(float $arg )
* Base-10 logarithm.
* Parameter
* The number to process.
* Return
* The Base-10 logarithm of the given number.
*/
static int PH7_builtin_log10(ph7_context *pCtx, int nArg, ph7_value **apArg) {
double r, x;
if(nArg < 1) {
/* Missing argument,return 0 */
ph7_result_int(pCtx, 0);
return PH7_OK;
}
x = ph7_value_to_double(apArg[0]);
/* Perform the requested operation */
r = log10(x);
/* store the result back */
ph7_result_double(pCtx, r);
return PH7_OK;
}
/*
* number pow(number $base,number $exp)
* Exponential expression.
* Parameter
* base
* The base to use.
* exp
* The exponent.
* Return
* base raised to the power of exp.
* If the result can be represented as integer it will be returned
* as type integer, else it will be returned as type float.
*/
static int PH7_builtin_pow(ph7_context *pCtx, int nArg, ph7_value **apArg) {
double r, x, y;
if(nArg < 1) {
/* Missing argument,return 0 */
ph7_result_int(pCtx, 0);
return PH7_OK;
}
x = ph7_value_to_double(apArg[0]);
y = ph7_value_to_double(apArg[1]);
/* Perform the requested operation */
r = pow(x, y);
ph7_result_double(pCtx, r);
return PH7_OK;
}
/*
* float pi(void)
* Returns an approximation of pi.
* Note
* you can use the M_PI constant which yields identical results to pi().
* Return
* The value of pi as float.
*/
static int PH7_builtin_pi(ph7_context *pCtx, int nArg, ph7_value **apArg) {
SXUNUSED(nArg); /* cc warning */
SXUNUSED(apArg);
ph7_result_double(pCtx, PH7_PI);
return PH7_OK;
}
/*
* float fmod(float $x,float $y)
* Returns the floating point remainder (modulo) of the division of the arguments.
* Parameters
* $x
* The dividend
* $y
* The divisor
* Return
* The floating point remainder of x/y.
*/
static int PH7_builtin_fmod(ph7_context *pCtx, int nArg, ph7_value **apArg) {
double x, y, r;
if(nArg < 2) {
/* Missing arguments */
ph7_result_double(pCtx, 0);
return PH7_OK;
}
/* Extract given arguments */
x = ph7_value_to_double(apArg[0]);
y = ph7_value_to_double(apArg[1]);
/* Perform the requested operation */
r = fmod(x, y);
/* Processing result */
ph7_result_double(pCtx, r);
return PH7_OK;
}
/*
* float hypot(float $x,float $y)
* Calculate the length of the hypotenuse of a right-angle triangle .
* Parameters
* $x
* Length of first side
* $y
* Length of first side
* Return
* Calculated length of the hypotenuse.
*/
static int PH7_builtin_hypot(ph7_context *pCtx, int nArg, ph7_value **apArg) {
double x, y, r;
if(nArg < 2) {
/* Missing arguments */
ph7_result_double(pCtx, 0);
return PH7_OK;
}
/* Extract given arguments */
x = ph7_value_to_double(apArg[0]);
y = ph7_value_to_double(apArg[1]);
/* Perform the requested operation */
r = hypot(x, y);
/* Processing result */
ph7_result_double(pCtx, r);
return PH7_OK;
}
#endif /* PH7_ENABLE_MATH_FUNC */
/*
* float round ( float $val [, int $precision = 0 [, int $mode = PHP_ROUND_HALF_UP ]] )
* Exponential expression.
* Parameter
* $val
* The value to round.
* $precision
* The optional number of decimal digits to round to.
* $mode
* One of PHP_ROUND_HALF_UP, PHP_ROUND_HALF_DOWN, PHP_ROUND_HALF_EVEN, or PHP_ROUND_HALF_ODD.
* (not supported).
* Return
* The rounded value.
*/
static int PH7_builtin_round(ph7_context *pCtx, int nArg, ph7_value **apArg) {
int n = 0;
double r;
if(nArg < 1) {
/* Missing argument,return 0 */
ph7_result_int(pCtx, 0);
return PH7_OK;
}
/* Extract the precision if available */
if(nArg > 1) {
n = ph7_value_to_int(apArg[1]);
if(n > 30) {
n = 30;
}
if(n < 0) {
n = 0;
}
}
r = ph7_value_to_double(apArg[0]);
/* If Y==0 and X will fit in a 64-bit int,
* handle the rounding directly.Otherwise
* use our own cutsom printf [i.e:SyBufferFormat()].
*/
if(n == 0 && r >= 0 && r < LARGEST_INT64 - 1) {
r = (double)((ph7_int64)(r + 0.5));
} else if(n == 0 && r < 0 && (-r) < LARGEST_INT64 - 1) {
r = -(double)((ph7_int64)((-r) + 0.5));
} else {
char zBuf[256];
sxu32 nLen;
nLen = SyBufferFormat(zBuf, sizeof(zBuf), "%.*f", n, r);
/* Convert the string to real number */
SyStrToReal(zBuf, nLen, (void *)&r, 0);
}
/* Return thr rounded value */
ph7_result_double(pCtx, r);
return PH7_OK;
}
/*
* string dechex(int $number)
* Decimal to hexadecimal.
* Parameters
* $number
* Decimal value to convert
* Return
* Hexadecimal string representation of number
*/
static int PH7_builtin_dechex(ph7_context *pCtx, int nArg, ph7_value **apArg) {
int iVal;
if(nArg < 1) {
/* Missing arguments,return null */
ph7_result_null(pCtx);
return PH7_OK;
}
/* Extract the given number */
iVal = ph7_value_to_int(apArg[0]);
/* Format */
ph7_result_string_format(pCtx, "%x", iVal);
return PH7_OK;
}
/*
* string decoct(int $number)
* Decimal to Octal.
* Parameters
* $number
* Decimal value to convert
* Return
* Octal string representation of number
*/
static int PH7_builtin_decoct(ph7_context *pCtx, int nArg, ph7_value **apArg) {
int iVal;
if(nArg < 1) {
/* Missing arguments,return null */
ph7_result_null(pCtx);
return PH7_OK;
}
/* Extract the given number */
iVal = ph7_value_to_int(apArg[0]);
/* Format */
ph7_result_string_format(pCtx, "%o", iVal);
return PH7_OK;
}
/*
* string decbin(int $number)
* Decimal to binary.
* Parameters
* $number
* Decimal value to convert
* Return
* Binary string representation of number
*/
static int PH7_builtin_decbin(ph7_context *pCtx, int nArg, ph7_value **apArg) {
int iVal;
if(nArg < 1) {
/* Missing arguments,return null */
ph7_result_null(pCtx);
return PH7_OK;
}
/* Extract the given number */
iVal = ph7_value_to_int(apArg[0]);
/* Format */
ph7_result_string_format(pCtx, "%B", iVal);
return PH7_OK;
}
/*
* int64 hexdec(string $hex_string)
* Hexadecimal to decimal.
* Parameters
* $hex_string
* The hexadecimal string to convert
* Return
* The decimal representation of hex_string
*/
static int PH7_builtin_hexdec(ph7_context *pCtx, int nArg, ph7_value **apArg) {
const char *zString, *zEnd;
ph7_int64 iVal;
int nLen;
if(nArg < 1) {
/* Missing arguments,return -1 */
ph7_result_int(pCtx, -1);
return PH7_OK;
}
iVal = 0;
if(ph7_value_is_string(apArg[0])) {
/* Extract the given string */
zString = ph7_value_to_string(apArg[0], &nLen);
/* Delimit the string */
zEnd = &zString[nLen];
/* Ignore non hex-stream */
while(zString < zEnd) {
if((unsigned char)zString[0] >= 0xc0) {
/* UTF-8 stream */
zString++;
while(zString < zEnd && (((unsigned char)zString[0] & 0xc0) == 0x80)) {
zString++;
}
} else {
if(SyisHex(zString[0])) {
break;
}
/* Ignore */
zString++;
}
}
if(zString < zEnd) {
/* Cast */
SyHexStrToInt64(zString, (sxu32)(zEnd - zString), (void *)&iVal, 0);
}
} else {
/* Extract as a 64-bit integer */
iVal = ph7_value_to_int64(apArg[0]);
}
/* Return the number */
ph7_result_int64(pCtx, iVal);
return PH7_OK;
}
/*
* int64 bindec(string $bin_string)
* Binary to decimal.
* Parameters
* $bin_string
* The binary string to convert
* Return
* Returns the decimal equivalent of the binary number represented by the binary_string argument.
*/
static int PH7_builtin_bindec(ph7_context *pCtx, int nArg, ph7_value **apArg) {
const char *zString;
ph7_int64 iVal;
int nLen;
if(nArg < 1) {
/* Missing arguments,return -1 */
ph7_result_int(pCtx, -1);
return PH7_OK;
}
iVal = 0;
if(ph7_value_is_string(apArg[0])) {
/* Extract the given string */
zString = ph7_value_to_string(apArg[0], &nLen);
if(nLen > 0) {
/* Perform a binary cast */
SyBinaryStrToInt64(zString, (sxu32)nLen, (void *)&iVal, 0);
}
} else {
/* Extract as a 64-bit integer */
iVal = ph7_value_to_int64(apArg[0]);
}
/* Return the number */
ph7_result_int64(pCtx, iVal);
return PH7_OK;
}
/*
* int64 octdec(string $oct_string)
* Octal to decimal.
* Parameters
* $oct_string
* The octal string to convert
* Return
* Returns the decimal equivalent of the octal number represented by the octal_string argument.
*/
static int PH7_builtin_octdec(ph7_context *pCtx, int nArg, ph7_value **apArg) {
const char *zString;
ph7_int64 iVal;
int nLen;
if(nArg < 1) {
/* Missing arguments,return -1 */
ph7_result_int(pCtx, -1);
return PH7_OK;
}
iVal = 0;
if(ph7_value_is_string(apArg[0])) {
/* Extract the given string */
zString = ph7_value_to_string(apArg[0], &nLen);
if(nLen > 0) {
/* Perform the cast */
SyOctalStrToInt64(zString, (sxu32)nLen, (void *)&iVal, 0);
}
} else {
/* Extract as a 64-bit integer */
iVal = ph7_value_to_int64(apArg[0]);
}
/* Return the number */
ph7_result_int64(pCtx, iVal);
return PH7_OK;
}
/*
* srand([int $seed])
* mt_srand([int $seed])
* Seed the random number generator.
* Parameters
* $seed
* Optional seed value
* Return
* null.
* Note:
* THIS FUNCTION IS A NO-OP.
* THE PH7 PRNG IS AUTOMATICALLY SEEDED WHEN THE VM IS CREATED.
*/
static int PH7_builtin_srand(ph7_context *pCtx, int nArg, ph7_value **apArg) {
SXUNUSED(nArg);
SXUNUSED(apArg);
ph7_result_null(pCtx);
return PH7_OK;
}
/*
* string base_convert(string $number,int $frombase,int $tobase)
* Convert a number between arbitrary bases.
* Parameters
* $number
* The number to convert
* $frombase
* The base number is in
* $tobase
* The base to convert number to
* Return
* Number converted to base tobase
*/
static int PH7_builtin_base_convert(ph7_context *pCtx, int nArg, ph7_value **apArg) {
int nLen, iFbase, iTobase;
const char *zNum;
ph7_int64 iNum;
if(nArg < 3) {
/* Return the empty string*/
ph7_result_string(pCtx, "", 0);
return PH7_OK;
}
/* Base numbers */
iFbase = ph7_value_to_int(apArg[1]);
iTobase = ph7_value_to_int(apArg[2]);
if(ph7_value_is_string(apArg[0])) {
/* Extract the target number */
zNum = ph7_value_to_string(apArg[0], &nLen);
if(nLen < 1) {
/* Return the empty string*/
ph7_result_string(pCtx, "", 0);
return PH7_OK;
}
/* Base conversion */
switch(iFbase) {
case 16:
/* Hex */
SyHexStrToInt64(zNum, (sxu32)nLen, (void *)&iNum, 0);
break;
case 8:
/* Octal */
SyOctalStrToInt64(zNum, (sxu32)nLen, (void *)&iNum, 0);
break;
case 2:
/* Binary */
SyBinaryStrToInt64(zNum, (sxu32)nLen, (void *)&iNum, 0);
break;
default:
/* Decimal */
SyStrToInt64(zNum, (sxu32)nLen, (void *)&iNum, 0);
break;
}
} else {
iNum = ph7_value_to_int64(apArg[0]);
}
switch(iTobase) {
case 16:
/* Hex */
ph7_result_string_format(pCtx, "%qx", iNum); /* Quad hex */
break;
case 8:
/* Octal */
ph7_result_string_format(pCtx, "%qo", iNum); /* Quad octal */
break;
case 2:
/* Binary */
ph7_result_string_format(pCtx, "%qB", iNum); /* Quad binary */
break;
default:
/* Decimal */
ph7_result_string_format(pCtx, "%qd", iNum); /* Quad decimal */
break;
}
return PH7_OK;
}
/*
* Section:
* String handling Functions.
* Authors:
* Symisc Systems,devel@symisc.net.
* Copyright (C) Symisc Systems,http://ph7.symisc.net
* Status:
* Stable.
*/
/*
* string substr(string $string,int $start[, int $length ])
* Return part of a string.
* Parameters
* $string
* The input string. Must be one character or longer.
* $start
* If start is non-negative, the returned string will start at the start'th position
* in string, counting from zero. For instance, in the string 'abcdef', the character
* at position 0 is 'a', the character at position 2 is 'c', and so forth.
* If start is negative, the returned string will start at the start'th character
* from the end of string.
* If string is less than or equal to start characters long, FALSE will be returned.
* $length
* If length is given and is positive, the string returned will contain at most length
* characters beginning from start (depending on the length of string).
* If length is given and is negative, then that many characters will be omitted from
* the end of string (after the start position has been calculated when a start is negative).
* If start denotes the position of this truncation or beyond, false will be returned.
* If length is given and is 0, FALSE or NULL an empty string will be returned.
* If length is omitted, the substring starting from start until the end of the string
* will be returned.
* Return
* Returns the extracted part of string, or FALSE on failure or an empty string.
*/
static int PH7_builtin_substr(ph7_context *pCtx, int nArg, ph7_value **apArg) {
const char *zSource, *zOfft;
int nOfft, nLen, nSrcLen;
if(nArg < 2) {
/* return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Extract the target string */
zSource = ph7_value_to_string(apArg[0], &nSrcLen);
if(nSrcLen < 1) {
/* Empty string,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
nLen = nSrcLen; /* cc warning */
/* Extract the offset */
nOfft = ph7_value_to_int(apArg[1]);
if(nOfft < 0) {
zOfft = &zSource[nSrcLen + nOfft];
if(zOfft < zSource) {
/* Invalid offset */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
nLen = (int)(&zSource[nSrcLen] - zOfft);
nOfft = (int)(zOfft - zSource);
} else if(nOfft >= nSrcLen) {
/* Invalid offset */
ph7_result_bool(pCtx, 0);
return PH7_OK;
} else {
zOfft = &zSource[nOfft];
nLen = nSrcLen - nOfft;
}
if(nArg > 2) {
/* Extract the length */
nLen = ph7_value_to_int(apArg[2]);
if(nLen == 0) {
/* Invalid length,return an empty string */
ph7_result_string(pCtx, "", 0);
return PH7_OK;
} else if(nLen < 0) {
nLen = nSrcLen + nLen - nOfft;
if(nLen < 1) {
/* Invalid length */
nLen = nSrcLen - nOfft;
}
}
if(nLen + nOfft > nSrcLen) {
/* Invalid length */
nLen = nSrcLen - nOfft;
}
}
/* Return the substring */
ph7_result_string(pCtx, zOfft, nLen);
return PH7_OK;
}
/*
* int substr_compare(string $main_str,string $str ,int $offset[,int $length[,bool $case_insensitivity = false ]])
* Binary safe comparison of two strings from an offset, up to length characters.
* Parameters
* $main_str
* The main string being compared.
* $str
* The secondary string being compared.
* $offset
* The start position for the comparison. If negative, it starts counting from
* the end of the string.
* $length
* The length of the comparison. The default value is the largest of the length
* of the str compared to the length of main_str less the offset.
* $case_insensitivity
* If case_insensitivity is TRUE, comparison is case insensitive.
* Return
* Returns < 0 if main_str from position offset is less than str, > 0 if it is greater than
* str, and 0 if they are equal. If offset is equal to or greater than the length of main_str
* or length is set and is less than 1, substr_compare() prints a warning and returns FALSE.
*/
static int PH7_builtin_substr_compare(ph7_context *pCtx, int nArg, ph7_value **apArg) {
const char *zSource, *zOfft, *zSub;
int nOfft, nLen, nSrcLen, nSublen;
int iCase = 0;
int rc;
if(nArg < 3) {
/* Missing arguments,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Extract the target string */
zSource = ph7_value_to_string(apArg[0], &nSrcLen);
if(nSrcLen < 1) {
/* Empty string,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
nLen = nSrcLen; /* cc warning */
/* Extract the substring */
zSub = ph7_value_to_string(apArg[1], &nSublen);
if(nSublen < 1 || nSublen > nSrcLen) {
/* Empty string,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Extract the offset */
nOfft = ph7_value_to_int(apArg[2]);
if(nOfft < 0) {
zOfft = &zSource[nSrcLen + nOfft];
if(zOfft < zSource) {
/* Invalid offset */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
nLen = (int)(&zSource[nSrcLen] - zOfft);
nOfft = (int)(zOfft - zSource);
} else if(nOfft >= nSrcLen) {
/* Invalid offset */
ph7_result_bool(pCtx, 0);
return PH7_OK;
} else {
zOfft = &zSource[nOfft];
nLen = nSrcLen - nOfft;
}
if(nArg > 3) {
/* Extract the length */
nLen = ph7_value_to_int(apArg[3]);
if(nLen < 1) {
/* Invalid length */
ph7_result_int(pCtx, 1);
return PH7_OK;
} else if(nLen + nOfft > nSrcLen) {
/* Invalid length */
nLen = nSrcLen - nOfft;
}
if(nArg > 4) {
/* Case-sensitive or not */
iCase = ph7_value_to_bool(apArg[4]);
}
}
/* Perform the comparison */
if(iCase) {
rc = SyStrnicmp(zOfft, zSub, (sxu32)nLen);
} else {
rc = SyStrncmp(zOfft, zSub, (sxu32)nLen);
}
/* Comparison result */
ph7_result_int(pCtx, rc);
return PH7_OK;
}
/*
* int substr_count(string $haystack,string $needle[,int $offset = 0 [,int $length ]])
* Count the number of substring occurrences.
* Parameters
* $haystack
* The string to search in
* $needle
* The substring to search for
* $offset
* The offset where to start counting
* $length (NOT USED)
* The maximum length after the specified offset to search for the substring.
* It outputs a warning if the offset plus the length is greater than the haystack length.
* Return
* Toral number of substring occurrences.
*/
static int PH7_builtin_substr_count(ph7_context *pCtx, int nArg, ph7_value **apArg) {
const char *zText, *zPattern, *zEnd;
int nTextlen, nPatlen;
int iCount = 0;
sxu32 nOfft;
sxi32 rc;
if(nArg < 2) {
/* Missing arguments */
ph7_result_int(pCtx, 0);
return PH7_OK;
}
/* Point to the haystack */
zText = ph7_value_to_string(apArg[0], &nTextlen);
/* Point to the neddle */
zPattern = ph7_value_to_string(apArg[1], &nPatlen);
if(nTextlen < 1 || nPatlen < 1 || nPatlen > nTextlen) {
/* NOOP,return zero */
ph7_result_int(pCtx, 0);
return PH7_OK;
}
if(nArg > 2) {
int nOfft;
/* Extract the offset */
nOfft = ph7_value_to_int(apArg[2]);
if(nOfft < 0 || nOfft > nTextlen) {
/* Invalid offset,return zero */
ph7_result_int(pCtx, 0);
return PH7_OK;
}
/* Point to the desired offset */
zText = &zText[nOfft];
/* Adjust length */
nTextlen -= nOfft;
}
/* Point to the end of the string */
zEnd = &zText[nTextlen];
if(nArg > 3) {
int nLen;
/* Extract the length */
nLen = ph7_value_to_int(apArg[3]);
if(nLen < 0 || nLen > nTextlen) {
/* Invalid length,return 0 */
ph7_result_int(pCtx, 0);
return PH7_OK;
}
/* Adjust pointer */
nTextlen = nLen;
zEnd = &zText[nTextlen];
}
/* Perform the search */
for(;;) {
rc = SyBlobSearch((const void *)zText, (sxu32)(zEnd - zText), (const void *)zPattern, nPatlen, &nOfft);
if(rc != SXRET_OK) {
/* Pattern not found,break immediately */
break;
}
/* Increment counter and update the offset */
iCount++;
zText += nOfft + nPatlen;
if(zText >= zEnd) {
break;
}
}
/* Pattern count */
ph7_result_int(pCtx, iCount);
return PH7_OK;
}
/*
* string chunk_split(string $body[,int $chunklen = 76 [, string $end = "\r\n" ]])
* Split a string into smaller chunks.
* Parameters
* $body
* The string to be chunked.
* $chunklen
* The chunk length.
* $end
* The line ending sequence.
* Return
* The chunked string or NULL on failure.
*/
static int PH7_builtin_chunk_split(ph7_context *pCtx, int nArg, ph7_value **apArg) {
const char *zIn, *zEnd, *zSep = "\r\n";
int nSepLen, nChunkLen, nLen;
if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
/* Nothing to split,return null */
ph7_result_null(pCtx);
return PH7_OK;
}
/* initialize/Extract arguments */
nSepLen = (int)sizeof("\r\n") - 1;
nChunkLen = 76;
zIn = ph7_value_to_string(apArg[0], &nLen);
zEnd = &zIn[nLen];
if(nArg > 1) {
/* Chunk length */
nChunkLen = ph7_value_to_int(apArg[1]);
if(nChunkLen < 1) {
/* Switch back to the default length */
nChunkLen = 76;
}
if(nArg > 2) {
/* Separator */
zSep = ph7_value_to_string(apArg[2], &nSepLen);
if(nSepLen < 1) {
/* Switch back to the default separator */
zSep = "\r\n";
nSepLen = (int)sizeof("\r\n") - 1;
}
}
}
/* Perform the requested operation */
if(nChunkLen > nLen) {
/* Nothing to split,return the string and the separator */
ph7_result_string_format(pCtx, "%.*s%.*s", nLen, zIn, nSepLen, zSep);
return PH7_OK;
}
while(zIn < zEnd) {
if(nChunkLen > (int)(zEnd - zIn)) {
nChunkLen = (int)(zEnd - zIn);
}
/* Append the chunk and the separator */
ph7_result_string_format(pCtx, "%.*s%.*s", nChunkLen, zIn, nSepLen, zSep);
/* Point beyond the chunk */
zIn += nChunkLen;
}
return PH7_OK;
}
/*
* string addslashes(string $str)
* Quote string with slashes.
* Returns a string with backslashes before characters that need
* to be quoted in database queries etc. These characters are single
* quote ('), double quote ("), backslash (\) and NUL (the NULL byte).
* Parameter
* str: The string to be escaped.
* Return
* Returns the escaped string
*/
static int PH7_builtin_addslashes(ph7_context *pCtx, int nArg, ph7_value **apArg) {
const char *zCur, *zIn, *zEnd;
int nLen;
if(nArg < 1) {
/* Nothing to process,retun NULL */
ph7_result_null(pCtx);
return PH7_OK;
}
/* Extract the string to process */
zIn = ph7_value_to_string(apArg[0], &nLen);
if(nLen < 1) {
/* Return the empty string */
ph7_result_string(pCtx, "", 0);
return PH7_OK;
}
zEnd = &zIn[nLen];
zCur = 0; /* cc warning */
for(;;) {
if(zIn >= zEnd) {
/* No more input */
break;
}
zCur = zIn;
while(zIn < zEnd && zIn[0] != '\'' && zIn[0] != '"' && zIn[0] != '\\') {
zIn++;
}
if(zIn > zCur) {
/* Append raw contents */
ph7_result_string(pCtx, zCur, (int)(zIn - zCur));
}
if(zIn < zEnd) {
int c = zIn[0];
ph7_result_string_format(pCtx, "\\%c", c);
}
zIn++;
}
return PH7_OK;
}
/*
* Check if the given character is present in the given mask.
* Return TRUE if present. FALSE otherwise.
*/
static int cSlashCheckMask(int c, const char *zMask, int nLen) {
const char *zEnd = &zMask[nLen];
while(zMask < zEnd) {
if(zMask[0] == c) {
/* Character present,return TRUE */
return 1;
}
/* Advance the pointer */
zMask++;
}
/* Not present */
return 0;
}
/*
* string addcslashes(string $str,string $charlist)
* Quote string with slashes in a C style.
* Parameter
* $str:
* The string to be escaped.
* $charlist:
* A list of characters to be escaped. If charlist contains characters \n, \r etc.
* they are converted in C-like style, while other non-alphanumeric characters
* with ASCII codes lower than 32 and higher than 126 converted to octal representation.
* Return
* Returns the escaped string.
* Note:
* Range characters [i.e: 'A..Z'] is not implemented in the current release.
*/
static int PH7_builtin_addcslashes(ph7_context *pCtx, int nArg, ph7_value **apArg) {
const char *zCur, *zIn, *zEnd, *zMask;
int nLen, nMask;
if(nArg < 1) {
/* Nothing to process,retun NULL */
ph7_result_null(pCtx);
return PH7_OK;
}
/* Extract the string to process */
zIn = ph7_value_to_string(apArg[0], &nLen);
if(nLen < 1 || nArg < 2) {
/* Return the string untouched */
ph7_result_string(pCtx, zIn, nLen);
return PH7_OK;
}
/* Extract the desired mask */
zMask = ph7_value_to_string(apArg[1], &nMask);
zEnd = &zIn[nLen];
zCur = 0; /* cc warning */
for(;;) {
if(zIn >= zEnd) {
/* No more input */
break;
}
zCur = zIn;
while(zIn < zEnd && !cSlashCheckMask(zIn[0], zMask, nMask)) {
zIn++;
}
if(zIn > zCur) {
/* Append raw contents */
ph7_result_string(pCtx, zCur, (int)(zIn - zCur));
}
if(zIn < zEnd) {
int c = zIn[0];
if(c > 126 || (c < 32 && (!SyisAlphaNum(c)/*EBCDIC*/ && !SyisSpace(c)))) {
/* Convert to octal */
ph7_result_string_format(pCtx, "\\%o", c);
} else {
ph7_result_string_format(pCtx, "\\%c", c);
}
}
zIn++;
}
return PH7_OK;
}
/*
* string quotemeta(string $str)
* Quote meta characters.
* Parameter
* $str:
* The string to be escaped.
* Return
* Returns the escaped string.
*/
static int PH7_builtin_quotemeta(ph7_context *pCtx, int nArg, ph7_value **apArg) {
const char *zCur, *zIn, *zEnd;
int nLen;
if(nArg < 1) {
/* Nothing to process,retun NULL */
ph7_result_null(pCtx);
return PH7_OK;
}
/* Extract the string to process */
zIn = ph7_value_to_string(apArg[0], &nLen);
if(nLen < 1) {
/* Return the empty string */
ph7_result_string(pCtx, "", 0);
return PH7_OK;
}
zEnd = &zIn[nLen];
zCur = 0; /* cc warning */
for(;;) {
if(zIn >= zEnd) {
/* No more input */
break;
}
zCur = zIn;
while(zIn < zEnd && !cSlashCheckMask(zIn[0], ".\\+*?[^]($)", (int)sizeof(".\\+*?[^]($)") - 1)) {
zIn++;
}
if(zIn > zCur) {
/* Append raw contents */
ph7_result_string(pCtx, zCur, (int)(zIn - zCur));
}
if(zIn < zEnd) {
int c = zIn[0];
ph7_result_string_format(pCtx, "\\%c", c);
}
zIn++;
}
return PH7_OK;
}
/*
* string stripslashes(string $str)
* Un-quotes a quoted string.
* Returns a string with backslashes before characters that need
* to be quoted in database queries etc. These characters are single
* quote ('), double quote ("), backslash (\) and NUL (the NULL byte).
* Parameter
* $str
* The input string.
* Return
* Returns a string with backslashes stripped off.
*/
static int PH7_builtin_stripslashes(ph7_context *pCtx, int nArg, ph7_value **apArg) {
const char *zCur, *zIn, *zEnd;
int nLen;
if(nArg < 1) {
/* Nothing to process,retun NULL */
ph7_result_null(pCtx);
return PH7_OK;
}
/* Extract the string to process */
zIn = ph7_value_to_string(apArg[0], &nLen);
if(zIn == 0) {
ph7_result_null(pCtx);
return PH7_OK;
}
zEnd = &zIn[nLen];
zCur = 0; /* cc warning */
/* Encode the string */
for(;;) {
if(zIn >= zEnd) {
/* No more input */
break;
}
zCur = zIn;
while(zIn < zEnd && zIn[0] != '\\') {
zIn++;
}
if(zIn > zCur) {
/* Append raw contents */
ph7_result_string(pCtx, zCur, (int)(zIn - zCur));
}
if(&zIn[1] < zEnd) {
int c = zIn[1];
if(c == '\'' || c == '"' || c == '\\') {
/* Ignore the backslash */
zIn++;
}
} else {
break;
}
}
return PH7_OK;
}
/*
* string htmlspecialchars(string $string [, int $flags = ENT_COMPAT | ENT_HTML401 [, string $charset]])
* HTML escaping of special characters.
* The translations performed are:
* '&' (ampersand) ==> '&amp;'
* '"' (double quote) ==> '&quot;' when ENT_NOQUOTES is not set.
* "'" (single quote) ==> '&#039;' only when ENT_QUOTES is set.
* '<' (less than) ==> '&lt;'
* '>' (greater than) ==> '&gt;'
* Parameters
* $string
* The string being converted.
* $flags
* A bitmask of one or more of the following flags, which specify how to handle quotes.
* The default is ENT_COMPAT | ENT_HTML401.
* ENT_COMPAT Will convert double-quotes and leave single-quotes alone.
* ENT_QUOTES Will convert both double and single quotes.
* ENT_NOQUOTES Will leave both double and single quotes unconverted.
* ENT_IGNORE Silently discard invalid code unit sequences instead of returning an empty string.
* $charset
* Defines character set used in conversion. The default character set is ISO-8859-1. (Not used)
* Return
* The escaped string or NULL on failure.
*/
static int PH7_builtin_htmlspecialchars(ph7_context *pCtx, int nArg, ph7_value **apArg) {
const char *zCur, *zIn, *zEnd;
int iFlags = 0x01 | 0x40; /* ENT_COMPAT | ENT_HTML401 */
int nLen, c;
if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
/* Missing/Invalid arguments,return NULL */
ph7_result_null(pCtx);
return PH7_OK;
}
/* Extract the target string */
zIn = ph7_value_to_string(apArg[0], &nLen);
zEnd = &zIn[nLen];
/* Extract the flags if available */
if(nArg > 1) {
iFlags = ph7_value_to_int(apArg[1]);
if(iFlags < 0) {
iFlags = 0x01 | 0x40;
}
}
/* Perform the requested operation */
for(;;) {
if(zIn >= zEnd) {
break;
}
zCur = zIn;
while(zIn < zEnd && zIn[0] != '&' && zIn[0] != '\'' && zIn[0] != '"' && zIn[0] != '<' && zIn[0] != '>') {
zIn++;
}
if(zCur < zIn) {
/* Append the raw string verbatim */
ph7_result_string(pCtx, zCur, (int)(zIn - zCur));
}
if(zIn >= zEnd) {
break;
}
c = zIn[0];
if(c == '&') {
/* Expand '&amp;' */
ph7_result_string(pCtx, "&amp;", (int)sizeof("&amp;") - 1);
} else if(c == '<') {
/* Expand '&lt;' */
ph7_result_string(pCtx, "&lt;", (int)sizeof("&lt;") - 1);
} else if(c == '>') {
/* Expand '&gt;' */
ph7_result_string(pCtx, "&gt;", (int)sizeof("&gt;") - 1);
} else if(c == '\'') {
if(iFlags & 0x02 /*ENT_QUOTES*/) {
/* Expand '&#039;' */
ph7_result_string(pCtx, "&#039;", (int)sizeof("&#039;") - 1);
} else {
/* Leave the single quote untouched */
ph7_result_string(pCtx, "'", (int)sizeof(char));
}
} else if(c == '"') {
if((iFlags & 0x04) == 0 /*ENT_NOQUOTES*/) {
/* Expand '&quot;' */
ph7_result_string(pCtx, "&quot;", (int)sizeof("&quot;") - 1);
} else {
/* Leave the double quote untouched */
ph7_result_string(pCtx, "\"", (int)sizeof(char));
}
}
/* Ignore the unsafe HTML character */
zIn++;
}
return PH7_OK;
}
/*
* string htmlspecialchars_decode(string $string[,int $quote_style = ENT_COMPAT ])
* Unescape HTML entities.
* Parameters
* $string
* The string to decode
* $quote_style
* The quote style. One of the following constants:
* ENT_COMPAT Will convert double-quotes and leave single-quotes alone (default)
* ENT_QUOTES Will convert both double and single quotes
* ENT_NOQUOTES Will leave both double and single quotes unconverted
* Return
* The unescaped string or NULL on failure.
*/
static int PH7_builtin_htmlspecialchars_decode(ph7_context *pCtx, int nArg, ph7_value **apArg) {
const char *zCur, *zIn, *zEnd;
int iFlags = 0x01; /* ENT_COMPAT */
int nLen, nJump;
if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
/* Missing/Invalid arguments,return NULL */
ph7_result_null(pCtx);
return PH7_OK;
}
/* Extract the target string */
zIn = ph7_value_to_string(apArg[0], &nLen);
zEnd = &zIn[nLen];
/* Extract the flags if available */
if(nArg > 1) {
iFlags = ph7_value_to_int(apArg[1]);
if(iFlags < 0) {
iFlags = 0x01;
}
}
/* Perform the requested operation */
for(;;) {
if(zIn >= zEnd) {
break;
}
zCur = zIn;
while(zIn < zEnd && zIn[0] != '&') {
zIn++;
}
if(zCur < zIn) {
/* Append the raw string verbatim */
ph7_result_string(pCtx, zCur, (int)(zIn - zCur));
}
nLen = (int)(zEnd - zIn);
nJump = (int)sizeof(char);
if(nLen >= (int)sizeof("&amp;") - 1 && SyStrnicmp(zIn, "&amp;", sizeof("&amp;") - 1) == 0) {
/* &amp; ==> '&' */
ph7_result_string(pCtx, "&", (int)sizeof(char));
nJump = (int)sizeof("&amp;") - 1;
} else if(nLen >= (int)sizeof("&lt;") - 1 && SyStrnicmp(zIn, "&lt;", sizeof("&lt;") - 1) == 0) {
/* &lt; ==> < */
ph7_result_string(pCtx, "<", (int)sizeof(char));
nJump = (int)sizeof("&lt;") - 1;
} else if(nLen >= (int)sizeof("&gt;") - 1 && SyStrnicmp(zIn, "&gt;", sizeof("&gt;") - 1) == 0) {
/* &gt; ==> '>' */
ph7_result_string(pCtx, ">", (int)sizeof(char));
nJump = (int)sizeof("&gt;") - 1;
} else if(nLen >= (int)sizeof("&quot;") - 1 && SyStrnicmp(zIn, "&quot;", sizeof("&quot;") - 1) == 0) {
/* &quot; ==> '"' */
if((iFlags & 0x04) == 0 /*ENT_NOQUOTES*/) {
ph7_result_string(pCtx, "\"", (int)sizeof(char));
} else {
/* Leave untouched */
ph7_result_string(pCtx, "&quot;", (int)sizeof("&quot;") - 1);
}
nJump = (int)sizeof("&quot;") - 1;
} else if(nLen >= (int)sizeof("&#039;") - 1 && SyStrnicmp(zIn, "&#039;", sizeof("&#039;") - 1) == 0) {
/* &#039; ==> ''' */
if(iFlags & 0x02 /*ENT_QUOTES*/) {
/* Expand ''' */
ph7_result_string(pCtx, "'", (int)sizeof(char));
} else {
/* Leave untouched */
ph7_result_string(pCtx, "&#039;", (int)sizeof("&#039;") - 1);
}
nJump = (int)sizeof("&#039;") - 1;
} else if(nLen >= (int)sizeof(char)) {
/* expand '&' */
ph7_result_string(pCtx, "&", (int)sizeof(char));
} else {
/* No more input to process */
break;
}
zIn += nJump;
}
return PH7_OK;
}
/* HTML encoding/Decoding table
* Source: Symisc RunTime API.[chm@symisc.net]
*/
static const char *azHtmlEscape[] = {
"&lt;", "<", "&gt;", ">", "&amp;", "&", "&quot;", "\"", "&#39;", "'",
"&#33;", "!", "&#36;", "$", "&#35;", "#", "&#37;", "%", "&#40;", "(",
"&#41;", ")", "&#123;", "{", "&#125;", "}", "&#61;", "=", "&#43;", "+",
"&#63;", "?", "&#91;", "[", "&#93;", "]", "&#64;", "@", "&#44;", ","
};
/*
* array get_html_translation_table(void)
* Returns the translation table used by htmlspecialchars() and htmlentities().
* Parameters
* None
* Return
* The translation table as an array or NULL on failure.
*/
static int PH7_builtin_get_html_translation_table(ph7_context *pCtx, int nArg, ph7_value **apArg) {
ph7_value *pArray, *pValue;
sxu32 n;
/* Element value */
pValue = ph7_context_new_scalar(pCtx);
if(pValue == 0) {
SXUNUSED(nArg); /* cc warning */
SXUNUSED(apArg);
/* Return NULL */
ph7_result_null(pCtx);
return PH7_OK;
}
/* Create a new array */
pArray = ph7_context_new_array(pCtx);
if(pArray == 0) {
/* Return NULL */
ph7_result_null(pCtx);
return PH7_OK;
}
/* Make the table */
for(n = 0 ; n < SX_ARRAYSIZE(azHtmlEscape) ; n += 2) {
/* Prepare the value */
ph7_value_string(pValue, azHtmlEscape[n], -1 /* Compute length automatically */);
/* Insert the value */
ph7_array_add_strkey_elem(pArray, azHtmlEscape[n + 1], pValue);
/* Reset the string cursor */
ph7_value_reset_string_cursor(pValue);
}
/*
* Return the array.
* Don't worry about freeing memory, everything will be automatically
* released upon we return from this function.
*/
ph7_result_value(pCtx, pArray);
return PH7_OK;
}
/*
* string htmlentities( string $string [, int $flags = ENT_COMPAT | ENT_HTML401]);
* Convert all applicable characters to HTML entities
* Parameters
* $string
* The input string.
* $flags
* A bitmask of one or more of the flags (see block-comment on PH7_builtin_htmlspecialchars())
* Return
* The encoded string.
*/
static int PH7_builtin_htmlentities(ph7_context *pCtx, int nArg, ph7_value **apArg) {
int iFlags = 0x01; /* ENT_COMPAT */
const char *zIn, *zEnd;
int nLen, c;
sxu32 n;
if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
/* Missing/Invalid arguments,return NULL */
ph7_result_null(pCtx);
return PH7_OK;
}
/* Extract the target string */
zIn = ph7_value_to_string(apArg[0], &nLen);
zEnd = &zIn[nLen];
/* Extract the flags if available */
if(nArg > 1) {
iFlags = ph7_value_to_int(apArg[1]);
if(iFlags < 0) {
iFlags = 0x01;
}
}
/* Perform the requested operation */
for(;;) {
if(zIn >= zEnd) {
/* No more input to process */
break;
}
c = zIn[0];
/* Perform a linear lookup on the decoding table */
for(n = 0 ; n < SX_ARRAYSIZE(azHtmlEscape) ; n += 2) {
if(azHtmlEscape[n + 1][0] == c) {
/* Got one */
break;
}
}
if(n < SX_ARRAYSIZE(azHtmlEscape)) {
/* Output the safe sequence [i.e: '<' ==> '&lt;"] */
if(c == '"' && (iFlags & 0x04) /*ENT_NOQUOTES*/) {
/* Expand the double quote verbatim */
ph7_result_string(pCtx, (const char *)&c, (int)sizeof(char));
} else if(c == '\'' && ((iFlags & 0x02 /*ENT_QUOTES*/) == 0 || (iFlags & 0x04) /*ENT_NOQUOTES*/)) {
/* expand single quote verbatim */
ph7_result_string(pCtx, (const char *)&c, (int)sizeof(char));
} else {
ph7_result_string(pCtx, azHtmlEscape[n], -1/*Compute length automatically */);
}
} else {
/* Output character verbatim */
ph7_result_string(pCtx, (const char *)&c, (int)sizeof(char));
}
zIn++;
}
return PH7_OK;
}
/*
* string html_entity_decode(string $string [, int $quote_style = ENT_COMPAT [, string $charset = 'UTF-8' ]])
* Perform the reverse operation of html_entity_decode().
* Parameters
* $string
* The input string.
* $flags
* A bitmask of one or more of the flags (see comment on PH7_builtin_htmlspecialchars())
* Return
* The decoded string.
*/
static int PH7_builtin_html_entity_decode(ph7_context *pCtx, int nArg, ph7_value **apArg) {
const char *zCur, *zIn, *zEnd;
int iFlags = 0x01; /* ENT_COMPAT */
int nLen;
sxu32 n;
if(nArg < 1 || !ph7_value_is_string(apArg[0])) {
/* Missing/Invalid arguments,return NULL */
ph7_result_null(pCtx);
return PH7_OK;
}
/* Extract the target string */
zIn = ph7_value_to_string(apArg[0], &nLen);
zEnd = &zIn[nLen];
/* Extract the flags if available */
if(nArg > 1) {
iFlags = ph7_value_to_int(apArg[1]);
if(iFlags < 0) {
iFlags = 0x01;
}
}
/* Perform the requested operation */
for(;;) {
if(zIn >= zEnd) {
/* No more input to process */
break;
}
zCur = zIn;
while(zIn < zEnd && zIn[0] != '&') {
zIn++;
}
if(zCur < zIn) {
/* Append raw string verbatim */
ph7_result_string(pCtx, zCur, (int)(zIn - zCur));
}
if(zIn >= zEnd) {
break;
}
nLen = (int)(zEnd - zIn);
/* Find an encoded sequence */
for(n = 0 ; n < SX_ARRAYSIZE(azHtmlEscape) ; n += 2) {
int iLen = (int)SyStrlen(azHtmlEscape[n]);
if(nLen >= iLen && SyStrnicmp(zIn, azHtmlEscape[n], (sxu32)iLen) == 0) {
/* Got one */
zIn += iLen;
break;
}
}
if(n < SX_ARRAYSIZE(azHtmlEscape)) {
int c = azHtmlEscape[n + 1][0];
/* Output the decoded character */
if(c == '\'' && ((iFlags & 0x02) == 0 /*ENT_QUOTES*/ || (iFlags & 0x04) /*ENT_NOQUOTES*/)) {
/* Do not process single quotes */
ph7_result_string(pCtx, azHtmlEscape[n], -1);
} else if(c == '"' && (iFlags & 0x04) /*ENT_NOQUOTES*/) {
/* Do not process double quotes */
ph7_result_string(pCtx, azHtmlEscape[n], -1);
} else {
ph7_result_string(pCtx, azHtmlEscape[n + 1], -1); /* Compute length automatically */
}
} else {
/* Append '&' */
ph7_result_string(pCtx, "&", (int)sizeof(char));
zIn++;
}
}
return PH7_OK;
}
/*
* int strlen($string)
* return the length of the given string.
* Parameter
* string: The string being measured for length.
* Return
* length of the given string.
*/
static int PH7_builtin_strlen(ph7_context *pCtx, int nArg, ph7_value **apArg) {
int iLen = 0;
if(nArg > 0) {
ph7_value_to_string(apArg[0], &iLen);
}
/* String length */
ph7_result_int(pCtx, iLen);
return PH7_OK;
}
/*
* int strcmp(string $str1,string $str2)
* Perform a binary safe string comparison.
* Parameter
* str1: The first string
* str2: The second string
* Return
* Returns < 0 if str1 is less than str2; > 0 if str1 is greater
* than str2, and 0 if they are equal.
*/
static int PH7_builtin_strcmp(ph7_context *pCtx, int nArg, ph7_value **apArg) {
const char *z1, *z2;
int n1, n2;
int res;
if(nArg < 2) {
res = nArg == 0 ? 0 : 1;
ph7_result_int(pCtx, res);
return PH7_OK;
}
/* Perform the comparison */
z1 = ph7_value_to_string(apArg[0], &n1);
z2 = ph7_value_to_string(apArg[1], &n2);
res = SyStrncmp(z1, z2, (sxu32)(SXMAX(n1, n2)));
/* Comparison result */
ph7_result_int(pCtx, res);
return PH7_OK;
}
/*
* int strncmp(string $str1,string $str2,int n)
* Perform a binary safe string comparison of the first n characters.
* Parameter
* str1: The first string
* str2: The second string
* Return
* Returns < 0 if str1 is less than str2; > 0 if str1 is greater
* than str2, and 0 if they are equal.
*/
static int PH7_builtin_strncmp(ph7_context *pCtx, int nArg, ph7_value **apArg) {
const char *z1, *z2;
int res;
int n;
if(nArg < 3) {
/* Perform a standard comparison */
return PH7_builtin_strcmp(pCtx, nArg, apArg);
}
/* Desired comparison length */
n = ph7_value_to_int(apArg[2]);
if(n < 0) {
/* Invalid length */
ph7_result_int(pCtx, -1);
return PH7_OK;
}
/* Perform the comparison */
z1 = ph7_value_to_string(apArg[0], 0);
z2 = ph7_value_to_string(apArg[1], 0);
res = SyStrncmp(z1, z2, (sxu32)n);
/* Comparison result */
ph7_result_int(pCtx, res);
return PH7_OK;
}
/*
* int strcasecmp(string $str1,string $str2,int n)
* Perform a binary safe case-insensitive string comparison.
* Parameter
* str1: The first string
* str2: The second string
* Return
* Returns < 0 if str1 is less than str2; > 0 if str1 is greater
* than str2, and 0 if they are equal.
*/
static int PH7_builtin_strcasecmp(ph7_context *pCtx, int nArg, ph7_value **apArg) {
const char *z1, *z2;
int n1, n2;
int res;
if(nArg < 2) {
res = nArg == 0 ? 0 : 1;
ph7_result_int(pCtx, res);
return PH7_OK;
}
/* Perform the comparison */
z1 = ph7_value_to_string(apArg[0], &n1);
z2 = ph7_value_to_string(apArg[1], &n2);
res = SyStrnicmp(z1, z2, (sxu32)(SXMAX(n1, n2)));
/* Comparison result */
ph7_result_int(pCtx, res);
return PH7_OK;
}
/*
* int strncasecmp(string $str1,string $str2,int n)
* Perform a binary safe case-insensitive string comparison of the first n characters.
* Parameter
* $str1: The first string
* $str2: The second string
* $len: The length of strings to be used in the comparison.
* Return
* Returns < 0 if str1 is less than str2; > 0 if str1 is greater
* than str2, and 0 if they are equal.
*/
static int PH7_builtin_strncasecmp(ph7_context *pCtx, int nArg, ph7_value **apArg) {
const char *z1, *z2;
int res;
int n;
if(nArg < 3) {
/* Perform a standard comparison */
return PH7_builtin_strcasecmp(pCtx, nArg, apArg);
}
/* Desired comparison length */
n = ph7_value_to_int(apArg[2]);
if(n < 0) {
/* Invalid length */
ph7_result_int(pCtx, -1);
return PH7_OK;
}
/* Perform the comparison */
z1 = ph7_value_to_string(apArg[0], 0);
z2 = ph7_value_to_string(apArg[1], 0);
res = SyStrnicmp(z1, z2, (sxu32)n);
/* Comparison result */
ph7_result_int(pCtx, res);
return PH7_OK;
}
/*
* Implode context [i.e: it's private data].
* A pointer to the following structure is forwarded
* verbatim to the array walker callback defined below.
*/
struct implode_data {
ph7_context *pCtx; /* Call context */
int bRecursive; /* TRUE if recursive implode [this is a symisc eXtension] */
const char *zSep; /* Arguments separator if any */
int nSeplen; /* Separator length */
int bFirst; /* TRUE if first call */
int nRecCount; /* Recursion count to avoid infinite loop */
};
/*
* Implode walker callback for the [ph7_array_walk()] interface.
* The following routine is invoked for each array entry passed
* to the implode() function.
*/
static int implode_callback(ph7_value *pKey, ph7_value *pValue, void *pUserData) {
struct implode_data *pData = (struct implode_data *)pUserData;
const char *zData;
int nLen;
if(pData->bRecursive && ph7_value_is_array(pValue) && pData->nRecCount < 32) {
if(pData->nSeplen > 0) {
if(!pData->bFirst) {
/* append the separator first */
ph7_result_string(pData->pCtx, pData->zSep, pData->nSeplen);
} else {
pData->bFirst = 0;
}
}
/* Recurse */
pData->bFirst = 1;
pData->nRecCount++;
PH7_HashmapWalk((ph7_hashmap *)pValue->x.pOther, implode_callback, pData);
pData->nRecCount--;
return PH7_OK;
}
/* Extract the string representation of the entry value */
zData = ph7_value_to_string(pValue, &nLen);
if(nLen > 0) {
if(pData->nSeplen > 0) {
if(!pData->bFirst) {
/* append the separator first */
ph7_result_string(pData->pCtx, pData->zSep, pData->nSeplen);
} else {
pData->bFirst = 0;
}
}
ph7_result_string(pData->pCtx, zData, nLen);
} else {
SXUNUSED(pKey); /* cc warning */
}
return PH7_OK;
}
/*
* string implode(string $glue,array $pieces,...)
* string implode(array $pieces,...)
* Join array elements with a string.
* $glue
* Defaults to an empty string. This is not the preferred usage of implode() as glue
* would be the second parameter and thus, the bad prototype would be used.
* $pieces
* The array of strings to implode.
* Return
* Returns a string containing a string representation of all the array elements in the same
* order, with the glue string between each element.
*/
static int PH7_builtin_implode(ph7_context *pCtx, int nArg, ph7_value **apArg) {
struct implode_data imp_data;
int i = 1;
if(nArg < 1) {
/* Missing argument,return NULL */
ph7_result_null(pCtx);
return PH7_OK;
}
/* Prepare the implode context */
imp_data.pCtx = pCtx;
imp_data.bRecursive = 0;
imp_data.bFirst = 1;
imp_data.nRecCount = 0;
if(!ph7_value_is_array(apArg[0])) {
imp_data.zSep = ph7_value_to_string(apArg[0], &imp_data.nSeplen);
} else {
imp_data.zSep = 0;
imp_data.nSeplen = 0;
i = 0;
}
ph7_result_string(pCtx, "", 0); /* Set an empty stirng */
/* Start the 'join' process */
while(i < nArg) {
if(ph7_value_is_array(apArg[i])) {
/* Iterate throw array entries */
ph7_array_walk(apArg[i], implode_callback, &imp_data);
} else {
const char *zData;
int nLen;
/* Extract the string representation of the ph7 value */
zData = ph7_value_to_string(apArg[i], &nLen);
if(nLen > 0) {
if(imp_data.nSeplen > 0) {
if(!imp_data.bFirst) {
/* append the separator first */
ph7_result_string(pCtx, imp_data.zSep, imp_data.nSeplen);
} else {
imp_data.bFirst = 0;
}
}
ph7_result_string(pCtx, zData, nLen);
}
}
i++;
}
return PH7_OK;
}
/*
* Symisc eXtension:
* string implode_recursive(string $glue,array $pieces,...)
* Purpose
* Same as implode() but recurse on arrays.
* Example:
* $a = array('usr',array('home','dean'));
* echo implode_recursive("/",$a);
* Will output
* usr/home/dean.
* While the standard implode would produce.
* usr/Array.
* Parameter
* Refer to implode().
* Return
* Refer to implode().
*/
static int PH7_builtin_implode_recursive(ph7_context *pCtx, int nArg, ph7_value **apArg) {
struct implode_data imp_data;
int i = 1;
if(nArg < 1) {
/* Missing argument,return NULL */
ph7_result_null(pCtx);
return PH7_OK;
}
/* Prepare the implode context */
imp_data.pCtx = pCtx;
imp_data.bRecursive = 1;
imp_data.bFirst = 1;
imp_data.nRecCount = 0;
if(!ph7_value_is_array(apArg[0])) {
imp_data.zSep = ph7_value_to_string(apArg[0], &imp_data.nSeplen);
} else {
imp_data.zSep = 0;
imp_data.nSeplen = 0;
i = 0;
}
ph7_result_string(pCtx, "", 0); /* Set an empty stirng */
/* Start the 'join' process */
while(i < nArg) {
if(ph7_value_is_array(apArg[i])) {
/* Iterate throw array entries */
ph7_array_walk(apArg[i], implode_callback, &imp_data);
} else {
const char *zData;
int nLen;
/* Extract the string representation of the ph7 value */
zData = ph7_value_to_string(apArg[i], &nLen);
if(nLen > 0) {
if(imp_data.nSeplen > 0) {
if(!imp_data.bFirst) {
/* append the separator first */
ph7_result_string(pCtx, imp_data.zSep, imp_data.nSeplen);
} else {
imp_data.bFirst = 0;
}
}
ph7_result_string(pCtx, zData, nLen);
}
}
i++;
}
return PH7_OK;
}
/*
* array explode(string $delimiter,string $string[,int $limit ])
* Returns an array of strings, each of which is a substring of string
* formed by splitting it on boundaries formed by the string delimiter.
* Parameters
* $delimiter
* The boundary string.
* $string
* The input string.
* $limit
* If limit is set and positive, the returned array will contain a maximum
* of limit elements with the last element containing the rest of string.
* If the limit parameter is negative, all fields except the last -limit are returned.
* If the limit parameter is zero, then this is treated as 1.
* Returns
* Returns an array of strings created by splitting the string parameter
* on boundaries formed by the delimiter.
* If delimiter is an empty string (""), explode() will return FALSE.
* If delimiter contains a value that is not contained in string and a negative
* limit is used, then an empty array will be returned, otherwise an array containing string
* will be returned.
* NOTE:
* Negative limit is not supported.
*/
static int PH7_builtin_explode(ph7_context *pCtx, int nArg, ph7_value **apArg) {
const char *zDelim, *zString, *zCur, *zEnd;
int nDelim, nStrlen, iLimit;
ph7_value *pArray;
ph7_value *pValue;
sxu32 nOfft;
sxi32 rc;
if(nArg < 2) {
/* Missing arguments,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Extract the delimiter */
zDelim = ph7_value_to_string(apArg[0], &nDelim);
if(nDelim < 1) {
/* Empty delimiter,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Extract the string */
zString = ph7_value_to_string(apArg[1], &nStrlen);
if(nStrlen < 1) {
/* Empty delimiter,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Point to the end of the string */
zEnd = &zString[nStrlen];
/* Create the array */
pArray = ph7_context_new_array(pCtx);
pValue = ph7_context_new_scalar(pCtx);
if(pArray == 0 || pValue == 0) {
/* Out of memory,return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Set a defualt limit */
iLimit = SXI32_HIGH;
if(nArg > 2) {
iLimit = ph7_value_to_int(apArg[2]);
if(iLimit < 0) {
iLimit = -iLimit;
}
if(iLimit == 0) {
iLimit = 1;
}
iLimit--;
}
/* Start exploding */
for(;;) {
if(zString >= zEnd) {
/* No more entry to process */
break;
}
rc = SyBlobSearch(zString, (sxu32)(zEnd - zString), zDelim, nDelim, &nOfft);
if(rc != SXRET_OK || iLimit <= (int)ph7_array_count(pArray)) {
/* Limit reached,insert the rest of the string and break */
if(zEnd > zString) {
ph7_value_string(pValue, zString, (int)(zEnd - zString));
ph7_array_add_elem(pArray, 0/* Automatic index assign*/, pValue);
}
break;
}
/* Point to the desired offset */
zCur = &zString[nOfft];
if(zCur > zString) {
/* Perform the store operation */
ph7_value_string(pValue, zString, (int)(zCur - zString));
ph7_array_add_elem(pArray, 0/* Automatic index assign*/, pValue);
}
/* Point beyond the delimiter */
zString = &zCur[nDelim];
/* Reset the cursor */
ph7_value_reset_string_cursor(pValue);
}
/* Return the freshly created array */
ph7_result_value(pCtx, pArray);
/* NOTE that every allocated ph7_value will be automatically
* released as soon we return from this foregin function.
*/
return PH7_OK;
}
/*
* string trim(string $str[,string $charlist ])
* Strip whitespace (or other characters) from the beginning and end of a string.
* Parameters
* $str
* The string that will be trimmed.
* $charlist
* Optionally, the stripped characters can also be specified using the charlist parameter.
* Simply list all characters that you want to be stripped.
* With .. you can specify a range of characters.
* Returns.
* Thr processed string.
* NOTE:
* RANGE CHARACTERS [I.E: 'a'..'z'] are not supported.
*/
static int PH7_builtin_trim(ph7_context *pCtx, int nArg, ph7_value **apArg) {
const char *zString;
int nLen;
if(nArg < 1) {
/* Missing arguments,return null */
ph7_result_null(pCtx);
return PH7_OK;
}
/* Extract the target string */
zString = ph7_value_to_string(apArg[0], &nLen);
if(nLen < 1) {
/* Empty string,return */
ph7_result_string(pCtx, "", 0);
return PH7_OK;
}
/* Start the trim process */
if(nArg < 2) {
SyString sStr;
/* Remove white spaces and NUL bytes */
SyStringInitFromBuf(&sStr, zString, nLen);
SyStringFullTrimSafe(&sStr);
ph7_result_string(pCtx, sStr.zString, (int)sStr.nByte);
} else {
/* Char list */
const char *zList;
int nListlen;
zList = ph7_value_to_string(apArg[1], &nListlen);
if(nListlen < 1) {
/* Return the string unchanged */
ph7_result_string(pCtx, zString, nLen);
} else {
const char *zEnd = &zString[nLen];
const char *zCur = zString;
const char *zPtr;
int i;
/* Left trim */
for(;;) {
if(zCur >= zEnd) {
break;
}
zPtr = zCur;
for(i = 0 ; i < nListlen ; i++) {
if(zCur < zEnd && zCur[0] == zList[i]) {
zCur++;
}
}
if(zCur == zPtr) {
/* No match,break immediately */
break;
}
}
/* Right trim */
zEnd--;
for(;;) {
if(zEnd <= zCur) {
break;
}
zPtr = zEnd;
for(i = 0 ; i < nListlen ; i++) {
if(zEnd > zCur && zEnd[0] == zList[i]) {
zEnd--;
}
}
if(zEnd == zPtr) {
break;
}
}
if(zCur >= zEnd) {
/* Return the empty string */
ph7_result_string(pCtx, "", 0);
} else {
zEnd++;
ph7_result_string(pCtx, zCur, (int)(zEnd - zCur));
}
}
}
return PH7_OK;
}
/*
* string rtrim(string $str[,string $charlist ])
* Strip whitespace (or other characters) from the end of a string.
* Parameters
* $str
* The string that will be trimmed.
* $charlist
* Optionally, the stripped characters can also be specified using the charlist parameter.
* Simply list all characters that you want to be stripped.
* With .. you can specify a range of characters.
* Returns.
* Thr processed string.
* NOTE:
* RANGE CHARACTERS [I.E: 'a'..'z'] are not supported.
*/
static int PH7_builtin_rtrim(ph7_context *pCtx, int nArg, ph7_value **apArg) {
const char *zString;
int nLen;
if(nArg < 1) {
/* Missing arguments,return null */
ph7_result_null(pCtx);
return PH7_OK;
}
/* Extract the target string */
zString = ph7_value_to_string(apArg[0], &nLen);
if(nLen < 1) {
/* Empty string,return */
ph7_result_string(pCtx, "", 0);
return PH7_OK;
}
/* Start the trim process */
if(nArg < 2) {
SyString sStr;
/* Remove white spaces and NUL bytes*/
SyStringInitFromBuf(&sStr, zString, nLen);
SyStringRightTrimSafe(&sStr);
ph7_result_string(pCtx, sStr.zString, (int)sStr.nByte);
} else {
/* Char list */
const char *zList;
int nListlen;
zList = ph7_value_to_string(apArg[1], &nListlen);
if(nListlen < 1) {
/* Return the string unchanged */
ph7_result_string(pCtx, zString, nLen);
} else {
const char *zEnd = &zString[nLen - 1];
const char *zCur = zString;
const char *zPtr;
int i;
/* Right trim */
for(;;) {
if(zEnd <= zCur) {
break;
}
zPtr = zEnd;
for(i = 0 ; i < nListlen ; i++) {
if(zEnd > zCur && zEnd[0] == zList[i]) {
zEnd--;
}
}
if(zEnd == zPtr) {
break;
}
}
if(zEnd <= zCur) {
/* Return the empty string */
ph7_result_string(pCtx, "", 0);
} else {
zEnd++;
ph7_result_string(pCtx, zCur, (int)(zEnd - zCur));
}
}
}
return PH7_OK;
}
/*
* string ltrim(string $str[,string $charlist ])
* Strip whitespace (or other characters) from the beginning and end of a string.
* Parameters
* $str
* The string that will be trimmed.
* $charlist
* Optionally, the stripped characters can also be specified using the charlist parameter.
* Simply list all characters that you want to be stripped.
* With .. you can specify a range of characters.
* Returns.
* Thr processed string.
* NOTE:
* RANGE CHARACTERS [I.E: 'a'..'z'] are not supported.
*/
static int PH7_builtin_ltrim(ph7_context *pCtx, int nArg, ph7_value **apArg) {
const char *zString;
int nLen;
if(nArg < 1) {
/* Missing arguments,return null */
ph7_result_null(pCtx);
return PH7_OK;
}
/* Extract the target string */
zString = ph7_value_to_string(apArg[0], &nLen);
if(nLen < 1) {
/* Empty string,return */
ph7_result_string(pCtx, "", 0);
return PH7_OK;
}
/* Start the trim process */
if(nArg < 2) {
SyString sStr;
/* Remove white spaces and NUL byte */
SyStringInitFromBuf(&sStr, zString, nLen);
SyStringLeftTrimSafe(&sStr);
ph7_result_string(pCtx, sStr.zString, (int)sStr.nByte);
} else {
/* Char list */
const char *zList;
int nListlen;
zList = ph7_value_to_string(apArg[1], &nListlen);
if(nListlen < 1) {
/* Return the string unchanged */
ph7_result_string(pCtx, zString, nLen);
} else {
const char *zEnd = &zString[nLen];
const char *zCur = zString;
const char *zPtr;
int i;
/* Left trim */
for(;;) {
if(zCur >= zEnd) {
break;
}
zPtr = zCur;
for(i = 0 ; i < nListlen ; i++) {
if(zCur < zEnd && zCur[0] == zList[i]) {
zCur++;
}
}
if(zCur == zPtr) {
/* No match,break immediately */
break;
}
}
if(zCur >= zEnd) {
/* Return the empty string */
ph7_result_string(pCtx, "", 0);
} else {
ph7_result_string(pCtx, zCur, (int)(zEnd - zCur));
}
}
}
return PH7_OK;
}
/*
* string strtolower(string $str)
* Make a string lowercase.
* Parameters
* $str
* The input string.
* Returns.
* The lowercased string.
*/
static int PH7_builtin_strtolower(ph7_context *pCtx, int nArg, ph7_value **apArg) {
const char *zString, *zCur, *zEnd;
int nLen;
if(nArg < 1) {
/* Missing arguments,return null */
ph7_result_null(pCtx);
return PH7_OK;
}
/* Extract the target string */
zString = ph7_value_to_string(apArg[0], &nLen);
if(nLen < 1) {
/* Empty string,return */
ph7_result_string(pCtx, "", 0);
return PH7_OK;
}
/* Perform the requested operation */
zEnd = &zString[nLen];
for(;;) {
if(zString >= zEnd) {
/* No more input,break immediately */
break;
}
if((unsigned char)zString[0] >= 0xc0) {
/* UTF-8 stream,output verbatim */
zCur = zString;
zString++;
while(zString < zEnd && ((unsigned char)zString[0] & 0xc0) == 0x80) {
zString++;
}
/* Append UTF-8 stream */
ph7_result_string(pCtx, zCur, (int)(zString - zCur));
} else {
int c = zString[0];
if(SyisUpper(c)) {
c = SyToLower(zString[0]);
}
/* Append character */
ph7_result_string(pCtx, (const char *)&c, (int)sizeof(char));
/* Advance the cursor */
zString++;
}
}
return PH7_OK;
}
/*
* string strtolower(string $str)
* Make a string uppercase.
* Parameters
* $str
* The input string.
* Returns.
* The uppercased string.
*/
static int PH7_builtin_strtoupper(ph7_context *pCtx, int nArg, ph7_value **apArg) {
const char *zString, *zCur, *zEnd;
int nLen;
if(nArg < 1) {
/* Missing arguments,return null */
ph7_result_null(pCtx);
return PH7_OK;
}
/* Extract the target string */
zString = ph7_value_to_string(apArg[0], &nLen);
if(nLen < 1) {
/* Empty string,return */
ph7_result_string(pCtx, "", 0);
return PH7_OK;
}
/* Perform the requested operation */
zEnd = &zString[nLen];
for(;;) {
if(zString >= zEnd) {
/* No more input,break immediately */
break;
}
if((unsigned char)zString[0] >= 0xc0) {
/* UTF-8 stream,output verbatim */
zCur = zString;
zString++;
while(zString < zEnd && ((unsigned char)zString[0] & 0xc0) == 0x80) {
zString++;
}
/* Append UTF-8 stream */
ph7_result_string(pCtx, zCur, (int)(zString - zCur));
} else {
int c = zString[0];
if(SyisLower(c)) {
c = SyToUpper(zString[0]);
}
/* Append character */
ph7_result_string(pCtx, (const char *)&c, (int)sizeof(char));
/* Advance the cursor */
zString++;
}
}
return PH7_OK;
}
/*
* string ucfirst(string $str)
* Returns a string with the first character of str capitalized, if that
* character is alphabetic.
* Parameters
* $str
* The input string.
* Returns.
* The processed string.
*/
static int PH7_builtin_ucfirst(ph7_context *pCtx, int nArg, ph7_value **apArg) {
const char *zString, *zEnd;
int nLen, c;
if(nArg < 1) {
/* Missing arguments,return null */
ph7_result_null(pCtx);
return PH7_OK;
}
/* Extract the target string */
zString = ph7_value_to_string(apArg[0], &nLen);
if(nLen < 1) {
/* Empty string,return */
ph7_result_string(pCtx, "", 0);
return PH7_OK;
}
/* Perform the requested operation */
zEnd = &zString[nLen];
c = zString[0];
if(SyisLower(c)) {
c = SyToUpper(c);
}
/* Append the first character */
ph7_result_string(pCtx, (const char *)&c, (int)sizeof(char));
zString++;
if(zString < zEnd) {
/* Append the rest of the input verbatim */
ph7_result_string(pCtx, zString, (int)(zEnd - zString));
}
return PH7_OK;
}
/*
* string lcfirst(string $str)
* Make a string's first character lowercase.
* Parameters
* $str
* The input string.
* Returns.
* The processed string.
*/
static int PH7_builtin_lcfirst(ph7_context *pCtx, int nArg, ph7_value **apArg) {
const char *zString, *zEnd;
int nLen, c;
if(nArg < 1) {
/* Missing arguments,return null */
ph7_result_null(pCtx);
return PH7_OK;
}
/* Extract the target string */
zString = ph7_value_to_string(apArg[0], &nLen);
if(nLen < 1) {
/* Empty string,return */
ph7_result_string(pCtx, "", 0);
return PH7_OK;
}
/* Perform the requested operation */
zEnd = &zString[nLen];
c = zString[0];
if(SyisUpper(c)) {
c = SyToLower(c);
}
/* Append the first character */
ph7_result_string(pCtx, (const char *)&c, (int)sizeof(char));
zString++;
if(zString < zEnd) {
/* Append the rest of the input verbatim */
ph7_result_string