Exemplo n.º 1
0
/**
 * @brief unittest to check back slash entity conversion
 */
TEST_F(ParserTest, ParserWithEntity)
{
	const char* string = "\n\taaaa \"  \\n  \\t  \\\"  \"";
	const char* cursor = string;
	const char* token;

	token = Com_Parse(&cursor);
	ASSERT_NE(Com_GetType(&cursor), TT_QUOTED_WORD);
	ASSERT_STREQ(token, "aaaa");

	token = Com_Parse(&cursor);
	ASSERT_EQ(Com_GetType(&cursor), TT_QUOTED_WORD);
	ASSERT_STREQ(token, "  \n  \t  \"  ");
}
Exemplo n.º 2
0
/**
 * @brief unittest around default use of parser
 */
TEST_F(ParserTest, ParserWithUnParse)
{
	const char* string = "aaaaa\n\tbbbbb \"ccccc\"";
	const char* cursor = string;
	const char* token;

	token = Com_Parse(&cursor);
	ASSERT_NE(Com_GetType(&cursor), TT_QUOTED_WORD);
	ASSERT_STREQ(token, "aaaaa");

	Com_UnParseLastToken();

	token = Com_Parse(&cursor);
	ASSERT_NE(Com_GetType(&cursor), TT_QUOTED_WORD);
	ASSERT_STREQ(token, "aaaaa");

	Com_UnParseLastToken();

	token = Com_Parse(&cursor);
	ASSERT_NE(Com_GetType(&cursor), TT_QUOTED_WORD);
	ASSERT_STREQ(token, "aaaaa");

	token = Com_Parse(&cursor);
	ASSERT_NE(Com_GetType(&cursor), TT_QUOTED_WORD);
	ASSERT_STREQ(token, "bbbbb");

	Com_UnParseLastToken();

	token = Com_Parse(&cursor);
	ASSERT_NE(Com_GetType(&cursor), TT_QUOTED_WORD);
	ASSERT_STREQ(token, "bbbbb");

	Com_UnParseLastToken();

	token = Com_Parse(&cursor);
	ASSERT_NE(Com_GetType(&cursor), TT_QUOTED_WORD);
	ASSERT_STREQ(token, "bbbbb");

	token = Com_Parse(&cursor);
	ASSERT_EQ(Com_GetType(&cursor), TT_QUOTED_WORD);
	ASSERT_STREQ(token, "ccccc");

	Com_UnParseLastToken();

	token = Com_Parse(&cursor);
	ASSERT_EQ(Com_GetType(&cursor), TT_QUOTED_WORD);
	ASSERT_STREQ(token, "ccccc");

	Com_UnParseLastToken();

	token = Com_Parse(&cursor);
	ASSERT_EQ(Com_GetType(&cursor), TT_QUOTED_WORD);
	ASSERT_STREQ(token, "ccccc");
}
Exemplo n.º 3
0
/**
 * @brief unittest around default use of parser
 */
TEST_F(ParserTest, Parser)
{
	const char* string = "aa \t\n {\"bbb(bbb bbb)bbb {\"{a}\n/* foooo { } \n { } */\n// fooooo\naaaa";
	const char* cursor = string;
	const char* token;

	token = Com_Parse(&cursor);
	ASSERT_NE(Com_GetType(&cursor), TT_QUOTED_WORD);
	ASSERT_STREQ(token, "aa");

	token = Com_Parse(&cursor);
	ASSERT_NE(Com_GetType(&cursor), TT_QUOTED_WORD);
	ASSERT_STREQ(token, "{");

	token = Com_Parse(&cursor);
	ASSERT_EQ(Com_GetType(&cursor), TT_QUOTED_WORD);
	ASSERT_STREQ(token, "bbb(bbb bbb)bbb {");

	token = Com_Parse(&cursor);
	ASSERT_NE(Com_GetType(&cursor), TT_QUOTED_WORD);
	ASSERT_STREQ(token, "{");

	token = Com_Parse(&cursor);
	ASSERT_NE(Com_GetType(&cursor), TT_QUOTED_WORD);
	ASSERT_STREQ(token, "a");

	token = Com_Parse(&cursor);
	ASSERT_NE(Com_GetType(&cursor), TT_QUOTED_WORD);
	ASSERT_STREQ(token, "}");

	token = Com_Parse(&cursor);
	ASSERT_NE(Com_GetType(&cursor), TT_QUOTED_WORD);
	ASSERT_STREQ(token, "aaaa");

	token = Com_Parse(&cursor);
	ASSERT_EQ(Com_GetType(&cursor), TT_EOF);
	ASSERT_STREQ(token, "\0");
}
Exemplo n.º 4
0
/**
 * @brief Parse a property value
 * @todo don't read the next token (need to change the script language)
 */
