/**
|
|
* @PROJECT PH7 Engine for the AerScript Interpreter
|
|
* @COPYRIGHT See COPYING in the top level directory
|
|
* @FILE engine/builtin.c
|
|
* @DESCRIPTION Built-in foreign functions for the PH7 Engine
|
|
* @DEVELOPERS Symisc Systems <devel@symisc.net>
|
|
* Rafal Kupiec <belliash@codingworkshop.eu.org>
|
|
*/
|
|
#include "ph7int.h"
|
|
/*
|
|
* Section:
|
|
* Variable handling Functions.
|
|
* Authors:
|
|
* Symisc Systems,devel@symisc.net.
|
|
* Copyright (C) Symisc Systems,https://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_callback($var)
|
|
* Finds out whether a variable is a callback.
|
|
* Parameters
|
|
* $var: The variable being evaluated.
|
|
* Return
|
|
* TRUE if var is a callback. False otherwise.
|
|
*/
|
|
static int PH7_builtin_is_callback(ph7_context *pCtx, int nArg, ph7_value **apArg) {
|
|
int res = 0; /* Assume false by default */
|
|
if(nArg > 0) {
|
|
res = ph7_value_is_callback(apArg[0]);
|
|
}
|
|
/* Query result */
|
|
ph7_result_bool(pCtx, res);
|
|
return PH7_OK;
|
|
}
|
|
/*
|
|
* bool is_char($var)
|
|
* Finds out whether a variable is a character.
|
|
* Parameters
|
|
* $var: The variable being evaluated.
|
|
* Return
|
|
* TRUE if var is a character. False otherwise.
|
|
*/
|
|
static int PH7_builtin_is_char(ph7_context *pCtx, int nArg, ph7_value **apArg) {
|
|
int res = 0; /* Assume false by default */
|
|
if(nArg > 0) {
|
|
res = ph7_value_is_char(apArg[0]);
|
|
}
|
|
/* Query result */
|
|
ph7_result_bool(pCtx, res);
|
|
return PH7_OK;
|
|
}
|
|
/*
|
|
* bool is_float($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)
|
|
* 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_void($var)
|
|
* Finds out whether a variable is a void.
|
|
* Parameters
|
|
* $var: The variable being evaluated.
|
|
* Return
|
|
* TRUE if var is void. False otherwise.
|
|
*/
|
|
static int PH7_builtin_is_void(ph7_context *pCtx, int nArg, ph7_value **apArg) {
|
|
int res = 0; /* Assume false by default */
|
|
if(nArg > 0) {
|
|
res = ph7_value_is_void(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_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 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 custom 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,https://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) ==> '&'
|
|
* '"' (double quote) ==> '"' when ENT_NOQUOTES is not set.
|
|
* "'" (single quote) ==> ''' only when ENT_QUOTES is set.
|
|
* '<' (less than) ==> '<'
|
|
* '>' (greater than) ==> '>'
|
|
* 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 '&' */
|
|
ph7_result_string(pCtx, "&", (int)sizeof("&") - 1);
|
|
} else if(c == '<') {
|
|
/* Expand '<' */
|
|
ph7_result_string(pCtx, "<", (int)sizeof("<") - 1);
|
|
} else if(c == '>') {
|
|
/* Expand '>' */
|
|
ph7_result_string(pCtx, ">", (int)sizeof(">") - 1);
|
|
} else if(c == '\'') {
|
|
if(iFlags & 0x02 /*ENT_QUOTES*/) {
|
|
/* Expand ''' */
|
|
ph7_result_string(pCtx, "'", (int)sizeof("'") - 1);
|
|
} else {
|
|
/* Leave the single quote untouched */
|
|
ph7_result_string(pCtx, "'", (int)sizeof(char));
|
|
}
|
|
} else if(c == '"') {
|
|
if((iFlags & 0x04) == 0 /*ENT_NOQUOTES*/) {
|
|
/* Expand '"' */
|
|
ph7_result_string(pCtx, """, (int)sizeof(""") - 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("&") - 1 && SyStrnicmp(zIn, "&", sizeof("&") - 1) == 0) {
|
|
/* & ==> '&' */
|
|
ph7_result_string(pCtx, "&", (int)sizeof(char));
|
|
nJump = (int)sizeof("&") - 1;
|
|
} else if(nLen >= (int)sizeof("<") - 1 && SyStrnicmp(zIn, "<", sizeof("<") - 1) == 0) {
|
|
/* < ==> < */
|
|
ph7_result_string(pCtx, "<", (int)sizeof(char));
|
|
nJump = (int)sizeof("<") - 1;
|
|
} else if(nLen >= (int)sizeof(">") - 1 && SyStrnicmp(zIn, ">", sizeof(">") - 1) == 0) {
|
|
/* > ==> '>' */
|
|
ph7_result_string(pCtx, ">", (int)sizeof(char));
|
|
nJump = (int)sizeof(">") - 1;
|
|
} else if(nLen >= (int)sizeof(""") - 1 && SyStrnicmp(zIn, """, sizeof(""") - 1) == 0) {
|
|
/* " ==> '"' */
|
|
if((iFlags & 0x04) == 0 /*ENT_NOQUOTES*/) {
|
|
ph7_result_string(pCtx, "\"", (int)sizeof(char));
|
|
} else {
|
|
/* Leave untouched */
|
|
ph7_result_string(pCtx, """, (int)sizeof(""") - 1);
|
|
}
|
|
nJump = (int)sizeof(""") - 1;
|
|
} else if(nLen >= (int)sizeof("'") - 1 && SyStrnicmp(zIn, "'", sizeof("'") - 1) == 0) {
|
|
/* ' ==> ''' */
|
|
if(iFlags & 0x02 /*ENT_QUOTES*/) {
|
|
/* Expand ''' */
|
|
ph7_result_string(pCtx, "'", (int)sizeof(char));
|
|
} else {
|
|
/* Leave untouched */
|
|
ph7_result_string(pCtx, "'", (int)sizeof("'") - 1);
|
|
}
|
|
nJump = (int)sizeof("'") - 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[] = {
|
|
"<", "<", ">", ">", "&", "&", """, "\"", "'", "'",
|
|
"!", "!", "$", "$", "#", "#", "%", "%", "(", "(",
|
|
")", ")", "{", "{", "}", "}", "=", "=", "+", "+",
|
|
"?", "?", "[", "[", "]", "]", "@", "@", ",", ","
|
|
};
|
|
/*
|
|
* 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: '<' ==> '<"] */
|
|
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 = (const unsigned char *)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;
|
|
}
|
|