Пример #1
0
/**
 * @brief Parser for call command
 */
static bool UI_ParseCallAction (uiNode_t* node, uiAction_t* action, const char** text, const char** token, const char* errhead)
{
	uiAction_t* expression;
	uiAction_t* lastParam = nullptr;
	int paramID = 0;
	expression = UI_ParseExpression(text);
	if (expression == nullptr)
		return false;

	if (expression->type != EA_VALUE_PATHNODE_WITHINJECTION && expression->type != EA_VALUE_PATHNODE && expression->type != EA_VALUE_PATHPROPERTY && expression->type != EA_VALUE_PATHPROPERTY_WITHINJECTION) {
		Com_Printf("UI_ParseCallAction: \"call\" keyword only support pathnode and pathproperty (node: %s)\n", UI_GetPath(node));
		return false;
	}

	action->d.nonTerminal.left = expression;

	/* check parameters */
	*token = Com_EParse(text, errhead, nullptr);
	if ((*token)[0] == '\0')
		return false;

	/* there is no parameters */
	if (!Q_streq(*token, "(")) {
		Com_UnParseLastToken();
		return true;
	}

	/* read parameters */
	do {
		uiAction_t* param;
		paramID++;

		/* parameter */
		param = UI_ParseExpression(text);
		if (param == nullptr) {
			Com_Printf("UI_ParseCallAction: problem with the %i parameter\n", paramID);
			return false;
		}
		if (lastParam == nullptr)
			action->d.nonTerminal.right = param;
		else
			lastParam->next = param;
		lastParam = param;

		/* separator */
		*token = Com_EParse(text, errhead, nullptr);
		if (!*token)
			return false;
		if (!Q_streq(*token, ",")) {
			if (Q_streq(*token, ")"))
				break;
			Com_UnParseLastToken();
			Com_Printf("UI_ParseCallAction: Invalidate end of 'call' after param %i\n", paramID);
			return false;
		}
	} while(true);

	return true;
}
Пример #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");
}
Пример #3
0
/**
 * @brief unittest around default use of parser
 */
static void testParserWithUnParse (void)
{
    const char* string = "aaaaa\n\tbbbbb \"ccccc\"";
    const char* cursor = string;
    const char *token;

    token = Com_Parse(&cursor);
    CU_ASSERT_FALSE(Com_ParsedTokenIsQuoted());
    CU_ASSERT_STRING_EQUAL(token, "aaaaa");

    Com_UnParseLastToken();

    token = Com_Parse(&cursor);
    CU_ASSERT_FALSE(Com_ParsedTokenIsQuoted());
    CU_ASSERT_STRING_EQUAL(token, "aaaaa");

    Com_UnParseLastToken();

    token = Com_Parse(&cursor);
    CU_ASSERT_FALSE(Com_ParsedTokenIsQuoted());
    CU_ASSERT_STRING_EQUAL(token, "aaaaa");

    token = Com_Parse(&cursor);
    CU_ASSERT_FALSE(Com_ParsedTokenIsQuoted());
    CU_ASSERT_STRING_EQUAL(token, "bbbbb");

    Com_UnParseLastToken();

    token = Com_Parse(&cursor);
    CU_ASSERT_FALSE(Com_ParsedTokenIsQuoted());
    CU_ASSERT_STRING_EQUAL(token, "bbbbb");

    Com_UnParseLastToken();

    token = Com_Parse(&cursor);
    CU_ASSERT_FALSE(Com_ParsedTokenIsQuoted());
    CU_ASSERT_STRING_EQUAL(token, "bbbbb");

    token = Com_Parse(&cursor);
    CU_ASSERT_TRUE(Com_ParsedTokenIsQuoted());
    CU_ASSERT_STRING_EQUAL(token, "ccccc");

    Com_UnParseLastToken();

    token = Com_Parse(&cursor);
    CU_ASSERT_TRUE(Com_ParsedTokenIsQuoted());
    CU_ASSERT_STRING_EQUAL(token, "ccccc");

    Com_UnParseLastToken();

    token = Com_Parse(&cursor);
    CU_ASSERT_TRUE(Com_ParsedTokenIsQuoted());
    CU_ASSERT_STRING_EQUAL(token, "ccccc");
}
Пример #4
0
/**
 * @brief Parser for setter command
 */
