void FParser::OPdivide(svalue_t &result, int start, int n, int stop) { svalue_t left, right; evaluate_leftnright(start, n, stop); // haleyjd: 8-17 if(left.type == svt_fixed || right.type == svt_fixed) { auto fr = floatvalue(right); if(fr == 0) script_error("divide by zero\n"); else { result.setDouble(floatvalue(left) / fr); } } else { auto ir = intvalue(right); if(!ir) script_error("divide by zero\n"); else { result.type = svt_int; result.value.i = intvalue(left) / ir; } } }
void FParser::OPminus(svalue_t &result, int start, int n, int stop) { svalue_t left, right; // do they mean minus as in '-1' rather than '2-1'? if(start == n) { // kinda hack, hehe EvaluateExpression(right, n+1, stop); } else { evaluate_leftnright(start, n, stop); } // haleyjd: 8-17 if(left.type == svt_fixed || right.type == svt_fixed) { result.type = svt_fixed; result.value.f = fixedvalue(left) - fixedvalue(right); } else { result.type = svt_int; result.value.i = intvalue(left) - intvalue(right); } }
void FParser::OPplus(svalue_t &result, int start, int n, int stop) { svalue_t left, right; evaluate_leftnright(start, n, stop); if (left.type == svt_string) { if (right.type == svt_string) { result.string.Format("%s%s", left.string.GetChars(), right.string.GetChars()); } else if (right.type == svt_fixed) { result.string.Format("%s%4.4f", left.string.GetChars(), floatvalue(right)); } else { result.string.Format("%s%i", left.string.GetChars(), intvalue(right)); } result.type = svt_string; } // haleyjd: 8-17 else if(left.type == svt_fixed || right.type == svt_fixed) { result.type = svt_fixed; result.value.f = fixedvalue(left) + fixedvalue(right); } else { result.type = svt_int; result.value.i = intvalue(left) + intvalue(right); } }
void FParser::OPcmp(svalue_t &result, int start, int n, int stop) { svalue_t left, right; evaluate_leftnright(start, n, stop); result.type = svt_int; // always an int returned if(left.type == svt_string && right.type == svt_string) { result.value.i = !strcmp(left.string, right.string); return; } // haleyjd: direct mobj comparison when both are mobj if(left.type == svt_mobj && right.type == svt_mobj) { // we can safely assume reference equivalency for // AActor's in all cases since they are static for the // duration of a level result.value.i = (left.value.mobj == right.value.mobj); return; } if(left.type == svt_fixed || right.type == svt_fixed) { result.value.i = (fixedvalue(left) == fixedvalue(right)); return; } result.value.i = (intvalue(left) == intvalue(right)); }
void FParser::OPand_bin(svalue_t &result, int start, int n, int stop) { svalue_t left, right; evaluate_leftnright(start, n, stop); result.type = svt_int; result.value.i = intvalue(left) & intvalue(right); }
void FParser::OPdecrement(svalue_t &result, int start, int n, int stop) { if(start == n) // ++n { DFsVariable *var; var = Script->FindVariable(Tokens[stop]); if(!var) { script_error("unknown variable '%s'\n", Tokens[stop]); } var->GetValue(result); // haleyjd if(var->type != svt_fixed) { result.value.i = intvalue(result) - 1; result.type = svt_int; var->SetValue (result); } else { result.setDouble(floatvalue(result)-1); result.type = svt_fixed; var->SetValue (result); } } else if(stop == n) // n++ { svalue_t newvalue; DFsVariable *var; var = Script->FindVariable(Tokens[start]); if(!var) { script_error("unknown variable '%s'\n", Tokens[start]); } var->GetValue(result); // haleyjd if(var->type != svt_fixed) { newvalue.type = svt_int; newvalue.value.i = intvalue(result) - 1; var->SetValue (newvalue); } else { newvalue.setDouble(floatvalue(result)-1); var->SetValue (newvalue); } } else { script_error("incorrect arguments to ++ operator\n"); } }
static int numeric_equal(const SpnValue *lhs, const SpnValue *rhs) { assert(isnum(lhs) && isnum(rhs)); if (isfloat(lhs)) { return isfloat(rhs) ? floatvalue(lhs) == floatvalue(rhs) : floatvalue(lhs) == intvalue(rhs); } else { return isfloat(rhs) ? intvalue(lhs) == floatvalue(rhs) : intvalue(lhs) == intvalue(rhs); } }
void setvariablevalue(svariable_t *v, svalue_t newvalue) { if(killscript) return; // protect the variables when killing script if(!v) return; if(v->type == svt_const) { // const adapts to the value it is set to v->type = newvalue.type; // alloc memory for string if(v->type == svt_string) // static incase a global_script var v->value.s = Z_Malloc(128, PU_STATIC, 0); } if(v->type == svt_int) v->value.i = intvalue(newvalue); if(v->type == svt_string) strcpy(v->value.s, stringvalue(newvalue)); if(v->type == svt_fixed) v->value.fixed = fixedvalue(newvalue); if(v->type == svt_mobj) v->value.mobj = MobjForSvalue(newvalue); if(v->type == svt_pInt) *v->value.pI = intvalue(newvalue); if(v->type == svt_pString) { // free old value free(*v->value.pS); // dup new string *v->value.pS = strdup(stringvalue(newvalue)); } if(v->type == svt_pFixed) *v->value.pFixed = fixedvalue(newvalue); if(v->type == svt_pMobj) *v->value.pMobj = MobjForSvalue(newvalue); if(v->type == svt_function) script_error("attempt to set function to a value\n"); }
void FParser::OPgreaterthanorequal(svalue_t &result, int start, int n, int stop) { svalue_t left, right; evaluate_leftnright(start, n, stop); result.type = svt_int; if(left.type == svt_fixed || right.type == svt_fixed) result.value.i = (fixedvalue(left) >= fixedvalue(right)); else result.value.i = (intvalue(left) >= intvalue(right)); }
void FParser::OPgreaterthan(svalue_t &result, int start, int n, int stop) { svalue_t left, right; evaluate_leftnright(start, n, stop); // haleyjd: 8-17 result.type = svt_int; if(left.type == svt_fixed || right.type == svt_fixed) result.value.i = (fixedvalue(left) > fixedvalue(right)); else result.value.i = (intvalue(left) > intvalue(right)); }
void DFsVariable::SetValue(FLevelLocals *Level, const svalue_t &newvalue) { if(type == svt_const) { // const adapts to the value it is set to type = newvalue.type; } switch (type) { case svt_int: value.i = intvalue(newvalue); break; case svt_string: if (newvalue.type == svt_string) { string = newvalue.string; } else { string = stringvalue(newvalue); } break; case svt_fixed: value.fixed = fixedvalue(newvalue); break; case svt_mobj: actor = actorvalue(Level, newvalue); break; case svt_pInt: *value.pI = intvalue(newvalue); break; case svt_pMobj: *value.pMobj = actorvalue(Level, newvalue); break; case svt_function: script_error("attempt to set function to a value\n"); break; default: script_error("invalid variable type\n"); break; } }
static int numeric_compare(const SpnValue *lhs, const SpnValue *rhs) { assert(isnum(lhs) && isnum(rhs)); if (isfloat(lhs)) { if (isfloat(rhs)) { return floatvalue(lhs) < floatvalue(rhs) ? -1 : floatvalue(lhs) > floatvalue(rhs) ? +1 : 0; } else { return floatvalue(lhs) < intvalue(rhs) ? -1 : floatvalue(lhs) > intvalue(rhs) ? +1 : 0; } } else { if (isfloat(rhs)) { return intvalue(lhs) < floatvalue(rhs) ? -1 : intvalue(lhs) > floatvalue(rhs) ? +1 : 0; } else { return intvalue(lhs) < intvalue(rhs) ? -1 : intvalue(lhs) > intvalue(rhs) ? +1 : 0; } } }
void FParser::OPremainder(svalue_t &result, int start, int n, int stop) { svalue_t left, right; int ir; evaluate_leftnright(start, n, stop); if(!(ir = intvalue(right))) script_error("divide by zero\n"); else { result.type = svt_int; result.value.i = intvalue(left) % ir; } }
bool FParser::spec_if() { int endtoken; svalue_t eval; if((endtoken = FindOperator(0, NumTokens-1, ")")) == -1) { script_error("parse error in if statement\n"); return false; } // 2 to skip past the 'if' and '(' EvaluateExpression(eval, 2, endtoken-1); bool ifresult = !!intvalue(eval); if(Section && BraceType == bracket_open && endtoken == NumTokens-1) { // {} braces if(!ifresult) // skip to end of section Rover = Script->SectionEnd(Section) + 1; } else if(ifresult) // if() without {} braces { // nothing to do ? if(endtoken != NumTokens-1) EvaluateExpression(eval, endtoken+1, NumTokens-1); } return ifresult; }
void FParser::OPnot(svalue_t &result, int start, int n, int stop) { EvaluateExpression(result, n+1, stop); result.value.i = !intvalue(result); result.type = svt_int; }
AActor* actorvalue(FLevelLocals *Level, const svalue_t &svalue) { int intval; if(svalue.type == svt_mobj) { // Inventory items in the player's inventory have to be considered non-present. if (svalue.value.mobj == NULL || !svalue.value.mobj->IsMapActor()) { return NULL; } return svalue.value.mobj; } else { auto &SpawnedThings = Level->FraggleScriptThinker->SpawnedThings; // this requires some creativity. We use the intvalue // as the thing number of a thing in the level intval = intvalue(svalue); if(intval < 0 || intval >= (int)SpawnedThings.Size()) { return NULL; } // Inventory items in the player's inventory have to be considered non-present. if (SpawnedThings[intval] == nullptr || !SpawnedThings[intval]->IsMapActor()) { return NULL; } return SpawnedThings[intval]; } }
SpnSourceLocation spn_dbg_get_raw_source_location(SpnHashMap *debug_info, ptrdiff_t address) { SpnSourceLocation loc = { 0, 0 }; if (debug_info) { SpnValue vinsns = spn_hashmap_get_strkey(debug_info, "insns"); SpnArray *insns = arrayvalue(&vinsns); size_t n = spn_array_count(insns); size_t i; /* this is a 'long', because there's no PTRDIFF_MAX in C89 */ long address_window_width = LONG_MAX; /* search for narrowest bytecode range containing 'address'. * XXX: TODO: this may potentially be slow for large files; * benchmark it and use binary search instead, if necessary. */ for (i = 0; i < n; i++) { SpnValue vexpression = spn_array_get(insns, i); SpnHashMap *expression = hashmapvalue(&vexpression); SpnValue vline = spn_hashmap_get_strkey(expression, "line"); SpnValue vcolumn = spn_hashmap_get_strkey(expression, "column"); SpnValue vbegin = spn_hashmap_get_strkey(expression, "begin"); SpnValue vend = spn_hashmap_get_strkey(expression, "end"); unsigned line = intvalue(&vline); unsigned column = intvalue(&vcolumn); ptrdiff_t begin = intvalue(&vbegin); ptrdiff_t end = intvalue(&vend); if (begin <= address && address < end && end - begin < address_window_width) { /* if the range contains the target address, and it * is narrower than the previous one, then memoize it */ loc.line = line; loc.column = column; address_window_width = end - begin; } } } return loc; }
// set a variable to a value from an svalue_t void svariable_t::setvalue(svalue_t newvalue) { if (killscript) return; // protect the variables when killing script if (type == svt_const) { // const adapts to the value it is set to type = newvalue.type; // alloc memory for string if(type == svt_string) // static incase a global_script var value.s = (char *)Z_Malloc(256, PU_STATIC, 0); } switch (type) { case svt_int: value.i = intvalue(newvalue); break; case svt_string: strcpy(value.s, stringvalue(newvalue)); break; case svt_fixed: value.i = fixedvalue(newvalue).value(); break; case svt_actor: value.mobj = MobjForSvalue(newvalue); break; case svt_pInt: *value.pI = intvalue(newvalue); break; case svt_pString: // free old value free(*value.pS); // dup new string *value.pS = strdup(stringvalue(newvalue)); break; case svt_pFixed: *value.pFixed = fixedvalue(newvalue); break; case svt_pActor: *value.pMobj = MobjForSvalue(newvalue); break; case svt_function: script_error("attempt to set function to a value\n"); } }
void FParser::OPmultiply(svalue_t &result,int start, int n, int stop) { svalue_t left, right; evaluate_leftnright(start, n, stop); // haleyjd: 8-17 if(left.type == svt_fixed || right.type == svt_fixed) { result.setDouble(floatvalue(left) * floatvalue(right)); } else { result.type = svt_int; result.value.i = intvalue(left) * intvalue(right); } }
void spn_value_print(const SpnValue *val) { switch (valtype(val)) { case SPN_TTAG_NIL: { fputs("nil", stdout); break; } case SPN_TTAG_BOOL: { fputs(boolvalue(val) ? "true" : "false", stdout); break; } case SPN_TTAG_NUMBER: { if (isfloat(val)) { printf("%.*g", DBL_DIG, floatvalue(val)); } else { printf("%ld", intvalue(val)); } break; } case SPN_TTAG_STRING: { SpnString *s = stringvalue(val); fputs(s->cstr, stdout); break; } case SPN_TTAG_ARRAY: { SpnArray *array = objvalue(val); print_array(array, 0); break; } case SPN_TTAG_HASHMAP: { SpnHashMap *hashmap = objvalue(val); print_hashmap(hashmap, 0); break; } case SPN_TTAG_FUNC: { SpnFunction *func = funcvalue(val); void *p; if (func->native) { p = (void *)(ptrdiff_t)(func->repr.fn); } else { p = func->repr.bc; } printf("<function %p>", p); break; } case SPN_TTAG_USERINFO: { void *ptr = isobject(val) ? objvalue(val) : ptrvalue(val); printf("<userinfo %p>", ptr); break; } default: SHANT_BE_REACHED(); break; } }
void FParser::OPand(svalue_t &result, int start, int n, int stop) { int exprtrue = true; // if first is false, do not eval second EvaluateExpression(result, start, n-1); if(!intvalue(result) ) exprtrue = false; else { EvaluateExpression(result, n+1, stop); exprtrue = !!intvalue(result); } result.type = svt_int; result.value.i = exprtrue; }
unsigned long spn_hash_value(const SpnValue *key) { switch (valtype(key)) { case SPN_TTAG_NIL: { return 0; } case SPN_TTAG_BOOL: { return boolvalue(key); /* 0 or 1 */ } case SPN_TTAG_NUMBER: { if (isfloat(key)) { double f = floatvalue(key); /* only test for integer if it fits into one (anti-UB) */ if (LONG_MIN <= f && f <= LONG_MAX) { long i = f; /* truncate */ if (f == i) { /* it's really an integer. * This takes care of the +/- 0 problem too * (since 0 itself is an integer) */ return i; } } else { return spn_hash_bytes(&f, sizeof f); } } /* the hash value of an integer is itself */ return intvalue(key); } case SPN_TTAG_STRING: case SPN_TTAG_ARRAY: case SPN_TTAG_HASHMAP: case SPN_TTAG_FUNC: { SpnObject *obj = objvalue(key); unsigned long (*hashfn)(void *) = obj->isa->hashfn; return hashfn ? hashfn(obj) : (unsigned long)(obj); } case SPN_TTAG_USERINFO: { if (isobject(key)) { SpnObject *obj = objvalue(key); unsigned long (*hashfn)(void *) = obj->isa->hashfn; return hashfn ? hashfn(obj) : (unsigned long)(obj); } return (unsigned long)(ptrvalue(key)); } default: SHANT_BE_REACHED(); } return 0; }
void FParser::spec_for() { svalue_t eval; int start; int comma1, comma2; // token numbers of the seperating commas if(!Section) { script_error("need {} delimiters for for()\n"); return; } // is a valid section start = 2; // skip "for" and "(": start on third token(2) // find the seperating commas first if( (comma1 = FindOperator(start, NumTokens-1, ",")) == -1 || (comma2 = FindOperator(comma1+1, NumTokens-1, ",")) == -1) { script_error("incorrect arguments to for()\n"); // haleyjd: return; // said if() } // are we looping back from a previous loop? if(Section == PrevSection) { // do the loop 'action' (third argument) EvaluateExpression(eval, comma2+1, NumTokens-2); // check if we should run the loop again (second argument) EvaluateExpression(eval, comma1+1, comma2-1); if(!intvalue(eval)) { // stop looping Rover = Script->SectionEnd(Section) + 1; } } else { // first time: starting the loop // just evaluate the starting expression (first arg) EvaluateExpression(eval, start, comma1-1); } }
unsigned long spn_hash_value(const SpnValue *key) { switch (valtype(key)) { case SPN_TTAG_NIL: { return 0; } case SPN_TTAG_BOOL: { return boolvalue(key); /* 0 or 1 */ } case SPN_TTAG_NUMBER: { if (isfloat(key)) { double f = floatvalue(key); long i = f; /* truncate */ if (f == i) { return i; /* it's really an integer */ } else { return spn_hash_bytes(&f, sizeof f); } } /* the hash value of an integer is itself */ return intvalue(key); } case SPN_TTAG_STRING: case SPN_TTAG_ARRAY: case SPN_TTAG_HASHMAP: case SPN_TTAG_FUNC: { SpnObject *obj = objvalue(key); unsigned long (*hashfn)(void *) = obj->isa->hashfn; return hashfn ? hashfn(obj) : (unsigned long)(obj); } case SPN_TTAG_USERINFO: { if (isobject(key)) { SpnObject *obj = objvalue(key); unsigned long (*hashfn)(void *) = obj->isa->hashfn; return hashfn ? hashfn(obj) : (unsigned long)(obj); } return (unsigned long)(ptrvalue(key)); } default: SHANT_BE_REACHED(); } return 0; }
void FParser::spec_while() { int endtoken; svalue_t eval; if(!Section) { script_error("no {} section given for loop\n"); return; } if( (endtoken = FindOperator(0, NumTokens-1, ")")) == -1) { script_error("parse error in loop statement\n"); return; } EvaluateExpression(eval, 2, endtoken-1); // skip if no longer valid if(!intvalue(eval)) Rover = Script->SectionEnd(Section) + 1; }
AActor* actorvalue(const svalue_t &svalue) { int intval; if(svalue.type == svt_mobj) { // Inventory items in the player's inventory have to be considered non-present. if (svalue.value.mobj != NULL && svalue.value.mobj->IsKindOf(RUNTIME_CLASS(AInventory)) && static_cast<AInventory*>(svalue.value.mobj)->Owner != NULL) { return NULL; } return svalue.value.mobj; } else { TArray<TObjPtr<AActor> > &SpawnedThings = DFraggleThinker::ActiveThinker->SpawnedThings; // this requires some creativity. We use the intvalue // as the thing number of a thing in the level. intval = intvalue(svalue); if(intval < 0 || intval >= (int)SpawnedThings.Size()) { return NULL; } // Inventory items in the player's inventory have to be considered non-present. if (SpawnedThings[intval] != NULL && SpawnedThings[intval]->IsKindOf(RUNTIME_CLASS(AInventory)) && barrier_cast<AInventory*>(SpawnedThings[intval])->Owner != NULL) { return NULL; } return SpawnedThings[intval]; } }
/* the actual string format parser * Although it's not in the documentation of `printf()`, but in addition to the * `%d` conversion specifier, this supports `%i`, which takes an `int` argument * instead of a `long`. It is used only for formatting error messages (since * Sparkling integers are all `long`s), but feel free to use it yourself. * * if `errmsg' is not a NULL pointer, and an error occurred while creating the * format string, then on return, `*errmsg' will point to a string containing * a message that describes the error. */ static char *make_format_string( const char *fmt, size_t *len, int argc, void *argv, int isval, char **errmsg ) { struct string_builder bld; int argidx = 0; const char *s = fmt; const char *p = s; /* points to the beginning of the next * non-format part of the format string */ init_builder(&bld); while (*s) { if (*s == '%') { struct format_args args; init_format_args(&args); /* append preceding non-format string chunk */ if (s > p) { append_string(&bld, p, s - p); } s++; /* Actually parse the format string. * '#' flag: prepend base prefix (0b, 0, 0x) */ if (*s == '#') { args.flags |= FLAG_BASEPREFIX; s++; } /* ' ' (space) flag: prepend space if non-negative * '+' flag: always prepend explicit + or - sign */ if (*s == ' ') { args.flags |= FLAG_PADSIGN; s++; } else if (*s == '+') { args.flags |= FLAG_EXPLICITSIGN; s++; } /* leading 0 flag: pad field with zeroes */ if (*s == '0') { args.flags |= FLAG_ZEROPAD; s++; } /* field width specifier */ if (isdigit(*s)) { args.width = 0; while (isdigit(*s)) { args.width *= 10; args.width += *s++ - '0'; } } else if (*s == '*') { s++; if (isval) { SpnValue *widthptr; /* check argc if the caller wants us to do so */ if (argc >= 0 && argidx >= argc) { format_errmsg(errmsg, OUT_OF_ARGUMENTS, argidx); free(bld.buf); return NULL; } /* width specifier must be an integer */ widthptr = getarg_val(argv, &argidx); if (!isnum(widthptr)) { format_errmsg( errmsg, TYPE_MISMATCH, argidx, SPN_TTAG_NUMBER, widthptr->type ); free(bld.buf); return NULL; } if (isfloat(widthptr)) { format_errmsg( errmsg, EXPECT_INTEGER, argidx ); free(bld.buf); return NULL; } args.width = intvalue(widthptr); } else { const int *widthptr = getarg_raw(argv, &argidx); args.width = *widthptr; } } /* precision/maximal length specifier */ if (*s == '.') { s++; if (*s == '+') { args.flags |= FLAG_EXPONENTSIGN; s++; } args.precision = 0; if (isdigit(*s)) { while (isdigit(*s)) { args.precision *= 10; args.precision += *s++ - '0'; } } else if (*s == '*') { s++; if (isval) { SpnValue *precptr; /* check argc if the caller wants us to do so */ if (argc >= 0 && argidx >= argc) { format_errmsg(errmsg, OUT_OF_ARGUMENTS, argidx); free(bld.buf); return NULL; } /* precision must be an integer too */ precptr = getarg_val(argv, &argidx); if (!isnum(precptr)) { format_errmsg( errmsg, TYPE_MISMATCH, argidx, SPN_TTAG_NUMBER, precptr->type ); free(bld.buf); return NULL; } if (isfloat(precptr)) { format_errmsg( errmsg, EXPECT_INTEGER, argidx ); free(bld.buf); return NULL; } args.precision = intvalue(precptr); } else { const int *precptr = getarg_raw(argv, &argidx); args.precision = *precptr; } } } args.spec = *s++; /* check argc if the caller wants us to do so */ if (argc >= 0 && argidx >= argc) { format_errmsg(errmsg, OUT_OF_ARGUMENTS, argidx); free(bld.buf); return NULL; } /* append parsed format string */ if (append_format(&bld, &args, argv, &argidx, isval, errmsg) != 0) { free(bld.buf); return NULL; } /* update non-format chunk base pointer */ p = s; } else { s++; } } /* if the format string doesn't end with a conversion specifier, * then just append the last non-format (literal) string chunk */ if (s > p) { append_string(&bld, p, s - p); } /* append terminating NUL byte */ expand_buffer(&bld, 1); bld.buf[bld.len] = 0; if (len != NULL) { *len = bld.len; } return bld.buf; }
/* returns zero on success, nonzero on error */ static int append_format( struct string_builder *bld, const struct format_args *args, void *argv, int *argidx, int isval, char **errmsg ) { switch (args->spec) { case '%': append_string(bld, "%", 1); break; case 's': { const char *str; size_t len; if (isval) { SpnString *strobj; /* must be a string */ SpnValue *val = getarg_val(argv, argidx); if (!isstring(val)) { format_errmsg( errmsg, TYPE_MISMATCH, *argidx, SPN_TYPE_STRING, val->type ); return -1; } strobj = stringvalue(val); str = strobj->cstr; len = strobj->len; } else { str = getarg_raw(argv, argidx); len = strlen(str); } if (args->precision >= 0 && args->precision < len) { len = args->precision; } if (args->width >= 0 && args->width > len) { size_t pad = args->width - len; expand_buffer(bld, pad); while (pad-- > 0) { bld->buf[bld->len++] = ' '; } } append_string(bld, str, len); break; } case 'i': case 'd': case 'b': case 'o': case 'u': case 'x': case 'X': { char *buf, *end, *begin; size_t len = PR_LONG_DIGITS; enum format_flags flags = args->flags; unsigned base = base_for_specifier(args->spec); long n; unsigned long u; if (isval) { /* must be a number */ SpnValue *val = getarg_val(argv, argidx); if (!isnum(val)) { format_errmsg( errmsg, TYPE_MISMATCH, *argidx, SPN_TTAG_NUMBER, val->type ); return -1; } if (isint(val)) { n = intvalue(val); } else { n = floatvalue(val); /* truncate */ } } else { /* "%i" expects an int, others expect a long */ if (args->spec == 'i') { n = *(const int *)getarg_raw(argv, argidx); } else { n = *(const long *)getarg_raw(argv, argidx); } } if (args->spec == 'i' || args->spec == 'd') { /* signed conversion specifiers */ if (n < 0) { flags |= FLAG_NEGATIVE; u = -n; } else { u = n; } } else { /* unsigned conversion specifiers */ u = n; } if (args->spec == 'X') { flags |= FLAG_CAPS; } if (args->width >= 0 && args->width > len) { len = args->width; } buf = spn_malloc(len); end = buf + len; begin = ulong2str(end, u, base, args->width, flags); assert(buf <= begin); append_string(bld, begin, end - begin); free(buf); break; } case 'c': { unsigned char ch; int len = 1; /* one character is one character long... */ if (isval) { /* must be an integer */ SpnValue *val = getarg_val(argv, argidx); if (!isnum(val)) { format_errmsg( errmsg, TYPE_MISMATCH, *argidx, SPN_TTAG_NUMBER, val->type ); return -1; } if (isfloat(val)) { format_errmsg(errmsg, EXPECT_INTEGER, *argidx); return -1; } ch = intvalue(val); } else { ch = *(const long *)getarg_raw(argv, argidx); } if (args->width > len) { len = args->width; } expand_buffer(bld, len); while (len-- > 1) { bld->buf[bld->len++] = ' '; } bld->buf[bld->len++] = ch; break; } case 'f': case 'F': { char *buf, *end, *begin; size_t len; int prec; double x; enum format_flags flags = args->flags; if (isval) { SpnValue *val = getarg_val(argv, argidx); if (!isnum(val)) { format_errmsg( errmsg, TYPE_MISMATCH, *argidx, SPN_TTAG_NUMBER, val->type ); return -1; } if (isfloat(val)) { x = floatvalue(val); } else { x = intvalue(val); } } else { x = *(const double *)getarg_raw(argv, argidx); } if (args->spec == 'F') { flags |= FLAG_CAPS; } /* handle special cases */ if (+1.0 / x == +1.0 / -0.0) { /* negative zero: set sign flag and carry on */ flags |= FLAG_NEGATIVE; } else if ( x != x /* NaN */ || x == +1.0 / 0.0 /* +inf */ || x == -1.0 / 0.0 /* -inf */ ) { print_special_fp(bld, flags, args->width, x); break; } if (x < 0.0) { flags |= FLAG_NEGATIVE; x = -x; } /* at this point, `x' is non-negative or -0 */ if (x >= 1.0) { len = ceil(log10(x)) + 1; /* 10 ^ n is n + 1 digits long */ } else { len = 1; /* leading zero needs exactly one character */ } prec = args->precision < 0 ? DBL_DIG : args->precision; len += prec + 3; /* decimal point, sign, leading zero */ if (args->width >= 0 && args->width > len) { len = args->width; } buf = spn_malloc(len); end = buf + len; begin = double2str(end, x, args->width, prec, flags); assert(buf <= begin); append_string(bld, begin, end - begin); free(buf); break; } case 'B': { int boolval; const char *str; size_t len; if (isval) { /* must be a boolean */ SpnValue *val = getarg_val(argv, argidx); if (!isbool(val)) { format_errmsg( errmsg, TYPE_MISMATCH, *argidx, SPN_TTAG_BOOL, val->type ); return -1; } boolval = boolvalue(val); } else { boolval = *(const int *)getarg_raw(argv, argidx); } str = boolval ? "true" : "false"; len = strlen(str); if (args->precision >= 0 && args->precision < len) { len = args->precision; } if (args->width >= 0 && args->width > len) { size_t pad = args->width - len; expand_buffer(bld, pad); while (pad-- > 0) { bld->buf[bld->len++] = ' '; } } append_string(bld, str, len); break; } default: format_errmsg(errmsg, INVALID_SPECIFIER, ++*argidx, args->spec); return -1; } return 0; }
void FParser::spec_script() { int scriptnum; int datasize; DFsScript *newscript; scriptnum = 0; if(!Section) { script_error("need seperators for newscript\n"); return; } // presume that the first token is "newscript" if(NumTokens < 2) { script_error("need newscript number\n"); return; } svalue_t result; EvaluateExpression(result, 1, NumTokens-1); scriptnum = intvalue(result); if(scriptnum < 0) { script_error("invalid newscript number\n"); return; } newscript = Create<DFsScript>(); // add to scripts list of parent Script->children[scriptnum] = newscript; GC::WriteBarrier(Script, newscript); // copy newscript data // workout newscript size: -2 to ignore { and } datasize = (Section->end_index - Section->start_index - 2); // alloc extra 10 for safety newscript->data = (char *)malloc(datasize+10); // copy from parent newscript (levelscript) // ignore first char which is { memcpy(newscript->data, Script->SectionStart(Section) + 1, datasize); // tack on a 0 to end the string newscript->data[datasize] = '\0'; newscript->scriptnum = scriptnum; newscript->parent = Script; // remember parent // preprocess the newscript now newscript->Preprocess(Level); // we dont want to run the newscript, only add it // jump past the newscript in parsing Rover = Script->SectionEnd(Section) + 1; }
fixed_t fixedvalue(const svalue_s & v) { return (v.type == svt_fixed ? v.value.f : v.type == svt_string ? (fixed_t)(atof(v.value.s) * FRACUNIT) : v.type == svt_mobj ? -1*FRACUNIT : intvalue(v) * FRACUNIT ); }