static bool UI_ParseProperty (void* object, const value_t* property, const char* objectName, const char** text, const char** token)
{
	const char* errhead = "UI_ParseProperty: unexpected end of file (object";
	static const char* notWellFormedValue = "UI_ParseProperty: \"%s\" is not a well formed node name (it must be quoted, uppercase const, a number, or prefixed with '*')\n";
	size_t bytes;
	int result;
	const int specialType = property->type & V_UI_MASK;

	if (property->type == V_NULL) {
		return false;
	}

	switch (specialType) {
	case V_NOT_UI:	/* common type */

		*token = Com_EParse(text, errhead, objectName);
		if (!*text)
			return false;
		if (!UI_TokenIsValue(*token, Com_GetType(text) == TT_QUOTED_WORD)) {
			Com_Printf(notWellFormedValue, *token);
			return false;
		}

		if (property->type == V_TRANSLATION_STRING) {
			/* selectbox values are static arrays */
			char* const target = Com_GetValue<char[]>(object, property);
			const char* translatableToken = *token;
			assert(property->size);
			if (translatableToken[0] == '_')
				translatableToken++;
			Q_strncpyz(target, translatableToken, property->size);
		} else {
			result = Com_ParseValue(object, *token, property->type, property->ofs, property->size, &bytes);
			if (result != RESULT_OK) {
				Com_Printf("UI_ParseProperty: Invalid value for property '%s': %s\n", property->string, Com_GetLastParseError());
				return false;
			}
		}
		break;

	case V_UI_REF:
		*token = Com_EParse(text, errhead, objectName);
		if (!*text)
			return false;
		if (!UI_TokenIsValue(*token, Com_GetType(text) == TT_QUOTED_WORD)) {
			Com_Printf(notWellFormedValue, *token);
			return false;
		}

		/* a reference to data is handled like this */
		ui_global.curadata = (byte*) Com_AlignPtr(ui_global.curadata, (valueTypes_t) (property->type & V_BASETYPEMASK));
		Com_GetValue<byte*>(object, property) = ui_global.curadata;

		/** @todo check for the moment its not a cvar */
		assert((*token)[0] != '*');

		/* sanity check */
		if ((property->type & V_BASETYPEMASK) == V_STRING && strlen(*token) > MAX_VAR - 1) {
			Com_Printf("UI_ParseProperty: Value '%s' is too long (key %s)\n", *token, property->string);
			return false;
		}

		result = Com_ParseValue(ui_global.curadata, *token, (valueTypes_t) (property->type & V_BASETYPEMASK), 0, property->size, &bytes);
		if (result != RESULT_OK) {
			Com_Printf("UI_ParseProperty: Invalid value for property '%s': %s\n", property->string, Com_GetLastParseError());
			return false;
		}
		ui_global.curadata += bytes;

		break;

	case V_UI_CVAR:	/* common type */
		*token = Com_EParse(text, errhead, objectName);
		if (!*text)
			return false;
		if (!UI_TokenIsValue(*token, Com_GetType(text) == TT_QUOTED_WORD)) {
			Com_Printf(notWellFormedValue, *token);
			return false;
		}

		/* references are parsed as string */
		if ((*token)[0] == '*') {
			/* a reference to data */
			ui_global.curadata = (byte*) Com_AlignPtr(ui_global.curadata, V_STRING);
			Com_GetValue<byte*>(object, property) = ui_global.curadata;

			/* sanity check */
			if (strlen(*token) > MAX_VAR - 1) {
				Com_Printf("UI_ParseProperty: Value '%s' is too long (key %s)\n", *token, property->string);
				return false;
			}

			result = Com_ParseValue(ui_global.curadata, *token, V_STRING, 0, 0, &bytes);
			if (result != RESULT_OK) {
				Com_Printf("UI_ParseProperty: Invalid value for property '%s': %s\n", property->string, Com_GetLastParseError());
				return false;
			}
			ui_global.curadata += bytes;
		} else {
			/* a reference to data */
			ui_global.curadata = (byte*) Com_AlignPtr(ui_global.curadata, (valueTypes_t)(property->type & V_BASETYPEMASK));
			Com_GetValue<byte*>(object, property) = ui_global.curadata;

			/* sanity check */
			if ((property->type & V_BASETYPEMASK) == V_STRING && strlen(*token) > MAX_VAR - 1) {
				Com_Printf("UI_ParseProperty: Value '%s' is too long (key %s)\n", *token, property->string);
				return false;
			}

			result = Com_ParseValue(ui_global.curadata, *token, (valueTypes_t)(property->type & V_BASETYPEMASK), 0, property->size, &bytes);
			if (result != RESULT_OK) {
				Com_Printf("UI_ParseProperty: Invalid value for property '%s': %s\n", property->string, Com_GetLastParseError());
				return false;
			}
			ui_global.curadata += bytes;
		}
		break;

	case V_UI:

		switch ((int)property->type) {
		case V_UI_ACTION:
			result = UI_ParseEventProperty(static_cast<uiNode_t*>(object), property, text, token, errhead);
			if (!result)
				return false;
			break;

		case V_UI_EXCLUDERECT:
			result = UI_ParseExcludeRect(static_cast<uiNode_t*>(object), text, token, errhead);
			if (!result)
				return false;
			break;

		case V_UI_SPRITEREF:
			{
				*token = Com_EParse(text, errhead, objectName);
				if (!*text)
					return false;

				uiSprite_t const*& sprite = Com_GetValue<uiSprite_t const*>(object, property);
				sprite = UI_GetSpriteByName(*token);
				if (!sprite) {
					Com_Printf("UI_ParseProperty: sprite '%s' not found (object %s)\n", *token, objectName);
				}
			}
			break;

		case V_UI_IF:
			{
				*token = Com_EParse(text, errhead, objectName);
				if (!*text)
					return false;

				uiAction_t*& expression = Com_GetValue<uiAction_t*>(object, property);
				expression = UI_AllocStaticStringCondition(*token);
				if (!expression)
					return false;
			}
			break;

		case V_UI_DATAID:
			{
				*token = Com_EParse(text, errhead, objectName);
				if (!*text)
					return false;

				int& dataId = Com_GetValue<int>(object, property);
				dataId = UI_GetDataIDByName(*token);
				if (dataId < 0) {
					Com_Printf("UI_ParseProperty: Could not find shared data ID '%s' (%s@%s)\n",
							*token, objectName, property->string);
					return false;
				}
			}
			break;

		default:
			Com_Printf("UI_ParseProperty: unknown property type '%d' (0x%X) (%s@%s)\n",
					property->type, property->type, objectName, property->string);
			return false;
		}
		break;

	default:
		Com_Printf("UI_ParseProperties: unknown property type '%d' (0x%X) (%s@%s)\n",
				property->type, property->type, objectName, property->string);
		return false;
	}

	return true;
}
Exemplo n.º 5
0
/**
 * @brief Parse a window
 * @sa CL_ParseClientData
 * @code
 * window windowName {
 * }
 * @endcode
 */
