+static inline token_t validate_char(char *numb, impl_val *res, unsigned *lvl)
+{
+ char *endptr;
+ token_t typ = PSI_T_INT8;
+
+ res->i8 = numb[0];
+ endptr = &numb[1];
+
+ switch(res->i8) {
+ case '\\':
+ res->i8 = numb[1];
+ endptr = &numb[2];
+
+ switch(res->i8) {
+ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
+ res->i8 = strtol(&numb[1], &endptr, 8);
+ break;
+
+ case 'x':
+ res->i8 = strtol(&numb[2], &endptr, 16);
+ break;
+
+ case 'a':
+ res->i8 = '\a';
+ break;
+ case 'b':
+ res->i8 = '\b';
+ break;
+ case 'f':
+ res->i8 = '\f';
+ break;
+ case 'n':
+ res->i8 = '\n';
+ break;
+ case 'r':
+ res->i8 = '\r';
+ break;
+ case 't':
+ res->i8 = '\t';
+ break;
+ case 'v':
+ res->i8 = '\v';
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* more to grok? */
+ if (*endptr) {
+ impl_val tmp_val = {0};
+ token_t tmp_typ = validate_char(endptr, &tmp_val, lvl);
+
+ if (!tmp_typ) {
+ return 0;
+ }
+
+ res->i32 = res->i8 << (8 * *lvl);
+ typ = psi_calc_add(PSI_T_INT32, res, tmp_typ, &tmp_val, res);
+ }
+
+ ++(*lvl);
+
+ return typ;
+}
+static inline bool psi_number_validate_char(struct psi_data *data, struct psi_number *exp)
+{
+ impl_val val = {0};
+ unsigned lvl = 1;
+ token_t typ = validate_char(exp->data.numb, &val, &lvl);
+
+ if (!typ) {
+ return false;
+ }
+
+ free(exp->data.numb);
+ exp->type = typ;
+ exp->data.ival = val;
+ return true;
+}
+
+static inline bool psi_number_validate_number(struct psi_data *data, struct psi_number *exp)
+{
+ impl_val tmp = {0};
+
+ if (exp->flags) {
+ switch (exp->flags & 0x0f) {
+ case PSI_NUMBER_INT:
+ switch (exp->flags & 0x0f00) {
+ case PSI_NUMBER_L:
+ default:
+ tmp.i64 = strtol(exp->data.numb, NULL, 0);
+ free(exp->data.numb);
+ exp->type = PSI_T_INT64;
+ exp->data.ival.i64 = tmp.i64;
+ break;
+ case PSI_NUMBER_LL:
+ tmp.i64 = strtoll(exp->data.numb, NULL, 0);
+ free(exp->data.numb);
+ exp->type = PSI_T_INT64;
+ exp->data.ival.i64 = tmp.i64;
+ break;
+ case PSI_NUMBER_U:
+ case PSI_NUMBER_UL:
+ tmp.u64 = strtoul(exp->data.numb, NULL, 0);
+ free(exp->data.numb);
+ exp->type = PSI_T_UINT64;
+ exp->data.ival.u64 = tmp.u64;
+ break;
+ case PSI_NUMBER_ULL:
+ tmp.u64 = strtoull(exp->data.numb, NULL, 0);
+ free(exp->data.numb);
+ exp->type = PSI_T_UINT64;
+ exp->data.ival.u64 = tmp.u64;
+ break;
+ }
+ return true;
+
+ case PSI_NUMBER_FLT:
+ switch (exp->flags & 0x0ff00) {
+ case PSI_NUMBER_F:
+ case PSI_NUMBER_DF:
+ tmp.fval = strtof(exp->data.numb, NULL);
+ free(exp->data.numb);
+ exp->type = PSI_T_FLOAT;
+ exp->data.ival.fval = tmp.fval;
+ break;
+ case PSI_NUMBER_L:
+ case PSI_NUMBER_DL:
+#if HAVE_LONG_DOUBLE
+ tmp.ldval = strtold(exp->data.numb, NULL);
+ free(exp->data.numb);
+ exp->type = PSI_T_LONG_DOUBLE;
+ exp->data.ival.ldval = tmp.ldval;
+ break;
+#endif
+ case PSI_NUMBER_DD:
+ default:
+ tmp.dval = strtod(exp->data.numb, NULL);
+ free(exp->data.numb);
+ exp->type = PSI_T_DOUBLE;
+ exp->data.ival.dval = tmp.dval;
+ break;
+ }
+ return true;
+ default:
+ assert(0);
+ break;
+ }
+ } else {
+ switch (is_numeric_string(exp->data.numb, strlen(exp->data.numb), (zend_long *) &tmp, (double *) &tmp, 1)) {
+ case IS_LONG:
+ free(exp->data.numb);
+ exp->type = PSI_T_INT64;
+ exp->data.ival.i64 = tmp.zend.lval;
+ return true;
+
+ case IS_DOUBLE:
+ free(exp->data.numb);
+ exp->type = PSI_T_DOUBLE;
+ exp->data.ival.dval = tmp.dval;
+ return true;
+ }
+ }
+ data->error(data, exp->token, PSI_WARNING, "Expected numeric entity (parser error?)");
+ return false;
+
+}