* xmlXPathSubstringFunction: * @ctxt: the XPath Parser context * @nargs: the number of arguments * * Implement the substring() XPath function * string substring(string, number, number?) * The substring function returns the substring of the first argument * starting at the position specified in the second argument with * length specified in the third argument. For example, * substring
| 8974 | * - substring("12345", -1 div 0, 1 div 0) returns "" |
| 8975 | */ |
| 8976 | void |
| 8977 | xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) { |
| 8978 | xmlXPathObjectPtr str, start, len; |
| 8979 | double le=0, in; |
| 8980 | int i, l, m; |
| 8981 | xmlChar *ret; |
| 8982 | |
| 8983 | if (nargs < 2) { |
| 8984 | CHECK_ARITY(2); |
| 8985 | } |
| 8986 | if (nargs > 3) { |
| 8987 | CHECK_ARITY(3); |
| 8988 | } |
| 8989 | /* |
| 8990 | * take care of possible last (position) argument |
| 8991 | */ |
| 8992 | if (nargs == 3) { |
| 8993 | CAST_TO_NUMBER; |
| 8994 | CHECK_TYPE(XPATH_NUMBER); |
| 8995 | len = valuePop(ctxt); |
| 8996 | le = len->floatval; |
| 8997 | xmlXPathReleaseObject(ctxt->context, len); |
| 8998 | } |
| 8999 | |
| 9000 | CAST_TO_NUMBER; |
| 9001 | CHECK_TYPE(XPATH_NUMBER); |
| 9002 | start = valuePop(ctxt); |
| 9003 | in = start->floatval; |
| 9004 | xmlXPathReleaseObject(ctxt->context, start); |
| 9005 | CAST_TO_STRING; |
| 9006 | CHECK_TYPE(XPATH_STRING); |
| 9007 | str = valuePop(ctxt); |
| 9008 | m = xmlUTF8Strlen((const unsigned char *)str->stringval); |
| 9009 | |
| 9010 | /* |
| 9011 | * If last pos not present, calculate last position |
| 9012 | */ |
| 9013 | if (nargs != 3) { |
| 9014 | le = (double)m; |
| 9015 | if (in < 1.0) |
| 9016 | in = 1.0; |
| 9017 | } |
| 9018 | |
| 9019 | /* Need to check for the special cases where either |
| 9020 | * the index is NaN, the length is NaN, or both |
| 9021 | * arguments are infinity (relying on Inf + -Inf = NaN) |
| 9022 | */ |
| 9023 | if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) { |
| 9024 | /* |
| 9025 | * To meet the requirements of the spec, the arguments |
| 9026 | * must be converted to integer format before |
| 9027 | * initial index calculations are done |
| 9028 | * |
| 9029 | * First we go to integer form, rounding up |
| 9030 | * and checking for special cases |
| 9031 | */ |
| 9032 | i = (int) in; |
| 9033 | if (((double)i)+0.5 <= in) i++; |