bool UI_ParseWindow (const char* type, const char* name, const char** text)
{
	const char* errhead = "UI_ParseWindow: unexpected end of file (window";
	uiNode_t* window;
	const char* token;
	int i;

	if (!Q_streq(type, "window")) {
		Com_Error(ERR_FATAL, "UI_ParseWindow: '%s %s' is not a window node\n", type, name);
		return false;	/* never reached */
	}

	if (!UI_TokenIsName(name, Com_GetType(text) == TT_QUOTED_WORD)) {
		Com_Printf("UI_ParseWindow: \"%s\" is not a well formed node name ([a-zA-Z_][a-zA-Z0-9_]*)\n", name);
		return false;
	}
	if (UI_TokenIsReserved(name)) {
		Com_Printf("UI_ParseWindow: \"%s\" is a reserved token, we can't call a node with it (node \"%s\")\n", name, name);
		return false;
	}

	/* search for windows with same name */
	for (i = 0; i < ui_global.numWindows; i++)
		if (!strncmp(name, ui_global.windows[i]->name, sizeof(ui_global.windows[i]->name)))
			break;

	if (i < ui_global.numWindows) {
		Com_Printf("UI_ParseWindow: %s \"%s\" with same name found, second ignored\n", type, name);
	}

	if (ui_global.numWindows >= UI_MAX_WINDOWS) {
		Com_Error(ERR_FATAL, "UI_ParseWindow: max windows exceeded (%i) - ignore '%s'\n", UI_MAX_WINDOWS, name);
		return false;	/* never reached */
	}

	/* get window body */
	token = Com_Parse(text);

	/* does this window inherit data from another window? */
	if (Q_streq(token, "extends")) {
		uiNode_t* superWindow;
		token = Com_Parse(text);
		superWindow = UI_GetWindow(token);
		if (superWindow == nullptr)
			Sys_Error("Could not get the super window \"%s\"", token);
		window = UI_CloneNode(superWindow, nullptr, true, name, false);
		token = Com_Parse(text);
	} else {
		window = UI_AllocNode(name, type, false);
		window->root = window;
	}

	UI_InsertWindow(window);

	/* parse it's body */
	bool result = UI_ParseNodeBody(window, text, &token, errhead);
	if (!result) {
		Com_Error(ERR_FATAL, "UI_ParseWindow: window \"%s\" has a bad body\n", window->name);
	}

	UI_Node_Loaded(window);
	return true;
}
Exemplo n.º 6
0
/**
 * @brief parse a node
 * @sa UI_ParseNodeProperties
 * @todo we can think about merging UI_ParseNodeProperties here
 * @note first token already read
 * @note dont read more than the need token (last right token is '}' of end of node)
 */
