Aer/builtin.c

8753 lines
242 KiB
C

/*
* 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(pCtx,zString,(int)(zEnd-zString));
}
return PH7_OK;
}
/*
* int ord(string $string)
* Returns the ASCII value of the first character of string.
* Parameters
* $str
* The input string.
* Returns.
* The ASCII value as an integer.
*/
static int PH7_builtin_ord(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const unsigned char *zString;
int nLen,c;
if( nArg < 1 ){
/* Missing arguments,return -1 */
ph7_result_int(pCtx,-1);
return PH7_OK;
}
/* Extract the target string */
zString = ph7_value_to_string(apArg[0],&nLen);
if( nLen < 1 ){
/* Empty string,return -1 */
ph7_result_int(pCtx,-1);
return PH7_OK;
}
/* Extract the ASCII value of the first character */
c = zString[0];
/* Return that value */
ph7_result_int(pCtx,c);
return PH7_OK;
}
/*
* string chr(int $ascii)
* Returns a one-character string containing the character specified by ascii.
* Parameters
* $ascii
* The ascii code.
* Returns.
* The specified character.
*/
static int PH7_builtin_chr(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
int c;
if( nArg < 1 ){
/* Missing arguments,return null */
ph7_result_null(pCtx);
return PH7_OK;
}
/* Extract the ASCII value */
c = ph7_value_to_int(apArg[0]);
/* Return the specified character */
ph7_result_string(pCtx,(const char *)&c,(int)sizeof(char));
return PH7_OK;
}
/*
* Binary to hex consumer callback.
* This callback is the default consumer used by the hash functions
* [i.e: bin2hex(),md5(),sha1(),md5_file() ... ] defined below.
*/
static int HashConsumer(const void *pData,unsigned int nLen,void *pUserData)
{
/* Append hex chunk verbatim */
ph7_result_string((ph7_context *)pUserData,(const char *)pData,(int)nLen);
return SXRET_OK;
}
/*
* string bin2hex(string $str)
* Convert binary data into hexadecimal representation.
* Parameters
* $str
* The input string.
* Returns.
* Returns the hexadecimal representation of the given string.
*/
static int PH7_builtin_bin2hex(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;
}
/* Perform the requested operation */
SyBinToHexConsumer((const void *)zString,(sxu32)nLen,HashConsumer,pCtx);
return PH7_OK;
}
/* Search callback signature */
typedef sxi32 (*ProcStringMatch)(const void *,sxu32,const void *,sxu32,sxu32 *);
/*
* Case-insensitive pattern match.
* Brute force is the default search method used here.
* This is due to the fact that brute-forcing works quite
* well for short/medium texts on modern hardware.
*/
static sxi32 iPatternMatch(const void *pText,sxu32 nLen,const void *pPattern,sxu32 iPatLen,sxu32 *pOfft)
{
const char *zpIn = (const char *)pPattern;
const char *zIn = (const char *)pText;
const char *zpEnd = &zpIn[iPatLen];
const char *zEnd = &zIn[nLen];
const char *zPtr,*zPtr2;
int c,d;
if( iPatLen > nLen ){
/* Don't bother processing */
return SXERR_NOTFOUND;
}
for(;;){
if( zIn >= zEnd ){
break;
}
c = SyToLower(zIn[0]);
d = SyToLower(zpIn[0]);
if( c == d ){
zPtr = &zIn[1];
zPtr2 = &zpIn[1];
for(;;){
if( zPtr2 >= zpEnd ){
/* Pattern found */
if( pOfft ){ *pOfft = (sxu32)(zIn-(const char *)pText); }
return SXRET_OK;
}
if( zPtr >= zEnd ){
break;
}
c = SyToLower(zPtr[0]);
d = SyToLower(zPtr2[0]);
if( c != d ){
break;
}
zPtr++; zPtr2++;
}
}
zIn++;
}
/* Pattern not found */
return SXERR_NOTFOUND;
}
/*
* string strstr(string $haystack,string $needle[,bool $before_needle = false ])
* Find the first occurrence of a string.
* Parameters
* $haystack
* The input string.
* $needle
* Search pattern (must be a string).
* $before_needle
* If TRUE, strstr() returns the part of the haystack before the first occurrence
* of the needle (excluding the needle).
* Return
* Returns the portion of string, or FALSE if needle is not found.
*/
static int PH7_builtin_strstr(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
ProcStringMatch xPatternMatch = SyBlobSearch; /* Case-sensitive pattern match */
const char *zBlob,*zPattern;
int nLen,nPatLen;
sxu32 nOfft;
sxi32 rc;
if( nArg < 2 ){
/* Missing arguments,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the needle and the haystack */
zBlob = ph7_value_to_string(apArg[0],&nLen);
zPattern = ph7_value_to_string(apArg[1],&nPatLen);
nOfft = 0; /* cc warning */
if( nLen > 0 && nPatLen > 0 ){
int before = 0;
/* Perform the lookup */
rc = xPatternMatch(zBlob,(sxu32)nLen,zPattern,(sxu32)nPatLen,&nOfft);
if( rc != SXRET_OK ){
/* Pattern not found,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Return the portion of the string */
if( nArg > 2 ){
before = ph7_value_to_int(apArg[2]);
}
if( before ){
ph7_result_string(pCtx,zBlob,(int)(&zBlob[nOfft]-zBlob));
}else{
ph7_result_string(pCtx,&zBlob[nOfft],(int)(&zBlob[nLen]-&zBlob[nOfft]));
}
}else{
ph7_result_bool(pCtx,0);
}
return PH7_OK;
}
/*
* string stristr(string $haystack,string $needle[,bool $before_needle = false ])
* Case-insensitive strstr().
* Parameters
* $haystack
* The input string.
* $needle
* Search pattern (must be a string).
* $before_needle
* If TRUE, strstr() returns the part of the haystack before the first occurrence
* of the needle (excluding the needle).
* Return
* Returns the portion of string, or FALSE if needle is not found.
*/
static int PH7_builtin_stristr(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
ProcStringMatch xPatternMatch = iPatternMatch; /* Case-insensitive pattern match */
const char *zBlob,*zPattern;
int nLen,nPatLen;
sxu32 nOfft;
sxi32 rc;
if( nArg < 2 ){
/* Missing arguments,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the needle and the haystack */
zBlob = ph7_value_to_string(apArg[0],&nLen);
zPattern = ph7_value_to_string(apArg[1],&nPatLen);
nOfft = 0; /* cc warning */
if( nLen > 0 && nPatLen > 0 ){
int before = 0;
/* Perform the lookup */
rc = xPatternMatch(zBlob,(sxu32)nLen,zPattern,(sxu32)nPatLen,&nOfft);
if( rc != SXRET_OK ){
/* Pattern not found,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Return the portion of the string */
if( nArg > 2 ){
before = ph7_value_to_int(apArg[2]);
}
if( before ){
ph7_result_string(pCtx,zBlob,(int)(&zBlob[nOfft]-zBlob));
}else{
ph7_result_string(pCtx,&zBlob[nOfft],(int)(&zBlob[nLen]-&zBlob[nOfft]));
}
}else{
ph7_result_bool(pCtx,0);
}
return PH7_OK;
}
/*
* int strpos(string $haystack,string $needle [,int $offset = 0 ] )
* Returns the numeric position of the first occurrence of needle in the haystack string.
* Parameters
* $haystack
* The input string.
* $needle
* Search pattern (must be a string).
* $offset
* This optional offset parameter allows you to specify which character in haystack
* to start searching. The position returned is still relative to the beginning
* of haystack.
* Return
* Returns the position as an integer.If needle is not found, strpos() will return FALSE.
*/
static int PH7_builtin_strpos(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
ProcStringMatch xPatternMatch = SyBlobSearch; /* Case-sensitive pattern match */
const char *zBlob,*zPattern;
int nLen,nPatLen,nStart;
sxu32 nOfft;
sxi32 rc;
if( nArg < 2 ){
/* Missing arguments,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the needle and the haystack */
zBlob = ph7_value_to_string(apArg[0],&nLen);
zPattern = ph7_value_to_string(apArg[1],&nPatLen);
nOfft = 0; /* cc warning */
nStart = 0;
/* Peek the starting offset if available */
if( nArg > 2 ){
nStart = ph7_value_to_int(apArg[2]);
if( nStart < 0 ){
nStart = -nStart;
}
if( nStart >= nLen ){
/* Invalid offset */
nStart = 0;
}else{
zBlob += nStart;
nLen -= nStart;
}
}
if( nLen > 0 && nPatLen > 0 ){
/* Perform the lookup */
rc = xPatternMatch(zBlob,(sxu32)nLen,zPattern,(sxu32)nPatLen,&nOfft);
if( rc != SXRET_OK ){
/* Pattern not found,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Return the pattern position */
ph7_result_int64(pCtx,(ph7_int64)(nOfft+nStart));
}else{
ph7_result_bool(pCtx,0);
}
return PH7_OK;
}
/*
* int stripos(string $haystack,string $needle [,int $offset = 0 ] )
* Case-insensitive strpos.
* Parameters
* $haystack
* The input string.
* $needle
* Search pattern (must be a string).
* $offset
* This optional offset parameter allows you to specify which character in haystack
* to start searching. The position returned is still relative to the beginning
* of haystack.
* Return
* Returns the position as an integer.If needle is not found, strpos() will return FALSE.
*/
static int PH7_builtin_stripos(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
ProcStringMatch xPatternMatch = iPatternMatch; /* Case-insensitive pattern match */
const char *zBlob,*zPattern;
int nLen,nPatLen,nStart;
sxu32 nOfft;
sxi32 rc;
if( nArg < 2 ){
/* Missing arguments,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the needle and the haystack */
zBlob = ph7_value_to_string(apArg[0],&nLen);
zPattern = ph7_value_to_string(apArg[1],&nPatLen);
nOfft = 0; /* cc warning */
nStart = 0;
/* Peek the starting offset if available */
if( nArg > 2 ){
nStart = ph7_value_to_int(apArg[2]);
if( nStart < 0 ){
nStart = -nStart;
}
if( nStart >= nLen ){
/* Invalid offset */
nStart = 0;
}else{
zBlob += nStart;
nLen -= nStart;
}
}
if( nLen > 0 && nPatLen > 0 ){
/* Perform the lookup */
rc = xPatternMatch(zBlob,(sxu32)nLen,zPattern,(sxu32)nPatLen,&nOfft);
if( rc != SXRET_OK ){
/* Pattern not found,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Return the pattern position */
ph7_result_int64(pCtx,(ph7_int64)(nOfft+nStart));
}else{
ph7_result_bool(pCtx,0);
}
return PH7_OK;
}
/*
* int strrpos(string $haystack,string $needle [,int $offset = 0 ] )
* Find the numeric position of the last occurrence of needle in the haystack string.
* Parameters
* $haystack
* The input string.
* $needle
* Search pattern (must be a string).
* $offset
* If specified, search will start this number of characters counted from the beginning
* of the string. If the value is negative, search will instead start from that many
* characters from the end of the string, searching backwards.
* Return
* Returns the position as an integer.If needle is not found, strrpos() will return FALSE.
*/
static int PH7_builtin_strrpos(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zStart,*zBlob,*zPattern,*zPtr,*zEnd;
ProcStringMatch xPatternMatch = SyBlobSearch; /* Case-sensitive pattern match */
int nLen,nPatLen;
sxu32 nOfft;
sxi32 rc;
if( nArg < 2 ){
/* Missing arguments,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the needle and the haystack */
zBlob = ph7_value_to_string(apArg[0],&nLen);
zPattern = ph7_value_to_string(apArg[1],&nPatLen);
/* Point to the end of the pattern */
zPtr = &zBlob[nLen - 1];
zEnd = &zBlob[nLen];
/* Save the starting posistion */
zStart = zBlob;
nOfft = 0; /* cc warning */
/* Peek the starting offset if available */
if( nArg > 2 ){
int nStart;
nStart = ph7_value_to_int(apArg[2]);
if( nStart < 0 ){
nStart = -nStart;
if( nStart >= nLen ){
/* Invalid offset */
ph7_result_bool(pCtx,0);
return PH7_OK;
}else{
nLen -= nStart;
zPtr = &zBlob[nLen - 1];
zEnd = &zBlob[nLen];
}
}else{
if( nStart >= nLen ){
/* Invalid offset */
ph7_result_bool(pCtx,0);
return PH7_OK;
}else{
zBlob += nStart;
nLen -= nStart;
}
}
}
if( nLen > 0 && nPatLen > 0 ){
/* Perform the lookup */
for(;;){
if( zBlob >= zPtr ){
break;
}
rc = xPatternMatch((const void *)zPtr,(sxu32)(zEnd-zPtr),(const void *)zPattern,(sxu32)nPatLen,&nOfft);
if( rc == SXRET_OK ){
/* Pattern found,return it's position */
ph7_result_int64(pCtx,(ph7_int64)(&zPtr[nOfft] - zStart));
return PH7_OK;
}
zPtr--;
}
/* Pattern not found,return FALSE */
ph7_result_bool(pCtx,0);
}else{
ph7_result_bool(pCtx,0);
}
return PH7_OK;
}
/*
* int strripos(string $haystack,string $needle [,int $offset = 0 ] )
* Case-insensitive strrpos.
* Parameters
* $haystack
* The input string.
* $needle
* Search pattern (must be a string).
* $offset
* If specified, search will start this number of characters counted from the beginning
* of the string. If the value is negative, search will instead start from that many
* characters from the end of the string, searching backwards.
* Return
* Returns the position as an integer.If needle is not found, strrpos() will return FALSE.
*/
static int PH7_builtin_strripos(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zStart,*zBlob,*zPattern,*zPtr,*zEnd;
ProcStringMatch xPatternMatch = iPatternMatch; /* Case-insensitive pattern match */
int nLen,nPatLen;
sxu32 nOfft;
sxi32 rc;
if( nArg < 2 ){
/* Missing arguments,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the needle and the haystack */
zBlob = ph7_value_to_string(apArg[0],&nLen);
zPattern = ph7_value_to_string(apArg[1],&nPatLen);
/* Point to the end of the pattern */
zPtr = &zBlob[nLen - 1];
zEnd = &zBlob[nLen];
/* Save the starting posistion */
zStart = zBlob;
nOfft = 0; /* cc warning */
/* Peek the starting offset if available */
if( nArg > 2 ){
int nStart;
nStart = ph7_value_to_int(apArg[2]);
if( nStart < 0 ){
nStart = -nStart;
if( nStart >= nLen ){
/* Invalid offset */
ph7_result_bool(pCtx,0);
return PH7_OK;
}else{
nLen -= nStart;
zPtr = &zBlob[nLen - 1];
zEnd = &zBlob[nLen];
}
}else{
if( nStart >= nLen ){
/* Invalid offset */
ph7_result_bool(pCtx,0);
return PH7_OK;
}else{
zBlob += nStart;
nLen -= nStart;
}
}
}
if( nLen > 0 && nPatLen > 0 ){
/* Perform the lookup */
for(;;){
if( zBlob >= zPtr ){
break;
}
rc = xPatternMatch((const void *)zPtr,(sxu32)(zEnd-zPtr),(const void *)zPattern,(sxu32)nPatLen,&nOfft);
if( rc == SXRET_OK ){
/* Pattern found,return it's position */
ph7_result_int64(pCtx,(ph7_int64)(&zPtr[nOfft] - zStart));
return PH7_OK;
}
zPtr--;
}
/* Pattern not found,return FALSE */
ph7_result_bool(pCtx,0);
}else{
ph7_result_bool(pCtx,0);
}
return PH7_OK;
}
/*
* int strrchr(string $haystack,mixed $needle)
* Find the last occurrence of a character in a string.
* Parameters
* $haystack
* The input string.
* $needle
* If needle contains more than one character, only the first is used.
* This behavior is different from that of strstr().
* If needle is not a string, it is converted to an integer and applied
* as the ordinal value of a character.
* Return
* This function returns the portion of string, or FALSE if needle is not found.
*/
static int PH7_builtin_strrchr(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zBlob;
int nLen,c;
if( nArg < 2 ){
/* Missing arguments,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the haystack */
zBlob = ph7_value_to_string(apArg[0],&nLen);
c = 0; /* cc warning */
if( nLen > 0 ){
sxu32 nOfft;
sxi32 rc;
if( ph7_value_is_string(apArg[1]) ){
const char *zPattern;
zPattern = ph7_value_to_string(apArg[1],0); /* Never fail,so there is no need to check
* for NULL pointer.
*/
c = zPattern[0];
}else{
/* Int cast */
c = ph7_value_to_int(apArg[1]);
}
/* Perform the lookup */
rc = SyByteFind2(zBlob,(sxu32)nLen,c,&nOfft);
if( rc != SXRET_OK ){
/* No such entry,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Return the string portion */
ph7_result_string(pCtx,&zBlob[nOfft],(int)(&zBlob[nLen]-&zBlob[nOfft]));
}else{
ph7_result_bool(pCtx,0);
}
return PH7_OK;
}
/*
* string strrev(string $string)
* Reverse a string.
* Parameters
* $string
* String to be reversed.
* Return
* The reversed string.
*/
static int PH7_builtin_strrev(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zIn,*zEnd;
int nLen,c;
if( nArg < 1 ){
/* Missing arguments,return NULL */
ph7_result_null(pCtx);
return PH7_OK;
}
/* Extract the target string */
zIn = ph7_value_to_string(apArg[0],&nLen);
if( nLen < 1 ){
/* Empty string Return null */
ph7_result_null(pCtx);
return PH7_OK;
}
/* Perform the requested operation */
zEnd = &zIn[nLen - 1];
for(;;){
if( zEnd < zIn ){
/* No more input to process */
break;
}
/* Append current character */
c = zEnd[0];
ph7_result_string(pCtx,(const char *)&c,(int)sizeof(char));
zEnd--;
}
return PH7_OK;
}
/*
* string ucwords(string $string)
* Uppercase the first character of each word in a string.
* The definition of a word is any string of characters that is immediately after
* a whitespace (These are: space, form-feed, newline, carriage return, horizontal tab, and vertical tab).
* Parameters
* $string
* The input string.
* Return
* The modified string..
*/
static int PH7_builtin_ucwords(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zIn,*zCur,*zEnd;
int nLen,c;
if( nArg < 1 ){
/* Missing arguments,return NULL */
ph7_result_null(pCtx);
return PH7_OK;
}
/* Extract the target string */
zIn = ph7_value_to_string(apArg[0],&nLen);
if( nLen < 1 ){
/* Empty string Return null */
ph7_result_null(pCtx);
return PH7_OK;
}
/* Perform the requested operation */
zEnd = &zIn[nLen];
for(;;){
/* Jump leading white spaces */
zCur = zIn;
while( zIn < zEnd && (unsigned char)zIn[0] < 0x80 && SyisSpace(zIn[0]) ){
zIn++;
}
if( zCur < zIn ){
/* Append white space stream */
ph7_result_string(pCtx,zCur,(int)(zIn-zCur));
}
if( zIn >= zEnd ){
/* No more input to process */
break;
}
c = zIn[0];
if( c < 0x80 && SyisLower(c) ){
c = SyToUpper(c);
}
/* Append the upper-cased character */
ph7_result_string(pCtx,(const char *)&c,(int)sizeof(char));
zIn++;
zCur = zIn;
/* Append the word varbatim */
while( zIn < zEnd ){
if( (unsigned char)zIn[0] >= 0xc0 ){
/* UTF-8 stream */
zIn++;
SX_JMP_UTF8(zIn,zEnd);
}else if( !SyisSpace(zIn[0]) ){
zIn++;
}else{
break;
}
}
if( zCur < zIn ){
ph7_result_string(pCtx,zCur,(int)(zIn-zCur));
}
}
return PH7_OK;
}
/*
* string str_repeat(string $input,int $multiplier)
* Returns input repeated multiplier times.
* Parameters
* $string
* String to be repeated.
* $multiplier
* Number of time the input string should be repeated.
* multiplier has to be greater than or equal to 0. If the multiplier is set
* to 0, the function will return an empty string.
* Return
* The repeated string.
*/
static int PH7_builtin_str_repeat(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zIn;
int nLen,nMul;
int rc;
if( nArg < 2 ){
/* Missing arguments,return NULL */
ph7_result_null(pCtx);
return PH7_OK;
}
/* Extract the target string */
zIn = ph7_value_to_string(apArg[0],&nLen);
if( nLen < 1 ){
/* Empty string.Return null */
ph7_result_null(pCtx);
return PH7_OK;
}
/* Extract the multiplier */
nMul = ph7_value_to_int(apArg[1]);
if( nMul < 1 ){
/* Return the empty string */
ph7_result_string(pCtx,"",0);
return PH7_OK;
}
/* Perform the requested operation */
for(;;){
if( !nMul ){
break;
}
/* Append the copy */
rc = ph7_result_string(pCtx,zIn,nLen);
if( rc != PH7_OK ){
/* Out of memory,break immediately */
break;
}
nMul--;
}
return PH7_OK;
}
/*
* string nl2br(string $string[,bool $is_xhtml = true ])
* Inserts HTML line breaks before all newlines in a string.
* Parameters
* $string
* The input string.
* $is_xhtml
* Whenever to use XHTML compatible line breaks or not.
* Return
* The processed string.
*/
static int PH7_builtin_nl2br(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zIn,*zCur,*zEnd;
int is_xhtml = 0;
int nLen;
if( nArg < 1 ){
/* Missing arguments,return the empty string */
ph7_result_string(pCtx,"",0);
return PH7_OK;
}
/* Extract the target string */
zIn = ph7_value_to_string(apArg[0],&nLen);
if( nLen < 1 ){
/* Empty string,return null */
ph7_result_null(pCtx);
return PH7_OK;
}
if( nArg > 1 ){
is_xhtml = ph7_value_to_bool(apArg[1]);
}
zEnd = &zIn[nLen];
/* Perform the requested operation */
for(;;){
zCur = zIn;
/* Delimit the string */
while( zIn < zEnd && (zIn[0] != '\n'&& zIn[0] != '\r') ){
zIn++;
}
if( zCur < zIn ){
/* Output chunk verbatim */
ph7_result_string(pCtx,zCur,(int)(zIn-zCur));
}
if( zIn >= zEnd ){
/* No more input to process */
break;
}
/* Output the HTML line break */
if( is_xhtml ){
ph7_result_string(pCtx,"<br>",(int)sizeof("<br>")-1);
}else{
ph7_result_string(pCtx,"<br/>",(int)sizeof("<br/>")-1);
}
zCur = zIn;
/* Append trailing line */
while( zIn < zEnd && (zIn[0] == '\n' || zIn[0] == '\r') ){
zIn++;
}
if( zCur < zIn ){
/* Output chunk verbatim */
ph7_result_string(pCtx,zCur,(int)(zIn-zCur));
}
}
return PH7_OK;
}
/*
* Format a given string and invoke the given callback on each processed chunk.
* According to the PHP reference manual.
* The format string is composed of zero or more directives: ordinary characters
* (excluding %) that are copied directly to the result, and conversion
* specifications, each of which results in fetching its own parameter.
* This applies to both sprintf() and printf().
* Each conversion specification consists of a percent sign (%), followed by one
* or more of these elements, in order:
* An optional sign specifier that forces a sign (- or +) to be used on a number.
* By default, only the - sign is used on a number if it's negative. This specifier forces
* positive numbers to have the + sign attached as well.
* An optional padding specifier that says what character will be used for padding
* the results to the right string size. This may be a space character or a 0 (zero character).
* The default is to pad with spaces. An alternate padding character can be specified by prefixing
* it with a single quote ('). See the examples below.
* An optional alignment specifier that says if the result should be left-justified or right-justified.
* The default is right-justified; a - character here will make it left-justified.
* An optional number, a width specifier that says how many characters (minimum) this conversion
* should result in.
* An optional precision specifier in the form of a period (`.') followed by an optional decimal
* digit string that says how many decimal digits should be displayed for floating-point numbers.
* When using this specifier on a string, it acts as a cutoff point, setting a maximum character
* limit to the string.
* A type specifier that says what type the argument data should be treated as. Possible types:
* % - a literal percent character. No argument is required.
* b - the argument is treated as an integer, and presented as a binary number.
* c - the argument is treated as an integer, and presented as the character with that ASCII value.
* d - the argument is treated as an integer, and presented as a (signed) decimal number.
* e - the argument is treated as scientific notation (e.g. 1.2e+2). The precision specifier stands
* for the number of digits after the decimal point.
* E - like %e but uses uppercase letter (e.g. 1.2E+2).
* u - the argument is treated as an integer, and presented as an unsigned decimal number.
* f - the argument is treated as a float, and presented as a floating-point number (locale aware).
* F - the argument is treated as a float, and presented as a floating-point number (non-locale aware).
* g - shorter of %e and %f.
* G - shorter of %E and %f.
* o - the argument is treated as an integer, and presented as an octal number.
* s - the argument is treated as and presented as a string.
* x - the argument is treated as an integer and presented as a hexadecimal number (with lowercase letters).
* X - the argument is treated as an integer and presented as a hexadecimal number (with uppercase letters).
*/
/*
* This implementation is based on the one found in the SQLite3 source tree.
*/
#define PH7_FMT_BUFSIZ 1024 /* Conversion buffer size */
/*
** Conversion types fall into various categories as defined by the
** following enumeration.
*/
#define PH7_FMT_RADIX 1 /* Integer types.%d, %x, %o, and so forth */
#define PH7_FMT_FLOAT 2 /* Floating point.%f */
#define PH7_FMT_EXP 3 /* Exponentional notation.%e and %E */
#define PH7_FMT_GENERIC 4 /* Floating or exponential, depending on exponent.%g */
#define PH7_FMT_SIZE 5 /* Total number of characters processed so far.%n */
#define PH7_FMT_STRING 6 /* Strings.%s */
#define PH7_FMT_PERCENT 7 /* Percent symbol.%% */
#define PH7_FMT_CHARX 8 /* Characters.%c */
#define PH7_FMT_ERROR 9 /* Used to indicate no such conversion type */
/*
** Allowed values for ph7_fmt_info.flags
*/
#define PH7_FMT_FLAG_SIGNED 0x01
#define PH7_FMT_FLAG_UNSIGNED 0x02
/*
** Each builtin conversion character (ex: the 'd' in "%d") is described
** by an instance of the following structure
*/
typedef struct ph7_fmt_info ph7_fmt_info;
struct ph7_fmt_info
{
char fmttype; /* The format field code letter [i.e: 'd','s','x'] */
sxu8 base; /* The base for radix conversion */
int flags; /* One or more of PH7_FMT_FLAG_ constants below */
sxu8 type; /* Conversion paradigm */
char *charset; /* The character set for conversion */
char *prefix; /* Prefix on non-zero values in alt format */
};
#ifndef PH7_OMIT_FLOATING_POINT
/*
** "*val" is a double such that 0.1 <= *val < 10.0
** Return the ascii code for the leading digit of *val, then
** multiply "*val" by 10.0 to renormalize.
**
** Example:
** input: *val = 3.14159
** output: *val = 1.4159 function return = '3'
**
** The counter *cnt is incremented each time. After counter exceeds
** 16 (the number of significant digits in a 64-bit float) '0' is
** always returned.
*/
static int vxGetdigit(sxlongreal *val,int *cnt)
{
sxlongreal d;
int digit;
if( (*cnt)++ >= 16 ){
return '0';
}
digit = (int)*val;
d = digit;
*val = (*val - d)*10.0;
return digit + '0' ;
}
#endif /* PH7_OMIT_FLOATING_POINT */
/*
* The following table is searched linearly, so it is good to put the most frequently
* used conversion types first.
*/
static const ph7_fmt_info aFmt[] = {
{ 'd', 10, PH7_FMT_FLAG_SIGNED, PH7_FMT_RADIX, "0123456789",0 },
{ 's', 0, 0, PH7_FMT_STRING, 0, 0 },
{ 'c', 0, 0, PH7_FMT_CHARX, 0, 0 },
{ 'x', 16, 0, PH7_FMT_RADIX, "0123456789abcdef", "x0" },
{ 'X', 16, 0, PH7_FMT_RADIX, "0123456789ABCDEF", "X0" },
{ 'b', 2, 0, PH7_FMT_RADIX, "01", "b0"},
{ 'o', 8, 0, PH7_FMT_RADIX, "01234567", "0" },
{ 'u', 10, 0, PH7_FMT_RADIX, "0123456789", 0 },
{ 'f', 0, PH7_FMT_FLAG_SIGNED, PH7_FMT_FLOAT, 0, 0 },
{ 'F', 0, PH7_FMT_FLAG_SIGNED, PH7_FMT_FLOAT, 0, 0 },
{ 'e', 0, PH7_FMT_FLAG_SIGNED, PH7_FMT_EXP, "e", 0 },
{ 'E', 0, PH7_FMT_FLAG_SIGNED, PH7_FMT_EXP, "E", 0 },
{ 'g', 0, PH7_FMT_FLAG_SIGNED, PH7_FMT_GENERIC, "e", 0 },
{ 'G', 0, PH7_FMT_FLAG_SIGNED, PH7_FMT_GENERIC, "E", 0 },
{ '%', 0, 0, PH7_FMT_PERCENT, 0, 0 }
};
/*
* Format a given string.
* The root program. All variations call this core.
* INPUTS:
* xConsumer This is a pointer to a function taking four arguments
* 1. A pointer to the call context.
* 2. A pointer to the list of characters to be output
* (Note, this list is NOT null terminated.)
* 3. An integer number of characters to be output.
* (Note: This number might be zero.)
* 4. Upper layer private data.
* zIn This is the format string, as in the usual print.
* apArg This is a pointer to a list of arguments.
*/
PH7_PRIVATE sxi32 PH7_InputFormat(
int (*xConsumer)(ph7_context *,const char *,int,void *), /* Format consumer */
ph7_context *pCtx, /* call context */
const char *zIn, /* Format string */
int nByte, /* Format string length */
int nArg, /* Total argument of the given arguments */
ph7_value **apArg, /* User arguments */
void *pUserData, /* Last argument to xConsumer() */
int vf /* TRUE if called from vfprintf,vsprintf context */
)
{
char spaces[] = " ";
#define etSPACESIZE ((int)sizeof(spaces)-1)
const char *zCur,*zEnd = &zIn[nByte];
char *zBuf,zWorker[PH7_FMT_BUFSIZ]; /* Working buffer */
const ph7_fmt_info *pInfo; /* Pointer to the appropriate info structure */
int flag_alternateform; /* True if "#" flag is present */
int flag_leftjustify; /* True if "-" flag is present */
int flag_blanksign; /* True if " " flag is present */
int flag_plussign; /* True if "+" flag is present */
int flag_zeropad; /* True if field width constant starts with zero */
ph7_value *pArg; /* Current processed argument */
ph7_int64 iVal;
int precision; /* Precision of the current field */
char *zExtra;
int c,rc,n;
int length; /* Length of the field */
int prefix;
sxu8 xtype; /* Conversion paradigm */
int width; /* Width of the current field */
int idx;
n = (vf == TRUE) ? 0 : 1;
#define NEXT_ARG ( n < nArg ? apArg[n++] : 0 )
/* Start the format process */
for(;;){
zCur = zIn;
while( zIn < zEnd && zIn[0] != '%' ){
zIn++;
}
if( zCur < zIn ){
/* Consume chunk verbatim */
rc = xConsumer(pCtx,zCur,(int)(zIn-zCur),pUserData);
if( rc == SXERR_ABORT ){
/* Callback request an operation abort */
break;
}
}
if( zIn >= zEnd ){
/* No more input to process,break immediately */
break;
}
/* Find out what flags are present */
flag_leftjustify = flag_plussign = flag_blanksign =
flag_alternateform = flag_zeropad = 0;
zIn++; /* Jump the precent sign */
do{
c = zIn[0];
switch( c ){
case '-': flag_leftjustify = 1; c = 0; break;
case '+': flag_plussign = 1; c = 0; break;
case ' ': flag_blanksign = 1; c = 0; break;
case '#': flag_alternateform = 1; c = 0; break;
case '0': flag_zeropad = 1; c = 0; break;
case '\'':
zIn++;
if( zIn < zEnd ){
/* An alternate padding character can be specified by prefixing it with a single quote (') */
c = zIn[0];
for(idx = 0 ; idx < etSPACESIZE ; ++idx ){
spaces[idx] = (char)c;
}
c = 0;
}
break;
default: break;
}
}while( c==0 && (zIn++ < zEnd) );
/* Get the field width */
width = 0;
while( zIn < zEnd && ( zIn[0] >='0' && zIn[0] <='9') ){
width = width*10 + (zIn[0] - '0');
zIn++;
}
if( zIn < zEnd && zIn[0] == '$' ){
/* Position specifer */
if( width > 0 ){
n = width;
if( vf && n > 0 ){
n--;
}
}
zIn++;
width = 0;
if( zIn < zEnd && zIn[0] == '0' ){
flag_zeropad = 1;
zIn++;
}
while( zIn < zEnd && ( zIn[0] >='0' && zIn[0] <='9') ){
width = width*10 + (zIn[0] - '0');
zIn++;
}
}
if( width > PH7_FMT_BUFSIZ-10 ){
width = PH7_FMT_BUFSIZ-10;
}
/* Get the precision */
precision = -1;
if( zIn < zEnd && zIn[0] == '.' ){
precision = 0;
zIn++;
while( zIn < zEnd && ( zIn[0] >='0' && zIn[0] <='9') ){
precision = precision*10 + (zIn[0] - '0');
zIn++;
}
}
if( zIn >= zEnd ){
/* No more input */
break;
}
/* Fetch the info entry for the field */
pInfo = 0;
xtype = PH7_FMT_ERROR;
c = zIn[0];
zIn++; /* Jump the format specifer */
for(idx=0; idx< (int)SX_ARRAYSIZE(aFmt); idx++){
if( c==aFmt[idx].fmttype ){
pInfo = &aFmt[idx];
xtype = pInfo->type;
break;
}
}
zBuf = zWorker; /* Point to the working buffer */
length = 0;
zExtra = 0;
/*
** At this point, variables are initialized as follows:
**
** flag_alternateform TRUE if a '#' is present.
** flag_plussign TRUE if a '+' is present.
** flag_leftjustify TRUE if a '-' is present or if the
** field width was negative.
** flag_zeropad TRUE if the width began with 0.
** the conversion character.
** flag_blanksign TRUE if a ' ' is present.
** width The specified field width. This is
** always non-negative. Zero is the default.
** precision The specified precision. The default
** is -1.
*/
switch(xtype){
case PH7_FMT_PERCENT:
/* A literal percent character */
zWorker[0] = '%';
length = (int)sizeof(char);
break;
case PH7_FMT_CHARX:
/* The argument is treated as an integer, and presented as the character
* with that ASCII value
*/
pArg = NEXT_ARG;
if( pArg == 0 ){
c = 0;
}else{
c = ph7_value_to_int(pArg);
}
/* NUL byte is an acceptable value */
zWorker[0] = (char)c;
length = (int)sizeof(char);
break;
case PH7_FMT_STRING:
/* the argument is treated as and presented as a string */
pArg = NEXT_ARG;
if( pArg == 0 ){
length = 0;
}else{
zBuf = (char *)ph7_value_to_string(pArg,&length);
}
if( length < 1 ){
zBuf = " ";
length = (int)sizeof(char);
}
if( precision>=0 && precision<length ){
length = precision;
}
if( flag_zeropad ){
/* zero-padding works on strings too */
for(idx = 0 ; idx < etSPACESIZE ; ++idx ){
spaces[idx] = '0';
}
}
break;
case PH7_FMT_RADIX:
pArg = NEXT_ARG;
if( pArg == 0 ){
iVal = 0;
}else{
iVal = ph7_value_to_int64(pArg);
}
/* Limit the precision to prevent overflowing buf[] during conversion */
if( precision>PH7_FMT_BUFSIZ-40 ){
precision = PH7_FMT_BUFSIZ-40;
}
#if 1
/* For the format %#x, the value zero is printed "0" not "0x0".
** I think this is stupid.*/
if( iVal==0 ) flag_alternateform = 0;
#else
/* More sensible: turn off the prefix for octal (to prevent "00"),
** but leave the prefix for hex.*/
if( iVal==0 && pInfo->base==8 ) flag_alternateform = 0;
#endif
if( pInfo->flags & PH7_FMT_FLAG_SIGNED ){
if( iVal<0 ){
iVal = -iVal;
/* Ticket 1433-003 */
if( iVal < 0 ){
/* Overflow */
iVal= 0x7FFFFFFFFFFFFFFF;
}
prefix = '-';
}else if( flag_plussign ) prefix = '+';
else if( flag_blanksign ) prefix = ' ';
else prefix = 0;
}else{
if( iVal<0 ){
iVal = -iVal;
/* Ticket 1433-003 */
if( iVal < 0 ){
/* Overflow */
iVal= 0x7FFFFFFFFFFFFFFF;
}
}
prefix = 0;
}
if( flag_zeropad && precision<width-(prefix!=0) ){
precision = width-(prefix!=0);
}
zBuf = &zWorker[PH7_FMT_BUFSIZ-1];
{
register char *cset; /* Use registers for speed */
register int base;
cset = pInfo->charset;
base = pInfo->base;
do{ /* Convert to ascii */
*(--zBuf) = cset[iVal%base];
iVal = iVal/base;
}while( iVal>0 );
}
length = &zWorker[PH7_FMT_BUFSIZ-1]-zBuf;
for(idx=precision-length; idx>0; idx--){
*(--zBuf) = '0'; /* Zero pad */
}
if( prefix ) *(--zBuf) = (char)prefix; /* Add sign */
if( flag_alternateform && pInfo->prefix ){ /* Add "0" or "0x" */
char *pre, x;
pre = pInfo->prefix;
if( *zBuf!=pre[0] ){
for(pre=pInfo->prefix; (x=(*pre))!=0; pre++) *(--zBuf) = x;
}
}
length = &zWorker[PH7_FMT_BUFSIZ-1]-zBuf;
break;
case PH7_FMT_FLOAT:
case PH7_FMT_EXP:
case PH7_FMT_GENERIC:{
#ifndef PH7_OMIT_FLOATING_POINT
long double realvalue;
int exp; /* exponent of real numbers */
double rounder; /* Used for rounding floating point values */
int flag_dp; /* True if decimal point should be shown */
int flag_rtz; /* True if trailing zeros should be removed */
int flag_exp; /* True to force display of the exponent */
int nsd; /* Number of significant digits returned */
pArg = NEXT_ARG;
if( pArg == 0 ){
realvalue = 0;
}else{
realvalue = ph7_value_to_double(pArg);
}
if( precision<0 ) precision = 6; /* Set default precision */
if( precision>PH7_FMT_BUFSIZ-40) precision = PH7_FMT_BUFSIZ-40;
if( realvalue<0.0 ){
realvalue = -realvalue;
prefix = '-';
}else{
if( flag_plussign ) prefix = '+';
else if( flag_blanksign ) prefix = ' ';
else prefix = 0;
}
if( pInfo->type==PH7_FMT_GENERIC && precision>0 ) precision--;
rounder = 0.0;
#if 0
/* Rounding works like BSD when the constant 0.4999 is used.Wierd! */
for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1);
#else
/* It makes more sense to use 0.5 */
for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1);
#endif
if( pInfo->type==PH7_FMT_FLOAT ) realvalue += rounder;
/* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
exp = 0;
if( realvalue>0.0 ){
while( realvalue>=1e8 && exp<=350 ){ realvalue *= 1e-8; exp+=8; }
while( realvalue>=10.0 && exp<=350 ){ realvalue *= 0.1; exp++; }
while( realvalue<1e-8 && exp>=-350 ){ realvalue *= 1e8; exp-=8; }
while( realvalue<1.0 && exp>=-350 ){ realvalue *= 10.0; exp--; }
if( exp>350 || exp<-350 ){
zBuf = "NaN";
length = 3;
break;
}
}
zBuf = zWorker;
/*
** If the field type is etGENERIC, then convert to either etEXP
** or etFLOAT, as appropriate.
*/
flag_exp = xtype==PH7_FMT_EXP;
if( xtype!=PH7_FMT_FLOAT ){
realvalue += rounder;
if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; }
}
if( xtype==PH7_FMT_GENERIC ){
flag_rtz = !flag_alternateform;
if( exp<-4 || exp>precision ){
xtype = PH7_FMT_EXP;
}else{
precision = precision - exp;
xtype = PH7_FMT_FLOAT;
}
}else{
flag_rtz = 0;
}
/*
** The "exp+precision" test causes output to be of type etEXP if
** the precision is too large to fit in buf[].
*/
nsd = 0;
if( xtype==PH7_FMT_FLOAT && exp+precision<PH7_FMT_BUFSIZ-30 ){
flag_dp = (precision>0 || flag_alternateform);
if( prefix ) *(zBuf++) = (char)prefix; /* Sign */
if( exp<0 ) *(zBuf++) = '0'; /* Digits before "." */
else for(; exp>=0; exp--) *(zBuf++) = (char)vxGetdigit(&realvalue,&nsd);
if( flag_dp ) *(zBuf++) = '.'; /* The decimal point */
for(exp++; exp<0 && precision>0; precision--, exp++){
*(zBuf++) = '0';
}
while( (precision--)>0 ) *(zBuf++) = (char)vxGetdigit(&realvalue,&nsd);
*(zBuf--) = 0; /* Null terminate */
if( flag_rtz && flag_dp ){ /* Remove trailing zeros and "." */
while( zBuf>=zWorker && *zBuf=='0' ) *(zBuf--) = 0;
if( zBuf>=zWorker && *zBuf=='.' ) *(zBuf--) = 0;
}
zBuf++; /* point to next free slot */
}else{ /* etEXP or etGENERIC */
flag_dp = (precision>0 || flag_alternateform);
if( prefix ) *(zBuf++) = (char)prefix; /* Sign */
*(zBuf++) = (char)vxGetdigit(&realvalue,&nsd); /* First digit */
if( flag_dp ) *(zBuf++) = '.'; /* Decimal point */
while( (precision--)>0 ) *(zBuf++) = (char)vxGetdigit(&realvalue,&nsd);
zBuf--; /* point to last digit */
if( flag_rtz && flag_dp ){ /* Remove tail zeros */
while( zBuf>=zWorker && *zBuf=='0' ) *(zBuf--) = 0;
if( zBuf>=zWorker && *zBuf=='.' ) *(zBuf--) = 0;
}
zBuf++; /* point to next free slot */
if( exp || flag_exp ){
*(zBuf++) = pInfo->charset[0];
if( exp<0 ){ *(zBuf++) = '-'; exp = -exp; } /* sign of exp */
else { *(zBuf++) = '+'; }
if( exp>=100 ){
*(zBuf++) = (char)((exp/100)+'0'); /* 100's digit */
exp %= 100;
}
*(zBuf++) = (char)(exp/10+'0'); /* 10's digit */
*(zBuf++) = (char)(exp%10+'0'); /* 1's digit */
}
}
/* The converted number is in buf[] and zero terminated.Output it.
** Note that the number is in the usual order, not reversed as with
** integer conversions.*/
length = (int)(zBuf-zWorker);
zBuf = zWorker;
/* Special case: Add leading zeros if the flag_zeropad flag is
** set and we are not left justified */
if( flag_zeropad && !flag_leftjustify && length < width){
int i;
int nPad = width - length;
for(i=width; i>=nPad; i--){
zBuf[i] = zBuf[i-nPad];
}
i = prefix!=0;
while( nPad-- ) zBuf[i++] = '0';
length = width;
}
#else
zBuf = " ";
length = (int)sizeof(char);
#endif /* PH7_OMIT_FLOATING_POINT */
break;
}
default:
/* Invalid format specifer */
zWorker[0] = '?';
length = (int)sizeof(char);
break;
}
/*
** The text of the conversion is pointed to by "zBuf" and is
** "length" characters long.The field width is "width".Do
** the output.
*/
if( !flag_leftjustify ){
register int nspace;
nspace = width-length;
if( nspace>0 ){
while( nspace>=etSPACESIZE ){
rc = xConsumer(pCtx,spaces,etSPACESIZE,pUserData);
if( rc != SXRET_OK ){
return SXERR_ABORT; /* Consumer routine request an operation abort */
}
nspace -= etSPACESIZE;
}
if( nspace>0 ){
rc = xConsumer(pCtx,spaces,(unsigned int)nspace,pUserData);
if( rc != SXRET_OK ){
return SXERR_ABORT; /* Consumer routine request an operation abort */
}
}
}
}
if( length>0 ){
rc = xConsumer(pCtx,zBuf,(unsigned int)length,pUserData);
if( rc != SXRET_OK ){
return SXERR_ABORT; /* Consumer routine request an operation abort */
}
}
if( flag_leftjustify ){
register int nspace;
nspace = width-length;
if( nspace>0 ){
while( nspace>=etSPACESIZE ){
rc = xConsumer(pCtx,spaces,etSPACESIZE,pUserData);
if( rc != SXRET_OK ){
return SXERR_ABORT; /* Consumer routine request an operation abort */
}
nspace -= etSPACESIZE;
}
if( nspace>0 ){
rc = xConsumer(pCtx,spaces,(unsigned int)nspace,pUserData);
if( rc != SXRET_OK ){
return SXERR_ABORT; /* Consumer routine request an operation abort */
}
}
}
}
}/* for(;;) */
return SXRET_OK;
}
/*
* Callback [i.e: Formatted input consumer] of the sprintf function.
*/
static int sprintfConsumer(ph7_context *pCtx,const char *zInput,int nLen,void *pUserData)
{
/* Consume directly */
ph7_result_string(pCtx,zInput,nLen);
SXUNUSED(pUserData); /* cc warning */
return PH7_OK;
}
/*
* string sprintf(string $format[,mixed $args [, mixed $... ]])
* Return a formatted string.
* Parameters
* $format
* The format string (see block comment above)
* Return
* A string produced according to the formatting string format.
*/
static int PH7_builtin_sprintf(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zFormat;
int nLen;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid arguments,return the empty string */
ph7_result_string(pCtx,"",0);
return PH7_OK;
}
/* Extract the string format */
zFormat = ph7_value_to_string(apArg[0],&nLen);
if( nLen < 1 ){
/* Empty string */
ph7_result_string(pCtx,"",0);
return PH7_OK;
}
/* Format the string */
PH7_InputFormat(sprintfConsumer,pCtx,zFormat,nLen,nArg,apArg,0,FALSE);
return PH7_OK;
}
/*
* Callback [i.e: Formatted input consumer] of the printf function.
*/
static int printfConsumer(ph7_context *pCtx,const char *zInput,int nLen,void *pUserData)
{
ph7_int64 *pCounter = (ph7_int64 *)pUserData;
/* Call the VM output consumer directly */
ph7_context_output(pCtx,zInput,nLen);
/* Increment counter */
*pCounter += nLen;
return PH7_OK;
}
/*
* int64 printf(string $format[,mixed $args[,mixed $... ]])
* Output a formatted string.
* Parameters
* $format
* See sprintf() for a description of format.
* Return
* The length of the outputted string.
*/
static int PH7_builtin_printf(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
ph7_int64 nCounter = 0;
const char *zFormat;
int nLen;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid arguments,return 0 */
ph7_result_int(pCtx,0);
return PH7_OK;
}
/* Extract the string format */
zFormat = ph7_value_to_string(apArg[0],&nLen);
if( nLen < 1 ){
/* Empty string */
ph7_result_int(pCtx,0);
return PH7_OK;
}
/* Format the string */
PH7_InputFormat(printfConsumer,pCtx,zFormat,nLen,nArg,apArg,(void *)&nCounter,FALSE);
/* Return the length of the outputted string */
ph7_result_int64(pCtx,nCounter);
return PH7_OK;
}
/*
* int vprintf(string $format,array $args)
* Output a formatted string.
* Parameters
* $format
* See sprintf() for a description of format.
* Return
* The length of the outputted string.
*/
static int PH7_builtin_vprintf(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
ph7_int64 nCounter = 0;
const char *zFormat;
ph7_hashmap *pMap;
SySet sArg;
int nLen,n;
if( nArg < 2 || !ph7_value_is_string(apArg[0]) || !ph7_value_is_array(apArg[1]) ){
/* Missing/Invalid arguments,return 0 */
ph7_result_int(pCtx,0);
return PH7_OK;
}
/* Extract the string format */
zFormat = ph7_value_to_string(apArg[0],&nLen);
if( nLen < 1 ){
/* Empty string */
ph7_result_int(pCtx,0);
return PH7_OK;
}
/* Point to the hashmap */
pMap = (ph7_hashmap *)apArg[1]->x.pOther;
/* Extract arguments from the hashmap */
n = PH7_HashmapValuesToSet(pMap,&sArg);
/* Format the string */
PH7_InputFormat(printfConsumer,pCtx,zFormat,nLen,n,(ph7_value **)SySetBasePtr(&sArg),(void *)&nCounter,TRUE);
/* Return the length of the outputted string */
ph7_result_int64(pCtx,nCounter);
/* Release the container */
SySetRelease(&sArg);
return PH7_OK;
}
/*
* int vsprintf(string $format,array $args)
* Output a formatted string.
* Parameters
* $format
* See sprintf() for a description of format.
* Return
* A string produced according to the formatting string format.
*/
static int PH7_builtin_vsprintf(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zFormat;
ph7_hashmap *pMap;
SySet sArg;
int nLen,n;
if( nArg < 2 || !ph7_value_is_string(apArg[0]) || !ph7_value_is_array(apArg[1]) ){
/* Missing/Invalid arguments,return the empty string */
ph7_result_string(pCtx,"",0);
return PH7_OK;
}
/* Extract the string format */
zFormat = ph7_value_to_string(apArg[0],&nLen);
if( nLen < 1 ){
/* Empty string */
ph7_result_string(pCtx,"",0);
return PH7_OK;
}
/* Point to hashmap */
pMap = (ph7_hashmap *)apArg[1]->x.pOther;
/* Extract arguments from the hashmap */
n = PH7_HashmapValuesToSet(pMap,&sArg);
/* Format the string */
PH7_InputFormat(sprintfConsumer,pCtx,zFormat,nLen,n,(ph7_value **)SySetBasePtr(&sArg),0,TRUE);
/* Release the container */
SySetRelease(&sArg);
return PH7_OK;
}
/*
* Symisc eXtension.
* string size_format(int64 $size)
* Return a smart string represenation of the given size [i.e: 64-bit integer]
* Example:
* echo size_format(1*1024*1024*1024);// 1GB
* echo size_format(512*1024*1024); // 512 MB
* echo size_format(file_size(/path/to/my/file_8192)); //8KB
* Parameter
* $size
* Entity size in bytes.
* Return
* Formatted string representation of the given size.
*/
static int PH7_builtin_size_format(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
/*Kilo*/ /*Mega*/ /*Giga*/ /*Tera*/ /*Peta*/ /*Exa*/ /*Zeta*/
static const char zUnit[] = {"KMGTPEZ"};
sxi32 nRest,i_32;
ph7_int64 iSize;
int c = -1; /* index in zUnit[] */
if( nArg < 1 ){
/* Missing argument,return the empty string */
ph7_result_string(pCtx,"",0);
return PH7_OK;
}
/* Extract the given size */
iSize = ph7_value_to_int64(apArg[0]);
if( iSize < 100 /* Bytes */ ){
/* Don't bother formatting,return immediately */
ph7_result_string(pCtx,"0.1 KB",(int)sizeof("0.1 KB")-1);
return PH7_OK;
}
for(;;){
nRest = (sxi32)(iSize & 0x3FF);
iSize >>= 10;
c++;
if( (iSize & (~0 ^ 1023)) == 0 ){
break;
}
}
nRest /= 100;
if( nRest > 9 ){
nRest = 9;
}
if( iSize > 999 ){
c++;
nRest = 9;
iSize = 0;
}
i_32 = (sxi32)iSize;
/* Format */
ph7_result_string_format(pCtx,"%d.%d %cB",i_32,nRest,zUnit[c]);
return PH7_OK;
}
#if !defined(PH7_DISABLE_HASH_FUNC)
/*
* string md5(string $str[,bool $raw_output = false])
* Calculate the md5 hash of a string.
* Parameter
* $str
* Input string
* $raw_output
* If the optional raw_output is set to TRUE, then the md5 digest
* is instead returned in raw binary format with a length of 16.
* Return
* MD5 Hash as a 32-character hexadecimal string.
*/
static int PH7_builtin_md5(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
unsigned char zDigest[16];
int raw_output = FALSE;
const void *pIn;
int nLen;
if( nArg < 1 ){
/* Missing arguments,return the empty string */
ph7_result_string(pCtx,"",0);
return PH7_OK;
}
/* Extract the input string */
pIn = (const void *)ph7_value_to_string(apArg[0],&nLen);
if( nLen < 1 ){
/* Empty string */
ph7_result_string(pCtx,"",0);
return PH7_OK;
}
if( nArg > 1 && ph7_value_is_bool(apArg[1])){
raw_output = ph7_value_to_bool(apArg[1]);
}
/* Compute the MD5 digest */
SyMD5Compute(pIn,(sxu32)nLen,zDigest);
if( raw_output ){
/* Output raw digest */
ph7_result_string(pCtx,(const char *)zDigest,(int)sizeof(zDigest));
}else{
/* Perform a binary to hex conversion */
SyBinToHexConsumer((const void *)zDigest,sizeof(zDigest),HashConsumer,pCtx);
}
return PH7_OK;
}
/*
* string sha1(string $str[,bool $raw_output = false])
* Calculate the sha1 hash of a string.
* Parameter
* $str
* Input string
* $raw_output
* If the optional raw_output is set to TRUE, then the md5 digest
* is instead returned in raw binary format with a length of 16.
* Return
* SHA1 Hash as a 40-character hexadecimal string.
*/
static int PH7_builtin_sha1(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
unsigned char zDigest[20];
int raw_output = FALSE;
const void *pIn;
int nLen;
if( nArg < 1 ){
/* Missing arguments,return the empty string */
ph7_result_string(pCtx,"",0);
return PH7_OK;
}
/* Extract the input string */
pIn = (const void *)ph7_value_to_string(apArg[0],&nLen);
if( nLen < 1 ){
/* Empty string */
ph7_result_string(pCtx,"",0);
return PH7_OK;
}
if( nArg > 1 && ph7_value_is_bool(apArg[1])){
raw_output = ph7_value_to_bool(apArg[1]);
}
/* Compute the SHA1 digest */
SySha1Compute(pIn,(sxu32)nLen,zDigest);
if( raw_output ){
/* Output raw digest */
ph7_result_string(pCtx,(const char *)zDigest,(int)sizeof(zDigest));
}else{
/* Perform a binary to hex conversion */
SyBinToHexConsumer((const void *)zDigest,sizeof(zDigest),HashConsumer,pCtx);
}
return PH7_OK;
}
/*
* int64 crc32(string $str)
* Calculates the crc32 polynomial of a strin.
* Parameter
* $str
* Input string
* Return
* CRC32 checksum of the given input (64-bit integer).
*/
static int PH7_builtin_crc32(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const void *pIn;
sxu32 nCRC;
int nLen;
if( nArg < 1 ){
/* Missing arguments,return 0 */
ph7_result_int(pCtx,0);
return PH7_OK;
}
/* Extract the input string */
pIn = (const void *)ph7_value_to_string(apArg[0],&nLen);
if( nLen < 1 ){
/* Empty string */
ph7_result_int(pCtx,0);
return PH7_OK;
}
/* Calculate the sum */
nCRC = SyCrc32(pIn,(sxu32)nLen);
/* Return the CRC32 as 64-bit integer */
ph7_result_int64(pCtx,(ph7_int64)nCRC^ 0xFFFFFFFF);
return PH7_OK;
}
#endif /* PH7_DISABLE_HASH_FUNC */
/*
* Parse a CSV string and invoke the supplied callback for each processed xhunk.
*/
PH7_PRIVATE sxi32 PH7_ProcessCsv(
const char *zInput, /* Raw input */
int nByte, /* Input length */
int delim, /* Delimiter */
int encl, /* Enclosure */
int escape, /* Escape character */
sxi32 (*xConsumer)(const char *,int,void *), /* User callback */
void *pUserData /* Last argument to xConsumer() */
)
{
const char *zEnd = &zInput[nByte];
const char *zIn = zInput;
const char *zPtr;
int isEnc;
/* Start processing */
for(;;){
if( zIn >= zEnd ){
/* No more input to process */
break;
}
isEnc = 0;
zPtr = zIn;
/* Find the first delimiter */
while( zIn < zEnd ){
if( zIn[0] == delim && !isEnc){
/* Delimiter found,break imediately */
break;
}else if( zIn[0] == encl ){
/* Inside enclosure? */
isEnc = !isEnc;
}else if( zIn[0] == escape ){
/* Escape sequence */
zIn++;
}
/* Advance the cursor */
zIn++;
}
if( zIn > zPtr ){
int nByte = (int)(zIn-zPtr);
sxi32 rc;
/* Invoke the supllied callback */
if( zPtr[0] == encl ){
zPtr++;
nByte-=2;
}
if( nByte > 0 ){
rc = xConsumer(zPtr,nByte,pUserData);
if( rc == SXERR_ABORT ){
/* User callback request an operation abort */
break;
}
}
}
/* Ignore trailing delimiter */
while( zIn < zEnd && zIn[0] == delim ){
zIn++;
}
}
return SXRET_OK;
}
/*
* Default consumer callback for the CSV parsing routine defined above.
* All the processed input is insereted into an array passed as the last
* argument to this callback.
*/
PH7_PRIVATE sxi32 PH7_CsvConsumer(const char *zToken,int nTokenLen,void *pUserData)
{
ph7_value *pArray = (ph7_value *)pUserData;
ph7_value sEntry;
SyString sToken;
/* Insert the token in the given array */
SyStringInitFromBuf(&sToken,zToken,nTokenLen);
/* Remove trailing and leading white spcaces and null bytes */
SyStringFullTrimSafe(&sToken);
if( sToken.nByte < 1){
return SXRET_OK;
}
PH7_MemObjInitFromString(pArray->pVm,&sEntry,&sToken);
ph7_array_add_elem(pArray,0,&sEntry);
PH7_MemObjRelease(&sEntry);
return SXRET_OK;
}
/*
* array str_getcsv(string $input[,string $delimiter = ','[,string $enclosure = '"' [,string $escape='\\']]])
* Parse a CSV string into an array.
* Parameters
* $input
* The string to parse.
* $delimiter
* Set the field delimiter (one character only).
* $enclosure
* Set the field enclosure character (one character only).
* $escape
* Set the escape character (one character only). Defaults as a backslash (\)
* Return
* An indexed array containing the CSV fields or NULL on failure.
*/
static int PH7_builtin_str_getcsv(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zInput,*zPtr;
ph7_value *pArray;
int delim = ','; /* Delimiter */
int encl = '"' ; /* Enclosure */
int escape = '\\'; /* Escape character */
int nLen;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid arguments,return NULL */
ph7_result_null(pCtx);
return PH7_OK;
}
/* Extract the raw input */
zInput = ph7_value_to_string(apArg[0],&nLen);
if( nArg > 1 ){
int i;
if( ph7_value_is_string(apArg[1]) ){
/* Extract the delimiter */
zPtr = ph7_value_to_string(apArg[1],&i);
if( i > 0 ){
delim = zPtr[0];
}
}
if( nArg > 2 ){
if( ph7_value_is_string(apArg[2]) ){
/* Extract the enclosure */
zPtr = ph7_value_to_string(apArg[2],&i);
if( i > 0 ){
encl = zPtr[0];
}
}
if( nArg > 3 ){
if( ph7_value_is_string(apArg[3]) ){
/* Extract the escape character */
zPtr = ph7_value_to_string(apArg[3],&i);
if( i > 0 ){
escape = zPtr[0];
}
}
}
}
}
/* Create our array */
pArray = ph7_context_new_array(pCtx);
if( pArray == 0 ){
ph7_context_throw_error(pCtx,PH7_CTX_ERR,"PH7 is running out of memory");
ph7_result_null(pCtx);
return PH7_OK;
}
/* Parse the raw input */
PH7_ProcessCsv(zInput,nLen,delim,encl,escape,PH7_CsvConsumer,pArray);
/* Return the freshly created array */
ph7_result_value(pCtx,pArray);
return PH7_OK;
}
/*
* Extract a tag name from a raw HTML input and insert it in the given
* container.
* Refer to [strip_tags()].
*/
static sxi32 AddTag(SySet *pSet,const char *zTag,int nByte)
{
const char *zEnd = &zTag[nByte];
const char *zPtr;
SyString sEntry;
/* Strip tags */
for(;;){
while( zTag < zEnd && (zTag[0] == '<' || zTag[0] == '/' || zTag[0] == '?'
|| zTag[0] == '!' || zTag[0] == '-' || ((unsigned char)zTag[0] < 0xc0 && SyisSpace(zTag[0]))) ){
zTag++;
}
if( zTag >= zEnd ){
break;
}
zPtr = zTag;
/* Delimit the tag */
while(zTag < zEnd ){
if( (unsigned char)zTag[0] >= 0xc0 ){
/* UTF-8 stream */
zTag++;
SX_JMP_UTF8(zTag,zEnd);
}else if( !SyisAlphaNum(zTag[0]) ){
break;
}else{
zTag++;
}
}
if( zTag > zPtr ){
/* Perform the insertion */
SyStringInitFromBuf(&sEntry,zPtr,(int)(zTag-zPtr));
SyStringFullTrim(&sEntry);
SySetPut(pSet,(const void *)&sEntry);
}
/* Jump the trailing '>' */
zTag++;
}
return SXRET_OK;
}
/*
* Check if the given HTML tag name is present in the given container.
* Return SXRET_OK if present.SXERR_NOTFOUND otherwise.
* Refer to [strip_tags()].
*/
static sxi32 FindTag(SySet *pSet,const char *zTag,int nByte)
{
if( SySetUsed(pSet) > 0 ){
const char *zCur,*zEnd = &zTag[nByte];
SyString sTag;
while( zTag < zEnd && (zTag[0] == '<' || zTag[0] == '/' || zTag[0] == '?' ||
((unsigned char)zTag[0] < 0xc0 && SyisSpace(zTag[0]))) ){
zTag++;
}
/* Delimit the tag */
zCur = zTag;
while(zTag < zEnd ){
if( (unsigned char)zTag[0] >= 0xc0 ){
/* UTF-8 stream */
zTag++;
SX_JMP_UTF8(zTag,zEnd);
}else if( !SyisAlphaNum(zTag[0]) ){
break;
}else{
zTag++;
}
}
SyStringInitFromBuf(&sTag,zCur,zTag-zCur);
/* Trim leading white spaces and null bytes */
SyStringLeftTrimSafe(&sTag);
if( sTag.nByte > 0 ){
SyString *aEntry,*pEntry;
sxi32 rc;
sxu32 n;
/* Perform the lookup */
aEntry = (SyString *)SySetBasePtr(pSet);
for( n = 0 ; n < SySetUsed(pSet) ; ++n ){
pEntry = &aEntry[n];
/* Do the comparison */
rc = SyStringCmp(pEntry,&sTag,SyStrnicmp);
if( !rc ){
return SXRET_OK;
}
}
}
}
/* No such tag */
return SXERR_NOTFOUND;
}
/*
* This function tries to return a string [i.e: in the call context result buffer]
* with all NUL bytes,HTML and PHP tags stripped from a given string.
* Refer to [strip_tags()].
*/
PH7_PRIVATE sxi32 PH7_StripTagsFromString(ph7_context *pCtx,const char *zIn,int nByte,const char *zTaglist,int nTaglen)
{
const char *zEnd = &zIn[nByte];
const char *zPtr,*zTag;
SySet sSet;
/* initialize the set of allowed tags */
SySetInit(&sSet,&pCtx->pVm->sAllocator,sizeof(SyString));
if( nTaglen > 0 ){
/* Set of allowed tags */
AddTag(&sSet,zTaglist,nTaglen);
}
/* Set the empty string */
ph7_result_string(pCtx,"",0);
/* Start processing */
for(;;){
if(zIn >= zEnd){
/* No more input to process */
break;
}
zPtr = zIn;
/* Find a tag */
while( zIn < zEnd && zIn[0] != '<' && zIn[0] != 0 /* NUL byte */ ){
zIn++;
}
if( zIn > zPtr ){
/* Consume raw input */
ph7_result_string(pCtx,zPtr,(int)(zIn-zPtr));
}
/* Ignore trailing null bytes */
while( zIn < zEnd && zIn[0] == 0 ){
zIn++;
}
if(zIn >= zEnd){
/* No more input to process */
break;
}
if( zIn[0] == '<' ){
sxi32 rc;
zTag = zIn++;
/* Delimit the tag */
while( zIn < zEnd && zIn[0] != '>' ){
zIn++;
}
if( zIn < zEnd ){
zIn++; /* Ignore the trailing closing tag */
}
/* Query the set */
rc = FindTag(&sSet,zTag,(int)(zIn-zTag));
if( rc == SXRET_OK ){
/* Keep the tag */
ph7_result_string(pCtx,zTag,(int)(zIn-zTag));
}
}
}
/* Cleanup */
SySetRelease(&sSet);
return SXRET_OK;
}
/*
* string strip_tags(string $str[,string $allowable_tags])
* Strip HTML and PHP tags from a string.
* Parameters
* $str
* The input string.
* $allowable_tags
* You can use the optional second parameter to specify tags which should not be stripped.
* Return
* Returns the stripped string.
*/
static int PH7_builtin_strip_tags(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zTaglist = 0;
const char *zString;
int nTaglen = 0;
int nLen;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid arguments,return the empty string */
ph7_result_string(pCtx,"",0);
return PH7_OK;
}
/* Point to the raw string */
zString = ph7_value_to_string(apArg[0],&nLen);
if( nArg > 1 && ph7_value_is_string(apArg[1]) ){
/* Allowed tag */
zTaglist = ph7_value_to_string(apArg[1],&nTaglen);
}
/* Process input */
PH7_StripTagsFromString(pCtx,zString,nLen,zTaglist,nTaglen);
return PH7_OK;
}
/*
* string str_shuffle(string $str)
* Randomly shuffles a string.
* Parameters
* $str
* The input string.
* Return
* Returns the shuffled string.
*/
static int PH7_builtin_str_shuffle(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zString;
int nLen,i,c;
sxu32 iR;
if( nArg < 1 ){
/* Missing arguments,return the empty string */
ph7_result_string(pCtx,"",0);
return PH7_OK;
}
/* Extract the target string */
zString = ph7_value_to_string(apArg[0],&nLen);
if( nLen < 1 ){
/* Nothing to shuffle */
ph7_result_string(pCtx,"",0);
return PH7_OK;
}
/* Shuffle the string */
for( i = 0 ; i < nLen ; ++i ){
/* Generate a random number first */
iR = ph7_context_random_num(pCtx);
/* Extract a random offset */
c = zString[iR % nLen];
/* Append it */
ph7_result_string(pCtx,(const char *)&c,(int)sizeof(char));
}
return PH7_OK;
}
/*
* array str_split(string $string[,int $split_length = 1 ])
* Convert a string to an array.
* Parameters
* $str
* The input string.
* $split_length
* Maximum length of the chunk.
* Return
* If the optional split_length parameter is specified, the returned array
* will be broken down into chunks with each being split_length in length, otherwise
* each chunk will be one character in length. FALSE is returned if split_length is less than 1.
* If the split_length length exceeds the length of string, the entire string is returned
* as the first (and only) array element.
*/
static int PH7_builtin_str_split(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zString,*zEnd;
ph7_value *pArray,*pValue;
int split_len;
int nLen;
if( nArg < 1 ){
/* Missing arguments,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the target string */
zString = ph7_value_to_string(apArg[0],&nLen);
if( nLen < 1 ){
/* Nothing to process,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
split_len = (int)sizeof(char);
if( nArg > 1 ){
/* Split length */
split_len = ph7_value_to_int(apArg[1]);
if( split_len < 1 ){
/* Invalid length,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
if( split_len > nLen ){
split_len = nLen;
}
}
/* Create the array and the scalar value */
pArray = ph7_context_new_array(pCtx);
/*Chunk value */
pValue = ph7_context_new_scalar(pCtx);
if( pValue == 0 || pArray == 0 ){
/* Return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the end of the string */
zEnd = &zString[nLen];
/* Perform the requested operation */
for(;;){
int nMax;
if( zString >= zEnd ){
/* No more input to process */
break;
}
nMax = (int)(zEnd-zString);
if( nMax < split_len ){
split_len = nMax;
}
/* Copy the current chunk */
ph7_value_string(pValue,zString,split_len);
/* Insert it */
ph7_array_add_elem(pArray,0,pValue); /* Will make it's own copy */
/* reset the string cursor */
ph7_value_reset_string_cursor(pValue);
/* Update position */
zString += split_len;
}
/*
* 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;
}
/*
* Tokenize a raw string and extract the first non-space token.
* Refer to [strspn()].
*/
static sxi32 ExtractNonSpaceToken(const char **pzIn,const char *zEnd,SyString *pOut)
{
const char *zIn = *pzIn;
const char *zPtr;
/* Ignore leading white spaces */
while( zIn < zEnd && (unsigned char)zIn[0] < 0xc0 && SyisSpace(zIn[0]) ){
zIn++;
}
if( zIn >= zEnd ){
/* End of input */
return SXERR_EOF;
}
zPtr = zIn;
/* Extract the token */
while( zIn < zEnd && (unsigned char)zIn[0] < 0xc0 && !SyisSpace(zIn[0]) ){
zIn++;
}
SyStringInitFromBuf(pOut,zPtr,zIn-zPtr);
/* Synchronize pointers */
*pzIn = zIn;
/* Return to the caller */
return SXRET_OK;
}
/*
* Check if the given string contains only characters from the given mask.
* return the longest match.
* Refer to [strspn()].
*/
static int LongestStringMask(const char *zString,int nLen,const char *zMask,int nMaskLen)
{
const char *zEnd = &zString[nLen];
const char *zIn = zString;
int i,c;
for(;;){
if( zString >= zEnd ){
break;
}
/* Extract current character */
c = zString[0];
/* Perform the lookup */
for( i = 0 ; i < nMaskLen ; i++ ){
if( c == zMask[i] ){
/* Character found */
break;
}
}
if( i >= nMaskLen ){
/* Character not in the current mask,break immediately */
break;
}
/* Advance cursor */
zString++;
}
/* Longest match */
return (int)(zString-zIn);
}
/*
* Do the reverse operation of the previous function [i.e: LongestStringMask()].
* Refer to [strcspn()].
*/
static int LongestStringMask2(const char *zString,int nLen,const char *zMask,int nMaskLen)
{
const char *zEnd = &zString[nLen];
const char *zIn = zString;
int i,c;
for(;;){
if( zString >= zEnd ){
break;
}
/* Extract current character */
c = zString[0];
/* Perform the lookup */
for( i = 0 ; i < nMaskLen ; i++ ){
if( c == zMask[i] ){
break;
}
}
if( i < nMaskLen ){
/* Character in the current mask,break immediately */
break;
}
/* Advance cursor */
zString++;
}
/* Longest match */
return (int)(zString-zIn);
}
/*
* int strspn(string $str,string $mask[,int $start[,int $length]])
* Finds the length of the initial segment of a string consisting entirely
* of characters contained within a given mask.
* Parameters
* $str
* The input string.
* $mask
* The list of allowable characters.
* $start
* The position in subject to start searching.
* If start is given and is non-negative, then strspn() will begin examining
* subject at the start'th position. 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 given and is negative, then strspn() will begin examining subject at the
* start'th position from the end of subject.
* $length
* The length of the segment from subject to examine.
* If length is given and is non-negative, then subject will be examined for length
* characters after the starting position.
* If lengthis given and is negative, then subject will be examined from the starting
* position up to length characters from the end of subject.
* Return
* Returns the length of the initial segment of subject which consists entirely of characters
* in mask.
*/
static int PH7_builtin_strspn(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zString,*zMask,*zEnd;
int iMasklen,iLen;
SyString sToken;
int iCount = 0;
int rc;
if( nArg < 2 ){
/* Missing agruments,return zero */
ph7_result_int(pCtx,0);
return PH7_OK;
}
/* Extract the target string */
zString = ph7_value_to_string(apArg[0],&iLen);
/* Extract the mask */
zMask = ph7_value_to_string(apArg[1],&iMasklen);
if( iLen < 1 || iMasklen < 1 ){
/* Nothing to process,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 ){
const char *zBase = &zString[iLen + nOfft];
if( zBase > zString ){
iLen = (int)(&zString[iLen]-zBase);
zString = zBase;
}else{
/* Invalid offset */
ph7_result_int(pCtx,0);
return PH7_OK;
}
}else{
if( nOfft >= iLen ){
/* Invalid offset */
ph7_result_int(pCtx,0);
return PH7_OK;
}else{
/* Update offset */
zString += nOfft;
iLen -= nOfft;
}
}
if( nArg > 3 ){
int iUserlen;
/* Extract the desired length */
iUserlen = ph7_value_to_int(apArg[3]);
if( iUserlen > 0 && iUserlen < iLen ){
iLen = iUserlen;
}
}
}
/* Point to the end of the string */
zEnd = &zString[iLen];
/* Extract the first non-space token */
rc = ExtractNonSpaceToken(&zString,zEnd,&sToken);
if( rc == SXRET_OK && sToken.nByte > 0 ){
/* Compare against the current mask */
iCount = LongestStringMask(sToken.zString,(int)sToken.nByte,zMask,iMasklen);
}
/* Longest match */
ph7_result_int(pCtx,iCount);
return PH7_OK;
}
/*
* int strcspn(string $str,string $mask[,int $start[,int $length]])
* Find length of initial segment not matching mask.
* Parameters
* $str
* The input string.
* $mask
* The list of not allowed characters.
* $start
* The position in subject to start searching.
* If start is given and is non-negative, then strspn() will begin examining
* subject at the start'th position. 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 given and is negative, then strspn() will begin examining subject at the
* start'th position from the end of subject.
* $length
* The length of the segment from subject to examine.
* If length is given and is non-negative, then subject will be examined for length
* characters after the starting position.
* If lengthis given and is negative, then subject will be examined from the starting
* position up to length characters from the end of subject.
* Return
* Returns the length of the segment as an integer.
*/
static int PH7_builtin_strcspn(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zString,*zMask,*zEnd;
int iMasklen,iLen;
SyString sToken;
int iCount = 0;
int rc;
if( nArg < 2 ){
/* Missing agruments,return zero */
ph7_result_int(pCtx,0);
return PH7_OK;
}
/* Extract the target string */
zString = ph7_value_to_string(apArg[0],&iLen);
/* Extract the mask */
zMask = ph7_value_to_string(apArg[1],&iMasklen);
if( iLen < 1 ){
/* Nothing to process,return zero */
ph7_result_int(pCtx,0);
return PH7_OK;
}
if( iMasklen < 1 ){
/* No given mask,return the string length */
ph7_result_int(pCtx,iLen);
return PH7_OK;
}
if( nArg > 2 ){
int nOfft;
/* Extract the offset */
nOfft = ph7_value_to_int(apArg[2]);
if( nOfft < 0 ){
const char *zBase = &zString[iLen + nOfft];
if( zBase > zString ){
iLen = (int)(&zString[iLen]-zBase);
zString = zBase;
}else{
/* Invalid offset */
ph7_result_int(pCtx,0);
return PH7_OK;
}
}else{
if( nOfft >= iLen ){
/* Invalid offset */
ph7_result_int(pCtx,0);
return PH7_OK;
}else{
/* Update offset */
zString += nOfft;
iLen -= nOfft;
}
}
if( nArg > 3 ){
int iUserlen;
/* Extract the desired length */
iUserlen = ph7_value_to_int(apArg[3]);
if( iUserlen > 0 && iUserlen < iLen ){
iLen = iUserlen;
}
}
}
/* Point to the end of the string */
zEnd = &zString[iLen];
/* Extract the first non-space token */
rc = ExtractNonSpaceToken(&zString,zEnd,&sToken);
if( rc == SXRET_OK && sToken.nByte > 0 ){
/* Compare against the current mask */
iCount = LongestStringMask2(sToken.zString,(int)sToken.nByte,zMask,iMasklen);
}
/* Longest match */
ph7_result_int(pCtx,iCount);
return PH7_OK;
}
/*
* string strpbrk(string $haystack,string $char_list)
* Search a string for any of a set of characters.
* Parameters
* $haystack
* The string where char_list is looked for.
* $char_list
* This parameter is case sensitive.
* Return
* Returns a string starting from the character found, or FALSE if it is not found.
*/
static int PH7_builtin_strpbrk(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zString,*zList,*zEnd;
int iLen,iListLen,i,c;
sxu32 nOfft,nMax;
sxi32 rc;
if( nArg < 2 ){
/* Missing arguments,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the haystack and the char list */
zString = ph7_value_to_string(apArg[0],&iLen);
zList = ph7_value_to_string(apArg[1],&iListLen);
if( iLen < 1 ){
/* Nothing to process,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Point to the end of the string */
zEnd = &zString[iLen];
nOfft = nMax = SXU32_HIGH;
/* perform the requested operation */
for( i = 0 ; i < iListLen ; i++ ){
c = zList[i];
rc = SyByteFind(zString,(sxu32)iLen,c,&nMax);
if( rc == SXRET_OK ){
if( nMax < nOfft ){
nOfft = nMax;
}
}
}
if( nOfft == SXU32_HIGH ){
/* No such substring,return FALSE */
ph7_result_bool(pCtx,0);
}else{
/* Return the substring */
ph7_result_string(pCtx,&zString[nOfft],(int)(zEnd-&zString[nOfft]));
}
return PH7_OK;
}
/*
* string soundex(string $str)
* Calculate the soundex key of a string.
* Parameters
* $str
* The input string.
* Return
* Returns the soundex key as a string.
* Note:
* This implementation is based on the one found in the SQLite3
* source tree.
*/
static int PH7_builtin_soundex(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const unsigned char *zIn;
char zResult[8];
int i, j;
static const unsigned char iCode[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0,
1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0,
0, 0, 1, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0,
1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0,
};
if( nArg < 1 ){
/* Missing arguments,return the empty string */
ph7_result_string(pCtx,"",0);
return PH7_OK;
}
zIn = (unsigned char *)ph7_value_to_string(apArg[0],0);
for(i=0; zIn[i] && zIn[i] < 0xc0 && !SyisAlpha(zIn[i]); i++){}
if( zIn[i] ){
unsigned char prevcode = iCode[zIn[i]&0x7f];
zResult[0] = (char)SyToUpper(zIn[i]);
for(j=1; j<4 && zIn[i]; i++){
int code = iCode[zIn[i]&0x7f];
if( code>0 ){
if( code!=prevcode ){
prevcode = (unsigned char)code;
zResult[j++] = (char)code + '0';
}
}else{
prevcode = 0;
}
}
while( j<4 ){
zResult[j++] = '0';
}
ph7_result_string(pCtx,zResult,4);
}else{
ph7_result_string(pCtx,"?000",4);
}
return PH7_OK;
}
/*
* string wordwrap(string $str[,int $width = 75[,string $break = "\n"]])
* Wraps a string to a given number of characters.
* Parameters
* $str
* The input string.
* $width
* The column width.
* $break
* The line is broken using the optional break parameter.
* Return
* Returns the given string wrapped at the specified column.
*/
static int PH7_builtin_wordwrap(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zIn,*zEnd,*zBreak;
int iLen,iBreaklen,iChunk;
if( nArg < 1 ){
/* Missing arguments,return the empty string */
ph7_result_string(pCtx,"",0);
return PH7_OK;
}
/* Extract the input string */
zIn = ph7_value_to_string(apArg[0],&iLen);
if( iLen < 1 ){
/* Nothing to process,return the empty string */
ph7_result_string(pCtx,"",0);
return PH7_OK;
}
/* Chunk length */
iChunk = 75;
iBreaklen = 0;
zBreak = ""; /* cc warning */
if( nArg > 1 ){
iChunk = ph7_value_to_int(apArg[1]);
if( iChunk < 1 ){
iChunk = 75;
}
if( nArg > 2 ){
zBreak = ph7_value_to_string(apArg[2],&iBreaklen);
}
}
if( iBreaklen < 1 ){
/* Set a default column break */
#ifdef __WINNT__
zBreak = "\r\n";
iBreaklen = (int)sizeof("\r\n")-1;
#else
zBreak = "\n";
iBreaklen = (int)sizeof(char);
#endif
}
/* Perform the requested operation */
zEnd = &zIn[iLen];
for(;;){
int nMax;
if( zIn >= zEnd ){
/* No more input to process */
break;
}
nMax = (int)(zEnd-zIn);
if( iChunk > nMax ){
iChunk = nMax;
}
/* Append the column first */
ph7_result_string(pCtx,zIn,iChunk); /* Will make it's own copy */
/* Advance the cursor */
zIn += iChunk;
if( zIn < zEnd ){
/* Append the line break */
ph7_result_string(pCtx,zBreak,iBreaklen);
}
}
return PH7_OK;
}
/*
* Check if the given character is a member of the given mask.
* Return TRUE on success. FALSE otherwise.
* Refer to [strtok()].
*/
static int CheckMask(int c,const char *zMask,int nMasklen,int *pOfft)
{
int i;
for( i = 0 ; i < nMasklen ; ++i ){
if( c == zMask[i] ){
if( pOfft ){
*pOfft = i;
}
return TRUE;
}
}
return FALSE;
}
/*
* Extract a single token from the input stream.
* Refer to [strtok()].
*/
static sxi32 ExtractToken(const char **pzIn,const char *zEnd,const char *zMask,int nMasklen,SyString *pOut)
{
const char *zIn = *pzIn;
const char *zPtr;
/* Ignore leading delimiter */
while( zIn < zEnd && (unsigned char)zIn[0] < 0xc0 && CheckMask(zIn[0],zMask,nMasklen,0) ){
zIn++;
}
if( zIn >= zEnd ){
/* End of input */
return SXERR_EOF;
}
zPtr = zIn;
/* Extract the token */
while( zIn < zEnd ){
if( (unsigned char)zIn[0] >= 0xc0 ){
/* UTF-8 stream */
zIn++;
SX_JMP_UTF8(zIn,zEnd);
}else{
if( CheckMask(zIn[0],zMask,nMasklen,0) ){
break;
}
zIn++;
}
}
SyStringInitFromBuf(pOut,zPtr,zIn-zPtr);
/* Update the cursor */
*pzIn = zIn;
/* Return to the caller */
return SXRET_OK;
}
/* strtok auxiliary private data */
typedef struct strtok_aux_data strtok_aux_data;
struct strtok_aux_data
{
const char *zDup; /* Complete duplicate of the input */
const char *zIn; /* Current input stream */
const char *zEnd; /* End of input */
};
/*
* string strtok(string $str,string $token)
* string strtok(string $token)
* strtok() splits a string (str) into smaller strings (tokens), with each token
* being delimited by any character from token. That is, if you have a string like
* "This is an example string" you could tokenize this string into its individual
* words by using the space character as the token.
* Note that only the first call to strtok uses the string argument. Every subsequent
* call to strtok only needs the token to use, as it keeps track of where it is in
* the current string. To start over, or to tokenize a new string you simply call strtok
* with the string argument again to initialize it. Note that you may put multiple tokens
* in the token parameter. The string will be tokenized when any one of the characters in
* the argument are found.
* Parameters
* $str
* The string being split up into smaller strings (tokens).
* $token
* The delimiter used when splitting up str.
* Return
* Current token or FALSE on EOF.
*/
static int PH7_builtin_strtok(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
strtok_aux_data *pAux;
const char *zMask;
SyString sToken;
int nMasklen;
sxi32 rc;
if( nArg < 2 ){
/* Extract top aux data */
pAux = (strtok_aux_data *)ph7_context_peek_aux_data(pCtx);
if( pAux == 0 ){
/* No aux data,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
nMasklen = 0;
zMask = ""; /* cc warning */
if( nArg > 0 ){
/* Extract the mask */
zMask = ph7_value_to_string(apArg[0],&nMasklen);
}
if( nMasklen < 1 ){
/* Invalid mask,return FALSE */
ph7_context_free_chunk(pCtx,(void *)pAux->zDup);
ph7_context_free_chunk(pCtx,pAux);
(void)ph7_context_pop_aux_data(pCtx);
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the token */
rc = ExtractToken(&pAux->zIn,pAux->zEnd,zMask,nMasklen,&sToken);
if( rc != SXRET_OK ){
/* EOF ,discard the aux data */
ph7_context_free_chunk(pCtx,(void *)pAux->zDup);
ph7_context_free_chunk(pCtx,pAux);
(void)ph7_context_pop_aux_data(pCtx);
ph7_result_bool(pCtx,0);
}else{
/* Return the extracted token */
ph7_result_string(pCtx,sToken.zString,(int)sToken.nByte);
}
}else{
const char *zInput,*zCur;
char *zDup;
int nLen;
/* Extract the raw input */
zCur = zInput = ph7_value_to_string(apArg[0],&nLen);
if( nLen < 1 ){
/* Empty input,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the mask */
zMask = ph7_value_to_string(apArg[1],&nMasklen);
if( nMasklen < 1 ){
/* Set a default mask */
#define TOK_MASK " \n\t\r\f"
zMask = TOK_MASK;
nMasklen = (int)sizeof(TOK_MASK) - 1;
#undef TOK_MASK
}
/* Extract a single token */
rc = ExtractToken(&zInput,&zInput[nLen],zMask,nMasklen,&sToken);
if( rc != SXRET_OK ){
/* Empty input */
ph7_result_bool(pCtx,0);
return PH7_OK;
}else{
/* Return the extracted token */
ph7_result_string(pCtx,sToken.zString,(int)sToken.nByte);
}
/* Create our auxilliary data and copy the input */
pAux = (strtok_aux_data *)ph7_context_alloc_chunk(pCtx,sizeof(strtok_aux_data),TRUE,FALSE);
if( pAux ){
nLen -= (int)(zInput-zCur);
if( nLen < 1 ){
ph7_context_free_chunk(pCtx,pAux);
return PH7_OK;
}
/* Duplicate input */
zDup = (char *)ph7_context_alloc_chunk(pCtx,(unsigned int)(nLen+1),TRUE,FALSE);
if( zDup ){
SyMemcpy(zInput,zDup,(sxu32)nLen);
/* Register the aux data */
pAux->zDup = pAux->zIn = zDup;
pAux->zEnd = &zDup[nLen];
ph7_context_push_aux_data(pCtx,pAux);
}
}
}
return PH7_OK;
}
/*
* string str_pad(string $input,int $pad_length[,string $pad_string = " " [,int $pad_type = STR_PAD_RIGHT]])
* Pad a string to a certain length with another string
* Parameters
* $input
* The input string.
* $pad_length
* If the value of pad_length is negative, less than, or equal to the length of the input
* string, no padding takes place.
* $pad_string
* Note:
* The pad_string WIIL NOT BE truncated if the required number of padding characters can't be evenly
* divided by the pad_string's length.
* $pad_type
* Optional argument pad_type can be STR_PAD_RIGHT, STR_PAD_LEFT, or STR_PAD_BOTH. If pad_type
* is not specified it is assumed to be STR_PAD_RIGHT.
* Return
* The padded string.
*/
static int PH7_builtin_str_pad(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
int iLen,iPadlen,iType,i,iDiv,iStrpad,iRealPad,jPad;
const char *zIn,*zPad;
if( nArg < 2 ){
/* Missing arguments,return the empty string */
ph7_result_string(pCtx,"",0);
return PH7_OK;
}
/* Extract the target string */
zIn = ph7_value_to_string(apArg[0],&iLen);
/* Padding length */
iRealPad = iPadlen = ph7_value_to_int(apArg[1]);
if( iPadlen > 0 ){
iPadlen -= iLen;
}
if( iPadlen < 1 ){
/* Return the string verbatim */
ph7_result_string(pCtx,zIn,iLen);
return PH7_OK;
}
zPad = " "; /* Whitespace padding */
iStrpad = (int)sizeof(char);
iType = 1 ; /* STR_PAD_RIGHT */
if( nArg > 2 ){
/* Padding string */
zPad = ph7_value_to_string(apArg[2],&iStrpad);
if( iStrpad < 1 ){
/* Empty string */
zPad = " "; /* Whitespace padding */
iStrpad = (int)sizeof(char);
}
if( nArg > 3 ){
/* Padd type */
iType = ph7_value_to_int(apArg[3]);
if( iType != 0 /* STR_PAD_LEFT */ && iType != 2 /* STR_PAD_BOTH */ ){
iType = 1 ; /* STR_PAD_RIGHT */
}
}
}
iDiv = 1;
if( iType == 2 ){
iDiv = 2; /* STR_PAD_BOTH */
}
/* Perform the requested operation */
if( iType == 0 /* STR_PAD_LEFT */ || iType == 2 /* STR_PAD_BOTH */ ){
jPad = iStrpad;
for( i = 0 ; i < iPadlen/iDiv ; i += jPad ){
/* Padding */
if( (int)ph7_context_result_buf_length(pCtx) + iLen + jPad >= iRealPad ){
break;
}
ph7_result_string(pCtx,zPad,jPad);
}
if( iType == 0 /* STR_PAD_LEFT */ ){
while( (int)ph7_context_result_buf_length(pCtx) + iLen < iRealPad ){
jPad = iRealPad - (iLen + (int)ph7_context_result_buf_length(pCtx) );
if( jPad > iStrpad ){
jPad = iStrpad;
}
if( jPad < 1){
break;
}
ph7_result_string(pCtx,zPad,jPad);
}
}
}
if( iLen > 0 ){
/* Append the input string */
ph7_result_string(pCtx,zIn,iLen);
}
if( iType == 1 /* STR_PAD_RIGHT */ || iType == 2 /* STR_PAD_BOTH */ ){
for( i = 0 ; i < iPadlen/iDiv ; i += iStrpad ){
/* Padding */
if( (int)ph7_context_result_buf_length(pCtx) + iStrpad >= iRealPad ){
break;
}
ph7_result_string(pCtx,zPad,iStrpad);
}
while( (int)ph7_context_result_buf_length(pCtx) < iRealPad ){
jPad = iRealPad - (int)ph7_context_result_buf_length(pCtx);
if( jPad > iStrpad ){
jPad = iStrpad;
}
if( jPad < 1){
break;
}
ph7_result_string(pCtx,zPad,jPad);
}
}
return PH7_OK;
}
/*
* String replacement private data.
*/
typedef struct str_replace_data str_replace_data;
struct str_replace_data
{
/* The following two fields are only used by the strtr function */
SyBlob *pWorker; /* Working buffer */
ProcStringMatch xMatch; /* Pattern match routine */
/* The following two fields are only used by the str_replace function */
SySet *pCollector; /* Argument collector*/
ph7_context *pCtx; /* Call context */
};
/*
* Remove a substring.
*/
#define STRDEL(SRC,SLEN,OFFT,ILEN){\
for(;;){\
if( OFFT + ILEN >= SLEN ) break; SRC[OFFT] = SRC[OFFT+ILEN]; ++OFFT;\
}\
}
/*
* Shift right and insert algorithm.
*/
#define SHIFTRANDINSERT(SRC,LEN,OFFT,ENTRY,ELEN){\
sxu32 INLEN = LEN - OFFT;\
for(;;){\
if( LEN > 0 ){ LEN--; } if(INLEN < 1 ) break; SRC[LEN + ELEN] = SRC[LEN] ; --INLEN; \
}\
for(;;){\
if(ELEN < 1)break; SRC[OFFT] = ENTRY[0]; OFFT++; ENTRY++; --ELEN;\
}\
}
/*
* Replace all occurrences of the search string at offset (nOfft) with the given
* replacement string [i.e: zReplace].
*/
static int StringReplace(SyBlob *pWorker,sxu32 nOfft,int nLen,const char *zReplace,int nReplen)
{
char *zInput = (char *)SyBlobData(pWorker);
sxu32 n,m;
n = SyBlobLength(pWorker);
m = nOfft;
/* Delete the old entry */
STRDEL(zInput,n,m,nLen);
SyBlobLength(pWorker) -= nLen;
if( nReplen > 0 ){
sxi32 iRep = nReplen;
sxi32 rc;
/*
* Make sure the working buffer is big enough to hold the replacement
* string.
*/
rc = SyBlobAppend(pWorker,0/* Grow without an append operation*/,(sxu32)nReplen);
if( rc != SXRET_OK ){
/* Simply ignore any memory failure problem */
return SXRET_OK;
}
/* Perform the insertion now */
zInput = (char *)SyBlobData(pWorker);
n = SyBlobLength(pWorker);
SHIFTRANDINSERT(zInput,n,nOfft,zReplace,iRep);
SyBlobLength(pWorker) += nReplen;
}
return SXRET_OK;
}
/*
* String replacement walker callback.
* The following callback is invoked for each array entry that hold
* the replace string.
* Refer to the strtr() implementation for more information.
*/
static int StringReplaceWalker(ph7_value *pKey,ph7_value *pData,void *pUserData)
{
str_replace_data *pRepData = (str_replace_data *)pUserData;
const char *zTarget,*zReplace;
SyBlob *pWorker;
int tLen,nLen;
sxu32 nOfft;
sxi32 rc;
/* Point to the working buffer */
pWorker = pRepData->pWorker;
if( !ph7_value_is_string(pKey) ){
/* Target and replace must be a string */
return PH7_OK;
}
/* Extract the target and the replace */
zTarget = ph7_value_to_string(pKey,&tLen);
if( tLen < 1 ){
/* Empty target,return immediately */
return PH7_OK;
}
/* Perform a pattern search */
rc = pRepData->xMatch(SyBlobData(pWorker),SyBlobLength(pWorker),(const void *)zTarget,(sxu32)tLen,&nOfft);
if( rc != SXRET_OK ){
/* Pattern not found */
return PH7_OK;
}
/* Extract the replace string */
zReplace = ph7_value_to_string(pData,&nLen);
/* Perform the replace process */
StringReplace(pWorker,nOfft,tLen,zReplace,nLen);
/* All done */
return PH7_OK;
}
/*
* The following walker callback is invoked by the str_rplace() function inorder
* to collect search/replace string.
* This callback is invoked only if the given argument is of type array.
*/
static int StrReplaceWalker(ph7_value *pKey,ph7_value *pData,void *pUserData)
{
str_replace_data *pRep = (str_replace_data *)pUserData;
SyString sWorker;
const char *zIn;
int nByte;
/* Extract a string representation of the given argument */
zIn = ph7_value_to_string(pData,&nByte);
SyStringInitFromBuf(&sWorker,0,0);
if( nByte > 0 ){
char *zDup;
/* Duplicate the chunk */
zDup = (char *)ph7_context_alloc_chunk(pRep->pCtx,(unsigned int)nByte,FALSE,
TRUE /* Release the chunk automatically,upon this context is destroyd */
);
if( zDup == 0 ){
/* Ignore any memory failure problem */
ph7_context_throw_error(pRep->pCtx,PH7_CTX_ERR,"PH7 is running out of memory");
return PH7_OK;
}
SyMemcpy(zIn,zDup,(sxu32)nByte);
/* Save the chunk */
SyStringInitFromBuf(&sWorker,zDup,nByte);
}
/* Save for later processing */
SySetPut(pRep->pCollector,(const void *)&sWorker);
/* All done */
SXUNUSED(pKey); /* cc warning */
return PH7_OK;
}
/*
* mixed str_replace(mixed $search,mixed $replace,mixed $subject[,int &$count ])
* mixed str_ireplace(mixed $search,mixed $replace,mixed $subject[,int &$count ])
* Replace all occurrences of the search string with the replacement string.
* Parameters
* If search and replace are arrays, then str_replace() takes a value from each
* array and uses them to search and replace on subject. If replace has fewer values
* than search, then an empty string is used for the rest of replacement values.
* If search is an array and replace is a string, then this replacement string is used
* for every value of search. The converse would not make sense, though.
* If search or replace are arrays, their elements are processed first to last.
* $search
* The value being searched for, otherwise known as the needle. An array may be used
* to designate multiple needles.
* $replace
* The replacement value that replaces found search values. An array may be used
* to designate multiple replacements.
* $subject
* The string or array being searched and replaced on, otherwise known as the haystack.
* If subject is an array, then the search and replace is performed with every entry
* of subject, and the return value is an array as well.
* $count (Not used)
* If passed, this will be set to the number of replacements performed.
* Return
* This function returns a string or an array with the replaced values.
*/
static int PH7_builtin_str_replace(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
SyString sTemp,*pSearch,*pReplace;
ProcStringMatch xMatch;
const char *zIn,*zFunc;
str_replace_data sRep;
SyBlob sWorker;
SySet sReplace;
SySet sSearch;
int rep_str;
int nByte;
sxi32 rc;
if( nArg < 3 ){
/* Missing/Invalid arguments,return null */
ph7_result_null(pCtx);
return PH7_OK;
}
/* Initialize fields */
SySetInit(&sSearch,&pCtx->pVm->sAllocator,sizeof(SyString));
SySetInit(&sReplace,&pCtx->pVm->sAllocator,sizeof(SyString));
SyBlobInit(&sWorker,&pCtx->pVm->sAllocator);
SyZero(&sRep,sizeof(str_replace_data));
sRep.pCtx = pCtx;
sRep.pCollector = &sSearch;
rep_str = 0;
/* Extract the subject */
zIn = ph7_value_to_string(apArg[2],&nByte);
if( nByte < 1 ){
/* Nothing to replace,return the empty string */
ph7_result_string(pCtx,"",0);
return PH7_OK;
}
/* Copy the subject */
SyBlobAppend(&sWorker,(const void *)zIn,(sxu32)nByte);
/* Search string */
if( ph7_value_is_array(apArg[0]) ){
/* Collect search string */
ph7_array_walk(apArg[0],StrReplaceWalker,&sRep);
}else{
/* Single pattern */
zIn = ph7_value_to_string(apArg[0],&nByte);
if( nByte < 1 ){
/* Return the subject untouched since no search string is available */
ph7_result_value(pCtx,apArg[2]/* Subject as thrird argument*/);
return PH7_OK;
}
SyStringInitFromBuf(&sTemp,zIn,nByte);
/* Save for later processing */
SySetPut(&sSearch,(const void *)&sTemp);
}
/* Replace string */
if( ph7_value_is_array(apArg[1]) ){
/* Collect replace string */
sRep.pCollector = &sReplace;
ph7_array_walk(apArg[1],StrReplaceWalker,&sRep);
}else{
/* Single needle */
zIn = ph7_value_to_string(apArg[1],&nByte);
rep_str = 1;
SyStringInitFromBuf(&sTemp,zIn,nByte);
/* Save for later processing */
SySetPut(&sReplace,(const void *)&sTemp);
}
/* Reset loop cursors */
SySetResetCursor(&sSearch);
SySetResetCursor(&sReplace);
pReplace = pSearch = 0; /* cc warning */
SyStringInitFromBuf(&sTemp,"",0);
/* Extract function name */
zFunc = ph7_function_name(pCtx);
/* Set the default pattern match routine */
xMatch = SyBlobSearch;
if( SyStrncmp(zFunc,"str_ireplace",sizeof("str_ireplace") - 1) == 0 ){
/* Case insensitive pattern match */
xMatch = iPatternMatch;
}
/* Start the replace process */
while( SXRET_OK == SySetGetNextEntry(&sSearch,(void **)&pSearch) ){
sxu32 nCount,nOfft;
if( pSearch->nByte < 1 ){
/* Empty string,ignore */
continue;
}
/* Extract the replace string */
if( rep_str ){
pReplace = (SyString *)SySetPeek(&sReplace);
}else{
if( SXRET_OK != SySetGetNextEntry(&sReplace,(void **)&pReplace) ){
/* Sepecial case when 'replace set' has fewer values than the search set.
* An empty string is used for the rest of replacement values
*/
pReplace = 0;
}
}
if( pReplace == 0 ){
/* Use an empty string instead */
pReplace = &sTemp;
}
nOfft = nCount = 0;
for(;;){
if( nCount >= SyBlobLength(&sWorker) ){
break;
}
/* Perform a pattern lookup */
rc = xMatch(SyBlobDataAt(&sWorker,nCount),SyBlobLength(&sWorker) - nCount,(const void *)pSearch->zString,
pSearch->nByte,&nOfft);
if( rc != SXRET_OK ){
/* Pattern not found */
break;
}
/* Perform the replace operation */
StringReplace(&sWorker,nCount+nOfft,(int)pSearch->nByte,pReplace->zString,(int)pReplace->nByte);
/* Increment offset counter */
nCount += nOfft + pReplace->nByte;
}
}
/* All done,clean-up the mess left behind */
ph7_result_string(pCtx,(const char *)SyBlobData(&sWorker),(int)SyBlobLength(&sWorker));
SySetRelease(&sSearch);
SySetRelease(&sReplace);
SyBlobRelease(&sWorker);
return PH7_OK;
}
/*
* string strtr(string $str,string $from,string $to)
* string strtr(string $str,array $replace_pairs)
* Translate characters or replace substrings.
* Parameters
* $str
* The string being translated.
* $from
* The string being translated to to.
* $to
* The string replacing from.
* $replace_pairs
* The replace_pairs parameter may be used instead of to and
* from, in which case it's an array in the form array('from' => 'to', ...).
* Return
* The translated string.
* If replace_pairs contains a key which is an empty string (""), FALSE will be returned.
*/
static int PH7_builtin_strtr(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zIn;
int nLen;
if( nArg < 1 ){
/* Nothing to replace,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
zIn = ph7_value_to_string(apArg[0],&nLen);
if( nLen < 1 || nArg < 2 ){
/* Invalid arguments */
ph7_result_string(pCtx,zIn,nLen);
return PH7_OK;
}
if( nArg == 2 && ph7_value_is_array(apArg[1]) ){
str_replace_data sRepData;
SyBlob sWorker;
/* Initilaize the working buffer */
SyBlobInit(&sWorker,&pCtx->pVm->sAllocator);
/* Copy raw string */
SyBlobAppend(&sWorker,(const void *)zIn,(sxu32)nLen);
/* Init our replace data instance */
sRepData.pWorker = &sWorker;
sRepData.xMatch = SyBlobSearch;
/* Iterate throw array entries and perform the replace operation.*/
ph7_array_walk(apArg[1],StringReplaceWalker,&sRepData);
/* All done, return the result string */
ph7_result_string(pCtx,(const char *)SyBlobData(&sWorker),
(int)SyBlobLength(&sWorker)); /* Will make it's own copy */
/* Clean-up */
SyBlobRelease(&sWorker);
}else{
int i,flen,tlen,c,iOfft;
const char *zFrom,*zTo;
if( nArg < 3 ){
/* Nothing to replace */
ph7_result_string(pCtx,zIn,nLen);
return PH7_OK;
}
/* Extract given arguments */
zFrom = ph7_value_to_string(apArg[1],&flen);
zTo = ph7_value_to_string(apArg[2],&tlen);
if( flen < 1 || tlen < 1 ){
/* Nothing to replace */
ph7_result_string(pCtx,zIn,nLen);
return PH7_OK;
}
/* Start the replace process */
for( i = 0 ; i < nLen ; ++i ){
c = zIn[i];
if( CheckMask(c,zFrom,flen,&iOfft) ){
if ( iOfft < tlen ){
c = zTo[iOfft];
}
}
ph7_result_string(pCtx,(const char *)&c,(int)sizeof(char));
}
}
return PH7_OK;
}
/*
* Parse an INI string.
* According to wikipedia
* The INI file format is an informal standard for configuration files for some platforms or software.
* INI files are simple text files with a basic structure composed of "sections" and "properties".
* Format
* Properties
* The basic element contained in an INI file is the property. Every property has a name and a value
* delimited by an equals sign (=). The name appears to the left of the equals sign.
* Example:
* name=value
* Sections
* Properties may be grouped into arbitrarily named sections. The section name appears on a line by itself
* in square brackets ([ and ]). All properties after the section declaration are associated with that section.
* There is no explicit "end of section" delimiter; sections end at the next section declaration
* or the end of the file. Sections may not be nested.
* Example:
* [section]
* Comments
* Semicolons (;) at the beginning of the line indicate a comment. Comment lines are ignored.
* This function return an array holding parsed values on success.FALSE otherwise.
*/
PH7_PRIVATE sxi32 PH7_ParseIniString(ph7_context *pCtx,const char *zIn,sxu32 nByte,int bProcessSection)
{
ph7_value *pCur,*pArray,*pSection,*pWorker,*pValue;
const char *zCur,*zEnd = &zIn[nByte];
SyHashEntry *pEntry;
SyString sEntry;
SyHash sHash;
int c;
/* Create an empty array and worker variables */
pArray = ph7_context_new_array(pCtx);
pWorker = ph7_context_new_scalar(pCtx);
pValue = ph7_context_new_scalar(pCtx);
if( pArray == 0 || pWorker == 0 || pValue == 0){
/* Out of memory */
ph7_context_throw_error(pCtx,PH7_CTX_ERR,"PH7 is running out of memory");
/* Return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
SyHashInit(&sHash,&pCtx->pVm->sAllocator,0,0);
pCur = pArray;
/* Start the parse process */
for(;;){
/* Ignore leading white spaces */
while( zIn < zEnd && (unsigned char)zIn[0] < 0xc0 && SyisSpace(zIn[0])){
zIn++;
}
if( zIn >= zEnd ){
/* No more input to process */
break;
}
if( zIn[0] == ';' || zIn[0] == '#' ){
/* Comment til the end of line */
zIn++;
while(zIn < zEnd && zIn[0] != '\n' ){
zIn++;
}
continue;
}
/* Reset the string cursor of the working variable */
ph7_value_reset_string_cursor(pWorker);
if( zIn[0] == '[' ){
/* Section: Extract the section name */
zIn++;
zCur = zIn;
while( zIn < zEnd && zIn[0] != ']' ){
zIn++;
}
if( zIn > zCur && bProcessSection ){
/* Save the section name */
SyStringInitFromBuf(&sEntry,zCur,(int)(zIn-zCur));
SyStringFullTrim(&sEntry);
ph7_value_string(pWorker,sEntry.zString,(int)sEntry.nByte);
if( sEntry.nByte > 0 ){
/* Associate an array with the section */
pSection = ph7_context_new_array(pCtx);
if( pSection ){
ph7_array_add_elem(pArray,pWorker/*Section name*/,pSection);
pCur = pSection;
}
}
}
zIn++; /* Trailing square brackets ']' */
}else{
ph7_value *pOldCur;
int is_array;
int iLen;
/* Properties */
is_array = 0;
zCur = zIn;
iLen = 0; /* cc warning */
pOldCur = pCur;
while( zIn < zEnd && zIn[0] != '=' ){
if( zIn[0] == '[' && !is_array ){
/* Array */
iLen = (int)(zIn-zCur);
is_array = 1;
if( iLen > 0 ){
ph7_value *pvArr = 0; /* cc warning */
/* Query the hashtable */
SyStringInitFromBuf(&sEntry,zCur,iLen);
SyStringFullTrim(&sEntry);
pEntry = SyHashGet(&sHash,(const void *)sEntry.zString,sEntry.nByte);
if( pEntry ){
pvArr = (ph7_value *)SyHashEntryGetUserData(pEntry);
}else{
/* Create an empty array */
pvArr = ph7_context_new_array(pCtx);
if( pvArr ){
/* Save the entry */
SyHashInsert(&sHash,(const void *)sEntry.zString,sEntry.nByte,pvArr);
/* Insert the entry */
ph7_value_reset_string_cursor(pWorker);
ph7_value_string(pWorker,sEntry.zString,(int)sEntry.nByte);
ph7_array_add_elem(pCur,pWorker,pvArr);
ph7_value_reset_string_cursor(pWorker);
}
}
if( pvArr ){
pCur = pvArr;
}
}
while ( zIn < zEnd && zIn[0] != ']' ){
zIn++;
}
}
zIn++;
}
if( !is_array ){
iLen = (int)(zIn-zCur);
}
/* Trim the key */
SyStringInitFromBuf(&sEntry,zCur,iLen);
SyStringFullTrim(&sEntry);
if( sEntry.nByte > 0 ){
if( !is_array ){
/* Save the key name */
ph7_value_string(pWorker,sEntry.zString,(int)sEntry.nByte);
}
/* extract key value */
ph7_value_reset_string_cursor(pValue);
zIn++; /* '=' */
while( zIn < zEnd && (unsigned char)zIn[0] < 0xc0 && SyisSpace(zIn[0]) ){
zIn++;
}
if( zIn < zEnd ){
zCur = zIn;
c = zIn[0];
if( c == '"' || c == '\'' ){
zIn++;
/* Delimit the value */
while( zIn < zEnd ){
if ( zIn[0] == c && zIn[-1] != '\\' ){
break;
}
zIn++;
}
if( zIn < zEnd ){
zIn++;
}
}else{
while( zIn < zEnd ){
if( zIn[0] == '\n' ){
if( zIn[-1] != '\\' ){
break;
}
}else if( zIn[0] == ';' || zIn[0] == '#' ){
/* Inline comments */
break;
}
zIn++;
}
}
/* Trim the value */
SyStringInitFromBuf(&sEntry,zCur,(int)(zIn-zCur));
SyStringFullTrim(&sEntry);
if( c == '"' || c == '\'' ){
SyStringTrimLeadingChar(&sEntry,c);
SyStringTrimTrailingChar(&sEntry,c);
}
if( sEntry.nByte > 0 ){
ph7_value_string(pValue,sEntry.zString,(int)sEntry.nByte);
}
/* Insert the key and it's value */
ph7_array_add_elem(pCur,is_array ? 0 /*Automatic index assign */: pWorker,pValue);
}
}else{
while( zIn < zEnd && (unsigned char)zIn[0] < 0xc0 && ( SyisSpace(zIn[0]) || zIn[0] == '=' ) ){
zIn++;
}
}
pCur = pOldCur;
}
}
SyHashRelease(&sHash);
/* Return the parse of the INI string */
ph7_result_value(pCtx,pArray);
return SXRET_OK;
}
/*
* array parse_ini_string(string $ini[,bool $process_sections = false[,int $scanner_mode = INI_SCANNER_NORMAL ]])
* Parse a configuration string.
* Parameters
* $ini
* The contents of the ini file being parsed.
* $process_sections
* By setting the process_sections parameter to TRUE, you get a multidimensional array, with the section names
* and settings included. The default for process_sections is FALSE.
* $scanner_mode (Not used)
* Can either be INI_SCANNER_NORMAL (default) or INI_SCANNER_RAW. If INI_SCANNER_RAW is supplied
* then option values will not be parsed.
* Return
* The settings are returned as an associative array on success, and FALSE on failure.
*/
static int PH7_builtin_parse_ini_string(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zIni;
int nByte;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid arguments,return FALSE*/
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the raw INI buffer */
zIni = ph7_value_to_string(apArg[0],&nByte);
/* Process the INI buffer*/
PH7_ParseIniString(pCtx,zIni,(sxu32)nByte,(nArg > 1) ? ph7_value_to_bool(apArg[1]) : 0);
return PH7_OK;
}
/*
* Ctype Functions.
* Authors:
* Symisc Systems,devel@symisc.net.
* Copyright (C) Symisc Systems,http://ph7.symisc.net
* Status:
* Stable.
*/
/*
* bool ctype_alnum(string $text)
* Checks if all of the characters in the provided string, text, are alphanumeric.
* Parameters
* $text
* The tested string.
* Return
* TRUE if every character in text is either a letter or a digit, FALSE otherwise.
*/
static int PH7_builtin_ctype_alnum(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const unsigned char *zIn,*zEnd;
int nLen;
if( nArg < 1 ){
/* Missing arguments,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the target string */
zIn = (const unsigned char *)ph7_value_to_string(apArg[0],&nLen);
zEnd = &zIn[nLen];
if( nLen < 1 ){
/* Empty string,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Perform the requested operation */
for(;;){
if( zIn >= zEnd ){
/* If we reach the end of the string,then the test succeeded. */
ph7_result_bool(pCtx,1);
return PH7_OK;
}
if( !SyisAlphaNum(zIn[0]) ){
break;
}
/* Point to the next character */
zIn++;
}
/* The test failed,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/*
* bool ctype_alpha(string $text)
* Checks if all of the characters in the provided string, text, are alphabetic.
* Parameters
* $text
* The tested string.
* Return
* TRUE if every character in text is a letter from the current locale, FALSE otherwise.
*/
static int PH7_builtin_ctype_alpha(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const unsigned char *zIn,*zEnd;
int nLen;
if( nArg < 1 ){
/* Missing arguments,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the target string */
zIn = (const unsigned char *)ph7_value_to_string(apArg[0],&nLen);
zEnd = &zIn[nLen];
if( nLen < 1 ){
/* Empty string,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Perform the requested operation */
for(;;){
if( zIn >= zEnd ){
/* If we reach the end of the string,then the test succeeded. */
ph7_result_bool(pCtx,1);
return PH7_OK;
}
if( !SyisAlpha(zIn[0]) ){
break;
}
/* Point to the next character */
zIn++;
}
/* The test failed,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/*
* bool ctype_cntrl(string $text)
* Checks if all of the characters in the provided string, text, are control characters.
* Parameters
* $text
* The tested string.
* Return
* TRUE if every character in text is a control characters,FALSE otherwise.
*/
static int PH7_builtin_ctype_cntrl(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const unsigned char *zIn,*zEnd;
int nLen;
if( nArg < 1 ){
/* Missing arguments,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the target string */
zIn = (const unsigned char *)ph7_value_to_string(apArg[0],&nLen);
zEnd = &zIn[nLen];
if( nLen < 1 ){
/* Empty string,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Perform the requested operation */
for(;;){
if( zIn >= zEnd ){
/* If we reach the end of the string,then the test succeeded. */
ph7_result_bool(pCtx,1);
return PH7_OK;
}
if( zIn[0] >= 0xc0 ){
/* UTF-8 stream */
break;
}
if( !SyisCtrl(zIn[0]) ){
break;
}
/* Point to the next character */
zIn++;
}
/* The test failed,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/*
* bool ctype_digit(string $text)
* Checks if all of the characters in the provided string, text, are numerical.
* Parameters
* $text
* The tested string.
* Return
* TRUE if every character in the string text is a decimal digit, FALSE otherwise.
*/
static int PH7_builtin_ctype_digit(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const unsigned char *zIn,*zEnd;
int nLen;
if( nArg < 1 ){
/* Missing arguments,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the target string */
zIn = (const unsigned char *)ph7_value_to_string(apArg[0],&nLen);
zEnd = &zIn[nLen];
if( nLen < 1 ){
/* Empty string,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Perform the requested operation */
for(;;){
if( zIn >= zEnd ){
/* If we reach the end of the string,then the test succeeded. */
ph7_result_bool(pCtx,1);
return PH7_OK;
}
if( zIn[0] >= 0xc0 ){
/* UTF-8 stream */
break;
}
if( !SyisDigit(zIn[0]) ){
break;
}
/* Point to the next character */
zIn++;
}
/* The test failed,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/*
* bool ctype_xdigit(string $text)
* Check for character(s) representing a hexadecimal digit.
* Parameters
* $text
* The tested string.
* Return
* Returns TRUE if every character in text is a hexadecimal 'digit', that is
* a decimal digit or a character from [A-Fa-f] , FALSE otherwise.
*/
static int PH7_builtin_ctype_xdigit(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const unsigned char *zIn,*zEnd;
int nLen;
if( nArg < 1 ){
/* Missing arguments,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the target string */
zIn = (const unsigned char *)ph7_value_to_string(apArg[0],&nLen);
zEnd = &zIn[nLen];
if( nLen < 1 ){
/* Empty string,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Perform the requested operation */
for(;;){
if( zIn >= zEnd ){
/* If we reach the end of the string,then the test succeeded. */
ph7_result_bool(pCtx,1);
return PH7_OK;
}
if( zIn[0] >= 0xc0 ){
/* UTF-8 stream */
break;
}
if( !SyisHex(zIn[0]) ){
break;
}
/* Point to the next character */
zIn++;
}
/* The test failed,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/*
* bool ctype_graph(string $text)
* Checks if all of the characters in the provided string, text, creates visible output.
* Parameters
* $text
* The tested string.
* Return
* Returns TRUE if every character in text is printable and actually creates visible output
* (no white space), FALSE otherwise.
*/
static int PH7_builtin_ctype_graph(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const unsigned char *zIn,*zEnd;
int nLen;
if( nArg < 1 ){
/* Missing arguments,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the target string */
zIn = (const unsigned char *)ph7_value_to_string(apArg[0],&nLen);
zEnd = &zIn[nLen];
if( nLen < 1 ){
/* Empty string,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Perform the requested operation */
for(;;){
if( zIn >= zEnd ){
/* If we reach the end of the string,then the test succeeded. */
ph7_result_bool(pCtx,1);
return PH7_OK;
}
if( zIn[0] >= 0xc0 ){
/* UTF-8 stream */
break;
}
if( !SyisGraph(zIn[0]) ){
break;
}
/* Point to the next character */
zIn++;
}
/* The test failed,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/*
* bool ctype_print(string $text)
* Checks if all of the characters in the provided string, text, are printable.
* Parameters
* $text
* The tested string.
* Return
* Returns TRUE if every character in text will actually create output (including blanks).
* Returns FALSE if text contains control characters or characters that do not have any output
* or control function at all.
*/
static int PH7_builtin_ctype_print(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const unsigned char *zIn,*zEnd;
int nLen;
if( nArg < 1 ){
/* Missing arguments,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the target string */
zIn = (const unsigned char *)ph7_value_to_string(apArg[0],&nLen);
zEnd = &zIn[nLen];
if( nLen < 1 ){
/* Empty string,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Perform the requested operation */
for(;;){
if( zIn >= zEnd ){
/* If we reach the end of the string,then the test succeeded. */
ph7_result_bool(pCtx,1);
return PH7_OK;
}
if( zIn[0] >= 0xc0 ){
/* UTF-8 stream */
break;
}
if( !SyisPrint(zIn[0]) ){
break;
}
/* Point to the next character */
zIn++;
}
/* The test failed,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/*
* bool ctype_punct(string $text)
* Checks if all of the characters in the provided string, text, are punctuation character.
* Parameters
* $text
* The tested string.
* Return
* Returns TRUE if every character in text is printable, but neither letter
* digit or blank, FALSE otherwise.
*/
static int PH7_builtin_ctype_punct(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const unsigned char *zIn,*zEnd;
int nLen;
if( nArg < 1 ){
/* Missing arguments,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the target string */
zIn = (const unsigned char *)ph7_value_to_string(apArg[0],&nLen);
zEnd = &zIn[nLen];
if( nLen < 1 ){
/* Empty string,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Perform the requested operation */
for(;;){
if( zIn >= zEnd ){
/* If we reach the end of the string,then the test succeeded. */
ph7_result_bool(pCtx,1);
return PH7_OK;
}
if( zIn[0] >= 0xc0 ){
/* UTF-8 stream */
break;
}
if( !SyisPunct(zIn[0]) ){
break;
}
/* Point to the next character */
zIn++;
}
/* The test failed,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/*
* bool ctype_space(string $text)
* Checks if all of the characters in the provided string, text, creates whitespace.
* Parameters
* $text
* The tested string.
* Return
* Returns TRUE if every character in text creates some sort of white space, FALSE otherwise.
* Besides the blank character this also includes tab, vertical tab, line feed, carriage return
* and form feed characters.
*/
static int PH7_builtin_ctype_space(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const unsigned char *zIn,*zEnd;
int nLen;
if( nArg < 1 ){
/* Missing arguments,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the target string */
zIn = (const unsigned char *)ph7_value_to_string(apArg[0],&nLen);
zEnd = &zIn[nLen];
if( nLen < 1 ){
/* Empty string,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Perform the requested operation */
for(;;){
if( zIn >= zEnd ){
/* If we reach the end of the string,then the test succeeded. */
ph7_result_bool(pCtx,1);
return PH7_OK;
}
if( zIn[0] >= 0xc0 ){
/* UTF-8 stream */
break;
}
if( !SyisSpace(zIn[0]) ){
break;
}
/* Point to the next character */
zIn++;
}
/* The test failed,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/*
* bool ctype_lower(string $text)
* Checks if all of the characters in the provided string, text, are lowercase letters.
* Parameters
* $text
* The tested string.
* Return
* Returns TRUE if every character in text is a lowercase letter in the current locale.
*/
static int PH7_builtin_ctype_lower(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const unsigned char *zIn,*zEnd;
int nLen;
if( nArg < 1 ){
/* Missing arguments,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the target string */
zIn = (const unsigned char *)ph7_value_to_string(apArg[0],&nLen);
zEnd = &zIn[nLen];
if( nLen < 1 ){
/* Empty string,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Perform the requested operation */
for(;;){
if( zIn >= zEnd ){
/* If we reach the end of the string,then the test succeeded. */
ph7_result_bool(pCtx,1);
return PH7_OK;
}
if( !SyisLower(zIn[0]) ){
break;
}
/* Point to the next character */
zIn++;
}
/* The test failed,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/*
* bool ctype_upper(string $text)
* Checks if all of the characters in the provided string, text, are uppercase letters.
* Parameters
* $text
* The tested string.
* Return
* Returns TRUE if every character in text is a uppercase letter in the current locale.
*/
static int PH7_builtin_ctype_upper(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const unsigned char *zIn,*zEnd;
int nLen;
if( nArg < 1 ){
/* Missing arguments,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the target string */
zIn = (const unsigned char *)ph7_value_to_string(apArg[0],&nLen);
zEnd = &zIn[nLen];
if( nLen < 1 ){
/* Empty string,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Perform the requested operation */
for(;;){
if( zIn >= zEnd ){
/* If we reach the end of the string,then the test succeeded. */
ph7_result_bool(pCtx,1);
return PH7_OK;
}
if( !SyisUpper(zIn[0]) ){
break;
}
/* Point to the next character */
zIn++;
}
/* The test failed,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/*
* Date/Time functions
* Authors:
* Symisc Systems,devel@symisc.net.
* Copyright (C) Symisc Systems,http://ph7.symisc.net
* Status:
* Devel.
*/
#include <time.h>
#ifdef __WINNT__
/* GetSystemTime() */
#include <Windows.h>
#ifdef _WIN32_WCE
/*
** WindowsCE does not have a localtime() function. So create a
** substitute.
** Taken from the SQLite3 source tree.
** Status: Public domain
*/
struct tm *__cdecl localtime(const time_t *t)
{
static struct tm y;
FILETIME uTm, lTm;
SYSTEMTIME pTm;
ph7_int64 t64;
t64 = *t;
t64 = (t64 + 11644473600)*10000000;
uTm.dwLowDateTime = (DWORD)(t64 & 0xFFFFFFFF);
uTm.dwHighDateTime= (DWORD)(t64 >> 32);
FileTimeToLocalFileTime(&uTm,&lTm);
FileTimeToSystemTime(&lTm,&pTm);
y.tm_year = pTm.wYear - 1900;
y.tm_mon = pTm.wMonth - 1;
y.tm_wday = pTm.wDayOfWeek;
y.tm_mday = pTm.wDay;
y.tm_hour = pTm.wHour;
y.tm_min = pTm.wMinute;
y.tm_sec = pTm.wSecond;
return &y;
}
#endif /*_WIN32_WCE */
#elif defined(__UNIXES__)
#include <sys/time.h>
#endif /* __WINNT__*/
/*
* int64 time(void)
* Current Unix timestamp
* Parameters
* None.
* Return
* Returns the current time measured in the number of seconds
* since the Unix Epoch (January 1 1970 00:00:00 GMT).
*/
static int PH7_builtin_time(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
time_t tt;
SXUNUSED(nArg); /* cc warning */
SXUNUSED(apArg);
/* Extract the current time */
time(&tt);
/* Return as 64-bit integer */
ph7_result_int64(pCtx,(ph7_int64)tt);
return PH7_OK;
}
/*
* string/float microtime([ bool $get_as_float = false ])
* microtime() returns the current Unix timestamp with microseconds.
* Parameters
* $get_as_float
* If used and set to TRUE, microtime() will return a float instead of a string
* as described in the return values section below.
* Return
* By default, microtime() returns a string in the form "msec sec", where sec
* is the current time measured in the number of seconds since the Unix
* epoch (0:00:00 January 1, 1970 GMT), and msec is the number of microseconds
* that have elapsed since sec expressed in seconds.
* If get_as_float is set to TRUE, then microtime() returns a float, which represents
* the current time in seconds since the Unix epoch accurate to the nearest microsecond.
*/
static int PH7_builtin_microtime(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
int bFloat = 0;
sytime sTime;
#if defined(__UNIXES__)
struct timeval tv;
gettimeofday(&tv,0);
sTime.tm_sec = (long)tv.tv_sec;
sTime.tm_usec = (long)tv.tv_usec;
#else
time_t tt;
time(&tt);
sTime.tm_sec = (long)tt;
sTime.tm_usec = (long)(tt%SX_USEC_PER_SEC);
#endif /* __UNIXES__ */
if( nArg > 0 ){
bFloat = ph7_value_to_bool(apArg[0]);
}
if( bFloat ){
/* Return as float */
ph7_result_double(pCtx,(double)sTime.tm_sec);
}else{
/* Return as string */
ph7_result_string_format(pCtx,"%ld %ld",sTime.tm_usec,sTime.tm_sec);
}
return PH7_OK;
}
/*
* array getdate ([ int $timestamp = time() ])
* Get date/time information.
* Parameter
* $timestamp: The optional timestamp parameter is an integer Unix timestamp
* that defaults to the current local time if a timestamp is not given.
* In other words, it defaults to the value of time().
* Returns
* Returns an associative array of information related to the timestamp.
* Elements from the returned associative array are as follows:
* KEY VALUE
* --------- -------
* "seconds" Numeric representation of seconds 0 to 59
* "minutes" Numeric representation of minutes 0 to 59
* "hours" Numeric representation of hours 0 to 23
* "mday" Numeric representation of the day of the month 1 to 31
* "wday" Numeric representation of the day of the week 0 (for Sunday) through 6 (for Saturday)
* "mon" Numeric representation of a month 1 through 12
* "year" A full numeric representation of a year, 4 digits Examples: 1999 or 2003
* "yday" Numeric representation of the day of the year 0 through 365
* "weekday" A full textual representation of the day of the week Sunday through Saturday
* "month" A full textual representation of a month, such as January or March January through December
* 0 Seconds since the Unix Epoch, similar to the values returned by time() and used by date().
* NOTE:
* NULL is returned on failure.
*/
static int PH7_builtin_getdate(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
ph7_value *pValue,*pArray;
Sytm sTm;
if( nArg < 1 ){
#ifdef __WINNT__
SYSTEMTIME sOS;
GetSystemTime(&sOS);
SYSTEMTIME_TO_SYTM(&sOS,&sTm);
#else
struct tm *pTm;
time_t t;
time(&t);
pTm = localtime(&t);
STRUCT_TM_TO_SYTM(pTm,&sTm);
#endif
}else{
/* Use the given timestamp */
time_t t;
struct tm *pTm;
#ifdef __WINNT__
#ifdef _MSC_VER
#if _MSC_VER >= 1400 /* Visual Studio 2005 and up */
#pragma warning(disable:4996) /* _CRT_SECURE...*/
#endif
#endif
#endif
if( ph7_value_is_int(apArg[0]) ){
t = (time_t)ph7_value_to_int64(apArg[0]);
pTm = localtime(&t);
if( pTm == 0 ){
time(&t);
}
}else{
time(&t);
}
pTm = localtime(&t);
STRUCT_TM_TO_SYTM(pTm,&sTm);
}
/* Element value */
pValue = ph7_context_new_scalar(pCtx);
if( pValue == 0 ){
/* 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;
}
/* Fill the array */
/* Seconds */
ph7_value_int(pValue,sTm.tm_sec);
ph7_array_add_strkey_elem(pArray,"seconds",pValue);
/* Minutes */
ph7_value_int(pValue,sTm.tm_min);
ph7_array_add_strkey_elem(pArray,"minutes",pValue);
/* Hours */
ph7_value_int(pValue,sTm.tm_hour);
ph7_array_add_strkey_elem(pArray,"hours",pValue);
/* mday */
ph7_value_int(pValue,sTm.tm_mday);
ph7_array_add_strkey_elem(pArray,"mday",pValue);
/* wday */
ph7_value_int(pValue,sTm.tm_wday);
ph7_array_add_strkey_elem(pArray,"wday",pValue);
/* mon */
ph7_value_int(pValue,sTm.tm_mon+1);
ph7_array_add_strkey_elem(pArray,"mon",pValue);
/* year */
ph7_value_int(pValue,sTm.tm_year);
ph7_array_add_strkey_elem(pArray,"year",pValue);
/* yday */
ph7_value_int(pValue,sTm.tm_yday);
ph7_array_add_strkey_elem(pArray,"yday",pValue);
/* Weekday */
ph7_value_string(pValue,SyTimeGetDay(sTm.tm_wday),-1);
ph7_array_add_strkey_elem(pArray,"weekday",pValue);
/* Month */
ph7_value_reset_string_cursor(pValue);
ph7_value_string(pValue,SyTimeGetMonth(sTm.tm_mon),-1);
ph7_array_add_strkey_elem(pArray,"month",pValue);
/* Seconds since the epoch */
ph7_value_int64(pValue,(ph7_int64)time(0));
ph7_array_add_intkey_elem(pArray,0 /* Index zero */,pValue);
/* Return the freshly created array */
ph7_result_value(pCtx,pArray);
return PH7_OK;
}
/*
* mixed gettimeofday([ bool $return_float = false ] )
* Returns an associative array containing the data returned from the system call.
* Parameters
* $return_float
* When set to TRUE, a float instead of an array is returned.
* Return
* By default an array is returned. If return_float is set, then
* a float is returned.
*/
static int PH7_builtin_gettimeofday(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
int bFloat = 0;
sytime sTime;
#if defined(__UNIXES__)
struct timeval tv;
gettimeofday(&tv,0);
sTime.tm_sec = (long)tv.tv_sec;
sTime.tm_usec = (long)tv.tv_usec;
#else
time_t tt;
time(&tt);
sTime.tm_sec = (long)tt;
sTime.tm_usec = (long)(tt%SX_USEC_PER_SEC);
#endif /* __UNIXES__ */
if( nArg > 0 ){
bFloat = ph7_value_to_bool(apArg[0]);
}
if( bFloat ){
/* Return as float */
ph7_result_double(pCtx,(double)sTime.tm_sec);
}else{
/* Return an associative array */
ph7_value *pValue,*pArray;
/* Create a new array */
pArray = ph7_context_new_array(pCtx);
/* Element value */
pValue = ph7_context_new_scalar(pCtx);
if( pValue == 0 || pArray == 0 ){
/* Return NULL */
ph7_result_null(pCtx);
return PH7_OK;
}
/* Fill the array */
/* sec */
ph7_value_int64(pValue,sTime.tm_sec);
ph7_array_add_strkey_elem(pArray,"sec",pValue);
/* usec */
ph7_value_int64(pValue,sTime.tm_usec);
ph7_array_add_strkey_elem(pArray,"usec",pValue);
/* Return the array */
ph7_result_value(pCtx,pArray);
}
return PH7_OK;
}
/* Check if the given year is leap or not */
#define IS_LEAP_YEAR(YEAR) (YEAR % 400 ? ( YEAR % 100 ? ( YEAR % 4 ? 0 : 1 ) : 0 ) : 1)
/* ISO-8601 numeric representation of the day of the week */
static const int aISO8601[] = { 7 /* Sunday */,1 /* Monday */,2,3,4,5,6 };
/*
* Format a given date string.
* Supported format: (Taken from PHP online docs)
* character Description
* d Day of the month
* D A textual representation of a days
* j Day of the month without leading zeros
* l A full textual representation of the day of the week
* N ISO-8601 numeric representation of the day of the week
* w Numeric representation of the day of the week
* z The day of the year (starting from 0)
* F A full textual representation of a month, such as January or March
* m Numeric representation of a month, with leading zeros 01 through 12
* M A short textual representation of a month, three letters Jan through Dec
* n Numeric representation of a month, without leading zeros 1 through 12
* t Number of days in the given month 28 through 31
* L Whether it's a leap year 1 if it is a leap year, 0 otherwise.
* o ISO-8601 year number. This has the same value as Y, except that if the ISO week number
* (W) belongs to the previous or next year, that year is used instead. (added in PHP 5.1.0) Examples: 1999 or 2003
* Y A full numeric representation of a year, 4 digits Examples: 1999 or 2003
* y A two digit representation of a year Examples: 99 or 03
* a Lowercase Ante meridiem and Post meridiem am or pm
* A Uppercase Ante meridiem and Post meridiem AM or PM
* g 12-hour format of an hour without leading zeros 1 through 12
* G 24-hour format of an hour without leading zeros 0 through 23
* h 12-hour format of an hour with leading zeros 01 through 12
* H 24-hour format of an hour with leading zeros 00 through 23
* i Minutes with leading zeros 00 to 59
* s Seconds, with leading zeros 00 through 59
* u Microseconds Example: 654321
* e Timezone identifier Examples: UTC, GMT, Atlantic/Azores
* I (capital i) Whether or not the date is in daylight saving time 1 if Daylight Saving Time, 0 otherwise.
* r RFC 2822 formatted date Example: Thu, 21 Dec 2000 16:01:07 +0200
* U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)
* S English ordinal suffix for the day of the month, 2 characters
* O Difference to Greenwich time (GMT) in hours
* Z Timezone offset in seconds. The offset for timezones west of UTC is always negative, and for those
* east of UTC is always positive.
* c ISO 8601 date
*/
static sxi32 DateFormat(ph7_context *pCtx,const char *zIn,int nLen,Sytm *pTm)
{
const char *zEnd = &zIn[nLen];
const char *zCur;
/* Start the format process */
for(;;){
if( zIn >= zEnd ){
/* No more input to process */
break;
}
switch(zIn[0]){
case 'd':
/* Day of the month, 2 digits with leading zeros */
ph7_result_string_format(pCtx,"%02d",pTm->tm_mday);
break;
case 'D':
/*A textual representation of a day, three letters*/
zCur = SyTimeGetDay(pTm->tm_wday);
ph7_result_string(pCtx,zCur,3);
break;
case 'j':
/* Day of the month without leading zeros */
ph7_result_string_format(pCtx,"%d",pTm->tm_mday);
break;
case 'l':
/* A full textual representation of the day of the week */
zCur = SyTimeGetDay(pTm->tm_wday);
ph7_result_string(pCtx,zCur,-1/*Compute length automatically*/);
break;
case 'N':{
/* ISO-8601 numeric representation of the day of the week */
ph7_result_string_format(pCtx,"%d",aISO8601[pTm->tm_wday % 7 ]);
break;
}
case 'w':
/*Numeric representation of the day of the week*/
ph7_result_string_format(pCtx,"%d",pTm->tm_wday);
break;
case 'z':
/*The day of the year*/
ph7_result_string_format(pCtx,"%d",pTm->tm_yday);
break;
case 'F':
/*A full textual representation of a month, such as January or March*/
zCur = SyTimeGetMonth(pTm->tm_mon);
ph7_result_string(pCtx,zCur,-1/*Compute length automatically*/);
break;
case 'm':
/*Numeric representation of a month, with leading zeros*/
ph7_result_string_format(pCtx,"%02d",pTm->tm_mon + 1);
break;
case 'M':
/*A short textual representation of a month, three letters*/
zCur = SyTimeGetMonth(pTm->tm_mon);
ph7_result_string(pCtx,zCur,3);
break;
case 'n':
/*Numeric representation of a month, without leading zeros*/
ph7_result_string_format(pCtx,"%d",pTm->tm_mon + 1);
break;
case 't':{
static const int aMonDays[] = {31,29,31,30,31,30,31,31,30,31,30,31 };
int nDays = aMonDays[pTm->tm_mon % 12 ];
if( pTm->tm_mon == 1 /* 'February' */ && !IS_LEAP_YEAR(pTm->tm_year) ){
nDays = 28;
}
/*Number of days in the given month*/
ph7_result_string_format(pCtx,"%d",nDays);
break;
}
case 'L':{
int isLeap = IS_LEAP_YEAR(pTm->tm_year);
/* Whether it's a leap year */
ph7_result_string_format(pCtx,"%d",isLeap);
break;
}
case 'o':
/* ISO-8601 year number.*/
ph7_result_string_format(pCtx,"%4d",pTm->tm_year);
break;
case 'Y':
/* A full numeric representation of a year, 4 digits */
ph7_result_string_format(pCtx,"%4d",pTm->tm_year);
break;
case 'y':
/*A two digit representation of a year*/
ph7_result_string_format(pCtx,"%02d",pTm->tm_year%100);
break;
case 'a':
/* Lowercase Ante meridiem and Post meridiem */
ph7_result_string(pCtx,pTm->tm_hour > 12 ? "pm" : "am",2);
break;
case 'A':
/* Uppercase Ante meridiem and Post meridiem */
ph7_result_string(pCtx,pTm->tm_hour > 12 ? "PM" : "AM",2);
break;
case 'g':
/* 12-hour format of an hour without leading zeros*/
ph7_result_string_format(pCtx,"%d",1+(pTm->tm_hour%12));
break;
case 'G':
/* 24-hour format of an hour without leading zeros */
ph7_result_string_format(pCtx,"%d",pTm->tm_hour);
break;
case 'h':
/* 12-hour format of an hour with leading zeros */
ph7_result_string_format(pCtx,"%02d",1+(pTm->tm_hour%12));
break;
case 'H':
/* 24-hour format of an hour with leading zeros */
ph7_result_string_format(pCtx,"%02d",pTm->tm_hour);
break;
case 'i':
/* Minutes with leading zeros */
ph7_result_string_format(pCtx,"%02d",pTm->tm_min);
break;
case 's':
/* second with leading zeros */
ph7_result_string_format(pCtx,"%02d",pTm->tm_sec);
break;
case 'u':
/* Microseconds */
ph7_result_string_format(pCtx,"%u",pTm->tm_sec * SX_USEC_PER_SEC);
break;
case 'S':{
/* English ordinal suffix for the day of the month, 2 characters */
static const char zSuffix[] = "thstndrdthththththth";
int v = pTm->tm_mday;
ph7_result_string(pCtx,&zSuffix[2 * (int)(v / 10 % 10 != 1 ? v % 10 : 0)],(int)sizeof(char) * 2);
break;
}
case 'e':
/* Timezone identifier */
zCur = pTm->tm_zone;
if( zCur == 0 ){
/* Assume GMT */
zCur = "GMT";
}
ph7_result_string(pCtx,zCur,-1);
break;
case 'I':
/* Whether or not the date is in daylight saving time */
#ifdef __WINNT__
#ifdef _MSC_VER
#ifndef _WIN32_WCE
_get_daylight(&pTm->tm_isdst);
#endif
#endif
#endif
ph7_result_string_format(pCtx,"%d",pTm->tm_isdst == 1);
break;
case 'r':
/* RFC 2822 formatted date Example: Thu, 21 Dec 2000 16:01:07 */
ph7_result_string_format(pCtx,"%.3s, %02d %.3s %4d %02d:%02d:%02d",
SyTimeGetDay(pTm->tm_wday),
pTm->tm_mday,
SyTimeGetMonth(pTm->tm_mon),
pTm->tm_year,
pTm->tm_hour,
pTm->tm_min,
pTm->tm_sec
);
break;
case 'U':{
time_t tt;
/* Seconds since the Unix Epoch */
time(&tt);
ph7_result_string_format(pCtx,"%u",(unsigned int)tt);
break;
}
case 'O':
case 'P':
/* Difference to Greenwich time (GMT) in hours */
ph7_result_string_format(pCtx,"%+05d",pTm->tm_gmtoff);
break;
case 'Z':
/* Timezone offset in seconds. The offset for timezones west of UTC
* is always negative, and for those east of UTC is always positive.
*/
ph7_result_string_format(pCtx,"%+05d",pTm->tm_gmtoff);
break;
case 'c':
/* ISO 8601 date */
ph7_result_string_format(pCtx,"%4d-%02d-%02dT%02d:%02d:%02d%+05d",
pTm->tm_year,
pTm->tm_mon+1,
pTm->tm_mday,
pTm->tm_hour,
pTm->tm_min,
pTm->tm_sec,
pTm->tm_gmtoff
);
break;
case '\\':
zIn++;
/* Expand verbatim */
if( zIn < zEnd ){
ph7_result_string(pCtx,zIn,(int)sizeof(char));
}
break;
default:
/* Unknown format specifer,expand verbatim */
ph7_result_string(pCtx,zIn,(int)sizeof(char));
break;
}
/* Point to the next character */
zIn++;
}
return SXRET_OK;
}
/*
* PH7 implementation of the strftime() function.
* The following formats are supported:
* %a An abbreviated textual representation of the day
* %A A full textual representation of the day
* %d Two-digit day of the month (with leading zeros)
* %e Day of the month, with a space preceding single digits.
* %j Day of the year, 3 digits with leading zeros
* %u ISO-8601 numeric representation of the day of the week 1 (for Monday) though 7 (for Sunday)
* %w Numeric representation of the day of the week 0 (for Sunday) through 6 (for Saturday)
* %U Week number of the given year, starting with the first Sunday as the first week
* %V ISO-8601:1988 week number of the given year, starting with the first week of the year with at least
* 4 weekdays, with Monday being the start of the week.
* %W A numeric representation of the week of the year
* %b Abbreviated month name, based on the locale
* %B Full month name, based on the locale
* %h Abbreviated month name, based on the locale (an alias of %b)
* %m Two digit representation of the month
* %C Two digit representation of the century (year divided by 100, truncated to an integer)
* %g Two digit representation of the year going by ISO-8601:1988 standards (see %V)
* %G The full four-digit version of %g
* %y Two digit representation of the year
* %Y Four digit representation for the year
* %H Two digit representation of the hour in 24-hour format
* %I Two digit representation of the hour in 12-hour format
* %l (lower-case 'L') Hour in 12-hour format, with a space preceeding single digits
* %M Two digit representation of the minute
* %p UPPER-CASE 'AM' or 'PM' based on the given time
* %P lower-case 'am' or 'pm' based on the given time
* %r Same as "%I:%M:%S %p"
* %R Same as "%H:%M"
* %S Two digit representation of the second
* %T Same as "%H:%M:%S"
* %X Preferred time representation based on locale, without the date
* %z Either the time zone offset from UTC or the abbreviation
* %Z The time zone offset/abbreviation option NOT given by %z
* %c Preferred date and time stamp based on local
* %D Same as "%m/%d/%y"
* %F Same as "%Y-%m-%d"
* %s Unix Epoch Time timestamp (same as the time() function)
* %x Preferred date representation based on locale, without the time
* %n A newline character ("\n")
* %t A Tab character ("\t")
* %% A literal percentage character ("%")
*/
static int PH7_Strftime(
ph7_context *pCtx, /* Call context */
const char *zIn, /* Input string */
int nLen, /* Input length */
Sytm *pTm /* Parse of the given time */
)
{
const char *zCur,*zEnd = &zIn[nLen];
int c;
/* Start the format process */
for(;;){
zCur = zIn;
while(zIn < zEnd && zIn[0] != '%' ){
zIn++;
}
if( zIn > zCur ){
/* Consume input verbatim */
ph7_result_string(pCtx,zCur,(int)(zIn-zCur));
}
zIn++; /* Jump the percent sign */
if( zIn >= zEnd ){
/* No more input to process */
break;
}
c = zIn[0];
/* Act according to the current specifer */
switch(c){
case '%':
/* A literal percentage character ("%") */
ph7_result_string(pCtx,"%",(int)sizeof(char));
break;
case 't':
/* A Tab character */
ph7_result_string(pCtx,"\t",(int)sizeof(char));
break;
case 'n':
/* A newline character */
ph7_result_string(pCtx,"\n",(int)sizeof(char));
break;
case 'a':
/* An abbreviated textual representation of the day */
ph7_result_string(pCtx,SyTimeGetDay(pTm->tm_wday),(int)sizeof(char)*3);
break;
case 'A':
/* A full textual representation of the day */
ph7_result_string(pCtx,SyTimeGetDay(pTm->tm_wday),-1/*Compute length automatically*/);
break;
case 'e':
/* Day of the month, 2 digits with leading space for single digit*/
ph7_result_string_format(pCtx,"%2d",pTm->tm_mday);
break;
case 'd':
/* Two-digit day of the month (with leading zeros) */
ph7_result_string_format(pCtx,"%02d",pTm->tm_mon+1);
break;
case 'j':
/*The day of the year,3 digits with leading zeros*/
ph7_result_string_format(pCtx,"%03d",pTm->tm_yday);
break;
case 'u':
/* ISO-8601 numeric representation of the day of the week */
ph7_result_string_format(pCtx,"%d",aISO8601[pTm->tm_wday % 7 ]);
break;
case 'w':
/* Numeric representation of the day of the week */
ph7_result_string_format(pCtx,"%d",pTm->tm_wday);
break;
case 'b':
case 'h':
/*A short textual representation of a month, three letters (Not based on locale)*/
ph7_result_string(pCtx,SyTimeGetMonth(pTm->tm_mon),(int)sizeof(char)*3);
break;
case 'B':
/* Full month name (Not based on locale) */
ph7_result_string(pCtx,SyTimeGetMonth(pTm->tm_mon),-1/*Compute length automatically*/);
break;
case 'm':
/*Numeric representation of a month, with leading zeros*/
ph7_result_string_format(pCtx,"%02d",pTm->tm_mon + 1);
break;
case 'C':
/* Two digit representation of the century */
ph7_result_string_format(pCtx,"%2d",pTm->tm_year/100);
break;
case 'y':
case 'g':
/* Two digit representation of the year */
ph7_result_string_format(pCtx,"%2d",pTm->tm_year%100);
break;
case 'Y':
case 'G':
/* Four digit representation of the year */
ph7_result_string_format(pCtx,"%4d",pTm->tm_year);
break;
case 'I':
/* 12-hour format of an hour with leading zeros */
ph7_result_string_format(pCtx,"%02d",1+(pTm->tm_hour%12));
break;
case 'l':
/* 12-hour format of an hour with leading space */
ph7_result_string_format(pCtx,"%2d",1+(pTm->tm_hour%12));
break;
case 'H':
/* 24-hour format of an hour with leading zeros */
ph7_result_string_format(pCtx,"%02d",pTm->tm_hour);
break;
case 'M':
/* Minutes with leading zeros */
ph7_result_string_format(pCtx,"%02d",pTm->tm_min);
break;
case 'S':
/* Seconds with leading zeros */
ph7_result_string_format(pCtx,"%02d",pTm->tm_sec);
break;
case 'z':
case 'Z':
/* Timezone identifier */
zCur = pTm->tm_zone;
if( zCur == 0 ){
/* Assume GMT */
zCur = "GMT";
}
ph7_result_string(pCtx,zCur,-1);
break;
case 'T':
case 'X':
/* Same as "%H:%M:%S" */
ph7_result_string_format(pCtx,"%02d:%02d:%02d",pTm->tm_hour,pTm->tm_min,pTm->tm_sec);
break;
case 'R':
/* Same as "%H:%M" */
ph7_result_string_format(pCtx,"%02d:%02d",pTm->tm_hour,pTm->tm_min);
break;
case 'P':
/* Lowercase Ante meridiem and Post meridiem */
ph7_result_string(pCtx,pTm->tm_hour > 12 ? "pm" : "am",(int)sizeof(char)*2);
break;
case 'p':
/* Uppercase Ante meridiem and Post meridiem */
ph7_result_string(pCtx,pTm->tm_hour > 12 ? "PM" : "AM",(int)sizeof(char)*2);
break;
case 'r':
/* Same as "%I:%M:%S %p" */
ph7_result_string_format(pCtx,"%02d:%02d:%02d %s",
1+(pTm->tm_hour%12),
pTm->tm_min,
pTm->tm_sec,
pTm->tm_hour > 12 ? "PM" : "AM"
);
break;
case 'D':
case 'x':
/* Same as "%m/%d/%y" */
ph7_result_string_format(pCtx,"%02d/%02d/%02d",
pTm->tm_mon+1,
pTm->tm_mday,
pTm->tm_year%100
);
break;
case 'F':
/* Same as "%Y-%m-%d" */
ph7_result_string_format(pCtx,"%d-%02d-%02d",
pTm->tm_year,
pTm->tm_mon+1,
pTm->tm_mday
);
break;
case 'c':
ph7_result_string_format(pCtx,"%d-%02d-%02d %02d:%02d:%02d",
pTm->tm_year,
pTm->tm_mon+1,
pTm->tm_mday,
pTm->tm_hour,
pTm->tm_min,
pTm->tm_sec
);
break;
case 's':{
time_t tt;
/* Seconds since the Unix Epoch */
time(&tt);
ph7_result_string_format(pCtx,"%u",(unsigned int)tt);
break;
}
default:
/* unknown specifer,simply ignore*/
break;
}
/* Advance the cursor */
zIn++;
}
return SXRET_OK;
}
/*
* string date(string $format [, int $timestamp = time() ] )
* Returns a string formatted according to the given format string using
* the given integer timestamp or the current time if no timestamp is given.
* In other words, timestamp is optional and defaults to the value of time().
* Parameters
* $format
* The format of the outputted date string (See code above)
* $timestamp
* The optional timestamp parameter is an integer Unix timestamp
* that defaults to the current local time if a timestamp is not given.
* In other words, it defaults to the value of time().
* Return
* A formatted date string. If a non-numeric value is used for timestamp, FALSE is returned.
*/
static int PH7_builtin_date(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zFormat;
int nLen;
Sytm sTm;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid argument,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
zFormat = ph7_value_to_string(apArg[0],&nLen);
if( nLen < 1 ){
/* Don't bother processing return the empty string */
ph7_result_string(pCtx,"",0);
}
if( nArg < 2 ){
#ifdef __WINNT__
SYSTEMTIME sOS;
GetSystemTime(&sOS);
SYSTEMTIME_TO_SYTM(&sOS,&sTm);
#else
struct tm *pTm;
time_t t;
time(&t);
pTm = localtime(&t);
STRUCT_TM_TO_SYTM(pTm,&sTm);
#endif
}else{
/* Use the given timestamp */
time_t t;
struct tm *pTm;
if( ph7_value_is_int(apArg[1]) ){
t = (time_t)ph7_value_to_int64(apArg[1]);
pTm = localtime(&t);
if( pTm == 0 ){
time(&t);
}
}else{
time(&t);
}
pTm = localtime(&t);
STRUCT_TM_TO_SYTM(pTm,&sTm);
}
/* Format the given string */
DateFormat(pCtx,zFormat,nLen,&sTm);
return PH7_OK;
}
/*
* string strftime(string $format [, int $timestamp = time() ] )
* Format a local time/date (PLATFORM INDEPENDANT IMPLEENTATION NOT BASED ON LOCALE)
* Parameters
* $format
* The format of the outputted date string (See code above)
* $timestamp
* The optional timestamp parameter is an integer Unix timestamp
* that defaults to the current local time if a timestamp is not given.
* In other words, it defaults to the value of time().
* Return
* Returns a string formatted according format using the given timestamp
* or the current local time if no timestamp is given.
*/
static int PH7_builtin_strftime(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zFormat;
int nLen;
Sytm sTm;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid argument,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
zFormat = ph7_value_to_string(apArg[0],&nLen);
if( nLen < 1 ){
/* Don't bother processing return FALSE */
ph7_result_bool(pCtx,0);
}
if( nArg < 2 ){
#ifdef __WINNT__
SYSTEMTIME sOS;
GetSystemTime(&sOS);
SYSTEMTIME_TO_SYTM(&sOS,&sTm);
#else
struct tm *pTm;
time_t t;
time(&t);
pTm = localtime(&t);
STRUCT_TM_TO_SYTM(pTm,&sTm);
#endif
}else{
/* Use the given timestamp */
time_t t;
struct tm *pTm;
if( ph7_value_is_int(apArg[1]) ){
t = (time_t)ph7_value_to_int64(apArg[1]);
pTm = localtime(&t);
if( pTm == 0 ){
time(&t);
}
}else{
time(&t);
}
pTm = localtime(&t);
STRUCT_TM_TO_SYTM(pTm,&sTm);
}
/* Format the given string */
PH7_Strftime(pCtx,zFormat,nLen,&sTm);
if( ph7_context_result_buf_length(pCtx) < 1 ){
/* Nothing was formatted,return FALSE */
ph7_result_bool(pCtx,0);
}
return PH7_OK;
}
/*
* string gmdate(string $format [, int $timestamp = time() ] )
* Identical to the date() function except that the time returned
* is Greenwich Mean Time (GMT).
* Parameters
* $format
* The format of the outputted date string (See code above)
* $timestamp
* The optional timestamp parameter is an integer Unix timestamp
* that defaults to the current local time if a timestamp is not given.
* In other words, it defaults to the value of time().
* Return
* A formatted date string. If a non-numeric value is used for timestamp, FALSE is returned.
*/
static int PH7_builtin_gmdate(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zFormat;
int nLen;
Sytm sTm;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid argument,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
zFormat = ph7_value_to_string(apArg[0],&nLen);
if( nLen < 1 ){
/* Don't bother processing return the empty string */
ph7_result_string(pCtx,"",0);
}
if( nArg < 2 ){
#ifdef __WINNT__
SYSTEMTIME sOS;
GetSystemTime(&sOS);
SYSTEMTIME_TO_SYTM(&sOS,&sTm);
#else
struct tm *pTm;
time_t t;
time(&t);
pTm = gmtime(&t);
STRUCT_TM_TO_SYTM(pTm,&sTm);
#endif
}else{
/* Use the given timestamp */
time_t t;
struct tm *pTm;
if( ph7_value_is_int(apArg[1]) ){
t = (time_t)ph7_value_to_int64(apArg[1]);
pTm = gmtime(&t);
if( pTm == 0 ){
time(&t);
}
}else{
time(&t);
}
pTm = gmtime(&t);
STRUCT_TM_TO_SYTM(pTm,&sTm);
}
/* Format the given string */
DateFormat(pCtx,zFormat,nLen,&sTm);
return PH7_OK;
}
/*
* array localtime([ int $timestamp = time() [, bool $is_associative = false ]])
* Return the local time.
* Parameter
* $timestamp: The optional timestamp parameter is an integer Unix timestamp
* that defaults to the current local time if a timestamp is not given.
* In other words, it defaults to the value of time().
* $is_associative
* If set to FALSE or not supplied then the array is returned as a regular, numerically
* indexed array. If the argument is set to TRUE then localtime() returns an associative
* array containing all the different elements of the structure returned by the C function
* call to localtime. The names of the different keys of the associative array are as follows:
* "tm_sec" - seconds, 0 to 59
* "tm_min" - minutes, 0 to 59
* "tm_hour" - hours, 0 to 23
* "tm_mday" - day of the month, 1 to 31
* "tm_mon" - month of the year, 0 (Jan) to 11 (Dec)
* "tm_year" - years since 1900
* "tm_wday" - day of the week, 0 (Sun) to 6 (Sat)
* "tm_yday" - day of the year, 0 to 365
* "tm_isdst" - is daylight savings time in effect? Positive if yes, 0 if not, negative if unknown.
* Returns
* An associative array of information related to the timestamp.
*/
static int PH7_builtin_localtime(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
ph7_value *pValue,*pArray;
int isAssoc = 0;
Sytm sTm;
if( nArg < 1 ){
#ifdef __WINNT__
SYSTEMTIME sOS;
GetSystemTime(&sOS); /* TODO(chems): GMT not local */
SYSTEMTIME_TO_SYTM(&sOS,&sTm);
#else
struct tm *pTm;
time_t t;
time(&t);
pTm = localtime(&t);
STRUCT_TM_TO_SYTM(pTm,&sTm);
#endif
}else{
/* Use the given timestamp */
time_t t;
struct tm *pTm;
if( ph7_value_is_int(apArg[0]) ){
t = (time_t)ph7_value_to_int64(apArg[0]);
pTm = localtime(&t);
if( pTm == 0 ){
time(&t);
}
}else{
time(&t);
}
pTm = localtime(&t);
STRUCT_TM_TO_SYTM(pTm,&sTm);
}
/* Element value */
pValue = ph7_context_new_scalar(pCtx);
if( pValue == 0 ){
/* 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;
}
if( nArg > 1 ){
isAssoc = ph7_value_to_bool(apArg[1]);
}
/* Fill the array */
/* Seconds */
ph7_value_int(pValue,sTm.tm_sec);
if( isAssoc ){
ph7_array_add_strkey_elem(pArray,"tm_sec",pValue);
}else{
ph7_array_add_elem(pArray,0/* Automatic index */,pValue);
}
/* Minutes */
ph7_value_int(pValue,sTm.tm_min);
if( isAssoc ){
ph7_array_add_strkey_elem(pArray,"tm_min",pValue);
}else{
ph7_array_add_elem(pArray,0/* Automatic index */,pValue);
}
/* Hours */
ph7_value_int(pValue,sTm.tm_hour);
if( isAssoc ){
ph7_array_add_strkey_elem(pArray,"tm_hour",pValue);
}else{
ph7_array_add_elem(pArray,0/* Automatic index */,pValue);
}
/* mday */
ph7_value_int(pValue,sTm.tm_mday);
if( isAssoc ){
ph7_array_add_strkey_elem(pArray,"tm_mday",pValue);
}else{
ph7_array_add_elem(pArray,0/* Automatic index */,pValue);
}
/* mon */
ph7_value_int(pValue,sTm.tm_mon);
if( isAssoc ){
ph7_array_add_strkey_elem(pArray,"tm_mon",pValue);
}else{
ph7_array_add_elem(pArray,0/* Automatic index */,pValue);
}
/* year since 1900 */
ph7_value_int(pValue,sTm.tm_year-1900);
if( isAssoc ){
ph7_array_add_strkey_elem(pArray,"tm_year",pValue);
}else{
ph7_array_add_elem(pArray,0/* Automatic index */,pValue);
}
/* wday */
ph7_value_int(pValue,sTm.tm_wday);
if( isAssoc ){
ph7_array_add_strkey_elem(pArray,"tm_wday",pValue);
}else{
ph7_array_add_elem(pArray,0/* Automatic index */,pValue);
}
/* yday */
ph7_value_int(pValue,sTm.tm_yday);
if( isAssoc ){
ph7_array_add_strkey_elem(pArray,"tm_yday",pValue);
}else{
ph7_array_add_elem(pArray,0/* Automatic index */,pValue);
}
/* isdst */
#ifdef __WINNT__
#ifdef _MSC_VER
#ifndef _WIN32_WCE
_get_daylight(&sTm.tm_isdst);
#endif
#endif
#endif
ph7_value_int(pValue,sTm.tm_isdst);
if( isAssoc ){
ph7_array_add_strkey_elem(pArray,"tm_isdst",pValue);
}else{
ph7_array_add_elem(pArray,0/* Automatic index */,pValue);
}
/* Return the array */
ph7_result_value(pCtx,pArray);
return PH7_OK;
}
/*
* int idate(string $format [, int $timestamp = time() ])
* Returns a number formatted according to the given format string
* using the given integer timestamp or the current local time if
* no timestamp is given. In other words, timestamp is optional and defaults
* to the value of time().
* Unlike the function date(), idate() accepts just one char in the format
* parameter.
* $Parameters
* Supported format
* d Day of the month
* h Hour (12 hour format)
* H Hour (24 hour format)
* i Minutes
* I (uppercase i)1 if DST is activated, 0 otherwise
* L (uppercase l) returns 1 for leap year, 0 otherwise
* m Month number
* s Seconds
* t Days in current month
* U Seconds since the Unix Epoch - January 1 1970 00:00:00 UTC - this is the same as time()
* w Day of the week (0 on Sunday)
* W ISO-8601 week number of year, weeks starting on Monday
* y Year (1 or 2 digits - check note below)
* Y Year (4 digits)
* z Day of the year
* Z Timezone offset in seconds
* $timestamp
* The optional timestamp parameter is an integer Unix timestamp that defaults
* to the current local time if a timestamp is not given. In other words, it defaults
* to the value of time().
* Return
* An integer.
*/
static int PH7_builtin_idate(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zFormat;
ph7_int64 iVal = 0;
int nLen;
Sytm sTm;
if( nArg < 1 || !ph7_value_is_string(apArg[0]) ){
/* Missing/Invalid argument,return -1 */
ph7_result_int(pCtx,-1);
return PH7_OK;
}
zFormat = ph7_value_to_string(apArg[0],&nLen);
if( nLen < 1 ){
/* Don't bother processing return -1*/
ph7_result_int(pCtx,-1);
}
if( nArg < 2 ){
#ifdef __WINNT__
SYSTEMTIME sOS;
GetSystemTime(&sOS);
SYSTEMTIME_TO_SYTM(&sOS,&sTm);
#else
struct tm *pTm;
time_t t;
time(&t);
pTm = localtime(&t);
STRUCT_TM_TO_SYTM(pTm,&sTm);
#endif
}else{
/* Use the given timestamp */
time_t t;
struct tm *pTm;
if( ph7_value_is_int(apArg[1]) ){
t = (time_t)ph7_value_to_int64(apArg[1]);
pTm = localtime(&t);
if( pTm == 0 ){
time(&t);
}
}else{
time(&t);
}
pTm = localtime(&t);
STRUCT_TM_TO_SYTM(pTm,&sTm);
}
/* Perform the requested operation */
switch(zFormat[0]){
case 'd':
/* Day of the month */
iVal = sTm.tm_mday;
break;
case 'h':
/* Hour (12 hour format)*/
iVal = 1 + (sTm.tm_hour % 12);
break;
case 'H':
/* Hour (24 hour format)*/
iVal = sTm.tm_hour;
break;
case 'i':
/*Minutes*/
iVal = sTm.tm_min;
break;
case 'I':
/* returns 1 if DST is activated, 0 otherwise */
#ifdef __WINNT__
#ifdef _MSC_VER
#ifndef _WIN32_WCE
_get_daylight(&sTm.tm_isdst);
#endif
#endif
#endif
iVal = sTm.tm_isdst;
break;
case 'L':
/* returns 1 for leap year, 0 otherwise */
iVal = IS_LEAP_YEAR(sTm.tm_year);
break;
case 'm':
/* Month number*/
iVal = sTm.tm_mon;
break;
case 's':
/*Seconds*/
iVal = sTm.tm_sec;
break;
case 't':{
/*Days in current month*/
static const int aMonDays[] = {31,29,31,30,31,30,31,31,30,31,30,31 };
int nDays = aMonDays[sTm.tm_mon % 12 ];
if( sTm.tm_mon == 1 /* 'February' */ && !IS_LEAP_YEAR(sTm.tm_year) ){
nDays = 28;
}
iVal = nDays;
break;
}
case 'U':
/*Seconds since the Unix Epoch*/
iVal = (ph7_int64)time(0);
break;
case 'w':
/* Day of the week (0 on Sunday) */
iVal = sTm.tm_wday;
break;
case 'W': {
/* ISO-8601 week number of year, weeks starting on Monday */
static const int aISO8601[] = { 7 /* Sunday */,1 /* Monday */,2,3,4,5,6 };
iVal = aISO8601[sTm.tm_wday % 7 ];
break;
}
case 'y':
/* Year (2 digits) */
iVal = sTm.tm_year % 100;
break;
case 'Y':
/* Year (4 digits) */
iVal = sTm.tm_year;
break;
case 'z':
/* Day of the year */
iVal = sTm.tm_yday;
break;
case 'Z':
/*Timezone offset in seconds*/
iVal = sTm.tm_gmtoff;
break;
default:
/* unknown format,throw a warning */
ph7_context_throw_error(pCtx,PH7_CTX_WARNING,"Unknown date format token");
break;
}
/* Return the time value */
ph7_result_int64(pCtx,iVal);
return PH7_OK;
}
/*
* int mktime/gmmktime([ int $hour = date("H") [, int $minute = date("i") [, int $second = date("s")
* [, int $month = date("n") [, int $day = date("j") [, int $year = date("Y") [, int $is_dst = -1 ]]]]]]] )
* Returns the Unix timestamp corresponding to the arguments given. This timestamp is a 64bit integer
* containing the number of seconds between the Unix Epoch (January 1 1970 00:00:00 GMT) and the time
* specified.
* Arguments may be left out in order from right to left; any arguments thus omitted will be set to
* the current value according to the local date and time.
* Parameters
* $hour
* The number of the hour relevant to the start of the day determined by month, day and year.
* Negative values reference the hour before midnight of the day in question. Values greater
* than 23 reference the appropriate hour in the following day(s).
* $minute
* The number of the minute relevant to the start of the hour. Negative values reference
* the minute in the previous hour. Values greater than 59 reference the appropriate minute
* in the following hour(s).
* $second
* The number of seconds relevant to the start of the minute. Negative values reference
* the second in the previous minute. Values greater than 59 reference the appropriate
* second in the following minute(s).
* $month
* The number of the month relevant to the end of the previous year. Values 1 to 12 reference
* the normal calendar months of the year in question. Values less than 1 (including negative values)
* reference the months in the previous year in reverse order, so 0 is December, -1 is November)...
* $day
* The number of the day relevant to the end of the previous month. Values 1 to 28, 29, 30 or 31
* (depending upon the month) reference the normal days in the relevant month. Values less than 1
* (including negative values) reference the days in the previous month, so 0 is the last day
* of the previous month, -1 is the day before that, etc. Values greater than the number of days
* in the relevant month reference the appropriate day in the following month(s).
* $year
* The number of the year, may be a two or four digit value, with values between 0-69 mapping
* to 2000-2069 and 70-100 to 1970-2000. On systems where time_t is a 32bit signed integer, as
* most common today, the valid range for year is somewhere between 1901 and 2038.
* $is_dst
* This parameter can be set to 1 if the time is during daylight savings time (DST), 0 if it is not,
* or -1 (the default) if it is unknown whether the time is within daylight savings time or not.
* Return
* mktime() returns the Unix timestamp of the arguments given.
* If the arguments are invalid, the function returns FALSE
*/
static int PH7_builtin_mktime(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zFunction;
ph7_int64 iVal = 0;
struct tm *pTm;
time_t t;
/* Extract function name */
zFunction = ph7_function_name(pCtx);
/* Get the current time */
time(&t);
if( zFunction[0] == 'g' /* gmmktime */ ){
pTm = gmtime(&t);
}else{
/* localtime */
pTm = localtime(&t);
}
if( nArg > 0 ){
int iVal;
/* Hour */
iVal = ph7_value_to_int(apArg[0]);
pTm->tm_hour = iVal;
if( nArg > 1 ){
/* Minutes */
iVal = ph7_value_to_int(apArg[1]);
pTm->tm_min = iVal;
if( nArg > 2 ){
/* Seconds */
iVal = ph7_value_to_int(apArg[2]);
pTm->tm_sec = iVal;
if( nArg > 3 ){
/* Month */
iVal = ph7_value_to_int(apArg[3]);
pTm->tm_mon = iVal - 1;
if( nArg > 4 ){
/* mday */
iVal = ph7_value_to_int(apArg[4]);
pTm->tm_mday = iVal;
if( nArg > 5 ){
/* Year */
iVal = ph7_value_to_int(apArg[5]);
if( iVal > 1900 ){
iVal -= 1900;
}
pTm->tm_year = iVal;
if( nArg > 6 ){
/* is_dst */
iVal = ph7_value_to_bool(apArg[6]);
pTm->tm_isdst = iVal;
}
}
}
}
}
}
}
/* Make the time */
iVal = (ph7_int64)mktime(pTm);
/* Return the timesatmp as a 64bit integer */
ph7_result_int64(pCtx,iVal);
return PH7_OK;
}
/*
* Section:
* URL handling Functions.
* Authors:
* Symisc Systems,devel@symisc.net.
* Copyright (C) Symisc Systems,http://ph7.symisc.net
* Status:
* Stable.
*/
/*
* Output consumer callback for the standard Symisc routines.
* [i.e: SyBase64Encode(),SyBase64Decode(),SyUriEncode(),...].
*/
static int Consumer(const void *pData,unsigned int nLen,void *pUserData)
{
/* Store in the call context result buffer */
ph7_result_string((ph7_context *)pUserData,(const char *)pData,(int)nLen);
return SXRET_OK;
}
/*
* string base64_encode(string $data)
* string convert_uuencode(string $data)
* Encodes data with MIME base64
* Parameter
* $data
* Data to encode
* Return
* Encoded data or FALSE on failure.
*/
static int PH7_builtin_base64_encode(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zIn;
int nLen;
if( nArg < 1 ){
/* Missing arguments,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the input string */
zIn = ph7_value_to_string(apArg[0],&nLen);
if( nLen < 1 ){
/* Nothing to process,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Perform the BASE64 encoding */
SyBase64Encode(zIn,(sxu32)nLen,Consumer,pCtx);
return PH7_OK;
}
/*
* string base64_decode(string $data)
* string convert_uudecode(string $data)
* Decodes data encoded with MIME base64
* Parameter
* $data
* Encoded data.
* Return
* Returns the original data or FALSE on failure.
*/
static int PH7_builtin_base64_decode(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zIn;
int nLen;
if( nArg < 1 ){
/* Missing arguments,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the input string */
zIn = ph7_value_to_string(apArg[0],&nLen);
if( nLen < 1 ){
/* Nothing to process,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Perform the BASE64 decoding */
SyBase64Decode(zIn,(sxu32)nLen,Consumer,pCtx);
return PH7_OK;
}
/*
* string urlencode(string $str)
* URL encoding
* Parameter
* $data
* Input string.
* Return
* Returns a string in which all non-alphanumeric characters except -_. have
* been replaced with a percent (%) sign followed by two hex digits and spaces
* encoded as plus (+) signs.
*/
static int PH7_builtin_urlencode(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zIn;
int nLen;
if( nArg < 1 ){
/* Missing arguments,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the input string */
zIn = ph7_value_to_string(apArg[0],&nLen);
if( nLen < 1 ){
/* Nothing to process,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Perform the URL encoding */
SyUriEncode(zIn,(sxu32)nLen,Consumer,pCtx);
return PH7_OK;
}
/*
* string urldecode(string $str)
* Decodes any %## encoding in the given string.
* Plus symbols ('+') are decoded to a space character.
* Parameter
* $data
* Input string.
* Return
* Decoded URL or FALSE on failure.
*/
static int PH7_builtin_urldecode(ph7_context *pCtx,int nArg,ph7_value **apArg)
{
const char *zIn;
int nLen;
if( nArg < 1 ){
/* Missing arguments,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Extract the input string */
zIn = ph7_value_to_string(apArg[0],&nLen);
if( nLen < 1 ){
/* Nothing to process,return FALSE */
ph7_result_bool(pCtx,0);
return PH7_OK;
}
/* Perform the URL decoding */
SyUriDecode(zIn,(sxu32)nLen,Consumer,pCtx,TRUE);
return PH7_OK;
}
#endif /* PH7_DISABLE_BUILTIN_FUNC */
/* Table of the built-in functions */
static const ph7_builtin_func aBuiltInFunc[] = {
/* Variable handling functions */
{ "is_bool" , PH7_builtin_is_bool },
{ "is_float" , PH7_builtin_is_float },
{ "is_real" , PH7_builtin_is_float },
{ "is_double" , PH7_builtin_is_float },
{ "is_int" , PH7_builtin_is_int },
{ "is_integer" , PH7_builtin_is_int },
{ "is_long" , PH7_builtin_is_int },
{ "is_string" , PH7_builtin_is_string },
{ "is_null" , PH7_builtin_is_null },
{ "is_numeric" , PH7_builtin_is_numeric },
{ "is_scalar" , PH7_builtin_is_scalar },
{ "is_array" , PH7_builtin_is_array },
{ "is_object" , PH7_builtin_is_object },
{ "is_resource", PH7_builtin_is_resource },
{ "douleval" , PH7_builtin_floatval },
{ "floatval" , PH7_builtin_floatval },
{ "intval" , PH7_builtin_intval },
{ "strval" , PH7_builtin_strval },
{ "empty" , PH7_builtin_empty },
#ifndef PH7_DISABLE_BUILTIN_FUNC
#ifdef PH7_ENABLE_MATH_FUNC
/* Math functions */
{ "abs" , PH7_builtin_abs },
{ "sqrt" , PH7_builtin_sqrt },
{ "exp" , PH7_builtin_exp },
{ "floor", PH7_builtin_floor },
{ "cos" , PH7_builtin_cos },
{ "sin" , PH7_builtin_sin },
{ "acos" , PH7_builtin_acos },
{ "asin" , PH7_builtin_asin },
{ "cosh" , PH7_builtin_cosh },
{ "sinh" , PH7_builtin_sinh },
{ "ceil" , PH7_builtin_ceil },
{ "tan" , PH7_builtin_tan },
{ "tanh" , PH7_builtin_tanh },
{ "atan" , PH7_builtin_atan },
{ "atan2", PH7_builtin_atan2 },
{ "log" , PH7_builtin_log },
{ "log10" , PH7_builtin_log10 },
{ "pow" , PH7_builtin_pow },
{ "pi", PH7_builtin_pi },
{ "fmod", PH7_builtin_fmod },
{ "hypot", PH7_builtin_hypot },
#endif /* PH7_ENABLE_MATH_FUNC */
{ "round", PH7_builtin_round },
{ "dechex", PH7_builtin_dechex },
{ "decoct", PH7_builtin_decoct },
{ "decbin", PH7_builtin_decbin },
{ "hexdec", PH7_builtin_hexdec },
{ "bindec", PH7_builtin_bindec },
{ "octdec", PH7_builtin_octdec },
{ "srand", PH7_builtin_srand },
{ "mt_srand",PH7_builtin_srand },
{ "base_convert", PH7_builtin_base_convert },
/* String handling functions */
{ "substr", PH7_builtin_substr },
{ "substr_compare", PH7_builtin_substr_compare },
{ "substr_count", PH7_builtin_substr_count },
{ "chunk_split", PH7_builtin_chunk_split},
{ "addslashes" , PH7_builtin_addslashes },
{ "addcslashes", PH7_builtin_addcslashes},
{ "quotemeta", PH7_builtin_quotemeta },
{ "stripslashes", PH7_builtin_stripslashes },
{ "htmlspecialchars",PH7_builtin_htmlspecialchars },
{ "htmlspecialchars_decode", PH7_builtin_htmlspecialchars_decode },
{ "get_html_translation_table",PH7_builtin_get_html_translation_table },
{ "htmlentities",PH7_builtin_htmlentities},
{ "html_entity_decode", PH7_builtin_html_entity_decode},
{ "strlen" , PH7_builtin_strlen },
{ "strcmp" , PH7_builtin_strcmp },
{ "strcoll" , PH7_builtin_strcmp },
{ "strncmp" , PH7_builtin_strncmp },
{ "strcasecmp" , PH7_builtin_strcasecmp },
{ "strncasecmp", PH7_builtin_strncasecmp},
{ "implode" , PH7_builtin_implode },
{ "join" , PH7_builtin_implode },
{ "implode_recursive" , PH7_builtin_implode_recursive },
{ "join_recursive" , PH7_builtin_implode_recursive },
{ "explode" , PH7_builtin_explode },
{ "trim" , PH7_builtin_trim },
{ "rtrim" , PH7_builtin_rtrim },
{ "chop" , PH7_builtin_rtrim },
{ "ltrim" , PH7_builtin_ltrim },
{ "strtolower", PH7_builtin_strtolower },
{ "mb_strtolower",PH7_builtin_strtolower }, /* Only UTF-8 encoding is supported */
{ "strtoupper", PH7_builtin_strtoupper },
{ "mb_strtoupper",PH7_builtin_strtoupper }, /* Only UTF-8 encoding is supported */
{ "ucfirst", PH7_builtin_ucfirst },
{ "lcfirst", PH7_builtin_lcfirst },
{ "ord", PH7_builtin_ord },
{ "chr", PH7_builtin_chr },
{ "bin2hex", PH7_builtin_bin2hex },
{ "strstr", PH7_builtin_strstr },
{ "stristr", PH7_builtin_stristr },
{ "strchr", PH7_builtin_strstr },
{ "strpos", PH7_builtin_strpos },
{ "stripos", PH7_builtin_stripos },
{ "strrpos", PH7_builtin_strrpos },
{ "strripos", PH7_builtin_strripos },
{ "strrchr", PH7_builtin_strrchr },
{ "strrev", PH7_builtin_strrev },
{ "ucwords", PH7_builtin_ucwords },
{ "str_repeat", PH7_builtin_str_repeat },
{ "nl2br", PH7_builtin_nl2br },
{ "sprintf", PH7_builtin_sprintf },
{ "printf", PH7_builtin_printf },
{ "vprintf", PH7_builtin_vprintf },
{ "vsprintf", PH7_builtin_vsprintf },
{ "size_format", PH7_builtin_size_format},
#if !defined(PH7_DISABLE_HASH_FUNC)
{ "md5", PH7_builtin_md5 },
{ "sha1", PH7_builtin_sha1 },
{ "crc32", PH7_builtin_crc32 },
#endif /* PH7_DISABLE_HASH_FUNC */
{ "str_getcsv", PH7_builtin_str_getcsv },
{ "strip_tags", PH7_builtin_strip_tags },
{ "str_shuffle", PH7_builtin_str_shuffle},
{ "str_split", PH7_builtin_str_split },
{ "strspn", PH7_builtin_strspn },
{ "strcspn", PH7_builtin_strcspn },
{ "strpbrk", PH7_builtin_strpbrk },
{ "soundex", PH7_builtin_soundex },
{ "wordwrap", PH7_builtin_wordwrap },
{ "strtok", PH7_builtin_strtok },
{ "str_pad", PH7_builtin_str_pad },
{ "str_replace", PH7_builtin_str_replace},
{ "str_ireplace", PH7_builtin_str_replace},
{ "strtr", PH7_builtin_strtr },
{ "parse_ini_string", PH7_builtin_parse_ini_string},
/* Ctype functions */
{ "ctype_alnum", PH7_builtin_ctype_alnum },
{ "ctype_alpha", PH7_builtin_ctype_alpha },
{ "ctype_cntrl", PH7_builtin_ctype_cntrl },
{ "ctype_digit", PH7_builtin_ctype_digit },
{ "ctype_xdigit",PH7_builtin_ctype_xdigit},
{ "ctype_graph", PH7_builtin_ctype_graph },
{ "ctype_print", PH7_builtin_ctype_print },
{ "ctype_punct", PH7_builtin_ctype_punct },
{ "ctype_space", PH7_builtin_ctype_space },
{ "ctype_lower", PH7_builtin_ctype_lower },
{ "ctype_upper", PH7_builtin_ctype_upper },
/* Time functions */
{ "time" , PH7_builtin_time },
{ "microtime", PH7_builtin_microtime },
{ "getdate" , PH7_builtin_getdate },
{ "gettimeofday",PH7_builtin_gettimeofday },
{ "date", PH7_builtin_date },
{ "strftime", PH7_builtin_strftime },
{ "idate", PH7_builtin_idate },
{ "gmdate", PH7_builtin_gmdate },
{ "localtime", PH7_builtin_localtime },
{ "mktime", PH7_builtin_mktime },
{ "gmmktime", PH7_builtin_mktime },
/* URL functions */
{ "base64_encode",PH7_builtin_base64_encode },
{ "base64_decode",PH7_builtin_base64_decode },
{ "convert_uuencode",PH7_builtin_base64_encode },
{ "convert_uudecode",PH7_builtin_base64_decode },
{ "urlencode", PH7_builtin_urlencode },
{ "urldecode", PH7_builtin_urldecode },
{ "rawurlencode", PH7_builtin_urlencode },
{ "rawurldecode", PH7_builtin_urldecode },
#endif /* PH7_DISABLE_BUILTIN_FUNC */
};
/*
* Register the built-in functions defined above,the array functions
* defined in hashmap.c and the IO functions defined in vfs.c.
*/
PH7_PRIVATE void PH7_RegisterBuiltInFunction(ph7_vm *pVm)
{
sxu32 n;
for( n = 0 ; n < SX_ARRAYSIZE(aBuiltInFunc) ; ++n ){
ph7_create_function(&(*pVm),aBuiltInFunc[n].zName,aBuiltInFunc[n].xFunc,0);
}
/* Register hashmap functions [i.e: array_merge(),sort(),count(),array_diff(),...] */
PH7_RegisterHashmapFunctions(&(*pVm));
/* Register IO functions [i.e: fread(),fwrite(),chdir(),mkdir(),file(),...] */
PH7_RegisterIORoutine(&(*pVm));
}