Exemple #1
0
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;
		}
	}
}
Exemple #2
0
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);
	}
}
Exemple #3
0
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);
	}
}
Exemple #4
0
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));
}
Exemple #5
0
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);
}
Exemple #6
0
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");
	}
}
Exemple #7
0
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);
	}
}
Exemple #8
0
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");

}
Exemple #9
0
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));
}
Exemple #10
0
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));
}
Exemple #11
0
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;
	}
}
Exemple #12
0
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;
		}
	}
}
Exemple #13
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;
    }
}
Exemple #14
0
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;
}
Exemple #15
0
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;
}
Exemple #16
0
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];
	}
}
Exemple #17
0
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;
}
Exemple #18
0
// 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");
    }
}
Exemple #19
0
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);
	}
}
Exemple #20
0
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;
	}
}
Exemple #21
0
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;
}
Exemple #22
0
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;
}
Exemple #23
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);
    }
}
Exemple #24
0
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;
}
Exemple #25
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];
	}
}
Exemple #27
0
/* 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;
}
Exemple #28
0
/* 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;
}
Exemple #29
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;
}
Exemple #30
0
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 );
}