static uiNode_t* UI_ParseNode (uiNode_t* parent, const char** text, const char** token, const char* errhead)
{
	uiNode_t* node = nullptr;
	uiBehaviour_t* behaviour;
	uiNode_t* component = nullptr;

	/* get the behaviour */
	behaviour = UI_GetNodeBehaviour(*token);
	if (!behaviour) {
		component = UI_GetComponent(*token);
	}
	if (behaviour == nullptr && component == nullptr) {
		Com_Printf("UI_ParseNode: node behaviour/component '%s' doesn't exist (%s)\n", *token, UI_GetPath(parent));
		return nullptr;
	}

	/* get the name */
	*token = Com_EParse(text, errhead, "");
	if (!*text)
		return nullptr;
	if (!UI_TokenIsName(*token, Com_GetType(text) == TT_QUOTED_WORD)) {
		Com_Printf("UI_ParseNode: \"%s\" is not a well formed node name ([a-zA-Z_][a-zA-Z0-9_]*)\n", *token);
		return nullptr;
	}
	if (UI_TokenIsReserved(*token)) {
		Com_Printf("UI_ParseNode: \"%s\" is a reserved token, we can't call a node with it\n", *token);
		return nullptr;
	}

	/* test if node already exists */
	/* Already existing node should only come from inherited node, we should not have 2 definitions of the same node into the same window. */
	if (parent)
		node = UI_GetNode(parent, *token);

	/* reuse a node */
	if (node) {
		const uiBehaviour_t* test = (behaviour != nullptr) ? behaviour : (component != nullptr) ? component->behaviour : nullptr;
		if (node->behaviour != test) {
			Com_Printf("UI_ParseNode: we can't change node type (node \"%s\")\n", UI_GetPath(node));
			return nullptr;
		}
		Com_DPrintf(DEBUG_CLIENT, "... over-riding node %s\n", UI_GetPath(node));

	/* else initialize a component */
	} else if (component) {
		node = UI_CloneNode(component, nullptr, true, *token, false);
		if (parent) {
			if (parent->root)
				UI_UpdateRoot(node, parent->root);
			UI_AppendNode(parent, node);
		}

	/* else initialize a new node */
	} else {
		node = UI_AllocNode(*token, behaviour->name, false);
		node->parent = parent;
		if (parent)
			node->root = parent->root;
		/** @todo move it into caller */
		if (parent)
			UI_AppendNode(parent, node);
	}

	/* get body */
	const bool result = UI_ParseNodeBody(node, text, token, errhead);
	if (!result)
		return nullptr;

	/* validate properties */
	UI_Node_Loaded(node);

	return node;
}
Exemplo n.º 7
0
/**
 * @brief Read a value from the stream and init an action with it
 * @return An initialized action else nullptr
 */
