12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193 |
- #include <stdio.h>
- #include <limits.h>
- #include <ctype.h>
- #include "php.h"
- #include "php_variables.h"
- #include <locale.h>
- #include "zend_execute.h"
- #include "zend_operators.h"
- #include "zend_strtod.h"
- #include "php_globals.h"
- #include "basic_functions.h"
- #include "scanf.h"
- #define SCAN_NOSKIP 0x1
- #define SCAN_SUPPRESS 0x2
- #define SCAN_UNSIGNED 0x4
- #define SCAN_WIDTH 0x8
- #define SCAN_SIGNOK 0x10
- #define SCAN_NODIGITS 0x20
- #define SCAN_NOZERO 0x40
- #define SCAN_XOK 0x80
- #define SCAN_PTOK 0x100
- #define SCAN_EXPOK 0x200
- #define UCHAR(x) (zend_uchar)(x)
- typedef struct CharSet {
- int exclude;
- int nchars;
- char *chars;
- int nranges;
- struct Range {
- char start;
- char end;
- } *ranges;
- } CharSet;
- typedef zend_long (*int_string_formater)(const char*, char**, int);
- static char *BuildCharSet(CharSet *cset, char *format);
- static int CharInSet(CharSet *cset, int ch);
- static void ReleaseCharSet(CharSet *cset);
- static inline void scan_set_error_return(int numVars, zval *return_value);
- static char * BuildCharSet(CharSet *cset, char *format)
- {
- char *ch, start;
- int nranges;
- char *end;
- memset(cset, 0, sizeof(CharSet));
- ch = format;
- if (*ch == '^') {
- cset->exclude = 1;
- ch = ++format;
- }
- end = format + 1;
-
- if (*ch == ']') {
- ch = end++;
- }
- nranges = 0;
- while (*ch != ']') {
- if (*ch == '-') {
- nranges++;
- }
- ch = end++;
- }
- cset->chars = (char *) safe_emalloc(sizeof(char), (end - format - 1), 0);
- if (nranges > 0) {
- cset->ranges = (struct Range *) safe_emalloc(sizeof(struct Range), nranges, 0);
- } else {
- cset->ranges = NULL;
- }
-
- cset->nchars = cset->nranges = 0;
- ch = format++;
- start = *ch;
- if (*ch == ']' || *ch == '-') {
- cset->chars[cset->nchars++] = *ch;
- ch = format++;
- }
- while (*ch != ']') {
- if (*format == '-') {
-
- start = *ch;
- } else if (*ch == '-') {
-
- if (*format == ']') {
- cset->chars[cset->nchars++] = start;
- cset->chars[cset->nchars++] = *ch;
- } else {
- ch = format++;
-
- if (start < *ch) {
- cset->ranges[cset->nranges].start = start;
- cset->ranges[cset->nranges].end = *ch;
- } else {
- cset->ranges[cset->nranges].start = *ch;
- cset->ranges[cset->nranges].end = start;
- }
- cset->nranges++;
- }
- } else {
- cset->chars[cset->nchars++] = *ch;
- }
- ch = format++;
- }
- return format;
- }
- static int CharInSet(CharSet *cset, int c)
- {
- char ch = (char) c;
- int i, match = 0;
- for (i = 0; i < cset->nchars; i++) {
- if (cset->chars[i] == ch) {
- match = 1;
- break;
- }
- }
- if (!match) {
- for (i = 0; i < cset->nranges; i++) {
- if ((cset->ranges[i].start <= ch)
- && (ch <= cset->ranges[i].end)) {
- match = 1;
- break;
- }
- }
- }
- return (cset->exclude ? !match : match);
- }
- static void ReleaseCharSet(CharSet *cset)
- {
- efree((char *)cset->chars);
- if (cset->ranges) {
- efree((char *)cset->ranges);
- }
- }
- PHPAPI int ValidateFormat(char *format, int numVars, int *totalSubs)
- {
- #define STATIC_LIST_SIZE 16
- int gotXpg, gotSequential, value, i, flags;
- char *end, *ch = NULL;
- int staticAssign[STATIC_LIST_SIZE];
- int *nassign = staticAssign;
- int objIndex, xpgSize, nspace = STATIC_LIST_SIZE;
-
- if (numVars > nspace) {
- nassign = (int*)safe_emalloc(sizeof(int), numVars, 0);
- nspace = numVars;
- }
- for (i = 0; i < nspace; i++) {
- nassign[i] = 0;
- }
- xpgSize = objIndex = gotXpg = gotSequential = 0;
- while (*format != '\0') {
- ch = format++;
- flags = 0;
- if (*ch != '%') {
- continue;
- }
- ch = format++;
- if (*ch == '%') {
- continue;
- }
- if (*ch == '*') {
- flags |= SCAN_SUPPRESS;
- ch = format++;
- goto xpgCheckDone;
- }
- if ( isdigit( (int)*ch ) ) {
-
- value = ZEND_STRTOUL(format-1, &end, 10);
- if (*end != '$') {
- goto notXpg;
- }
- format = end+1;
- ch = format++;
- gotXpg = 1;
- if (gotSequential) {
- goto mixedXPG;
- }
- objIndex = value - 1;
- if ((objIndex < 0) || (numVars && (objIndex >= numVars))) {
- goto badIndex;
- } else if (numVars == 0) {
-
-
- if (value > SCAN_MAX_ARGS) {
- goto badIndex;
- }
- xpgSize = (xpgSize > value) ? xpgSize : value;
- }
- goto xpgCheckDone;
- }
- notXpg:
- gotSequential = 1;
- if (gotXpg) {
- mixedXPG:
- zend_value_error("%s", "cannot mix \"%\" and \"%n$\" conversion specifiers");
- goto error;
- }
- xpgCheckDone:
-
- if (isdigit(UCHAR(*ch))) {
- value = ZEND_STRTOUL(format-1, &format, 10);
- flags |= SCAN_WIDTH;
- ch = format++;
- }
-
- if ((*ch == 'l') || (*ch == 'L') || (*ch == 'h')) {
- ch = format++;
- }
- if (!(flags & SCAN_SUPPRESS) && numVars && (objIndex >= numVars)) {
- goto badIndex;
- }
-
- switch (*ch) {
- case 'n':
- case 'd':
- case 'D':
- case 'i':
- case 'o':
- case 'x':
- case 'X':
- case 'u':
- case 'f':
- case 'e':
- case 'E':
- case 'g':
- case 's':
- break;
- case 'c':
-
-
-
-
-
- break;
- case '[':
- if (*format == '\0') {
- goto badSet;
- }
- ch = format++;
- if (*ch == '^') {
- if (*format == '\0') {
- goto badSet;
- }
- ch = format++;
- }
- if (*ch == ']') {
- if (*format == '\0') {
- goto badSet;
- }
- ch = format++;
- }
- while (*ch != ']') {
- if (*format == '\0') {
- goto badSet;
- }
- ch = format++;
- }
- break;
- badSet:
- zend_value_error("Unmatched [ in format string");
- goto error;
- default: {
- zend_value_error("Bad scan conversion character \"%c\"", *ch);
- goto error;
- }
- }
- if (!(flags & SCAN_SUPPRESS)) {
- if (objIndex >= nspace) {
-
- value = nspace;
- if (xpgSize) {
- nspace = xpgSize;
- } else {
- nspace += STATIC_LIST_SIZE;
- }
- if (nassign == staticAssign) {
- nassign = (void *)safe_emalloc(nspace, sizeof(int), 0);
- for (i = 0; i < STATIC_LIST_SIZE; ++i) {
- nassign[i] = staticAssign[i];
- }
- } else {
- nassign = (void *)erealloc((void *)nassign, nspace * sizeof(int));
- }
- for (i = value; i < nspace; i++) {
- nassign[i] = 0;
- }
- }
- nassign[objIndex]++;
- objIndex++;
- }
- }
-
- if (numVars == 0) {
- if (xpgSize) {
- numVars = xpgSize;
- } else {
- numVars = objIndex;
- }
- }
- if (totalSubs) {
- *totalSubs = numVars;
- }
- for (i = 0; i < numVars; i++) {
- if (nassign[i] > 1) {
- zend_value_error("%s", "Variable is assigned by multiple \"%n$\" conversion specifiers");
- goto error;
- } else if (!xpgSize && (nassign[i] == 0)) {
-
- zend_value_error("Variable is not assigned by any conversion specifiers");
- goto error;
- }
- }
- if (nassign != staticAssign) {
- efree((char *)nassign);
- }
- return SCAN_SUCCESS;
- badIndex:
- if (gotXpg) {
- zend_value_error("%s", "\"%n$\" argument index out of range");
- } else {
- zend_value_error("Different numbers of variable names and field specifiers");
- }
- error:
- if (nassign != staticAssign) {
- efree((char *)nassign);
- }
- return SCAN_ERROR_INVALID_FORMAT;
- #undef STATIC_LIST_SIZE
- }
- PHPAPI int php_sscanf_internal( char *string, char *format,
- int argCount, zval *args,
- int varStart, zval *return_value)
- {
- int numVars, nconversions, totalVars = -1;
- int i, result;
- zend_long value;
- int objIndex;
- char *end, *baseString;
- zval *current;
- char op = 0;
- int base = 0;
- int underflow = 0;
- size_t width;
- int_string_formater fn = NULL;
- char *ch, sch;
- int flags;
- char buf[64];
-
- if ((varStart > argCount) || (varStart < 0)){
- varStart = SCAN_MAX_ARGS + 1;
- }
- numVars = argCount - varStart;
- if (numVars < 0) {
- numVars = 0;
- }
-
- if (ValidateFormat(format, numVars, &totalVars) != SCAN_SUCCESS) {
- scan_set_error_return( numVars, return_value );
- return SCAN_ERROR_INVALID_FORMAT;
- }
- objIndex = numVars ? varStart : 0;
-
- if (numVars) {
- for (i = varStart;i < argCount;i++){
- ZEND_ASSERT(Z_ISREF(args[i]) && "Parameter must be passed by reference");
- }
- }
-
- if (!numVars) {
- zval tmp;
-
- array_init(return_value);
- for (i = 0; i < totalVars; i++) {
- ZVAL_NULL(&tmp);
- if (add_next_index_zval(return_value, &tmp) == FAILURE) {
- scan_set_error_return(0, return_value);
- return FAILURE;
- }
- }
- varStart = 0;
- }
- baseString = string;
-
- nconversions = 0;
-
- while (*format != '\0') {
- ch = format++;
- flags = 0;
-
- if ( isspace( (int)*ch ) ) {
- sch = *string;
- while ( isspace( (int)sch ) ) {
- if (*string == '\0') {
- goto done;
- }
- string++;
- sch = *string;
- }
- continue;
- }
- if (*ch != '%') {
- literal:
- if (*string == '\0') {
- underflow = 1;
- goto done;
- }
- sch = *string;
- string++;
- if (*ch != sch) {
- goto done;
- }
- continue;
- }
- ch = format++;
- if (*ch == '%') {
- goto literal;
- }
-
- if (*ch == '*') {
- flags |= SCAN_SUPPRESS;
- ch = format++;
- } else if ( isdigit(UCHAR(*ch))) {
- value = ZEND_STRTOUL(format-1, &end, 10);
- if (*end == '$') {
- format = end+1;
- ch = format++;
- objIndex = varStart + value - 1;
- }
- }
-
- if ( isdigit(UCHAR(*ch))) {
- width = ZEND_STRTOUL(format-1, &format, 10);
- ch = format++;
- } else {
- width = 0;
- }
-
- if ((*ch == 'l') || (*ch == 'L') || (*ch == 'h')) {
- ch = format++;
- }
-
- switch (*ch) {
- case 'n':
- if (!(flags & SCAN_SUPPRESS)) {
- if (numVars && objIndex >= argCount) {
- break;
- } else if (numVars) {
- current = args + objIndex++;
- ZEND_TRY_ASSIGN_REF_LONG(current, (zend_long) (string - baseString));
- } else {
- add_index_long(return_value, objIndex++, string - baseString);
- }
- }
- nconversions++;
- continue;
- case 'd':
- case 'D':
- op = 'i';
- base = 10;
- fn = (int_string_formater)ZEND_STRTOL_PTR;
- break;
- case 'i':
- op = 'i';
- base = 0;
- fn = (int_string_formater)ZEND_STRTOL_PTR;
- break;
- case 'o':
- op = 'i';
- base = 8;
- fn = (int_string_formater)ZEND_STRTOL_PTR;
- break;
- case 'x':
- case 'X':
- op = 'i';
- base = 16;
- fn = (int_string_formater)ZEND_STRTOL_PTR;
- break;
- case 'u':
- op = 'i';
- base = 10;
- flags |= SCAN_UNSIGNED;
- fn = (int_string_formater)ZEND_STRTOUL_PTR;
- break;
- case 'f':
- case 'e':
- case 'E':
- case 'g':
- op = 'f';
- break;
- case 's':
- op = 's';
- break;
- case 'c':
- op = 's';
- flags |= SCAN_NOSKIP;
-
- if (0 == width) {
- width = 1;
- }
-
- break;
- case '[':
- op = '[';
- flags |= SCAN_NOSKIP;
- break;
- }
-
- if (*string == '\0') {
- underflow = 1;
- goto done;
- }
-
- if (!(flags & SCAN_NOSKIP)) {
- while (*string != '\0') {
- sch = *string;
- if (! isspace((int)sch) ) {
- break;
- }
- string++;
- }
- if (*string == '\0') {
- underflow = 1;
- goto done;
- }
- }
-
- switch (op) {
- case 'c':
- case 's':
-
- if (width == 0) {
- width = (size_t) ~0;
- }
- end = string;
- while (*end != '\0') {
- sch = *end;
- if ( isspace( (int)sch ) ) {
- break;
- }
- end++;
- if (--width == 0) {
- break;
- }
- }
- if (!(flags & SCAN_SUPPRESS)) {
- if (numVars && objIndex >= argCount) {
- break;
- } else if (numVars) {
- current = args + objIndex++;
- ZEND_TRY_ASSIGN_REF_STRINGL(current, string, end - string);
- } else {
- add_index_stringl(return_value, objIndex++, string, end-string);
- }
- }
- string = end;
- break;
- case '[': {
- CharSet cset;
- if (width == 0) {
- width = (size_t) ~0;
- }
- end = string;
- format = BuildCharSet(&cset, format);
- while (*end != '\0') {
- sch = *end;
- if (!CharInSet(&cset, (int)sch)) {
- break;
- }
- end++;
- if (--width == 0) {
- break;
- }
- }
- ReleaseCharSet(&cset);
- if (string == end) {
-
- goto done;
- }
- if (!(flags & SCAN_SUPPRESS)) {
- if (numVars && objIndex >= argCount) {
- break;
- } else if (numVars) {
- current = args + objIndex++;
- ZEND_TRY_ASSIGN_REF_STRINGL(current, string, end - string);
- } else {
- add_index_stringl(return_value, objIndex++, string, end-string);
- }
- }
- string = end;
- break;
- }
- case 'i':
-
-
- buf[0] = '\0';
-
- if ((width == 0) || (width > sizeof(buf) - 1)) {
- width = sizeof(buf) - 1;
- }
- flags |= SCAN_SIGNOK | SCAN_NODIGITS | SCAN_NOZERO;
- for (end = buf; width > 0; width--) {
- switch (*string) {
-
- case '0':
-
- if (base == 16) {
- flags |= SCAN_XOK;
- }
-
- if (base == 0) {
- base = 8;
- flags |= SCAN_XOK;
- }
- if (flags & SCAN_NOZERO) {
- flags &= ~(SCAN_SIGNOK | SCAN_NODIGITS | SCAN_NOZERO);
- } else {
- flags &= ~(SCAN_SIGNOK | SCAN_XOK | SCAN_NODIGITS);
- }
- goto addToInt;
- case '1': case '2': case '3': case '4':
- case '5': case '6': case '7':
- if (base == 0) {
- base = 10;
- }
- flags &= ~(SCAN_SIGNOK | SCAN_XOK | SCAN_NODIGITS);
- goto addToInt;
- case '8': case '9':
- if (base == 0) {
- base = 10;
- }
- if (base <= 8) {
- break;
- }
- flags &= ~(SCAN_SIGNOK | SCAN_XOK | SCAN_NODIGITS);
- goto addToInt;
- case 'A': case 'B': case 'C':
- case 'D': case 'E': case 'F':
- case 'a': case 'b': case 'c':
- case 'd': case 'e': case 'f':
- if (base <= 10) {
- break;
- }
- flags &= ~(SCAN_SIGNOK | SCAN_XOK | SCAN_NODIGITS);
- goto addToInt;
- case '+': case '-':
- if (flags & SCAN_SIGNOK) {
- flags &= ~SCAN_SIGNOK;
- goto addToInt;
- }
- break;
- case 'x': case 'X':
- if ((flags & SCAN_XOK) && (end == buf+1)) {
- base = 16;
- flags &= ~SCAN_XOK;
- goto addToInt;
- }
- break;
- }
-
- break;
- addToInt:
-
- *end++ = *string++;
- if (*string == '\0') {
- break;
- }
- }
-
- if (flags & SCAN_NODIGITS) {
- if (*string == '\0') {
- underflow = 1;
- }
- goto done;
- } else if (end[-1] == 'x' || end[-1] == 'X') {
- end--;
- string--;
- }
-
- if (!(flags & SCAN_SUPPRESS)) {
- *end = '\0';
- value = (zend_long) (*fn)(buf, NULL, base);
- if ((flags & SCAN_UNSIGNED) && (value < 0)) {
- snprintf(buf, sizeof(buf), ZEND_ULONG_FMT, value);
- if (numVars && objIndex >= argCount) {
- break;
- } else if (numVars) {
-
- current = args + objIndex++;
- ZEND_TRY_ASSIGN_REF_STRING(current, buf);
- } else {
- add_index_string(return_value, objIndex++, buf);
- }
- } else {
- if (numVars && objIndex >= argCount) {
- break;
- } else if (numVars) {
- current = args + objIndex++;
- ZEND_TRY_ASSIGN_REF_LONG(current, value);
- } else {
- add_index_long(return_value, objIndex++, value);
- }
- }
- }
- break;
- case 'f':
-
- buf[0] = '\0';
- if ((width == 0) || (width > sizeof(buf) - 1)) {
- width = sizeof(buf) - 1;
- }
- flags |= SCAN_SIGNOK | SCAN_NODIGITS | SCAN_PTOK | SCAN_EXPOK;
- for (end = buf; width > 0; width--) {
- switch (*string) {
- case '0': case '1': case '2': case '3':
- case '4': case '5': case '6': case '7':
- case '8': case '9':
- flags &= ~(SCAN_SIGNOK | SCAN_NODIGITS);
- goto addToFloat;
- case '+':
- case '-':
- if (flags & SCAN_SIGNOK) {
- flags &= ~SCAN_SIGNOK;
- goto addToFloat;
- }
- break;
- case '.':
- if (flags & SCAN_PTOK) {
- flags &= ~(SCAN_SIGNOK | SCAN_PTOK);
- goto addToFloat;
- }
- break;
- case 'e':
- case 'E':
-
- if ((flags & (SCAN_NODIGITS | SCAN_EXPOK)) == SCAN_EXPOK) {
- flags = (flags & ~(SCAN_EXPOK|SCAN_PTOK))
- | SCAN_SIGNOK | SCAN_NODIGITS;
- goto addToFloat;
- }
- break;
- }
-
- break;
- addToFloat:
-
- *end++ = *string++;
- if (*string == '\0') {
- break;
- }
- }
-
- if (flags & SCAN_NODIGITS) {
- if (flags & SCAN_EXPOK) {
-
- if (*string == '\0') {
- underflow = 1;
- }
- goto done;
- }
-
- end--;
- string--;
- if (*end != 'e' && *end != 'E') {
- end--;
- string--;
- }
- }
-
- if (!(flags & SCAN_SUPPRESS)) {
- double dvalue;
- *end = '\0';
- dvalue = zend_strtod(buf, NULL);
- if (numVars && objIndex >= argCount) {
- break;
- } else if (numVars) {
- current = args + objIndex++;
- ZEND_TRY_ASSIGN_REF_DOUBLE(current, dvalue);
- } else {
- add_index_double(return_value, objIndex++, dvalue );
- }
- }
- break;
- }
- nconversions++;
- }
- done:
- result = SCAN_SUCCESS;
- if (underflow && (0==nconversions)) {
- scan_set_error_return( numVars, return_value );
- result = SCAN_ERROR_EOF;
- } else if (numVars) {
- zval_ptr_dtor(return_value );
- ZVAL_LONG(return_value, nconversions);
- } else if (nconversions < totalVars) {
-
- }
- return result;
- }
- static inline void scan_set_error_return(int numVars, zval *return_value)
- {
- if (numVars) {
- ZVAL_LONG(return_value, SCAN_ERROR_EOF);
- } else {
-
- convert_to_null(return_value);
- }
- }
|