1 /*
2 ** c_expr.cpp
3 ** Console commands dealing with mathematical expressions
4 **
5 **---------------------------------------------------------------------------
6 ** Copyright 1998-2006 Randy Heit
7 ** All rights reserved.
8 **
9 ** Redistribution and use in source and binary forms, with or without
10 ** modification, are permitted provided that the following conditions
11 ** are met:
12 **
13 ** 1. Redistributions of source code must retain the above copyright
14 ** notice, this list of conditions and the following disclaimer.
15 ** 2. Redistributions in binary form must reproduce the above copyright
16 ** notice, this list of conditions and the following disclaimer in the
17 ** documentation and/or other materials provided with the distribution.
18 ** 3. The name of the author may not be used to endorse or promote products
19 ** derived from this software without specific prior written permission.
20 **
21 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 **---------------------------------------------------------------------------
32 **
33 */
34
35 // HEADER FILES ------------------------------------------------------------
36
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <math.h>
40 #include <string.h>
41
42 #include "c_dispatch.h"
43 #include "c_cvars.h"
44
45 // MACROS ------------------------------------------------------------------
46
47 // TYPES -------------------------------------------------------------------
48
49 enum EProductionType
50 {
51 PROD_String, PROD_Double
52 };
53
54 struct FProduction
55 {
56 EProductionType Type;
57 };
58
59 struct FStringProd : public FProduction
60 {
61 char Value[1];
62 };
63
64 struct FDoubleProd : public FProduction
65 {
66 double Value;
67 };
68
69 struct FProducer
70 {
71 char Token[4];
72 FProduction *(*DoubleProducer) (FDoubleProd *prod1, FDoubleProd *prod2);
73 FProduction *(*StringProducer) (FStringProd *prod1, FStringProd *prod2);
74 };
75
76 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
77
78 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
79
80 bool IsFloat (const char *str);
81
82 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
83
84 static FProduction *ParseExpression (FCommandLine &argv, int &parsept);
85 static const char *IsNum (const char *str);
86 static FStringProd *NewStringProd (const char *str);
87 static FStringProd *NewStringProd (size_t len);
88 static FDoubleProd *NewDoubleProd (double val);
89 static FStringProd *DoubleToString (FProduction *prod);
90 static FDoubleProd *StringToDouble (FProduction *prod);
91 void MaybeStringCoerce (FProduction *&prod1, FProduction *&prod2);
92 void MustStringCoerce (FProduction *&prod1, FProduction *&prod2);
93 void DoubleCoerce (FProduction *&prod1, FProduction *&prod2);
94
95 FProduction *ProdAddDbl (FDoubleProd *prod1, FDoubleProd *prod2);
96 FProduction *ProdAddStr (FStringProd *prod1, FStringProd *prod2);
97 FProduction *ProdSubDbl (FDoubleProd *prod1, FDoubleProd *prod2);
98 FProduction *ProdMulDbl (FDoubleProd *prod1, FDoubleProd *prod2);
99 FProduction *ProdDivDbl (FDoubleProd *prod1, FDoubleProd *prod2);
100 FProduction *ProdModDbl (FDoubleProd *prod1, FDoubleProd *prod2);
101 FProduction *ProdPowDbl (FDoubleProd *prod1, FDoubleProd *prod2);
102 FProduction *ProdLTDbl (FDoubleProd *prod1, FDoubleProd *prod2);
103 FProduction *ProdLTEDbl (FDoubleProd *prod1, FDoubleProd *prod2);
104 FProduction *ProdGTDbl (FDoubleProd *prod1, FDoubleProd *prod2);
105 FProduction *ProdGTEDbl (FDoubleProd *prod1, FDoubleProd *prod2);
106 FProduction *ProdEqDbl (FDoubleProd *prod1, FDoubleProd *prod2);
107 FProduction *ProdNeqDbl (FDoubleProd *prod1, FDoubleProd *prod2);
108 FProduction *ProdXorDbl (FDoubleProd *prod1, FDoubleProd *prod2);
109 FProduction *ProdAndDbl (FDoubleProd *prod1, FDoubleProd *prod2);
110 FProduction *ProdOrDbl (FDoubleProd *prod1, FDoubleProd *prod2);
111 FProduction *ProdLAndDbl (FDoubleProd *prod1, FDoubleProd *prod2);
112 FProduction *ProdLOrDbl (FDoubleProd *prod1, FDoubleProd *prod2);
113 FProduction *ProdLTStr (FStringProd *prod1, FStringProd *prod2);
114 FProduction *ProdLTEStr (FStringProd *prod1, FStringProd *prod2);
115 FProduction *ProdGTStr (FStringProd *prod1, FStringProd *prod2);
116 FProduction *ProdGTEStr (FStringProd *prod1, FStringProd *prod2);
117 FProduction *ProdEqStr (FStringProd *prod1, FStringProd *prod2);
118 FProduction *ProdNeqStr (FStringProd *prod1, FStringProd *prod2);
119
120 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
121
122 // PUBLIC DATA DEFINITIONS -------------------------------------------------
123
124 // PRIVATE DATA DEFINITIONS ------------------------------------------------
125
126 static FProducer Producers[] =
127 {
128 { "+", ProdAddDbl, ProdAddStr },
129 { "-", ProdSubDbl, NULL },
130 { "*", ProdMulDbl, NULL },
131 { "/", ProdDivDbl, NULL },
132 { "%", ProdModDbl, NULL },
133 { "^", ProdPowDbl, NULL },
134 { "<", ProdLTDbl, ProdLTStr },
135 { "<=", ProdLTEDbl, ProdLTEStr },
136 { ">", ProdGTDbl, ProdGTStr },
137 { ">=", ProdGTEDbl, ProdGTEStr },
138 { "=", ProdEqDbl, ProdEqStr },
139 { "==", ProdEqDbl, ProdEqStr },
140 { "!=", ProdNeqDbl, ProdNeqStr },
141 { "<>", ProdNeqDbl, ProdNeqStr },
142 { "xor", ProdXorDbl, NULL },
143 { "&", ProdAndDbl, NULL },
144 { "|", ProdOrDbl, NULL },
145 { "&&", ProdLAndDbl, NULL },
146 { "||", ProdLOrDbl, NULL }
147 };
148
149 // CODE --------------------------------------------------------------------
150
151 //==========================================================================
152 //
153 // ParseExpression
154 //
155 // Builds a production from an expression. The supported syntax is LISP-like
156 // but without parentheses.
157 //
158 //==========================================================================
159
ParseExpression(FCommandLine & argv,int & parsept)160 static FProduction *ParseExpression (FCommandLine &argv, int &parsept)
161 {
162 if (parsept >= argv.argc())
163 return NULL;
164
165 const char *token = argv[parsept++];
166 FProduction *prod1 = NULL, *prod2 = NULL, *prod3 = NULL;
167
168 if (IsFloat (token))
169 {
170 return NewDoubleProd (atof(token));
171 }
172 else if (stricmp (token, "true") == 0)
173 {
174 return NewDoubleProd (1.0);
175 }
176 else if (stricmp (token, "false") == 0)
177 {
178 return NewDoubleProd (0.0);
179 }
180 else
181 {
182 for (size_t i = 0; i < countof(Producers); ++i)
183 {
184 if (strcmp (Producers[i].Token, token) == 0)
185 {
186 prod1 = ParseExpression (argv, parsept);
187 prod2 = ParseExpression (argv, parsept);
188 if (prod1 == NULL || prod2 == NULL)
189 {
190 goto missing;
191 }
192 if (Producers[i].StringProducer == NULL)
193 {
194 DoubleCoerce (prod1, prod2);
195 }
196 else if (Producers[i].DoubleProducer == NULL)
197 {
198 MustStringCoerce (prod1, prod2);
199 }
200 else
201 {
202 MaybeStringCoerce (prod1, prod2);
203 }
204 if (prod1->Type == PROD_String)
205 {
206 prod3 = Producers[i].StringProducer ((FStringProd *)prod1, (FStringProd *)prod2);
207 }
208 else
209 {
210 prod3 = Producers[i].DoubleProducer ((FDoubleProd *)prod1, (FDoubleProd *)prod2);
211 }
212 goto done;
213 }
214 }
215 if (strcmp ("!", token) == 0)
216 {
217 prod1 = ParseExpression (argv, parsept);
218 if (prod1 == NULL)
219 {
220 goto missing;
221 }
222 if (prod1->Type == PROD_String)
223 {
224 prod1 = StringToDouble (prod1);
225 }
226 prod3 = NewDoubleProd (!static_cast<FDoubleProd *>(prod1)->Value);
227 goto done;
228 }
229 return NewStringProd (token);
230 }
231
232 missing:
233 Printf ("Missing argument to %s\n", token);
234
235 done:
236 if (prod2 != NULL) M_Free (prod2);
237 if (prod1 != NULL) M_Free (prod1);
238 return prod3;
239 }
240
241 //==========================================================================
242 //
243 // IsFloat
244 //
245 //==========================================================================
246
IsFloat(const char * str)247 bool IsFloat (const char *str)
248 {
249 const char *pt;
250
251 if (*str == '+' || *str == '-')
252 str++;
253
254 if (*str == '.')
255 {
256 pt = str;
257 }
258 else
259 {
260 pt = IsNum (str);
261 if (pt == NULL)
262 return false;
263 }
264 if (*pt == '.')
265 {
266 pt = IsNum (pt+1);
267 if (pt == NULL)
268 return false;
269 }
270 if (*pt == 'e' || *pt == 'E')
271 {
272 pt++;
273 if (*pt == '+' || *pt == '-')
274 pt++;
275 pt = IsNum (pt);
276 }
277 return pt != NULL && *pt == 0;
278 }
279
280 //==========================================================================
281 //
282 // IsNum
283 //
284 //==========================================================================
285
IsNum(const char * str)286 static const char *IsNum (const char *str)
287 {
288 const char *start = str;
289
290 while (*str)
291 {
292 if (*str >= '0' && *str <= '9')
293 str++;
294 else
295 break;
296 }
297
298 return (str > start) ? str : NULL;
299 }
300
301 //==========================================================================
302 //
303 // NewStringProd (from a string)
304 //
305 //==========================================================================
306
NewStringProd(const char * str)307 static FStringProd *NewStringProd (const char *str)
308 {
309 FStringProd *prod = (FStringProd *)M_Malloc (sizeof(FStringProd)+strlen(str));
310 prod->Type = PROD_String;
311 strcpy (prod->Value, str);
312 return prod;
313 }
314
315 //==========================================================================
316 //
317 // NewStringProd (from a length)
318 //
319 //==========================================================================
320
NewStringProd(size_t len)321 static FStringProd *NewStringProd (size_t len)
322 {
323 FStringProd *prod = (FStringProd *)M_Malloc (sizeof(FStringProd)+len);
324 prod->Type = PROD_String;
325 prod->Value[0] = 0;
326 return prod;
327 }
328
329 //==========================================================================
330 //
331 // NewDoubleProd
332 //
333 //==========================================================================
334
NewDoubleProd(double val)335 static FDoubleProd *NewDoubleProd (double val)
336 {
337 FDoubleProd *prod = (FDoubleProd *)M_Malloc (sizeof(FDoubleProd));
338 prod->Type = PROD_Double;
339 prod->Value = val;
340 return prod;
341 }
342
343 //==========================================================================
344 //
345 // DoubleToString
346 //
347 //==========================================================================
348
DoubleToString(FProduction * prod)349 static FStringProd *DoubleToString (FProduction *prod)
350 {
351 char buf[128];
352 FStringProd *newprod;
353
354 mysnprintf (buf, countof(buf), "%g", static_cast<FDoubleProd *>(prod)->Value);
355 newprod = NewStringProd (buf);
356 M_Free (prod);
357 return newprod;
358 }
359
360 //==========================================================================
361 //
362 // StringToDouble
363 //
364 //==========================================================================
365
StringToDouble(FProduction * prod)366 static FDoubleProd *StringToDouble (FProduction *prod)
367 {
368 FDoubleProd *newprod;
369
370 newprod = NewDoubleProd (atof (static_cast<FStringProd *>(prod)->Value));
371 M_Free (prod);
372 return newprod;
373 }
374
375 //==========================================================================
376 //
377 // MaybeStringCoerce
378 //
379 // If one of the parameters is a string, convert the other to a string.
380 //
381 //==========================================================================
382
MaybeStringCoerce(FProduction * & prod1,FProduction * & prod2)383 void MaybeStringCoerce (FProduction *&prod1, FProduction *&prod2)
384 {
385 if (prod1->Type == PROD_String)
386 {
387 if (prod2->Type == PROD_Double)
388 {
389 prod2 = DoubleToString (prod2);
390 }
391 }
392 else if (prod2->Type == PROD_String)
393 {
394 prod1 = DoubleToString (prod1);
395 }
396 }
397
398 //==========================================================================
399 //
400 // MustStringCoerce
401 //
402 // Ensures that both parameters are strings
403 //
404 //==========================================================================
405
MustStringCoerce(FProduction * & prod1,FProduction * & prod2)406 void MustStringCoerce (FProduction *&prod1, FProduction *&prod2)
407 {
408 if (prod1->Type == PROD_Double)
409 {
410 prod1 = DoubleToString (prod1);
411 }
412 if (prod2->Type == PROD_Double)
413 {
414 prod2 = DoubleToString (prod2);
415 }
416 }
417
418 //==========================================================================
419 //
420 // DoubleCoerce
421 //
422 // Ensures that both parameters are doubles
423 //
424 //==========================================================================
425
DoubleCoerce(FProduction * & prod1,FProduction * & prod2)426 void DoubleCoerce (FProduction *&prod1, FProduction *&prod2)
427 {
428 if (prod1->Type == PROD_String)
429 {
430 prod1 = StringToDouble (prod1);
431 }
432 if (prod2->Type == PROD_String)
433 {
434 prod2 = StringToDouble (prod2);
435 }
436 }
437
438 //==========================================================================
439 //
440 // ProdAddDbl
441 //
442 //==========================================================================
443
ProdAddDbl(FDoubleProd * prod1,FDoubleProd * prod2)444 FProduction *ProdAddDbl (FDoubleProd *prod1, FDoubleProd *prod2)
445 {
446 return NewDoubleProd (prod1->Value + prod2->Value);
447 }
448
449 //==========================================================================
450 //
451 // ProdAddStr
452 //
453 //==========================================================================
454
ProdAddStr(FStringProd * prod1,FStringProd * prod2)455 FProduction *ProdAddStr (FStringProd *prod1, FStringProd *prod2)
456 {
457 size_t len = strlen (prod1->Value) + strlen (prod2->Value) + 1;
458 FStringProd *prod = NewStringProd (len);
459 strcpy (prod->Value, prod1->Value);
460 strcat (prod->Value, prod2->Value);
461 return prod;
462 }
463
464 //==========================================================================
465 //
466 // ProdSubDbl
467 //
468 //==========================================================================
469
ProdSubDbl(FDoubleProd * prod1,FDoubleProd * prod2)470 FProduction *ProdSubDbl (FDoubleProd *prod1, FDoubleProd *prod2)
471 {
472 return NewDoubleProd (prod1->Value - prod2->Value);
473 }
474
475 //==========================================================================
476 //
477 // ProdMulDbl
478 //
479 //==========================================================================
480
ProdMulDbl(FDoubleProd * prod1,FDoubleProd * prod2)481 FProduction *ProdMulDbl (FDoubleProd *prod1, FDoubleProd *prod2)
482 {
483 return NewDoubleProd (prod1->Value * prod2->Value);
484 }
485
486 //==========================================================================
487 //
488 // ProdDivDbl
489 //
490 //==========================================================================
491
ProdDivDbl(FDoubleProd * prod1,FDoubleProd * prod2)492 FProduction *ProdDivDbl (FDoubleProd *prod1, FDoubleProd *prod2)
493 {
494 return NewDoubleProd (prod1->Value / prod2->Value);
495 }
496
497 //==========================================================================
498 //
499 // ProdModDbl
500 //
501 //==========================================================================
502
ProdModDbl(FDoubleProd * prod1,FDoubleProd * prod2)503 FProduction *ProdModDbl (FDoubleProd *prod1, FDoubleProd *prod2)
504 {
505 return NewDoubleProd (fmod (prod1->Value, prod2->Value));
506 }
507
508 //==========================================================================
509 //
510 // ProdPowDbl
511 //
512 //==========================================================================
513
ProdPowDbl(FDoubleProd * prod1,FDoubleProd * prod2)514 FProduction *ProdPowDbl (FDoubleProd *prod1, FDoubleProd *prod2)
515 {
516 return NewDoubleProd (pow (prod1->Value, prod2->Value));
517 }
518
519 //==========================================================================
520 //
521 // ProdLTDbl
522 //
523 //==========================================================================
524
ProdLTDbl(FDoubleProd * prod1,FDoubleProd * prod2)525 FProduction *ProdLTDbl (FDoubleProd *prod1, FDoubleProd *prod2)
526 {
527 return NewDoubleProd (prod1->Value < prod2->Value);
528 }
529
530 //==========================================================================
531 //
532 // ProdLTEDbl
533 //
534 //==========================================================================
535
ProdLTEDbl(FDoubleProd * prod1,FDoubleProd * prod2)536 FProduction *ProdLTEDbl (FDoubleProd *prod1, FDoubleProd *prod2)
537 {
538 return NewDoubleProd (prod1->Value <= prod2->Value);
539 }
540
541 //==========================================================================
542 //
543 // ProdGTDbl
544 //
545 //==========================================================================
546
ProdGTDbl(FDoubleProd * prod1,FDoubleProd * prod2)547 FProduction *ProdGTDbl (FDoubleProd *prod1, FDoubleProd *prod2)
548 {
549 return NewDoubleProd (prod1->Value > prod2->Value);
550 }
551
552 //==========================================================================
553 //
554 // ProdGTEDbl
555 //
556 //==========================================================================
557
ProdGTEDbl(FDoubleProd * prod1,FDoubleProd * prod2)558 FProduction *ProdGTEDbl (FDoubleProd *prod1, FDoubleProd *prod2)
559 {
560 return NewDoubleProd (prod1->Value >= prod2->Value);
561 }
562
563 //==========================================================================
564 //
565 // ProdEqDbl
566 //
567 //==========================================================================
568
ProdEqDbl(FDoubleProd * prod1,FDoubleProd * prod2)569 FProduction *ProdEqDbl (FDoubleProd *prod1, FDoubleProd *prod2)
570 {
571 return NewDoubleProd (prod1->Value == prod2->Value);
572 }
573
574 //==========================================================================
575 //
576 // ProdNeqDbl
577 //
578 //==========================================================================
579
ProdNeqDbl(FDoubleProd * prod1,FDoubleProd * prod2)580 FProduction *ProdNeqDbl (FDoubleProd *prod1, FDoubleProd *prod2)
581 {
582 return NewDoubleProd (prod1->Value != prod2->Value);
583 }
584
585 //==========================================================================
586 //
587 // ProdLTStr
588 //
589 //==========================================================================
590
ProdLTStr(FStringProd * prod1,FStringProd * prod2)591 FProduction *ProdLTStr (FStringProd *prod1, FStringProd *prod2)
592 {
593 return NewDoubleProd (stricmp (prod1->Value, prod2->Value) < 0);
594 }
595
596 //==========================================================================
597 //
598 // ProdLTEStr
599 //
600 //==========================================================================
601
ProdLTEStr(FStringProd * prod1,FStringProd * prod2)602 FProduction *ProdLTEStr (FStringProd *prod1, FStringProd *prod2)
603 {
604 return NewDoubleProd (stricmp (prod1->Value, prod2->Value) <= 0);
605 }
606
607 //==========================================================================
608 //
609 // ProdGTStr
610 //
611 //==========================================================================
612
ProdGTStr(FStringProd * prod1,FStringProd * prod2)613 FProduction *ProdGTStr (FStringProd *prod1, FStringProd *prod2)
614 {
615 return NewDoubleProd (stricmp (prod1->Value, prod2->Value) > 0);
616 }
617
618 //==========================================================================
619 //
620 // ProdGTEStr
621 //
622 //==========================================================================
623
ProdGTEStr(FStringProd * prod1,FStringProd * prod2)624 FProduction *ProdGTEStr (FStringProd *prod1, FStringProd *prod2)
625 {
626 return NewDoubleProd (stricmp (prod1->Value, prod2->Value) >= 0);
627 }
628
629 //==========================================================================
630 //
631 // ProdEqStr
632 //
633 //==========================================================================
634
ProdEqStr(FStringProd * prod1,FStringProd * prod2)635 FProduction *ProdEqStr (FStringProd *prod1, FStringProd *prod2)
636 {
637 return NewDoubleProd (stricmp (prod1->Value, prod2->Value) == 0);
638 }
639
640 //==========================================================================
641 //
642 // ProdNeqStr
643 //
644 //==========================================================================
645
ProdNeqStr(FStringProd * prod1,FStringProd * prod2)646 FProduction *ProdNeqStr (FStringProd *prod1, FStringProd *prod2)
647 {
648 return NewDoubleProd (stricmp (prod1->Value, prod2->Value) != 0);
649 }
650
651 //==========================================================================
652 //
653 // ProdXorDbl
654 //
655 //==========================================================================
656
ProdXorDbl(FDoubleProd * prod1,FDoubleProd * prod2)657 FProduction *ProdXorDbl (FDoubleProd *prod1, FDoubleProd *prod2)
658 {
659 return NewDoubleProd ((double)((SQWORD)prod1->Value ^ (SQWORD)prod2->Value));
660 }
661
662 //==========================================================================
663 //
664 // ProdAndDbl
665 //
666 //==========================================================================
667
ProdAndDbl(FDoubleProd * prod1,FDoubleProd * prod2)668 FProduction *ProdAndDbl (FDoubleProd *prod1, FDoubleProd *prod2)
669 {
670 return NewDoubleProd ((double)((SQWORD)prod1->Value & (SQWORD)prod2->Value));
671 }
672
673 //==========================================================================
674 //
675 // ProdOrDbl
676 //
677 //==========================================================================
678
ProdOrDbl(FDoubleProd * prod1,FDoubleProd * prod2)679 FProduction *ProdOrDbl (FDoubleProd *prod1, FDoubleProd *prod2)
680 {
681 return NewDoubleProd ((double)((SQWORD)prod1->Value | (SQWORD)prod2->Value));
682 }
683
684 //==========================================================================
685 //
686 // ProdLAndDbl
687 //
688 //==========================================================================
689
ProdLAndDbl(FDoubleProd * prod1,FDoubleProd * prod2)690 FProduction *ProdLAndDbl (FDoubleProd *prod1, FDoubleProd *prod2)
691 {
692 return NewDoubleProd ((double)((SQWORD)prod1->Value && (SQWORD)prod2->Value));
693 }
694
695 //==========================================================================
696 //
697 // ProdLOrDbl
698 //
699 //==========================================================================
700
ProdLOrDbl(FDoubleProd * prod1,FDoubleProd * prod2)701 FProduction *ProdLOrDbl (FDoubleProd *prod1, FDoubleProd *prod2)
702 {
703 return NewDoubleProd ((double)((SQWORD)prod1->Value || (SQWORD)prod2->Value));
704 }
705
706
707 //==========================================================================
708 //
709 //
710 //
711 //==========================================================================
712
713 //==========================================================================
714 //
715 // CCMD test
716 //
717 // If <expr> is non-zero, execute <true cmd>.
718 // If <expr> is zero, execute [false cmd] if specified.
719 //
720 //==========================================================================
721
CCMD(test)722 CCMD (test)
723 {
724 int parsept = 1;
725 FProduction *prod = ParseExpression (argv, parsept);
726
727 if (prod == NULL || parsept >= argv.argc())
728 {
729 Printf ("Usage: test <expr> <true cmd> [false cmd]\n");
730 }
731 else
732 {
733 if (prod->Type == PROD_String)
734 {
735 prod = StringToDouble (prod);
736 }
737
738 if (static_cast<FDoubleProd *>(prod)->Value != 0.0)
739 {
740 AddCommandString (argv[parsept]);
741 }
742 else if (++parsept < argv.argc())
743 {
744 AddCommandString (argv[parsept]);
745 }
746 }
747 if (prod != NULL)
748 {
749 M_Free (prod);
750 }
751 }
752
753 //==========================================================================
754 //
755 // CCMD eval
756 //
757 // Evaluates an expression and either prints it to the console or stores
758 // it in an existing cvar.
759 //
760 //==========================================================================
761
CCMD(eval)762 CCMD (eval)
763 {
764 if (argv.argc() >= 2)
765 {
766 int parsept = 1;
767 FProduction *prod = ParseExpression (argv, parsept);
768
769 if (prod != NULL)
770 {
771 if (parsept < argv.argc())
772 {
773 FBaseCVar *var = FindCVar (argv[parsept], NULL);
774 if (var == NULL)
775 {
776 Printf ("Unknown variable %s\n", argv[parsept]);
777 }
778 else
779 {
780 UCVarValue val;
781
782 if (prod->Type == PROD_Double)
783 {
784 val.Float = (float)static_cast<FDoubleProd *>(prod)->Value;
785 var->SetGenericRep (val, CVAR_Float);
786 }
787 else
788 {
789 val.String = static_cast<FStringProd *>(prod)->Value;
790 var->SetGenericRep (val, CVAR_String);
791 }
792 }
793 }
794 else
795 {
796 if (prod->Type == PROD_Double)
797 {
798 Printf ("%g\n", static_cast<FDoubleProd *>(prod)->Value);
799 }
800 else
801 {
802 Printf ("%s\n", static_cast<FStringProd *>(prod)->Value);
803 }
804 }
805 M_Free (prod);
806 return;
807 }
808 }
809
810 Printf ("Usage: eval <expression> [variable]\n");
811 }
812