static bool UI_ParseSetAction (uiNode_t* node, uiAction_t* action, const char** text, const char** token, const char* errhead)
{
	const value_t* property;
	int type;
	uiAction_t* localAction;

	assert((*token)[0] == '*');

	Com_UnParseLastToken();
	action->d.nonTerminal.left = UI_ParseExpression(text);

	type = action->d.nonTerminal.left->type;
	if (type != EA_VALUE_CVARNAME && type != EA_VALUE_CVARNAME_WITHINJECTION
		&& type != EA_VALUE_PATHPROPERTY && type != EA_VALUE_PATHPROPERTY_WITHINJECTION) {
		Com_Printf("UI_ParseSetAction: Cvar or Node property expected. Type '%i' found\n", type);
		return false;
	}

	/* must use "equal" char between name and value */
	*token = Com_EParse(text, errhead, nullptr);
	if (!*text)
		return false;
	if (!Q_streq(*token, "=")) {
		Com_Printf("UI_ParseSetAction: Assign sign '=' expected between variable and value. '%s' found in node %s.\n", *token, UI_GetPath(node));
		return false;
	}

	/* get the value */
	if (type == EA_VALUE_CVARNAME || type == EA_VALUE_CVARNAME_WITHINJECTION) {
		action->d.nonTerminal.right = UI_ParseExpression(text);
		return true;
	}

	property = (const value_t*) action->d.nonTerminal.left->d.terminal.d2.data;

	*token = Com_EParse(text, errhead, nullptr);
	if (!*text)
		return false;

	if (Q_streq(*token, "{")) {
		uiAction_t* actionList;

		if (property != nullptr && property->type != V_UI_ACTION) {
			Com_Printf("UI_ParseSetAction: Property %s@%s do not expect code block.\n", UI_GetPath(node), property->string);
			return false;
		}

		actionList = UI_ParseActionList(node, text, token);
		if (actionList == nullptr)
			return false;

		localAction = UI_AllocStaticAction();
		localAction->type = EA_VALUE_RAW;
		localAction->d.terminal.d1.data = actionList;
		localAction->d.terminal.d2.integer = V_UI_ACTION;
		action->d.nonTerminal.right = localAction;

		return true;
	}

	if (Q_streq(*token, "(")) {
		Com_UnParseLastToken();
		action->d.nonTerminal.right = UI_ParseExpression(text);
		return true;
	}

	/* @todo everything should come from UI_ParseExpression */

	if (UI_IsInjectedString(*token)) {
		localAction = UI_AllocStaticAction();
		localAction->type = EA_VALUE_STRING_WITHINJECTION;
		localAction->d.terminal.d1.data = UI_AllocStaticString(*token, 0);
		action->d.nonTerminal.right = localAction;
		return true;
	}

	localAction = UI_AllocStaticAction();
	UI_InitRawActionValue(localAction, node, property, *token);
	action->d.nonTerminal.right = localAction;
	return true;
}
Пример #5
0
/**
 * @brief Reads the sequence values from given text-pointer
 * @sa CL_ParseClientData
 */