static uiAction_t *UI_ParseValueExpression (const char **text)
{
	const char* token;
	uiAction_t *expression = UI_AllocStaticAction();

	token = Com_Parse(text);
	if (*text == nullptr) {
		Com_Printf("UI_ParseTerminalExpression: Token expected\n");
		return nullptr;
	}

	/* it is a const string (or an injection tag for compatibility) */
	if (Com_GetType(text) == TT_QUOTED_WORD || token[0] == '<') {
		expression->d.terminal.d1.constString = UI_AllocStaticString(token, 0);
		if (UI_IsInjectedString(token))
			expression->type = EA_VALUE_STRING_WITHINJECTION;
		else
			expression->type = EA_VALUE_STRING;
		return expression;
	}

	/* it is a param */
	if (!Q_strncasecmp(token, "param", 5)) {
		if (!Q_strcasecmp(token, "paramcount")) {
			expression->type = EA_VALUE_PARAMCOUNT;
			return expression;
		} else if (token[5] >= '1' && token[5] <= '9') {
			int i;
			if (sscanf(token + 5, "%i", &i) == 1) {
				/* token range 1-9 already avoid 0 */
				assert(i != 0);
				/** @todo when it is possible, we must check range of param id */
				expression->type = EA_VALUE_PARAM;
				expression->d.terminal.d1.integer = i;
				return expression;
			}
		}
	}

	/* it is a cvarname */
	if (char const* const cvarName = Q_strstart(token, "*cvar:")) {
		expression->d.terminal.d1.constString = UI_AllocStaticString(cvarName, 0);
		if (UI_IsInjectedString(cvarName))
			expression->type = EA_VALUE_CVARNAME_WITHINJECTION;
		else
			expression->type = EA_VALUE_CVARNAME;
		return expression;
	}

	/* it is a node property or it is a OLD syntax node property */
	/** @todo We MUST remove the OLD code as fast as possible */
	if (char const* path = Q_strstart(token, "*")) {
		const char *propertyName;
#if 0	/* it looks useless, an unused cache */
		const value_t *property;
#endif

		char const* const relativeToNode = Q_strstart(path, "node:");
		if (relativeToNode)
			path = relativeToNode;

		if (UI_IsInjectedString(path))
			expression->type = EA_VALUE_PATHPROPERTY_WITHINJECTION;
		else
			expression->type = EA_VALUE_PATHPROPERTY;
		if (!relativeToNode) {
			Com_Printf("UI_ParseExpression: Old syntax, please prefix '%s' with \"*node:root.\" \n", token);
			path = va("root.%s", path);
		}
		expression->d.terminal.d1.constString = UI_AllocStaticString(path, 0);

		/* get property name */
		propertyName = strchr(path, '@');
		if (propertyName == nullptr) {
			if (expression->type == EA_VALUE_PATHPROPERTY_WITHINJECTION)
				expression->type = EA_VALUE_PATHNODE_WITHINJECTION;
			else
				expression->type = EA_VALUE_PATHNODE;
			return expression;
		}
		propertyName++;

		return expression;
	}

	/* unsigned and signed number */
	if ((token[0] >= '0' && token[0] <= '9')
		|| (token[0] == '-' && token[1] >= '0' && token[1] <= '9')) {
		/** @todo use a better check - e.g. Com_ParseValue with V_INT or V_FLOAT */
		float f = atof(token);
		expression->d.terminal.d1.number = f;
		expression->type = EA_VALUE_FLOAT;
		return expression;
	}

	/* boolean */
	if (Q_streq(token, "true")) {
		expression->d.terminal.d1.number = 1.0;
		expression->type = EA_VALUE_FLOAT;
		return expression;
	}
	if (Q_streq(token, "false")) {
		expression->d.terminal.d1.number = 0.0;
		expression->type = EA_VALUE_FLOAT;
		return expression;
	}

	Com_Error(ERR_FATAL, "UI_ParseValueExpression: Token \"%s\" unknown. String must use quotes, cvar and nodes must use prefix.\n", token);
}
Exemplo n.º 8
0
/**
 * @brief unittest around default use of parser
 */
