/* +----------------------------------------------------------------------+ | PHP version 4.0 | +----------------------------------------------------------------------+ | Copyright (c) 1997, 1998, 1999 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 2.0 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available at through the world-wide-web at | | http://www.php.net/license/2_0.txt. | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Rasmus Lerdorf | | Stig Sæther Bakken | | Zeev Suraski | +----------------------------------------------------------------------+ */ /* $Id$ */ /* Synced with php3 revision 1.193 1999-06-16 [ssb] */ #include #include "php.h" #include "reg.h" #include "post.h" #include "php3_string.h" #ifdef HAVE_LOCALE_H # include #endif #include "zend_execute.h" #include "php_globals.h" static char hexconvtab[] = "0123456789abcdef"; static char *php_bin2hex(const unsigned char *old, const size_t oldlen, size_t *newlen) { unsigned char *new = NULL; size_t i, j; new = (char *) emalloc(oldlen * 2 * sizeof(char)); if(!new) { return new; } for(i = j = 0; i < oldlen; i++) { new[j++] = hexconvtab[old[i] >> 4]; new[j++] = hexconvtab[old[i] & 15]; } if(newlen) *newlen = oldlen * 2 * sizeof(char); return new; } /* proto bin2hex(string data) converts the binary representation of data to hex */ PHP_FUNCTION(bin2hex) { pval *data; char *new; size_t newlen; if(ARG_COUNT(ht) != 1 || getParameters(ht, 1, &data) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_string(data); new = php_bin2hex(data->value.str.val, data->value.str.len, &newlen); if(!new) { RETURN_FALSE; } RETURN_STRINGL(new, newlen, 0); } /* {{{ proto int strspn(string str, string mask) Find length of initial segment consisting entirely of characters found in mask */ PHP_FUNCTION(strspn) { pval *s1,*s2; if (ARG_COUNT(ht)!=2 || getParameters(ht, 2, &s1, &s2) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_string(s1); convert_to_string(s2); RETURN_LONG(strspn(s1->value.str.val,s2->value.str.val)); } /* }}} */ /* {{{ proto int strcspn(string str, string mask) Find length of initial segment consisting entirely of characters not found in mask */ PHP_FUNCTION(strcspn) { pval *s1,*s2; if (ARG_COUNT(ht)!=2 || getParameters(ht, 2, &s1, &s2) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_string(s1); convert_to_string(s2); RETURN_LONG(strcspn(s1->value.str.val,s2->value.str.val)); } /* }}} */ PHPAPI void _php3_trim(pval *str, pval * return_value, int mode) /* mode 1 : trim left mode 2 : trim right mode 3 : trim left and right */ { register int i; int len = str->value.str.len; int trimmed = 0; char *c = str->value.str.val; if (mode & 1) { for (i = 0; i < len; i++) { if (c[i] == ' ' || c[i] == '\n' || c[i] == '\r' || c[i] == '\t' || c[i] == '\v') { trimmed++; } else { break; } } len -= trimmed; c += trimmed; } if (mode & 2) { for (i = len - 1; i >= 0; i--) { if (c[i] == ' ' || c[i] == '\n' || c[i] == '\r' || c[i] == '\t' || c[i] == '\v') { len--; } else { break; } } } RETVAL_STRINGL(c, len, 1); } /* {{{ proto string rtrim(string str) An alias for chop */ /* }}} */ /* {{{ proto string chop(string str) Remove trailing whitespace */ PHP_FUNCTION(chop) { pval *str; if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &str) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_string(str); if (str->type == IS_STRING) { _php3_trim(str, return_value, 2); return; } RETURN_FALSE; } /* }}} */ /* {{{ proto string trim(string str) Strip whitespace from the beginning and end of a string */ PHP_FUNCTION(trim) { pval *str; if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &str) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_string(str); if (str->type == IS_STRING) { _php3_trim(str, return_value, 3); return; } RETURN_FALSE; } /* }}} */ /* {{{ proto string ltrim(string str) Strip whitespace from the beginning of a string */ PHP_FUNCTION(ltrim) { pval *str; if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &str) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_string(str); if (str->type == IS_STRING) { _php3_trim(str, return_value, 1); return; } RETURN_FALSE; } /* }}} */ void _php3_explode(pval *delim, pval *str, pval *return_value) { char *work_str, *p1, *p2; int i = 0; work_str = p1 = estrndup(str->value.str.val,str->value.str.len); p2 = strstr(p1, delim->value.str.val); if (p2 == NULL) { add_index_string(return_value, i++, p1, 1); } else do { p2[0] = 0; add_index_string(return_value, i++, p1, 1); p1 = p2 + delim->value.str.len; } while ((p2 = strstr(p1, delim->value.str.val)) && p2 != work_str); if (p1 != work_str) { add_index_string(return_value, i++, p1, 1); } efree(work_str); } /* {{{ proto array explode(string separator, string str) Split a string on string separator and return array of components */ PHP_FUNCTION(explode) { pval *str, *delim; if (ARG_COUNT(ht) != 2 || getParameters(ht, 2, &delim, &str) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_string(str); convert_to_string(delim); if (strlen(delim->value.str.val)==0) { /* the delimiter must be a valid C string that's at least 1 character long */ php_error(E_WARNING,"Empty delimiter"); RETURN_FALSE; } if (array_init(return_value) == FAILURE) { return; } _php3_explode(delim, str, return_value); } /* }}} */ /* {{{ proto string join(array src, string glue) An alias for implode */ /* }}} */ void _php3_implode(pval *delim, pval *arr, pval *return_value) { pval **tmp; int len = 0, count = 0; /* convert everything to strings, and calculate length */ zend_hash_internal_pointer_reset(arr->value.ht); while (zend_hash_get_current_data(arr->value.ht, (void **) &tmp) == SUCCESS) { SEPARATE_ZVAL(tmp); convert_to_string(*tmp); if ((*tmp)->type == IS_STRING && (*tmp)->value.str.val != undefined_variable_string) { len += (*tmp)->value.str.len; if (count>0) { len += delim->value.str.len; } count++; } zend_hash_move_forward(arr->value.ht); } /* do it */ return_value->value.str.val = (char *) emalloc(len + 1); return_value->value.str.val[0] = '\0'; return_value->value.str.val[len] = '\0'; zend_hash_internal_pointer_reset(arr->value.ht); while (zend_hash_get_current_data(arr->value.ht, (void **) &tmp) == SUCCESS) { if ((*tmp)->type == IS_STRING && (*tmp)->value.str.val != undefined_variable_string) { count--; strcat(return_value->value.str.val, (*tmp)->value.str.val); if (count > 0) { strcat(return_value->value.str.val, delim->value.str.val); } } zend_hash_move_forward(arr->value.ht); } return_value->type = IS_STRING; return_value->value.str.len = len; } /* {{{ proto string implode(array src, string glue) Join array elements placing glue string between items and return one string */ PHP_FUNCTION(implode) { pval *arg1, *arg2, *delim, *arr; if (ARG_COUNT(ht) != 2 || getParameters(ht, 2, &arg1, &arg2) == FAILURE) { WRONG_PARAM_COUNT; } if (arg1->type == IS_ARRAY && arg2->type == IS_STRING) { arr = arg1; delim = arg2; } else if (arg2->type == IS_ARRAY) { convert_to_string(arg1); arr = arg2; delim = arg1; } else { php_error(E_WARNING, "Bad arguments to %s()", get_active_function_name()); return; } _php3_implode(delim, arr, return_value); } /* }}} */ #ifndef THREAD_SAFE char *strtok_string; #endif /* {{{ proto string strtok([string str,] string token) Tokenize a string */ PHP_FUNCTION(strtok) { pval *str, *tok; #ifndef THREAD_SAFE static char *strtok_pos1 = NULL; static char *strtok_pos2 = NULL; #endif char *token = NULL, *tokp=NULL; char *first = NULL; int argc; argc = ARG_COUNT(ht); if ((argc == 1 && getParameters(ht, 1, &tok) == FAILURE) || (argc == 2 && getParameters(ht, 2, &str, &tok) == FAILURE) || argc < 1 || argc > 2) { WRONG_PARAM_COUNT; } convert_to_string(tok); tokp = token = tok->value.str.val; if (argc == 2) { convert_to_string(str); STR_FREE(strtok_string); strtok_string = estrndup(str->value.str.val,str->value.str.len); strtok_pos1 = strtok_string; strtok_pos2 = NULL; } if (strtok_pos1 && *strtok_pos1) { for ( /* NOP */ ; token && *token; token++) { strtok_pos2 = strchr(strtok_pos1, (int) *token); if (!first || (strtok_pos2 && strtok_pos2 < first)) { first = strtok_pos2; } } /* NB: token is unusable now */ strtok_pos2 = first; if (strtok_pos2) { *strtok_pos2 = '\0'; } RETVAL_STRING(strtok_pos1,1); #if 0 /* skip 'token' white space for next call to strtok */ while (strtok_pos2 && strchr(tokp, *(strtok_pos2+1))) { strtok_pos2++; } #endif if (strtok_pos2) strtok_pos1 = strtok_pos2 + 1; else strtok_pos1 = NULL; } else { RETVAL_FALSE; } } /* }}} */ PHPAPI char *_php3_strtoupper(char *s) { char *c; int ch; c = s; while (*c) { ch = toupper((unsigned char)*c); *c++ = ch; } return (s); } /* {{{ proto string strtoupper(string str) Make a string uppercase */ PHP_FUNCTION(strtoupper) { pval *arg; char *ret; if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &arg)) { WRONG_PARAM_COUNT; } convert_to_string(arg); ret = _php3_strtoupper(arg->value.str.val); RETVAL_STRING(ret,1); } /* }}} */ PHPAPI char *_php3_strtolower(char *s) { register int ch; char *c; c = s; while (*c) { ch = tolower((unsigned char)*c); *c++ = ch; } return (s); } /* {{{ proto string strtolower(string str) Make a string lowercase */ PHP_FUNCTION(strtolower) { pval *str; char *ret; if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &str)) { WRONG_PARAM_COUNT; } convert_to_string(str); ret = _php3_strtolower(str->value.str.val); RETVAL_STRING(ret,1); } /* }}} */ /* {{{ proto string basename(string path) Return the filename component of the path */ PHP_FUNCTION(basename) { pval *str; char *ret, *c; if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &str)) { WRONG_PARAM_COUNT; } convert_to_string(str); ret = estrdup(str->value.str.val); c = ret + str->value.str.len -1; while (*c == '/' #ifdef MSVC5 || *c == '\\' #endif ) c--; *(c + 1) = '\0'; if ((c = strrchr(ret, '/')) #ifdef MSVC5 || (c = strrchr(ret, '\\')) #endif ) { RETVAL_STRING(c + 1,1); } else { RETVAL_STRING(str->value.str.val,1); } efree(ret); } /* }}} */ PHPAPI void _php3_dirname(char *str, int len) { register char *c; c = str + len - 1; while (*c == '/' #ifdef MSVC5 || *c == '\\' #endif ) c--; /* strip trailing slashes */ *(c + 1) = '\0'; if ((c = strrchr(str, '/')) #ifdef MSVC5 || (c = strrchr(str, '\\')) #endif ) *c='\0'; } /* {{{ proto string dirname(string path) Return the directory name component of the path */ PHP_FUNCTION(dirname) { pval *str; char *ret; if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &str)) { WRONG_PARAM_COUNT; } convert_to_string(str); ret = estrdup(str->value.str.val); _php3_dirname(ret,str->value.str.len); RETVAL_STRING(ret,1); efree(ret); } /* }}} */ /* case insensitve strstr */ PHPAPI char *php3i_stristr(unsigned char *s, unsigned char *t) { int i, j, k, l; for (i = 0; s[i]; i++) { for (j = 0, l = k = i; s[k] && t[j] && tolower(s[k]) == tolower(t[j]); j++, k++) ; if (t[j] == '\0') return s + l; } return NULL; } /* {{{ proto string stristr(string haystack, string needle) Find first occurrence of a string within another, case insensitive */ PHP_FUNCTION(stristr) { pval *haystack, *needle; char *found = NULL; if (ARG_COUNT(ht) != 2 || getParameters(ht, 2, &haystack, &needle) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_string(haystack); convert_to_string(needle); if (strlen(needle->value.str.val)==0) { php_error(E_WARNING,"Empty delimiter"); RETURN_FALSE; } found = php3i_stristr(haystack->value.str.val, needle->value.str.val); if (found) { RETVAL_STRING(found,1); } else { RETVAL_FALSE; } } /* }}} */ /* {{{ proto string strstr(string haystack, string needle) Find first occurrence of a string within another */ PHP_FUNCTION(strstr) { pval *haystack, *needle; char *found = NULL; if (ARG_COUNT(ht) != 2 || getParameters(ht, 2, &haystack, &needle) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_string(haystack); if (needle->type == IS_STRING) { if (strlen(needle->value.str.val)==0) { php_error(E_WARNING,"Empty delimiter"); RETURN_FALSE; } found = strstr(haystack->value.str.val, needle->value.str.val); } else { convert_to_long(needle); found = strchr(haystack->value.str.val, (char) needle->value.lval); } if (found) { RETVAL_STRING(found,1); } else { RETVAL_FALSE; } } /* }}} */ /* {{{ proto string strchr(string haystack, string needle) An alias for strstr */ /* }}} */ /* {{{ proto int strpos(string haystack, string needle [, int offset]) Find position of first occurrence of a string within another */ PHP_FUNCTION(strpos) { pval *haystack, *needle, *OFFSET; int offset = 0; char *found = NULL; switch(ARG_COUNT(ht)) { case 2: if (getParameters(ht, 2, &haystack, &needle) == FAILURE) { WRONG_PARAM_COUNT; } break; case 3: if (getParameters(ht, 3, &haystack, &needle, &OFFSET) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_long(OFFSET); offset = OFFSET->value.lval; break; default: WRONG_PARAM_COUNT; } convert_to_string(haystack); if (offset > haystack->value.str.len) { php_error(E_WARNING,"offset not contained in string"); RETURN_FALSE; } if (needle->type == IS_STRING) { if (needle->value.str.len==0) { php_error(E_WARNING,"Empty delimiter"); RETURN_FALSE; } found = strstr(haystack->value.str.val+offset, needle->value.str.val); } else { convert_to_long(needle); found = strchr(haystack->value.str.val+offset, (char) needle->value.lval); } if (found) { RETVAL_LONG(found - haystack->value.str.val); } else { RETVAL_FALSE; } } /* }}} */ /* {{{ proto int strrpos(string haystack, string needle) Find the last occurrence of a character in a string within another */ PHP_FUNCTION(strrpos) { pval *haystack, *needle; char *found = NULL; if (ARG_COUNT(ht) != 2 || getParameters(ht, 2, &haystack, &needle) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_string(haystack); if (needle->type == IS_STRING) { found = strrchr(haystack->value.str.val, *needle->value.str.val); } else { convert_to_long(needle); found = strrchr(haystack->value.str.val, (char) needle->value.lval); } if (found) { RETVAL_LONG(haystack->value.str.len - strlen(found)); } else { RETVAL_FALSE; } } /* }}} */ /* {{{ proto string strrchr(string haystack, string needle) Find the last occurrence of a character in a string within another */ PHP_FUNCTION(strrchr) { pval *haystack, *needle; char *found = NULL; if (ARG_COUNT(ht) != 2 || getParameters(ht, 2, &haystack, &needle) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_string(haystack); if (needle->type == IS_STRING) { found = strrchr(haystack->value.str.val, *needle->value.str.val); } else { convert_to_long(needle); found = strrchr(haystack->value.str.val, needle->value.lval); } if (found) { RETVAL_STRING(found,1); } else { RETVAL_FALSE; } } /* }}} */ static char * _php3_chunk_split(char *src, int srclen, char *end, int endlen, int chunklen, int *destlen) { char *dest; char *p, *q; int chunks; /* complete chunks! */ int restlen; chunks = srclen / chunklen; restlen = srclen - chunks * chunklen; /* srclen % chunklen */ dest = emalloc((srclen + (chunks + 1) * endlen + 1) * sizeof(char)); for(p = src, q = dest; p < (src + srclen - chunklen + 1); ) { memcpy(q, p, chunklen); q += chunklen; memcpy(q, end, endlen); q += endlen; p += chunklen; } if(restlen) { memcpy(q, p, restlen); q += restlen; memcpy(q, end, endlen); q += endlen; } *q = '\0'; if (destlen) { *destlen = q - dest; } return(dest); } /* {{{ proto string chunk_split(string str [, int chunklen [, string ending]]) Return split line */ PHP_FUNCTION(chunk_split) { pval *p_str, *p_chunklen, *p_ending; int argc; char *result; char *end = "\r\n"; int endlen = 2; int chunklen = 76; int result_len; argc = ARG_COUNT(ht); if (argc < 1 || argc > 3 || getParameters(ht, argc, &p_str, &p_chunklen, &p_ending) == FAILURE) { WRONG_PARAM_COUNT; } switch(argc) { case 3: convert_to_string(p_ending); end = p_ending->value.str.val; endlen = p_ending->value.str.len; case 2: convert_to_long(p_chunklen); chunklen = p_chunklen->value.lval; case 1: convert_to_string(p_str); } if(chunklen == 0) { php_error(E_WARNING, "chunk length is 0"); RETURN_FALSE; } result = _php3_chunk_split(p_str->value.str.val, p_str->value.str.len, end, endlen, chunklen, &result_len); if(result) { RETVAL_STRINGL(result, result_len, 0); } else { RETURN_FALSE; } } /* }}} */ /* {{{ proto string substr(string str, int start [, int length]) Return part of a string */ PHP_FUNCTION(substr) { pval *string, *from, *len; int argc, l; int f; argc = ARG_COUNT(ht); if ((argc == 2 && getParameters(ht, 2, &string, &from) == FAILURE) || (argc == 3 && getParameters(ht, 3, &string, &from, &len) == FAILURE) || argc < 2 || argc > 3) { WRONG_PARAM_COUNT; } convert_to_string(string); convert_to_long(from); f = from->value.lval; if (argc == 2) { l = string->value.str.len; } else { convert_to_long(len); l = len->value.lval; } /* if "from" position is negative, count start position from the end * of the string */ if (f < 0) { f = string->value.str.len + f; if (f < 0) { f = 0; } } /* if "length" position is negative, set it to the length * needed to stop that many chars from the end of the string */ if (l < 0) { l = (string->value.str.len - f) + l; if (l < 0) { l = 0; } } if (f >= (int)string->value.str.len) { RETURN_FALSE; } if((f+l) > (int)string->value.str.len) { l = (int)string->value.str.len - f; } RETVAL_STRINGL(string->value.str.val + f, l, 1); } /* }}} */ /* {{{ proto string quotemeta(string str) Quote meta characters */ PHP_FUNCTION(quotemeta) { pval *arg; char *str, *old; char *p, *q; char c; if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &arg) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_string(arg); old = arg->value.str.val; if (!*old) { RETURN_FALSE; } str = emalloc(2 * arg->value.str.len + 1); for(p = old, q = str; (c = *p); p++) { switch(c) { case '.': case '\\': case '+': case '*': case '?': case '[': case '^': case ']': case '$': case '(': case ')': *q++ = '\\'; /* break is missing _intentionally_ */ default: *q++ = c; } } *q = 0; RETVAL_STRING(erealloc(str, q - str + 1), 0); } /* }}} */ /* {{{ proto int ord(string character) Return ASCII value of character */ PHP_FUNCTION(ord) { pval *str; if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &str) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_string(str); RETVAL_LONG((unsigned char)str->value.str.val[0]); } /* }}} */ /* {{{ proto string chr(int ascii) Convert ASCII code to a character */ PHP_FUNCTION(chr) { pval *num; char temp[2]; if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &num) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_long(num); temp[0] = (char) num->value.lval; temp[1] = '\0'; RETVAL_STRINGL(temp, 1,1); } /* }}} */ /* {{{ proto string ucfirst(string str) Make a string's first character uppercase */ PHP_FUNCTION(ucfirst) { pval *arg; if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &arg) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_string(arg); if (!*arg->value.str.val) { RETURN_FALSE; } *arg->value.str.val = toupper((unsigned char)*arg->value.str.val); RETVAL_STRING(arg->value.str.val,1); } /* }}} */ /* {{{ proto string ucwords(string str) Uppercase the first character of every word in a string */ PHP_FUNCTION(ucwords) { pval *arg; char *r; if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &arg) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_string(arg); if (!*arg->value.str.val) { RETURN_FALSE; } *arg->value.str.val = toupper((unsigned char)*arg->value.str.val); r=arg->value.str.val; while((r=strstr(r," "))){ if(*(r+1)){ r++; *r=toupper((unsigned char)*r); } else { break; } } RETVAL_STRING(arg->value.str.val,1); } /* }}} */ PHPAPI char *_php3_strtr(char *string, int len, char *str_from, char *str_to, int trlen) { int i; unsigned char xlat[256]; if ((trlen < 1) || (len < 1)) { return string; } for (i = 0; i < 256; xlat[i] = i, i++); for (i = 0; i < trlen; i++) { xlat[(unsigned char) str_from[i]] = str_to[i]; } for (i = 0; i < len; i++) { string[i] = xlat[(unsigned char) string[i]]; } return string; } /* {{{ proto string strtr(string str, string from, string to) Translate characters in str using given translation tables */ PHP_FUNCTION(strtr) { /* strtr(STRING,FROM,TO) */ pval *str, *from, *to; if (ARG_COUNT(ht) != 3 || getParameters(ht, 3, &str, &from, &to) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_string(str); convert_to_string(from); convert_to_string(to); RETVAL_STRING(_php3_strtr(str->value.str.val, str->value.str.len, from->value.str.val, to->value.str.val, MIN(from->value.str.len,to->value.str.len)), 1); } /* }}} */ /* {{{ proto string strrev(string str) Reverse a string */ PHP_FUNCTION(strrev) { pval *str; int i,len; char c; if (ARG_COUNT(ht)!=1 || getParameters(ht, 1, &str)==FAILURE) { WRONG_PARAM_COUNT; } convert_to_string(str); len = str->value.str.len; for (i=0; ivalue.str.val[i]; str->value.str.val[i] = str->value.str.val[len-1-i]; str->value.str.val[len-1-i]=c; } *return_value = *str; pval_copy_constructor(return_value); } /* }}} */ static void _php3_similar_str(const char *txt1, int len1, const char *txt2, int len2, int *pos1, int *pos2, int *max) { char *p, *q; char *end1 = (char *) txt1 + len1; char *end2 = (char *) txt2 + len2; int l; *max = 0; for (p = (char *) txt1; p < end1; p++) { for (q = (char *) txt2; q < end2; q++) { for (l = 0; (p + l < end1) && (q + l < end2) && (p[l] == q[l]); l++); if (l > *max) { *max = l; *pos1 = p - txt1; *pos2 = q - txt2; } } } } static int _php3_similar_char(const char *txt1, int len1, const char *txt2, int len2) { int sum; int pos1, pos2, max; _php3_similar_str(txt1, len1, txt2, len2, &pos1, &pos2, &max); if ((sum = max)) { if (pos1 && pos2) sum += _php3_similar_char(txt1, pos1, txt2, pos2); if ((pos1 + max < len1) && (pos2 + max < len2)) sum += _php3_similar_char(txt1 + pos1 + max, len1 - pos1 - max, txt2 + pos2 + max, len2 - pos2 -max); } return sum; } /* {{{ proto int similar_text(string str1, string str2 [, double percent]) Calculates the similarity between two strings */ PHP_FUNCTION(similar_text) { pval *t1, *t2, *percent; int ac = ARG_COUNT(ht); int sim; if (ac < 2 || ac > 3 || getParameters(ht, ac, &t1, &t2, &percent) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_string(t1); convert_to_string(t2); if (ac > 2) { convert_to_double(percent); } if ((t1->value.str.len + t2->value.str.len) == 0) { if(ac > 2) { percent->value.dval = 0; } RETURN_LONG(0); } sim = _php3_similar_char(t1->value.str.val, t1->value.str.len, t2->value.str.val, t2->value.str.len); if (ac > 2) { percent->value.dval = sim * 200.0 / (t1->value.str.len + t2->value.str.len); } RETURN_LONG(sim); } /* }}} */ /* be careful, this edits the string in-place */ PHPAPI void php_stripslashes(char *string, int *len) { char *s, *t; int l; char escape_char='\\'; PLS_FETCH(); if (PG(magic_quotes_sybase)) { escape_char='\''; } if (len != NULL) { l = *len; } else { l = strlen(string); } s = string; t = string; while (l > 0) { if (*t == escape_char) { t++; /* skip the slash */ if (len != NULL) (*len)--; l--; if (l > 0) { if(*t=='0') { *s++='\0'; t++; } else { *s++ = *t++; /* preserve the next character */ } l--; } } else { if (s != t) *s++ = *t++; else { s++; t++; } l--; } } if (s != t) { *s = '\0'; } } /* {{{ proto string addcslashes(string str, string charlist) Escape all chars mentioned in charlist with backslash. It creates octal representations if asked to backslash characters with 8th bit set or with ASCII<32 (except '\n', '\r', '\t' etc...) */ PHP_FUNCTION(addcslashes) { pval *str, *what; if (ARG_COUNT(ht) != 2 || getParameters(ht, 2, &str, &what) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_string(str); convert_to_string(what); return_value->value.str.val = php_addcslashes(str->value.str.val,str->value.str.len,&return_value->value.str.len,0,what->value.str.val,what->value.str.len); return_value->type = IS_STRING; } /* }}} */ /* {{{ proto string addslashes(string str) Escape single quote, double quotes and backslash characters in a string with backslashes */ PHP_FUNCTION(addslashes) { pval *str; if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &str) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_string(str); return_value->value.str.val = php_addslashes(str->value.str.val,str->value.str.len,&return_value->value.str.len,0); return_value->type = IS_STRING; } /* }}} */ /* {{{ proto string stripcslashes(string str) Strip backslashes from a string. Uses C-style conventions*/ PHP_FUNCTION(stripcslashes) { pval *str; if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &str) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_string(str); /* let RETVAL do the estrdup() */ RETVAL_STRING(str->value.str.val,1); php_stripcslashes(return_value->value.str.val,&return_value->value.str.len); } /* }}} */ /* {{{ proto string stripslashes(string str) Strip backslashes from a string */ PHP_FUNCTION(stripslashes) { pval *str; if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &str) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_string(str); /* let RETVAL do the estrdup() */ RETVAL_STRING(str->value.str.val,1); php_stripslashes(return_value->value.str.val,&return_value->value.str.len); } /* }}} */ #ifndef HAVE_STRERROR #if !APACHE char *strerror(int errnum) { extern int sys_nerr; extern char *sys_errlist[]; #ifndef THREAD_SAFE static char str_ebuf[40]; #endif if ((unsigned int)errnum < sys_nerr) return(sys_errlist[errnum]); (void)sprintf(str_ebuf, "Unknown error: %d", errnum); return(str_ebuf); } #endif #endif PHPAPI void php_stripcslashes(char *str, int *len) { char *source,*target,*end; int nlen = *len, i; char numtmp[4]; for (source=str,end=str+nlen,target=str; source='0' && *source<='7' && i<3) { numtmp[i++] = *source++; } if (i) { numtmp[i]='\0'; *target++=(char)strtol(numtmp, NULL, 8); nlen-=i; source--; } else { *target++='\\'; *target++=*source; } } } else { *target++=*source; } } *target='\0'; *len = nlen; } PHPAPI char *php_addcslashes(char *str, int length, int *new_length, int should_free, char *what, int wlength) { char flags[256]; char *new_str = emalloc((length?length:(length=strlen(str)))*4+1); char *source,*target; char *end; char c; int newlen; if (!wlength) { wlength = strlen(what); } if (!length) { length = strlen(str); } memset(flags, '\0', sizeof(flags)); for (source=what,end=source+wlength; (c=*source) || source=(unsigned char)c) { memset(flags+c, 1, (unsigned char)*(source+3)-(unsigned char)c+1); source+=3; } else flags[(unsigned char)c]=1; } for (source=str,end=source+length,target=new_str; (c=*source) || source126) { *target++ = '\\'; switch (c) { case '\n': *target++ = 'n'; break; case '\t': *target++ = 't'; break; case '\r': *target++ = 'r'; break; case '\a': *target++ = 'a'; break; case '\v': *target++ = 'v'; break; case '\b': *target++ = 'b'; break; case '\f': *target++ = 'f'; break; default: target += sprintf(target, "%03o", (unsigned char)c); } continue; } *target++ = '\\'; } *target++ = c; } *target = 0; newlen = target-new_str; if (target-new_str=224) && (((unsigned char) c)<=250)) ? 1 : 0) #define _isblank(c) (((((unsigned char) c)==' ' || ((unsigned char) c)=='\t')) ? 1 : 0) #define _isnewline(c) (((((unsigned char) c)=='\n' || ((unsigned char) c)=='\r')) ? 1 : 0) PHPAPI void _php3_char_to_str(char *str,uint len,char from,char *to,int to_len,pval *result) { int char_count=0; char *source,*target,*tmp,*source_end=str+len, *tmp_end=NULL; for (source=str; sourcetype = IS_STRING; if (char_count==0) { result->value.str.val = estrndup(str,len); result->value.str.len = len; return; } result->value.str.len = len+char_count*(to_len-1); result->value.str.val = target = (char *) emalloc(result->value.str.len+1); for (source=str; source 0) { s = (q) + (end - p); off = erealloc(new, s - new + 1); if(off != new) { if(!off) { goto finish; } q += off - new; new = off; s = q + (end - p); } memcpy(q, p, end - p); q = s; } finish: *q = '\0'; if(_new_length) *_new_length = q - new; return new; } /* {{{ proto string str_replace(string needle, string str, string haystack) Replace all occurrences of needle in haystack with str */ PHP_FUNCTION(str_replace) { pval *haystack, *needle, *str; char *new; int len = 0; if(ARG_COUNT(ht) != 3 || getParameters(ht, 3, &needle, &str, &haystack) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_string(haystack); convert_to_string(needle); convert_to_string(str); if(haystack->value.str.len == 0) { RETURN_STRING(empty_string,1); } if(needle->value.str.len == 1) { _php3_char_to_str(haystack->value.str.val, haystack->value.str.len, needle->value.str.val[0], str->value.str.val, str->value.str.len, return_value); return; } if(needle->value.str.len == 0) { php_error(E_WARNING, "The length of the needle must not be 0"); RETURN_FALSE; } new = _php3_str_to_str(haystack->value.str.val, haystack->value.str.len, needle->value.str.val, needle->value.str.len, str->value.str.val, str->value.str.len, &len); RETURN_STRINGL(new, len, 0); } /* }}} */ /* Converts Logical Hebrew text (Hebrew Windows style) to Visual text * Cheers/complaints/flames - Zeev Suraski */ static void _php3_hebrev(INTERNAL_FUNCTION_PARAMETERS,int convert_newlines) { pval *str,*max_chars_per_line; char *heb_str,*tmp,*target,*opposite_target,*broken_str; int block_start, block_end, block_type, block_length, i; int block_ended; long max_chars=0; int begin,end,char_count,orig_begin; switch(ARG_COUNT(ht)) { case 1: if (getParameters(ht, 1, &str)==FAILURE) { RETURN_FALSE; } break; case 2: if (getParameters(ht, 2, &str, &max_chars_per_line)==FAILURE) { RETURN_FALSE; } convert_to_long(max_chars_per_line); max_chars = max_chars_per_line->value.lval; break; default: WRONG_PARAM_COUNT; break; } convert_to_string(str); if (str->value.str.len==0) { RETURN_FALSE; } tmp = str->value.str.val; block_start=block_end=0; block_ended=0; heb_str = (char *) emalloc(str->value.str.len+1); target = heb_str+str->value.str.len; opposite_target = heb_str; *target = 0; target--; block_length=0; if (isheb(*tmp)) { block_type = _HEB_BLOCK_TYPE_HEB; } else { block_type = _HEB_BLOCK_TYPE_ENG; } do { if (block_type==_HEB_BLOCK_TYPE_HEB) { while((isheb((int)*(tmp+1)) || _isblank((int)*(tmp+1)) || ispunct((int)*(tmp+1)) || (int)*(tmp+1)=='\n' ) && block_endvalue.str.len-1) { tmp++; block_end++; block_length++; } for (i=block_start; i<=block_end; i++) { *target = str->value.str.val[i]; switch (*target) { case '(': *target = ')'; break; case ')': *target = '('; break; default: break; } target--; } block_type = _HEB_BLOCK_TYPE_ENG; } else { while(!isheb(*(tmp+1)) && (int)*(tmp+1)!='\n' && block_endvalue.str.len-1) { tmp++; block_end++; block_length++; } while ((_isblank((int)*tmp) || ispunct((int)*tmp)) && *tmp!='/' && *tmp!='-' && block_end>block_start) { tmp--; block_end--; } for (i=block_end; i>=block_start; i--) { *target = str->value.str.val[i]; target--; } block_type = _HEB_BLOCK_TYPE_HEB; } block_start=block_end+1; } while(block_endvalue.str.len-1); broken_str = (char *) emalloc(str->value.str.len+1); begin=end=str->value.str.len-1; target = broken_str; while (1) { char_count=0; while ((!max_chars || char_count0) { char_count++; begin--; if (begin<=0 || _isnewline(heb_str[begin])) { while(begin>0 && _isnewline(heb_str[begin-1])) { begin--; char_count++; } break; } } if (char_count==max_chars) { /* try to avoid breaking words */ int new_char_count=char_count, new_begin=begin; while (new_char_count>0) { if (_isblank(heb_str[new_begin]) || _isnewline(heb_str[new_begin])) { break; } new_begin++; new_char_count--; } if (new_char_count>0) { char_count=new_char_count; begin=new_begin; } } orig_begin=begin; if (_isblank(heb_str[begin])) { heb_str[begin]='\n'; } while (begin<=end && _isnewline(heb_str[begin])) { /* skip leading newlines */ begin++; } for (i=begin; i<=end; i++) { /* copy content */ *target = heb_str[i]; target++; } for (i=orig_begin; i<=end && _isnewline(heb_str[i]); i++) { *target = heb_str[i]; target++; } begin=orig_begin; if (begin<=0) { *target = 0; break; } begin--; end=begin; } efree(heb_str); if (convert_newlines) { _php3_char_to_str(broken_str,str->value.str.len,'\n',"
\n",5,return_value); efree(broken_str); } else { return_value->value.str.val = broken_str; return_value->value.str.len = str->value.str.len; return_value->type = IS_STRING; } } /* {{{ proto string hebrev(string str [, int max_chars_per_line]) Convert logical Hebrew text to visual text */ PHP_FUNCTION(hebrev) { _php3_hebrev(INTERNAL_FUNCTION_PARAM_PASSTHRU,0); } /* }}} */ /* {{{ proto string hebrevc(string str [, int max_chars_per_line]) Convert logical Hebrew text to visual text with newline conversion */ PHP_FUNCTION(hebrevc) { _php3_hebrev(INTERNAL_FUNCTION_PARAM_PASSTHRU,1); } /* }}} */ /* {{{ proto string nl2br(string str) Converts newlines to HTML line breaks */ PHP_FUNCTION(nl2br) { pval *str; if (ARG_COUNT(ht)!=1 || getParameters(ht, 1, &str)==FAILURE) { WRONG_PARAM_COUNT; } convert_to_string(str); _php3_char_to_str(str->value.str.val,str->value.str.len,'\n',"
\n",5,return_value); } /* }}} */ /* {{{ proto string strip_tags(string str [, string allowable_tags]) Strips HTML and PHP tags from a string */ PHP_FUNCTION(strip_tags) { char *buf; pval *str, *allow=NULL; switch(ARG_COUNT(ht)) { case 1: if(getParameters(ht, 1, &str)==FAILURE) { RETURN_FALSE; } break; case 2: if(getParameters(ht, 2, &str, &allow)==FAILURE) { RETURN_FALSE; } convert_to_string(allow); break; default: WRONG_PARAM_COUNT; break; } convert_to_string(str); buf = estrdup(str->value.str.val); _php3_strip_tags(buf, str->value.str.len, 0, allow?allow->value.str.val:NULL); RETURN_STRING(buf, 0); } /* }}} */ /* {{{ proto string setlocale(string category, string locale) Set locale information */ PHP_FUNCTION(setlocale) { pval *category, *locale; int cat; char *loc, *retval; if (ARG_COUNT(ht)!=2 || getParameters(ht, 2, &category, &locale)==FAILURE) WRONG_PARAM_COUNT; #ifdef HAVE_SETLOCALE convert_to_string(category); convert_to_string(locale); if (!strcasecmp ("LC_ALL", category->value.str.val)) cat = LC_ALL; else if (!strcasecmp ("LC_COLLATE", category->value.str.val)) cat = LC_COLLATE; else if (!strcasecmp ("LC_CTYPE", category->value.str.val)) cat = LC_CTYPE; else if (!strcasecmp ("LC_MONETARY", category->value.str.val)) cat = LC_MONETARY; else if (!strcasecmp ("LC_NUMERIC", category->value.str.val)) cat = LC_NUMERIC; else if (!strcasecmp ("LC_TIME", category->value.str.val)) cat = LC_TIME; else { php_error(E_WARNING,"Invalid locale category name %s, must be one of LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC or LC_TIME", category->value.str.val); RETURN_FALSE; } if (!strcmp ("0", locale->value.str.val)) loc = NULL; else loc = locale->value.str.val; retval = setlocale (cat, loc); if (retval) { RETVAL_STRING(retval,1); return; } #endif RETURN_FALSE; } /* }}} */ /* {{{ proto void parse_str(string encoded_string) Parses GET/POST/COOKIE data and sets global variables. */ PHP_FUNCTION(parse_str) { pval *arg; char *res = NULL; ELS_FETCH(); PLS_FETCH(); SLS_FETCH(); if (getParameters(ht, 1, &arg) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_string(arg); if (arg->value.str.val && *arg->value.str.val) { res = estrndup(arg->value.str.val,arg->value.str.len); } php_treat_data(PARSE_STRING, res ELS_CC PLS_CC SLS_CC); } /* }}} */ #define PHP_TAG_BUF_SIZE 1023 /* Check if tag is in a set of tags * * states: * * 0 start tag * 1 first non-whitespace char seen */ int php_tag_find(char *tag, int len, char *set) { char c, *n, *t; int i=0, state=0, done=0; char *norm = emalloc(len); n = norm; t = tag; c = tolower(*t); /* normalize the tag removing leading and trailing whitespace and turn any into just and any into */ while(i': done =1; break; default: if(!isspace((int)c)) { if(state==0) { state=1; if(c!='/') *(n++) = c; } else { *(n++) = c; } } else { if(state==1) done=1; } break; } c = tolower(*(++t)); } *(n++) = '>'; *n = '\0'; if(strstr(set,norm)) done=1; else done=0; efree(norm); return done; } /* A simple little state-machine to strip out html and php tags State 0 is the output state, State 1 means we are inside a normal html tag and state 2 means we are inside a php tag. The state variable is passed in to allow a function like fgetss to maintain state across calls to the function. lc holds the last significant character read and br is a bracket counter. When an allow string is passed in we keep track of the string in state 1 and when the tag is closed check it against the allow string to see if we should allow it. */ void _php3_strip_tags(char *rbuf, int len, int state, char *allow) { char *tbuf, *buf, *p, *tp, *rp, c, lc; int br, i=0; buf = estrdup(rbuf); c = *buf; lc = '\0'; p = buf; rp = rbuf; br = 0; if(allow) { _php3_strtolower(allow); tbuf = emalloc(PHP_TAG_BUF_SIZE+1); tp = tbuf; } else tp=NULL; while(i': if (state == 1) { lc = '>'; state = 0; if(allow) { *(tp++) = '>'; *tp='\0'; if(php_tag_find(tbuf, tp-tbuf, allow)) { memcpy(rp,tbuf,tp-tbuf); rp += tp-tbuf; } tp = tbuf; } } else if (state == 2) { if (!br && lc != '\"' && *(p-1)=='?') { state = 0; } } break; case '\"': if (state == 2) { if (lc == '\"') { lc = '\0'; } else if (lc != '\\') { lc = '\"'; } } else if (state == 0) { *(rp++) = c; } else if (allow && state == 1) { *(tp++) = c; } break; case '?': if (state==1 && *(p-1)=='<') { br=0; state=2; break; } /* fall-through */ default: if (state == 0) { *(rp++) = c; } else if(allow && state == 1) { *(tp++) = c; if( (tp-tbuf)>=PHP_TAG_BUF_SIZE ) { /* no buffer overflows */ tp = tbuf; } } break; } c = *(++p); i++; } *rp = '\0'; efree(buf); if(allow) efree(tbuf); } /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: */