1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
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 | |
37 | |
38 | |
39 | |
40 | |
41 | |
42 | uiNode_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 | |
154 | |
155 | float 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 | |
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 | |
287 | |
288 | |
289 | |
290 | const 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 | |
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 | |
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 | |
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 | |
426 | |
427 | |
428 | bool 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 | |
520 | |
521 | |
522 | |
523 | uiAction_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 | |
541 | |
542 | |
543 | static 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 | |
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 | |
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 | |
573 | assert(i != 0)(__builtin_expect(!(i != 0), 0) ? __assert_rtn(__func__, "src/client/ui/ui_expression.cpp" , 573, "i != 0") : (void)0); |
574 | |
575 | expression->type = EA_VALUE_PARAM; |
576 | expression->d.terminal.d1.integer = i; |
577 | return expression; |
578 | } |
579 | } |
580 | } |
581 | |
582 | |
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 | |
593 | |
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 | |
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 | |
629 | if ((token[0] >= '0' && token[0] <= '9') |
630 | || (token[0] == '-' && token[1] >= '0' && token[1] <= '9')) { |
631 | |
632 | float f = atof(token); |
633 | expression->d.terminal.d1.number = f; |
634 | expression->type = EA_VALUE_FLOAT; |
635 | return expression; |
636 | } |
637 | |
638 | |
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 | |
653 | uiAction_t *UI_ParseExpression (const char **text) |
654 | { |
655 | const char* token; |
656 | |
657 | token = Com_Parse(text); |
658 | if (*text == NULL__null) |
| |
| |
| |
659 | return NULL__null; |
660 | |
661 | if (Q_streq(token, "(")(strcmp(token, "(") == 0)) { |
| |
| |
| |
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 | |
672 | if (Q_streq(token, ")")(strcmp(token, ")") == 0)) |
673 | return e; |
674 | |
675 | |
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) { |
| |
| |
| |
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) { |
| |
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 | } |