TEST_F(ParserTest, ParserWithFunctionScriptToken)
{
	const char* string = "aa \t\n aa,({\"bbb(bbb bbb)bbb {\"{a}\n/* foooo { } \n { } */\n// fooooo\naaaa)";
	const char* cursor = string;
	const char* token;

	token = Com_Parse(&cursor);
	ASSERT_EQ(Com_GetType(&cursor), TT_WORD);
	ASSERT_STREQ(token, "aa");

	token = Com_Parse(&cursor);
	ASSERT_EQ(Com_GetType(&cursor), TT_WORD);
	ASSERT_STREQ(token, "aa");

	token = Com_Parse(&cursor);
	ASSERT_EQ(Com_GetType(&cursor), TT_COMMA);
	ASSERT_STREQ(token, ",");

	token = Com_Parse(&cursor);
	ASSERT_EQ(Com_GetType(&cursor), TT_BEGIN_LIST);
	ASSERT_STREQ(token, "(");

	token = Com_Parse(&cursor);
	ASSERT_EQ(Com_GetType(&cursor), TT_BEGIN_BLOCK);
	ASSERT_STREQ(token, "{");

	token = Com_Parse(&cursor);
	ASSERT_EQ(Com_GetType(&cursor), TT_QUOTED_WORD);
	ASSERT_STREQ(token, "bbb(bbb bbb)bbb {");

	token = Com_Parse(&cursor);
	ASSERT_EQ(Com_GetType(&cursor), TT_BEGIN_BLOCK);
	ASSERT_STREQ(token, "{");

	token = Com_Parse(&cursor);
	ASSERT_EQ(Com_GetType(&cursor), TT_WORD);
	ASSERT_STREQ(token, "a");

	token = Com_Parse(&cursor);
	ASSERT_EQ(Com_GetType(&cursor), TT_END_BLOCK);
	ASSERT_STREQ(token, "}");

	token = Com_Parse(&cursor);
	ASSERT_EQ(Com_GetType(&cursor), TT_WORD);
	ASSERT_STREQ(token, "aaaa");

	token = Com_Parse(&cursor);
	ASSERT_EQ(Com_GetType(&cursor), TT_END_LIST);
	ASSERT_STREQ(token, ")");

	token = Com_Parse(&cursor);
	ASSERT_EQ(Com_GetType(&cursor), TT_EOF);
	ASSERT_STREQ(token, "\0");
}