void CL_ParseSequence (const char *name, const char **text)
{
	const char *errhead = "CL_ParseSequence: unexpected end of file (sequence ";
	sequence_t *sp;
	const char *token;
	int i;

	/* search for sequences with same name */
	for (i = 0; i < numSequences; i++)
		if (Q_streq(name, sequences[i].name))
			break;

	if (i < numSequences) {
		Com_Printf("CL_ParseSequence: sequence def \"%s\" with same name found, second ignored\n", name);
		return;
	}

	/* initialize the sequence */
	if (numSequences >= MAX_SEQUENCES)
		Com_Error(ERR_FATAL, "Too many sequences");

	sp = &sequences[numSequences++];
	OBJZERO(*sp);
	Q_strncpyz(sp->name, name, sizeof(sp->name));
	sp->start = numSeqCmds;

	/* get it's body */
	token = Com_Parse(text);

	if (!*text || *token != '{') {
		Com_Printf("CL_ParseSequence: sequence def \"%s\" without body ignored\n", name);
		numSequences--;
		return;
	}

	do {
		token = Com_EParse(text, errhead, name);
		if (!*text)
			break;
		if (*token == '}')
			break;

		/* check for commands */
		int i = CL_FindSequenceCommand(token);
		if (i != -1) {
			int maxLength = MAX_DATA_LENGTH;
			char *data;
			seqCmd_t *sc;

			/* found a command */
			token = Com_EParse(text, errhead, name);
			if (!*text)
				return;

			if (numSeqCmds >= MAX_SEQCMDS)
				Com_Error(ERR_FATAL, "Too many sequence commands for %s", name);

			/* init seqCmd */
			if (seqCmds == NULL)
				seqCmds = Mem_PoolAllocTypeN(seqCmd_t, MAX_SEQCMDS, cl_genericPool);
			sc = &seqCmds[numSeqCmds++];
			OBJZERO(*sc);
			sc->handler = seqCmdFunc[i];
			sp->length++;

			/* copy name */
			Q_strncpyz(sc->name, token, sizeof(sc->name));

			/* read data */
			token = Com_EParse(text, errhead, name);
			if (!*text)
				return;
			if (*token == '{') {
				// TODO depth is useless IMHO (bayo)
				int depth = 1;
				data = &sc->data[0];
				while (depth) {
					if (maxLength <= 0) {
						Com_Printf("Too much data for sequence %s", sc->name);
						break;
					}
					token = Com_EParse(text, errhead, name);
					if (!*text)
						return;

					if (*token == '{')
						depth++;
					else if (*token == '}')
						depth--;
					if (depth) {
						Q_strncpyz(data, token, maxLength);
						data += strlen(token) + 1;
						maxLength -= (strlen(token) + 1);
					}
				}
			} else if (*token == '(') {
				linkedList_t *list;
				Com_UnParseLastToken();
				if (!Com_ParseList(text, &list)) {
					Com_Error(ERR_DROP, "CL_ParseSequence: error while reading list (sequence \"%s\")", name);
				}
				data = &sc->data[0];
				for (linkedList_t *element = list; element != NULL; element = element->next) {
					if (maxLength <= 0) {
						Com_Printf("Too much data for sequence %s", sc->name);
						break;
					}
					const char* v = (char*)element->data;
					Q_strncpyz(data, v, maxLength);
					data += strlen(v) + 1;
					maxLength -= (strlen(v) + 1);
				}
				LIST_Delete(&list);
			} else {
				Com_UnParseLastToken();
			}
		} else {
			Com_Printf("CL_ParseSequence: unknown command \"%s\" ignored (sequence %s)\n", token, name);
			Com_EParse(text, errhead, name);
		}
	} while (*text);
}
Пример #6
0
uiAction_t *UI_ParseExpression (const char **text)
{
	const char* token;

	token = Com_Parse(text);
	if (*text == nullptr)
		return nullptr;

	if (Q_streq(token, "(")) {
		uiAction_t *expression;
		uiAction_t *e;

		e = UI_ParseExpression(text);

		token = Com_Parse(text);
		if (*text == nullptr)
			return nullptr;

		/* unary operator or unneed "( ... )" */
		if (Q_streq(token, ")"))
			return e;

		/* then its an operator */
		expression = UI_AllocStaticAction();
		expression->d.nonTerminal.left = e;
		expression->type = UI_GetActionTokenType(token, EA_BINARYOPERATOR);
		if (expression->type == EA_nullptr) {
			Com_Printf("UI_ParseExpression: Invalid 'expression' statement. Unknown '%s' operator\n", token);
			return nullptr;
		}

		e = UI_ParseExpression(text);
		expression->d.nonTerminal.right = e;

		token = Com_Parse(text);
		if (*text == nullptr)
			return nullptr;
		if (!Q_streq(token, ")")) {
			Com_Printf("UI_ParseExpression: Token ')' expected\n");
			return nullptr;
		}

		return expression;
	} else {
		const int type = UI_GetActionTokenType(token, EA_UNARYOPERATOR);
		if (type == EA_nullptr) {
			Com_UnParseLastToken();
			return UI_ParseValueExpression(text);
		} else {
			uiAction_t *expression = UI_AllocStaticAction();
			uiAction_t *e;

			e = UI_ParseExpression(text);
			expression->type = type;
			expression->d.nonTerminal.left = e;

			if (expression->type == EA_OPERATOR_EXISTS) {
				switch (e->type) {
				case EA_VALUE_CVARNAME:
				case EA_VALUE_CVARNAME_WITHINJECTION:
				case EA_VALUE_PATHNODE:
				case EA_VALUE_PATHNODE_WITHINJECTION:
					break;
				default:
					Com_Printf("UI_ParseExpression: Cvar or Node path expected, but type %d found\n", e->type);
					return nullptr;
				}
			}
			return expression;
		}
	}
}