Bug Summary

File:client/ui/ui_expression.cpp
Location:line 710, column 9
Description:Access to field 'type' results in a dereference of a null pointer (loaded from variable 'e')

Annotated Source Code

1/**
2 * @file
3 */
4
5/*
6Copyright (C) 2002-2011 UFO: Alien Invasion.
7
8This program is free software; you can redistribute it and/or
9modify it under the terms of the GNU General Public License
10as published by the Free Software Foundation; either version 2
11of the License, or (at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
17See the GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with this program; if not, write to the Free Software
21Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23*/
24
25#include "ui_expression.h"
26#include "ui_main.h"
27#include "ui_node.h"
28#include "ui_internal.h"
29#include "ui_parse.h"
30#include "ui_actions.h"
31#include "node/ui_node_abstractnode.h"
32#include "../../shared/parse.h"
33#include "../../shared/shared.h"
34
35/**
36 * @brief Get a node and a property from an expression
37 * @param expression Expression tree to analyse
38 * @param context Call context
39 * @param[out] property A node property
40 * @return A node (else NULL, if no node found) and a property (else NULL if no/wrong property defined)
41 */
42uiNode_t* UI_GetNodeFromExpression (uiAction_t *expression, const uiCallContext_t *context, const value_t **property)
43{
44 if (property != NULL__null)
45 *property = NULL__null;
46
47 switch (expression->type & EA_HIGHT_MASK) {
48 case EA_VALUE:
49 switch (expression->type) {
50 case EA_VALUE_VAR:
51 {
52 uiValue_t *variable = UI_GetVariable(context, expression->d.terminal.d1.integer);
53 switch (variable->type) {
54 case EA_VALUE_NODE:
55 return variable->value.node;
56 default:
57 break;
58 }
59 }
60 break;
61
62 case EA_VALUE_PATHNODE:
63 case EA_VALUE_PATHNODE_WITHINJECTION:
64 {
65 uiNode_t *node;
66 const value_t *propertyTmp;
67 const char *path = expression->d.terminal.d1.constString;
68 if (expression->type == EA_VALUE_PATHNODE_WITHINJECTION)
69 path = UI_GenInjectedString(path, false, context);
70
71 UI_ReadNodePath(path, context->source, &node, &propertyTmp);
72 if (!node) {
73 Com_Printf("UI_GetNodeFromExpression: Node '%s' wasn't found; NULL returned\n", path);
74 return NULL__null;
75 }
76 if (propertyTmp != NULL__null)
77 Com_Printf("UI_GetNodeFromExpression: No property expected, but path '%s' contain a property. Property ignored.\n", path);
78
79 return node;
80 }
81
82 case EA_VALUE_PATHPROPERTY:
83 case EA_VALUE_PATHPROPERTY_WITHINJECTION:
84 {
85 uiNode_t *node;
86 const value_t *propertyTmp;
87 const char *path = expression->d.terminal.d1.constString;
88 if (expression->type == EA_VALUE_PATHPROPERTY_WITHINJECTION)
89 path = UI_GenInjectedString(path, false, context);
90
91 UI_ReadNodePath(path, context->source, &node, &propertyTmp);
92 if (!node) {
93 Com_Printf("UI_GetNodeFromExpression: Node '%s' wasn't found; NULL returned\n", path);
94 return NULL__null;
95 }
96 if (property == NULL__null) {
97 if (propertyTmp != NULL__null)
98 Com_Printf("UI_GetNodeFromExpression: No property expected, but path '%s' contain a property. Property ignored.\n", path);
99 } else {
100 *property = propertyTmp;
101 }
102
103 return node;
104 }
105
106 case EA_VALUE_THIS:
107 return context->source;
108
109 case EA_VALUE_PARENT:
110 return context->source->parent;
111
112 case EA_VALUE_WINDOW:
113 return context->source->root;
114
115 default:
116 break;
117 }
118
119 case EA_OPERATOR_UNARY:
120 switch (expression->type) {
121 case EA_OPERATOR_PATHPROPERTYFROM:
122 {
123 uiNode_t *relativeTo = UI_GetNodeFromExpression(expression->d.nonTerminal.left, context, NULL__null);
124 uiNode_t *node;
125 const value_t *propertyTmp;
126 const char* path = expression->d.terminal.d2.constString;
127 UI_ReadNodePath(path, relativeTo, &node, &propertyTmp);
128 if (!node) {
129 Com_Printf("UI_GetNodeFromExpression: Path '%s' from node '%s' found no node; NULL returned\n", path, UI_GetPath(relativeTo));
130 return NULL__null;
131 }
132 if (property == NULL__null) {
133 if (propertyTmp != NULL__null)
134 Com_Printf("UI_GetNodeFromExpression: No property expected, but path '%s' from node '%s' found no node; NULL returned\n", path, UI_GetPath(relativeTo));
135 } else {
136 *property = propertyTmp;
137 }
138 return node;
139 }
140 default:
141 break;
142 }
143
144 default:
145 break;
146 }
147
148 return NULL__null;
149}
150
151
152/**
153 * @return A float value, else 0
154 */
155float UI_GetFloatFromExpression (uiAction_t *expression, const uiCallContext_t *context)
156{
157 switch (expression->type & EA_HIGHT_MASK) {
158 case EA_VALUE:
159 switch (expression->type) {
160 case EA_VALUE_VAR:
161 {
162 uiValue_t *variable = UI_GetVariable(context, expression->d.terminal.d1.integer);
163 switch (variable->type) {
164 case EA_VALUE_STRING:
165 if (variable->value.string == NULL__null) {
166 Com_Printf("UI_GetFloatFromExpression: String variable not initialized. '0' returned");
167 return 0;
168 }
169 return atof(variable->value.string);
170 case EA_VALUE_FLOAT:
171 return variable->value.number;
172 case EA_VALUE_CVAR:
173 {
174 cvar_t *cvar = variable->value.cvar;
175 if (cvar == NULL__null) {
176 Com_Printf("UI_GetFloatFromExpression: Cvar variable not initialized. '0' returned");
177 return 0;
178 }
179 return cvar->value;
180 }
181 default:
182 Com_Printf("UI_GetFloatFromExpression: Unsupported variable type: %i. '0' returned", variable->type);
183 return 0;
184 }
185 }
186 case EA_VALUE_STRING:
187 case EA_VALUE_STRING_WITHINJECTION:
188 {
189 const char* string = expression->d.terminal.d1.constString;
190 if (expression->type == EA_VALUE_STRING_WITHINJECTION)
191 string = UI_GenInjectedString(string, false, context);
192 return atof(string);
193 }
194 case EA_VALUE_FLOAT:
195 return expression->d.terminal.d1.number;
196 case EA_VALUE_CVARNAME:
197 case EA_VALUE_CVARNAME_WITHINJECTION:
198 {
199 cvar_t *cvar = NULL__null;
200 const char *cvarName = expression->d.terminal.d1.constString;
201 if (expression->type == EA_VALUE_CVARNAME_WITHINJECTION)
202 cvarName = UI_GenInjectedString(cvarName, false, context);
203 cvar = Cvar_Get(cvarName, "", 0, "Cvar from UI script expression");
204 return cvar->value;
205 }
206 case EA_VALUE_PATHPROPERTY:
207 case EA_VALUE_PATHPROPERTY_WITHINJECTION:
208 {
209 uiNode_t *node;
210 const value_t *property;
211 node = UI_GetNodeFromExpression(expression, context, &property);
212 if (!node) {
213 Com_Printf("UI_GetFloatFromParam: Node wasn't found; '0'\n");
214 return 0;
215 }
216 if (!property) {
217 Com_Printf("UI_GetFloatFromParam: Property wasn't found; '0' returned\n");
218 return 0;
219 }
220 return UI_GetFloatFromNodeProperty(node, property);
221 }
222 case EA_VALUE_PARAM:
223 {
224 const int paramId = expression->d.terminal.d1.integer;
225 const char *string = UI_GetParam(context, paramId);
226 if (string[0] == '\0') {
227 Com_Printf("UI_GetFloatFromParam: Param '%i' is out of range, or empty; '0' returned\n", paramId);
228 return 0;
229 }
230 return atof(string);
231 }
232 case EA_VALUE_PARAMCOUNT:
233 return UI_GetParamNumber(context);
234 }
235 break;
236
237 case EA_OPERATOR_FLOAT2FLOAT:
238 {
239 const float value1 = UI_GetFloatFromExpression(expression->d.nonTerminal.left, context);
240 const float value2 = UI_GetFloatFromExpression(expression->d.nonTerminal.right, context);
241
242 switch (expression->type) {
243 case EA_OPERATOR_ADD:
244 return value1 + value2;
245 case EA_OPERATOR_SUB:
246 return value1 - value2;
247 case EA_OPERATOR_MUL:
248 return value1 * value2;
249 case EA_OPERATOR_DIV:
250 if (value2 == 0) {
251 Com_Printf("UI_GetFloatFromExpression: Div by 0. '0' returned");
252 return 0;
253 } else
254 return value1 / value2;
255 case EA_OPERATOR_MOD:
256 {
257 const int v1 = value1;
258 const int v2 = value2;
259 /** @todo do we have some check to do? */
260 return v1 % v2;
261 }
262 }
263 }
264 break;
265
266 case EA_OPERATOR_UNARY:
267 switch (expression->type) {
268 case EA_OPERATOR_PATHPROPERTYFROM:
269 {
270 uiNode_t *node;
271 const value_t *property;
272 node = UI_GetNodeFromExpression(expression, context, &property);
273 return UI_GetFloatFromNodeProperty(node, property);
274 }
275 default:
276 Com_Error(ERR_FATAL0, "UI_GetFloatFromExpression: (EA_OPERATOR_UNARY) Invalid expression type %i", expression->type);
277 }
278
279 }
280
281 Com_Printf("UI_GetFloatFromExpression: Unsupported expression type: %i. '0' returned", expression->type);
282 return 0;
283}
284
285/**
286 * @return A string, else an empty string
287 * @todo this should not work very well, because too much va are used
288 * then we should locally cache values, or manage a temporary string structure
289 */
290const char* UI_GetStringFromExpression (uiAction_t *expression, const uiCallContext_t *context)
291{
292 switch (expression->type & EA_HIGHT_MASK) {
293 case EA_VALUE:
294 switch (expression->type) {
295 case EA_VALUE_VAR:
296 {
297 uiValue_t *variable = UI_GetVariable(context, expression->d.terminal.d1.integer);
298 switch (variable->type) {
299 case EA_VALUE_STRING:
300 if (variable->value.string == NULL__null) {
301 Com_Printf("UI_GetStringFromExpression: String variable not initialized. Empty string returned");
302 return "";
303 }
304 return variable->value.string;
305 case EA_VALUE_FLOAT:
306 {
307 const float number = variable->value.number;
308 const int integer = number;
309 /** @todo should we add a delta? */
310 if (number == integer)
311 return va("%i", integer);
312 else
313 return va("%f", number);
314 }
315 case EA_VALUE_CVAR:
316 {
317 cvar_t *cvar = variable->value.cvar;
318 if (cvar == NULL__null) {
319 Com_Printf("UI_GetStringFromExpression: Cvar variable not initialized. Empty string returned");
320 return "";
321 }
322 return cvar->string;
323 }
324 default:
325 Com_Printf("UI_GetStringFromExpression: Unsupported variable type: %i. Empty string returned", variable->type);
326 return "";
327 }
328 }
329 case EA_VALUE_STRING:
330 case EA_VALUE_STRING_WITHINJECTION:
331 {
332 const char* string = expression->d.terminal.d1.constString;
333 if (expression->type == EA_VALUE_STRING_WITHINJECTION)
334 string = UI_GenInjectedString(string, false, context);
335 return string;
336 }
337 case EA_VALUE_FLOAT:
338 {
339 const float number = expression->d.terminal.d1.number;
340 const int integer = number;
341 /** @todo should we add a delta? */
342 if (number == integer)
343 return va("%i", integer);
344 else
345 return va("%f", number);
346 }
347 case EA_VALUE_CVARNAME:
348 case EA_VALUE_CVARNAME_WITHINJECTION:
349 {
350 cvar_t *cvar = NULL__null;
351 const char *cvarName = expression->d.terminal.d1.constString;
352 if (expression->type == EA_VALUE_CVARNAME_WITHINJECTION)
353 cvarName = UI_GenInjectedString(cvarName, false, context);
354 cvar = Cvar_Get(cvarName, "", 0, "Cvar from UI script expression");
355 return cvar->string;
356 }
357 case EA_VALUE_PATHPROPERTY:
358 case EA_VALUE_PATHPROPERTY_WITHINJECTION:
359 {
360 uiNode_t *node;
361 const value_t *property;
362 const char* string;
363 node = UI_GetNodeFromExpression(expression, context, &property);
364 if (!node) {
365 Com_Printf("UI_GetStringFromExpression: Node wasn't found; Empty string returned\n");
366 return "";
367 }
368 if (!property) {
369 Com_Printf("UI_GetStringFromExpression: Property wasn't found; Empty string returned\n");
370 return "";
371 }
372 string = UI_GetStringFromNodeProperty(node, property);
373 if (string == NULL__null) {
374 Com_Printf("UI_GetStringFromExpression: String getter for '%s@%s' property do not exists; '' returned\n", UI_Node_GetWidgetName(node), property->string);
375 return "";
376 }
377 return string;
378 }
379 break;
380 case EA_VALUE_PARAM:
381 return UI_GetParam(context, expression->d.terminal.d1.integer);
382 case EA_VALUE_PARAMCOUNT:
383 return va("%i", UI_GetParamNumber(context));
384 }
385 break;
386
387 case EA_OPERATOR_UNARY:
388 switch (expression->type) {
389 case EA_OPERATOR_PATHPROPERTYFROM:
390 {
391 uiNode_t *node;
392 const value_t *property;
393 node = UI_GetNodeFromExpression(expression, context, &property);
394 return UI_GetStringFromNodeProperty(node, property);
395 }
396 default:
397 Com_Error(ERR_FATAL0, "UI_GetFloatFromExpression: (EA_OPERATOR_UNARY) Invalid expression type %i", expression->type);
398 }
399
400 case EA_OPERATOR_BOOLEAN2BOOLEAN:
401 case EA_OPERATOR_FLOAT2BOOLEAN:
402 case EA_OPERATOR_STRING2BOOLEAN:
403 {
404 const bool v = UI_GetBooleanFromExpression(expression, context);
405 return (v)?"1":"0";
406 }
407
408 case EA_OPERATOR_FLOAT2FLOAT:
409 {
410 const float number = UI_GetFloatFromExpression(expression, context);
411 const int integer = number;
412 /** @todo should we add a delta? */
413 if (number == integer)
414 return va("%i", integer);
415 else
416 return va("%f", number);
417 }
418 }
419
420 Com_Printf("UI_GetStringFromExpression: Unsupported expression type: %i", expression->type);
421 return "";
422}
423
424/**
425 * @brief Check if an expression is true
426 * @return True if the expression is true
427 */
428bool UI_GetBooleanFromExpression (uiAction_t *expression, const uiCallContext_t *context)
429{
430 if (expression == NULL__null)
431 return false;
432
433 switch (expression->type & EA_HIGHT_MASK) {
434 case EA_VALUE:
435 return UI_GetFloatFromExpression(expression, context) != 0;
436
437 case EA_OPERATOR_BOOLEAN2BOOLEAN:
438 {
439#define VALUE1UI_GetBooleanFromExpression(expression->d.nonTerminal.left
, context)
UI_GetBooleanFromExpression(expression->d.nonTerminal.left, context)
440#define VALUE2UI_GetBooleanFromExpression(expression->d.nonTerminal.right
, context)
UI_GetBooleanFromExpression(expression->d.nonTerminal.right, context)
441
442 switch (expression->type) {
443 case EA_OPERATOR_AND:
444 return VALUE1UI_GetBooleanFromExpression(expression->d.nonTerminal.left
, context)
&& VALUE2UI_GetBooleanFromExpression(expression->d.nonTerminal.right
, context)
;
445 case EA_OPERATOR_OR:
446 return VALUE1UI_GetBooleanFromExpression(expression->d.nonTerminal.left
, context)
|| VALUE2UI_GetBooleanFromExpression(expression->d.nonTerminal.right
, context)
;
447 case EA_OPERATOR_XOR:
448 return VALUE1UI_GetBooleanFromExpression(expression->d.nonTerminal.left
, context)
^ VALUE2UI_GetBooleanFromExpression(expression->d.nonTerminal.right
, context)
;
449 case EA_OPERATOR_NOT:
450 return !VALUE1UI_GetBooleanFromExpression(expression->d.nonTerminal.left
, context)
;
451 default:
452 Com_Error(ERR_FATAL0, "UI_GetBooleanFromExpression: (BOOL2BOOL) Invalid expression type");
453 }
454 }
455
456 case EA_OPERATOR_FLOAT2BOOLEAN:
457 {
458 const float value1 = UI_GetFloatFromExpression(expression->d.nonTerminal.left, context);
459 const float value2 = UI_GetFloatFromExpression(expression->d.nonTerminal.right, context);
460
461 switch (expression->type) {
462 case EA_OPERATOR_EQ:
463 return value1 == value2;
464 case EA_OPERATOR_LE:
465 return value1 <= value2;
466 case EA_OPERATOR_GE:
467 return value1 >= value2;
468 case EA_OPERATOR_GT:
469 return value1 > value2;
470 case EA_OPERATOR_LT:
471 return value1 < value2;
472 case EA_OPERATOR_NE:
473 return value1 != value2;
474 default:
475 Com_Error(ERR_FATAL0, "UI_GetBooleanFromExpression: (FLOAT2BOOL) Invalid expression type");
476 }
477 }
478
479 case EA_OPERATOR_UNARY:
480 switch (expression->type) {
481 case EA_OPERATOR_EXISTS:
482 {
483 const uiAction_t *e = expression->d.nonTerminal.left;
484 const char* cvarName;
485 assert(e)(__builtin_expect(!(e), 0) ? __assert_rtn(__func__, "src/client/ui/ui_expression.cpp"
, 485, "e") : (void)0)
;
486 assert(e->type == EA_VALUE_CVARNAME || e->type == EA_VALUE_CVARNAME_WITHINJECTION)(__builtin_expect(!(e->type == EA_VALUE_CVARNAME || e->
type == EA_VALUE_CVARNAME_WITHINJECTION), 0) ? __assert_rtn(__func__
, "src/client/ui/ui_expression.cpp", 486, "e->type == EA_VALUE_CVARNAME || e->type == EA_VALUE_CVARNAME_WITHINJECTION"
) : (void)0)
;
487 cvarName = e->d.terminal.d1.constString;
488 if (e->type == EA_VALUE_CVARNAME_WITHINJECTION)
489 cvarName = UI_GenInjectedString(cvarName, false, context);
490 return Cvar_FindVar(cvarName) != NULL__null;
491 }
492 case EA_OPERATOR_PATHPROPERTYFROM:
493 return UI_GetFloatFromExpression(expression, context) != 0;
494 default:
495 Com_Error(ERR_FATAL0, "UI_GetBooleanFromExpression: (EA_OPERATOR_UNARY) Invalid expression type %i", expression->type);
496 }
497
498 case EA_OPERATOR_STRING2BOOLEAN:
499 {
500 const char* value1 = UI_GetStringFromExpression(expression->d.nonTerminal.left, context);
501 const char* value2 = UI_GetStringFromExpression(expression->d.nonTerminal.right, context);
502
503 switch (expression->type) {
504 case EA_OPERATOR_STR_EQ:
505 return Q_streq(value1, value2)(strcmp(value1, value2) == 0);
506 case EA_OPERATOR_STR_NE:
507 return !Q_streq(value1, value2)(strcmp(value1, value2) == 0);
508 default:
509 Com_Error(ERR_FATAL0, "UI_GetBooleanFromExpression: (STRING2BOOL) Invalid expression type");
510 }
511 }
512
513 default:
514 Com_Error(ERR_FATAL0, "UI_GetBooleanFromExpression: Unsupported expression type: %i", expression->type);
515 }
516}
517
518/**
519 * @brief Allocate and initialize an expression according to a string
520 * @param[in] description String describing a condition
521 * @return The condition if everything is ok, NULL otherwise
522 */
523uiAction_t *UI_AllocStaticStringCondition (const char *description)
524{
525 const char *text, *base;
526 uiAction_t *expression;
527
528 base = va("( %s )", description);
529 text = base;
530 expression = UI_ParseExpression(&text);
1
Calling 'UI_ParseExpression'
531 if (!expression) {
532 Com_Printf("UI_AllocStaticStringCondition: Parse error on expression \"%s\"\n", base);
533 return NULL__null;
534 }
535
536 return expression;
537}
538
539/**
540 * @brief Read a value from the stream and init an action with it
541 * @return An initialized action else NULL
542 */
543static uiAction_t *UI_ParseValueExpression (const char **text)
544{
545 const char* token;
546 uiAction_t *expression = UI_AllocStaticAction();
547
548 token = Com_Parse(text);
549 if (*text == NULL__null) {
550 Com_Printf("UI_ParseTerminalExpression: Token expected\n");
551 return NULL__null;
552 }
553
554 /* it is a const string (or an injection tag for compatibility) */
555 if (Com_GetType(text) == TT_QUOTED_WORD || token[0] == '<') {
556 expression->d.terminal.d1.constString = UI_AllocStaticString(token, 0);
557 if (UI_IsInjectedString(token))
558 expression->type = EA_VALUE_STRING_WITHINJECTION;
559 else
560 expression->type = EA_VALUE_STRING;
561 return expression;
562 }
563
564 /* it is a param */
565 if (!Q_strncasecmp(token, "param", 5)strncasecmp((token), ("param"), (5))) {
566 if (!Q_strcasecmp(token, "paramcount")strcasecmp((token), ("paramcount"))) {
567 expression->type = EA_VALUE_PARAMCOUNT;
568 return expression;
569 } else if (token[5] >= '1' && token[5] <= '9') {
570 int i;
571 if (sscanf(token + 5, "%i", &i) == 1) {
572 /* token range 1-9 already avoid 0 */
573 assert(i != 0)(__builtin_expect(!(i != 0), 0) ? __assert_rtn(__func__, "src/client/ui/ui_expression.cpp"
, 573, "i != 0") : (void)0)
;
574 /** @todo when it is possible, we must check range of param id */
575 expression->type = EA_VALUE_PARAM;
576 expression->d.terminal.d1.integer = i;
577 return expression;
578 }
579 }
580 }
581
582 /* it is a cvarname */
583 if (char const* const cvarName = Q_strstart(token, "*cvar:")) {
584 expression->d.terminal.d1.constString = UI_AllocStaticString(cvarName, 0);
585 if (UI_IsInjectedString(cvarName))
586 expression->type = EA_VALUE_CVARNAME_WITHINJECTION;
587 else
588 expression->type = EA_VALUE_CVARNAME;
589 return expression;
590 }
591
592 /* it is a node property or it is a OLD syntax node property */
593 /** @todo We MUST remove the OLD code as fast as possible */
594 if (char const* path = Q_strstart(token, "*")) {
595 const char *propertyName;
596#if 0 /* it looks useless, an unused cache */
597 const value_t *property;
598#endif
599
600 char const* const relativeToNode = Q_strstart(path, "node:");
601 if (relativeToNode)
602 path = relativeToNode;
603
604 if (UI_IsInjectedString(path))
605 expression->type = EA_VALUE_PATHPROPERTY_WITHINJECTION;
606 else
607 expression->type = EA_VALUE_PATHPROPERTY;
608 if (!relativeToNode) {
609 Com_Printf("UI_ParseExpression: Old syntax, please prefix '%s' with \"*node:root.\" \n", token);
610 path = va("root.%s", path);
611 }
612 expression->d.terminal.d1.constString = UI_AllocStaticString(path, 0);
613
614 /* get property name */
615 propertyName = strchr(path, '@');
616 if (propertyName == NULL__null) {
617 if (expression->type == EA_VALUE_PATHPROPERTY_WITHINJECTION)
618 expression->type = EA_VALUE_PATHNODE_WITHINJECTION;
619 else
620 expression->type = EA_VALUE_PATHNODE;
621 return expression;
622 }
623 propertyName++;
624
625 return expression;
626 }
627
628 /* unsigned and signed number */
629 if ((token[0] >= '0' && token[0] <= '9')
630 || (token[0] == '-' && token[1] >= '0' && token[1] <= '9')) {
631 /** @todo use a better check - e.g. Com_ParseValue with V_INT or V_FLOAT */
632 float f = atof(token);
633 expression->d.terminal.d1.number = f;
634 expression->type = EA_VALUE_FLOAT;
635 return expression;
636 }
637
638 /* boolean */
639 if (Q_streq(token, "true")(strcmp(token, "true") == 0)) {
640 expression->d.terminal.d1.number = 1.0;
641 expression->type = EA_VALUE_FLOAT;
642 return expression;
643 }
644 if (Q_streq(token, "false")(strcmp(token, "false") == 0)) {
645 expression->d.terminal.d1.number = 0.0;
646 expression->type = EA_VALUE_FLOAT;
647 return expression;
648 }
649
650 Com_Error(ERR_FATAL0, "UI_ParseValueExpression: Token \"%s\" unknown. String must use quotes, cvar and nodes must use prefix.\n", token);
651}
652
653uiAction_t *UI_ParseExpression (const char **text)
654{
655 const char* token;
656
657 token = Com_Parse(text);
658 if (*text == NULL__null)
2
Taking false branch
6
Taking false branch
10
Taking false branch
659 return NULL__null;
660
661 if (Q_streq(token, "(")(strcmp(token, "(") == 0)) {
3
Taking false branch
7
Taking false branch
11
Taking false branch
662 uiAction_t *expression;
663 uiAction_t *e;
664
665 e = UI_ParseExpression(text);
666
667 token = Com_Parse(text);
668 if (*text == NULL__null)
669 return NULL__null;
670
671 /* unary operator or unneed "( ... )" */
672 if (Q_streq(token, ")")(strcmp(token, ")") == 0))
673 return e;
674
675 /* then its an operator */
676 expression = UI_AllocStaticAction();
677 expression->d.nonTerminal.left = e;
678 expression->type = UI_GetActionTokenType(token, EA_BINARYOPERATOR);
679 if (expression->type == EA_NULL) {
680 Com_Printf("UI_ParseExpression: Invalid 'expression' statement. Unknown '%s' operator\n", token);
681 return NULL__null;
682 }
683
684 e = UI_ParseExpression(text);
685 expression->d.nonTerminal.right = e;
686
687 token = Com_Parse(text);
688 if (*text == NULL__null)
689 return NULL__null;
690 if (!Q_streq(token, ")")(strcmp(token, ")") == 0)) {
691 Com_Printf("UI_ParseExpression: Token ')' expected\n");
692 return NULL__null;
693 }
694
695 return expression;
696 } else {
697 const int type = UI_GetActionTokenType(token, EA_UNARYOPERATOR);
698 if (type == EA_NULL) {
4
Taking false branch
8
Taking false branch
12
Taking false branch
699 Com_UnParseLastToken();
700 return UI_ParseValueExpression(text);
701 } else {
702 uiAction_t *expression = UI_AllocStaticAction();
703 uiAction_t *e;
704
705 e = UI_ParseExpression(text);
5
Calling 'UI_ParseExpression'
9
Calling 'UI_ParseExpression'
706 expression->type = type;
707 expression->d.nonTerminal.left = e;
708
709 if (expression->type == EA_OPERATOR_EXISTS) {
13
Taking true branch
710 if (e->type != EA_VALUE_CVARNAME && e->type != EA_VALUE_CVARNAME_WITHINJECTION) {
14
Access to field 'type' results in a dereference of a null pointer (loaded from variable 'e')
711 Com_Printf("UI_ParseExpression: Cvar expected, but type %d found\n", e->type);
712 return NULL__null;
713 }
714 }
715 return expression;
716 }
717 }
718}