1 /***********************************************************************************************************************************
2 Variant Data Type
3 ***********************************************************************************************************************************/
4 #include "build.auto.h"
5 
6 #include <errno.h>
7 #include <inttypes.h>
8 #include <limits.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <strings.h>
13 
14 #include "common/debug.h"
15 #include "common/memContext.h"
16 #include "common/type/convert.h"
17 #include "common/type/variant.h"
18 
19 /***********************************************************************************************************************************
20 Constant variants that are generally useful
21 ***********************************************************************************************************************************/
22 // Used to declare Bool Variant constants that will be externed using VARIANT_DECLARE().  Must be used in a .c file.
23 #define VARIANT_BOOL_EXTERN(name, dataParam)                                                                                       \
24     const Variant *const name = ((const Variant *)&(const VariantBoolPub){.type = varTypeBool, .data = dataParam})
25 
26 VARIANT_BOOL_EXTERN(BOOL_FALSE_VAR,                                 false);
27 VARIANT_BOOL_EXTERN(BOOL_TRUE_VAR,                                  true);
28 
29 /***********************************************************************************************************************************
30 Information about the variant
31 ***********************************************************************************************************************************/
32 struct Variant
33 {
34     VariantPub pub;                                                 // Publicly accessible variables
35 };
36 
37 typedef struct VariantBool
38 {
39     VariantBoolPub pub;                                             // Publicly accessible variables
40     MemContext *memContext;
41 } VariantBool;
42 
43 typedef struct VariantInt
44 {
45     VariantIntPub pub;                                              // Publicly accessible variables
46     MemContext *memContext;
47 } VariantInt;
48 
49 typedef struct VariantInt64
50 {
51     VariantInt64Pub pub;                                            // Publicly accessible variables
52     MemContext *memContext;
53 } VariantInt64;
54 
55 typedef struct VariantKeyValue
56 {
57     VARIANT_COMMON
58     KeyValue *data;                                                 // KeyValue data
59     MemContext *memContext;
60 } VariantKeyValue;
61 
62 typedef struct VariantString
63 {
64     VariantStringPub pub;                                           // Publicly accessible variables
65     MemContext *memContext;
66 } VariantString;
67 
68 typedef struct VariantUInt
69 {
70     VariantUIntPub pub;                                             // Publicly accessible variables
71     MemContext *memContext;
72 } VariantUInt;
73 
74 typedef struct VariantUInt64
75 {
76     VariantUInt64Pub pub;                                           // Publicly accessible variables
77     MemContext *memContext;
78 } VariantUInt64;
79 
80 typedef struct VariantVariantList
81 {
82     VARIANT_COMMON
83     VariantList *data;                                              // VariantList data
84     MemContext *memContext;
85 } VariantVariantList;
86 
87 /***********************************************************************************************************************************
88 Variant type names
89 ***********************************************************************************************************************************/
90 static const char *const variantTypeName[] =
91 {
92     "bool",                                                         // varTypeBool
93     "int",                                                          // varTypeInt
94     "int64",                                                        // varTypeInt64
95     "KeyValue",                                                     // varTypeKeyValue
96     "String",                                                       // varTypeString
97     "unsigned int",                                                 // varTypeUInt
98     "uint64",                                                       // varTypeUInt64
99     "VariantList",                                                  // varTypeVariantList
100 };
101 
102 /**********************************************************************************************************************************/
103 Variant *
varDup(const Variant * this)104 varDup(const Variant *this)
105 {
106     FUNCTION_TEST_BEGIN();
107         FUNCTION_TEST_PARAM(VARIANT, this);
108     FUNCTION_TEST_END();
109 
110     Variant *result = NULL;
111 
112     if (this != NULL)
113     {
114         switch (varType(this))
115         {
116             case varTypeBool:
117                 result = varNewBool(varBool(this));
118                 break;
119 
120             case varTypeInt:
121                 result = varNewInt(varInt(this));
122                 break;
123 
124             case varTypeInt64:
125                 result = varNewInt64(varInt64(this));
126                 break;
127 
128             case varTypeKeyValue:
129             {
130                 VariantKeyValue *keyValue = memNew(sizeof(VariantKeyValue));
131 
132                 *keyValue = (VariantKeyValue)
133                 {
134                     .memContext = memContextCurrent(),
135                     .type = varTypeKeyValue,
136                     .data = kvDup(varKv(this)),
137                 };
138 
139                 result = (Variant *)keyValue;
140                 break;
141             }
142 
143             case varTypeString:
144                 result = varNewStr(varStr(this));
145                 break;
146 
147             case varTypeUInt:
148                 result = varNewUInt(varUInt(this));
149                 break;
150 
151             case varTypeUInt64:
152                 result = varNewUInt64(varUInt64(this));
153                 break;
154 
155             case varTypeVariantList:
156                 result = varNewVarLst(varVarLst(this));
157                 break;
158         }
159     }
160 
161     FUNCTION_TEST_RETURN(result);
162 }
163 
164 /**********************************************************************************************************************************/
165 bool
varEq(const Variant * this1,const Variant * this2)166 varEq(const Variant *this1, const Variant *this2)
167 {
168     FUNCTION_TEST_BEGIN();
169         FUNCTION_TEST_PARAM(VARIANT, this1);
170         FUNCTION_TEST_PARAM(VARIANT, this2);
171     FUNCTION_TEST_END();
172 
173     bool result = false;
174 
175     // Test if both variants are non-null
176     if (this1 != NULL && this2 != NULL)
177     {
178         // Test if both variants are of the same type
179         if (varType(this1) == varType(this2))
180         {
181             switch (varType(this1))
182             {
183                 case varTypeBool:
184                     result = varBool(this1) == varBool(this2);
185                     break;
186 
187                 case varTypeInt:
188                     result = varInt(this1) == varInt(this2);
189                     break;
190 
191                 case varTypeInt64:
192                     result = varInt64(this1) == varInt64(this2);
193                     break;
194 
195                 case varTypeString:
196                     result = strEq(varStr(this1), varStr(this2));
197                     break;
198 
199                 case varTypeUInt:
200                     result = varUInt(this1) == varUInt(this2);
201                     break;
202 
203                 case varTypeUInt64:
204                     result = varUInt64(this1) == varUInt64(this2);
205                     break;
206 
207                 default:
208                     THROW_FMT(AssertError, "unable to test equality for %s", variantTypeName[varType(this1)]);
209             }
210         }
211     }
212     // Else they are equal if they are both null
213     else
214         result = this1 == NULL && this2 == NULL;
215 
216     FUNCTION_TEST_RETURN(result);
217 }
218 
219 /**********************************************************************************************************************************/
220 Variant *
varNewBool(bool data)221 varNewBool(bool data)
222 {
223     FUNCTION_TEST_BEGIN();
224         FUNCTION_TEST_PARAM(BOOL, data);
225     FUNCTION_TEST_END();
226 
227     // Allocate memory for the variant and set the type and data
228     VariantBool *this = memNew(sizeof(VariantBool));
229 
230     *this = (VariantBool)
231     {
232         .pub =
233         {
234             .type = varTypeBool,
235             .data = data,
236         },
237         .memContext = memContextCurrent(),
238     };
239 
240     FUNCTION_TEST_RETURN((Variant *)this);
241 }
242 
243 /**********************************************************************************************************************************/
244 bool
varBool(const Variant * this)245 varBool(const Variant *this)
246 {
247     FUNCTION_TEST_BEGIN();
248         FUNCTION_TEST_PARAM(VARIANT, this);
249     FUNCTION_TEST_END();
250 
251     ASSERT(this != NULL);
252     ASSERT(varType(this) == varTypeBool);
253 
254     FUNCTION_TEST_RETURN(((VariantBool *)this)->pub.data);
255 }
256 
257 bool
varBoolForce(const Variant * this)258 varBoolForce(const Variant *this)
259 {
260     FUNCTION_TEST_BEGIN();
261         FUNCTION_TEST_PARAM(VARIANT, this);
262     FUNCTION_TEST_END();
263 
264     ASSERT(this != NULL);
265 
266     bool result = false;
267 
268     switch (varType(this))
269     {
270         case varTypeBool:
271             result = varBool(this);
272             break;
273 
274         case varTypeInt:
275             result = varInt(this) != 0;
276             break;
277 
278         case varTypeInt64:
279             result = varInt64(this) != 0;
280             break;
281 
282         case varTypeString:
283         {
284             // List of false/true boolean string values.  Note that false/true values must be equal.
285             static const char *const boolString[] =
286             {
287                 "n", "f", "0",  "no", FALSE_Z, "off",
288                 "y", "t", "1", "yes",  TRUE_Z,  "on",
289             };
290 
291             // Search for the string
292             const char *string = strZ(varStr(this));
293             unsigned int boolIdx;
294 
295             for (boolIdx = 0; boolIdx < sizeof(boolString) / sizeof(char *); boolIdx++)
296                 if (strcasecmp(string, boolString[boolIdx]) == 0)
297                     break;
298 
299             // If string was not found then not a boolean
300             if (boolIdx == sizeof(boolString) / sizeof(char *))
301                 THROW_FMT(FormatError, "unable to convert str '%s' to bool", string);
302 
303             // False if in first half of list, true if in second half
304             result = boolIdx / (sizeof(boolString) / sizeof(char *) / 2);
305 
306             break;
307         }
308 
309         case varTypeUInt:
310             result = varUInt(this) != 0;
311             break;
312 
313         case varTypeUInt64:
314             result = varUInt64(this) != 0;
315             break;
316 
317         default:
318             THROW_FMT(AssertError, "unable to force %s to %s", variantTypeName[varType(this)], variantTypeName[varTypeBool]);
319     }
320 
321     FUNCTION_TEST_RETURN(result);
322 }
323 
324 /**********************************************************************************************************************************/
325 Variant *
varNewInt(int data)326 varNewInt(int data)
327 {
328     FUNCTION_TEST_BEGIN();
329         FUNCTION_TEST_PARAM(INT, data);
330     FUNCTION_TEST_END();
331 
332     // Allocate memory for the variant and set the type and data
333     VariantInt *this = memNew(sizeof(VariantInt));
334 
335     *this = (VariantInt)
336     {
337         .pub =
338         {
339             .type = varTypeInt,
340             .data = data,
341         },
342         .memContext = memContextCurrent(),
343     };
344 
345     FUNCTION_TEST_RETURN((Variant *)this);
346 }
347 
348 /**********************************************************************************************************************************/
349 int
varInt(const Variant * this)350 varInt(const Variant *this)
351 {
352     FUNCTION_TEST_BEGIN();
353         FUNCTION_TEST_PARAM(VARIANT, this);
354     FUNCTION_TEST_END();
355 
356     ASSERT(this != NULL);
357     ASSERT(varType(this) == varTypeInt);
358 
359     FUNCTION_TEST_RETURN(((VariantInt *)this)->pub.data);
360 }
361 
362 int
varIntForce(const Variant * this)363 varIntForce(const Variant *this)
364 {
365     FUNCTION_TEST_BEGIN();
366         FUNCTION_TEST_PARAM(VARIANT, this);
367     FUNCTION_TEST_END();
368 
369     ASSERT(this != NULL);
370 
371     int result = 0;
372 
373     switch (varType(this))
374     {
375         case varTypeBool:
376             result = varBool(this);
377             break;
378 
379         case varTypeInt:
380             result = varInt(this);
381             break;
382 
383         case varTypeInt64:
384         {
385             int64_t resultTest = varInt64(this);
386 
387             // Make sure the value fits into a normal 32-bit int range since 32-bit platforms are supported
388             if (resultTest > INT32_MAX || resultTest < INT32_MIN)
389                 THROW_FMT(
390                     FormatError, "unable to convert %s %" PRId64 " to %s", variantTypeName[varType(this)], resultTest,
391                     variantTypeName[varTypeInt]);
392 
393             result = (int)resultTest;
394             break;
395         }
396 
397         case varTypeString:
398             result = cvtZToInt(strZ(varStr(this)));
399             break;
400 
401         case varTypeUInt:
402         {
403             unsigned int resultTest = varUInt(this);
404 
405             // Make sure the value fits into a normal 32-bit int range
406             if (resultTest > INT32_MAX)
407                 THROW_FMT(
408                     FormatError, "unable to convert %s %u to %s", variantTypeName[varType(this)], resultTest,
409                     variantTypeName[varTypeInt]);
410 
411             result = (int)resultTest;
412             break;
413         }
414 
415         case varTypeUInt64:
416         {
417             uint64_t resultTest = varUInt64(this);
418 
419             // Make sure the value fits into a normal 32-bit int range
420             if (resultTest > INT32_MAX)
421                 THROW_FMT(
422                     FormatError, "unable to convert %s %" PRIu64 " to %s", variantTypeName[varType(this)], resultTest,
423                     variantTypeName[varTypeInt]);
424 
425             result = (int)resultTest;
426             break;
427         }
428 
429         default:
430             THROW_FMT(AssertError, "unable to force %s to %s", variantTypeName[varType(this)], variantTypeName[varTypeInt]);
431     }
432 
433     FUNCTION_TEST_RETURN(result);
434 }
435 
436 /**********************************************************************************************************************************/
437 Variant *
varNewInt64(int64_t data)438 varNewInt64(int64_t data)
439 {
440     FUNCTION_TEST_BEGIN();
441         FUNCTION_TEST_PARAM(INT64, data);
442     FUNCTION_TEST_END();
443 
444     // Allocate memory for the variant and set the type and data
445     VariantInt64 *this = memNew(sizeof(VariantInt64));
446 
447     *this = (VariantInt64)
448     {
449         .pub =
450         {
451             .type = varTypeInt64,
452             .data = data,
453         },
454         .memContext = memContextCurrent(),
455     };
456 
457     FUNCTION_TEST_RETURN((Variant *)this);
458 }
459 
460 /**********************************************************************************************************************************/
461 int64_t
varInt64(const Variant * this)462 varInt64(const Variant *this)
463 {
464     FUNCTION_TEST_BEGIN();
465         FUNCTION_TEST_PARAM(VARIANT, this);
466     FUNCTION_TEST_END();
467 
468     ASSERT(this != NULL);
469     ASSERT(varType(this) == varTypeInt64);
470 
471     FUNCTION_TEST_RETURN(((VariantInt64 *)this)->pub.data);
472 }
473 
474 int64_t
varInt64Force(const Variant * this)475 varInt64Force(const Variant *this)
476 {
477     FUNCTION_TEST_BEGIN();
478         FUNCTION_TEST_PARAM(VARIANT, this);
479     FUNCTION_TEST_END();
480 
481     ASSERT(this != NULL);
482 
483     int64_t result = 0;
484 
485     switch (varType(this))
486     {
487         case varTypeBool:
488             result = varBool(this);
489             break;
490 
491         case varTypeInt:
492             result = (int64_t)varInt(this);
493             break;
494 
495         case varTypeInt64:
496             result = varInt64(this);
497             break;
498 
499         case varTypeString:
500             result = cvtZToInt64(strZ(varStr(this)));
501             break;
502 
503         case varTypeUInt:
504             result = varUInt(this);
505 
506             break;
507 
508         case varTypeUInt64:
509         {
510             uint64_t resultTest = varUInt64(this);
511 
512             // If max number of unsigned 64-bit integer is greater than max 64-bit signed integer can hold, then error
513             if (resultTest <= INT64_MAX)
514                 result = (int64_t)resultTest;
515             else
516             {
517                 THROW_FMT(
518                     FormatError, "unable to convert %s %" PRIu64 " to %s", variantTypeName[varType(this)], resultTest,
519                     variantTypeName[varTypeInt64]);
520             }
521 
522             break;
523         }
524 
525         default:
526             THROW_FMT(AssertError, "unable to force %s to %s", variantTypeName[varType(this)], variantTypeName[varTypeInt64]);
527     }
528 
529     FUNCTION_TEST_RETURN(result);
530 }
531 
532 /**********************************************************************************************************************************/
533 Variant *
varNewUInt(unsigned int data)534 varNewUInt(unsigned int data)
535 {
536     FUNCTION_TEST_BEGIN();
537         FUNCTION_TEST_PARAM(UINT, data);
538     FUNCTION_TEST_END();
539 
540     // Allocate memory for the variant and set the type and data
541     VariantUInt *this = memNew(sizeof(VariantUInt));
542 
543     *this = (VariantUInt)
544     {
545         .pub =
546         {
547             .type = varTypeUInt,
548             .data = data,
549         },
550         .memContext = memContextCurrent(),
551     };
552 
553     FUNCTION_TEST_RETURN((Variant *)this);
554 }
555 
556 /**********************************************************************************************************************************/
557 unsigned int
varUInt(const Variant * this)558 varUInt(const Variant *this)
559 {
560     FUNCTION_TEST_BEGIN();
561         FUNCTION_TEST_PARAM(VARIANT, this);
562     FUNCTION_TEST_END();
563 
564     ASSERT(this != NULL);
565     ASSERT(varType(this) == varTypeUInt);
566 
567     FUNCTION_TEST_RETURN(((VariantUInt *)this)->pub.data);
568 }
569 
570 unsigned int
varUIntForce(const Variant * this)571 varUIntForce(const Variant *this)
572 {
573     FUNCTION_TEST_BEGIN();
574         FUNCTION_TEST_PARAM(VARIANT, this);
575     FUNCTION_TEST_END();
576 
577     ASSERT(this != NULL);
578 
579     unsigned int result = 0;
580 
581     switch (varType(this))
582     {
583         case varTypeBool:
584             result = varBool(this);
585             break;
586 
587         case varTypeInt:
588         {
589             int resultTest = varInt(this);
590 
591             // If integer is a negative number, throw an error since the resulting conversion would be a different number
592             if (resultTest >= 0)
593                 result = (unsigned int)resultTest;
594             else
595             {
596                 THROW_FMT(
597                     FormatError, "unable to convert %s %d to %s", variantTypeName[varType(this)], resultTest,
598                     variantTypeName[varTypeUInt]);
599             }
600 
601             break;
602         }
603 
604         case varTypeInt64:
605         {
606             int64_t resultTest = varInt64(this);
607 
608             // If integer is a negative number or too large, throw an error since the resulting conversion would be out of bounds
609             if (resultTest >= 0 && resultTest <= UINT_MAX)
610                 result = (unsigned int)resultTest;
611             else
612             {
613                 THROW_FMT(
614                     FormatError, "unable to convert %s %" PRId64 " to %s", variantTypeName[varType(this)], resultTest,
615                     variantTypeName[varTypeUInt]);
616             }
617 
618             break;
619         }
620 
621         case varTypeUInt:
622             result = varUInt(this);
623             break;
624 
625         case varTypeUInt64:
626         {
627             uint64_t resultTest = varUInt64(this);
628 
629             // If integer is too large, throw an error since the resulting conversion would be out of bounds
630             if (resultTest <= UINT_MAX)
631                 result = (unsigned int)resultTest;
632             else
633             {
634                 THROW_FMT(
635                     FormatError, "unable to convert %s %" PRIu64 " to %s", variantTypeName[varType(this)], resultTest,
636                     variantTypeName[varTypeUInt]);
637             }
638 
639             break;
640         }
641 
642         case varTypeString:
643             result = cvtZToUInt(strZ(varStr(this)));
644             break;
645 
646         default:
647             THROW_FMT(AssertError, "unable to force %s to %s", variantTypeName[varType(this)], variantTypeName[varTypeUInt]);
648     }
649 
650     FUNCTION_TEST_RETURN(result);
651 }
652 
653 /**********************************************************************************************************************************/
654 Variant *
varNewUInt64(uint64_t data)655 varNewUInt64(uint64_t data)
656 {
657     FUNCTION_TEST_BEGIN();
658         FUNCTION_TEST_PARAM(UINT64, data);
659     FUNCTION_TEST_END();
660 
661     // Allocate memory for the variant and set the type and data
662     VariantUInt64 *this = memNew(sizeof(VariantUInt64));
663 
664     *this = (VariantUInt64)
665     {
666         .pub =
667         {
668             .type = varTypeUInt64,
669             .data = data,
670         },
671         .memContext = memContextCurrent(),
672     };
673 
674     FUNCTION_TEST_RETURN((Variant *)this);
675 }
676 
677 /**********************************************************************************************************************************/
678 uint64_t
varUInt64(const Variant * this)679 varUInt64(const Variant *this)
680 {
681     FUNCTION_TEST_BEGIN();
682         FUNCTION_TEST_PARAM(VARIANT, this);
683     FUNCTION_TEST_END();
684 
685     ASSERT(this != NULL);
686     ASSERT(varType(this) == varTypeUInt64);
687 
688     FUNCTION_TEST_RETURN(((VariantUInt64 *)this)->pub.data);
689 }
690 
691 uint64_t
varUInt64Force(const Variant * this)692 varUInt64Force(const Variant *this)
693 {
694     FUNCTION_TEST_BEGIN();
695         FUNCTION_TEST_PARAM(VARIANT, this);
696     FUNCTION_TEST_END();
697 
698     ASSERT(this != NULL);
699 
700     uint64_t result = 0;
701 
702     switch (varType(this))
703     {
704         case varTypeBool:
705             result = varBool(this);
706             break;
707 
708         case varTypeInt:
709         {
710             int resultTest = varInt(this);
711 
712             // If integer is a negative number, throw an error since the resulting conversion would be a different number
713             if (resultTest >= 0)
714                 result = (uint64_t)resultTest;
715             else
716             {
717                 THROW_FMT(
718                     FormatError, "unable to convert %s %d to %s", variantTypeName[varType(this)], resultTest,
719                     variantTypeName[varTypeUInt64]);
720             }
721 
722             break;
723         }
724 
725         case varTypeInt64:
726         {
727             int64_t resultTest = varInt64(this);
728 
729             // If integer is a negative number, throw an error since the resulting conversion would be out of bounds
730             if (resultTest >= 0)
731                 result = (uint64_t)resultTest;
732             else
733             {
734                 THROW_FMT(
735                     FormatError, "unable to convert %s %" PRId64 " to %s", variantTypeName[varType(this)], resultTest,
736                     variantTypeName[varTypeUInt64]);
737             }
738 
739             break;
740         }
741 
742         case varTypeString:
743             result = cvtZToUInt64(strZ(varStr(this)));
744             break;
745 
746         case varTypeUInt:
747             result = varUInt(this);
748             break;
749 
750         case varTypeUInt64:
751             result = varUInt64(this);
752             break;
753 
754         default:
755             THROW_FMT(AssertError, "unable to force %s to %s", variantTypeName[varType(this)], variantTypeName[varTypeUInt64]);
756     }
757 
758     FUNCTION_TEST_RETURN(result);
759 }
760 
761 /**********************************************************************************************************************************/
762 Variant *
varNewKv(KeyValue * data)763 varNewKv(KeyValue *data)
764 {
765     FUNCTION_TEST_BEGIN();
766         FUNCTION_TEST_PARAM(KEY_VALUE, data);
767     FUNCTION_TEST_END();
768 
769     // Allocate memory for the variant and set the type and data
770     VariantKeyValue *this = memNew(sizeof(VariantKeyValue));
771 
772     *this = (VariantKeyValue)
773     {
774         .memContext = memContextCurrent(),
775         .type = varTypeKeyValue,
776     };
777 
778     if (data != NULL)
779         this->data = kvMove(data, memContextCurrent());
780 
781     FUNCTION_TEST_RETURN((Variant *)this);
782 }
783 
784 /**********************************************************************************************************************************/
785 KeyValue *
varKv(const Variant * this)786 varKv(const Variant *this)
787 {
788     FUNCTION_TEST_BEGIN();
789         FUNCTION_TEST_PARAM(VARIANT, this);
790     FUNCTION_TEST_END();
791 
792     KeyValue *result = NULL;
793 
794     if (this != NULL)
795     {
796         ASSERT(varType(this) == varTypeKeyValue);
797         result = ((VariantKeyValue *)this)->data;
798     }
799 
800     FUNCTION_TEST_RETURN(result);
801 }
802 
803 /**********************************************************************************************************************************/
804 Variant *
varNewStr(const String * data)805 varNewStr(const String *data)
806 {
807     FUNCTION_TEST_BEGIN();
808         FUNCTION_TEST_PARAM(STRING, data);
809     FUNCTION_TEST_END();
810 
811     // Allocate memory for the variant and set the type and data
812     VariantString *this = memNew(sizeof(VariantString));
813 
814     *this = (VariantString)
815     {
816         .pub =
817         {
818             .type = varTypeString,
819             .data = strDup(data),
820         },
821         .memContext = memContextCurrent(),
822     };
823 
824     FUNCTION_TEST_RETURN((Variant *)this);
825 }
826 
827 Variant *
varNewStrZ(const char * data)828 varNewStrZ(const char *data)
829 {
830     FUNCTION_TEST_BEGIN();
831         FUNCTION_TEST_PARAM(STRINGZ, data);
832     FUNCTION_TEST_END();
833 
834     FUNCTION_TEST_RETURN(varNewStr(data == NULL ? NULL : strNewZ(data)));
835 }
836 
837 /**********************************************************************************************************************************/
838 const String *
varStr(const Variant * this)839 varStr(const Variant *this)
840 {
841     FUNCTION_TEST_BEGIN();
842         FUNCTION_TEST_PARAM(VARIANT, this);
843     FUNCTION_TEST_END();
844 
845     String *result = NULL;
846 
847     if (this != NULL)
848     {
849         ASSERT(varType(this) == varTypeString);
850         result = ((VariantString *)this)->pub.data;
851     }
852 
853     FUNCTION_TEST_RETURN(result);
854 }
855 
856 String *
varStrForce(const Variant * this)857 varStrForce(const Variant *this)
858 {
859     FUNCTION_TEST_BEGIN();
860         FUNCTION_TEST_PARAM(VARIANT, this);
861     FUNCTION_TEST_END();
862 
863     ASSERT(this != NULL);
864 
865     String *result = NULL;
866 
867     switch (varType(this))
868     {
869         case varTypeBool:
870             result = strNewZ(cvtBoolToConstZ(varBool(this)));
871             break;
872 
873         case varTypeInt:
874         {
875             char working[CVT_BASE10_BUFFER_SIZE];
876 
877             cvtIntToZ(varInt(this), working, sizeof(working));
878             result = strNewZ(working);
879             break;
880         }
881 
882         case varTypeInt64:
883         {
884             char working[CVT_BASE10_BUFFER_SIZE];
885 
886             cvtInt64ToZ(varInt64(this), working, sizeof(working));
887             result = strNewZ(working);
888             break;
889         }
890 
891         case varTypeString:
892             result = strDup(varStr(this));
893             break;
894 
895         case varTypeUInt:
896         {
897             char working[CVT_BASE10_BUFFER_SIZE];
898 
899             cvtUIntToZ(varUInt(this), working, sizeof(working));
900             result = strNewZ(working);
901             break;
902         }
903 
904         case varTypeUInt64:
905         {
906             char working[CVT_BASE10_BUFFER_SIZE];
907 
908             cvtUInt64ToZ(varUInt64(this), working, sizeof(working));
909             result = strNewZ(working);
910             break;
911         }
912 
913         default:
914             THROW_FMT(FormatError, "unable to force %s to %s", variantTypeName[varType(this)], variantTypeName[varTypeString]);
915     }
916 
917     FUNCTION_TEST_RETURN(result);
918 }
919 
920 /**********************************************************************************************************************************/
921 Variant *
varNewVarLst(const VariantList * data)922 varNewVarLst(const VariantList *data)
923 {
924     FUNCTION_TEST_BEGIN();
925         FUNCTION_TEST_PARAM(VARIANT_LIST, data);
926     FUNCTION_TEST_END();
927 
928     // Allocate memory for the variant and set the type and data
929     VariantVariantList *this = memNew(sizeof(VariantVariantList));
930 
931     *this = (VariantVariantList)
932     {
933         .memContext = memContextCurrent(),
934         .type = varTypeVariantList,
935     };
936 
937     if (data != NULL)
938         this->data = varLstDup(data);
939 
940     FUNCTION_TEST_RETURN((Variant *)this);
941 }
942 
943 /**********************************************************************************************************************************/
944 VariantList *
varVarLst(const Variant * this)945 varVarLst(const Variant *this)
946 {
947     FUNCTION_TEST_BEGIN();
948         FUNCTION_TEST_PARAM(VARIANT, this);
949     FUNCTION_TEST_END();
950 
951     VariantList *result = NULL;
952 
953     if (this != NULL)
954     {
955         ASSERT(varType(this) == varTypeVariantList);
956         result = ((VariantVariantList *)this)->data;
957     }
958 
959     FUNCTION_TEST_RETURN(result);
960 }
961 
962 /**********************************************************************************************************************************/
963 String *
varToLog(const Variant * this)964 varToLog(const Variant *this)
965 {
966     String *result = NULL;
967 
968     if (this == NULL)
969         result = strDup(NULL_STR);
970     else
971     {
972         switch (varType(this))
973         {
974             case varTypeString:
975                 result = strToLog(varStr(this));
976                 break;
977 
978             case varTypeKeyValue:
979                 result = strNewZ("{KeyValue}");
980                 break;
981 
982             case varTypeVariantList:
983                 result = strNewZ("{VariantList}");
984                 break;
985 
986             case varTypeBool:
987             case varTypeInt:
988             case varTypeInt64:
989             case varTypeUInt:
990             case varTypeUInt64:
991             {
992                 result = strNewFmt("{%s}", strZ(varStrForce(this)));
993                 break;
994             }
995         }
996     }
997 
998     return result;
999 }
1000 
1001 /**********************************************************************************************************************************/
1002 void
varFree(Variant * this)1003 varFree(Variant *this)
1004 {
1005     FUNCTION_TEST_BEGIN();
1006         FUNCTION_TEST_PARAM(VARIANT, this);
1007     FUNCTION_TEST_END();
1008 
1009     if (this != NULL)
1010     {
1011         MemContext *memContext = NULL;
1012 
1013         switch (varType(this))
1014         {
1015             case varTypeBool:
1016                 memContext = ((VariantBool *)this)->memContext;
1017                 break;
1018 
1019             case varTypeInt:
1020                 memContext = ((VariantInt *)this)->memContext;
1021                 break;
1022 
1023             case varTypeInt64:
1024                 memContext = ((VariantInt64 *)this)->memContext;
1025                 break;
1026 
1027             case varTypeKeyValue:
1028                 memContext = ((VariantKeyValue *)this)->memContext;
1029                 kvFree(((VariantKeyValue *)this)->data);
1030                 break;
1031 
1032             case varTypeString:
1033                 memContext = ((VariantString *)this)->memContext;
1034                 strFree(((VariantString *)this)->pub.data);
1035                 break;
1036 
1037             case varTypeUInt:
1038                 memContext = ((VariantUInt *)this)->memContext;
1039                 break;
1040 
1041             case varTypeUInt64:
1042                 memContext = ((VariantUInt64 *)this)->memContext;
1043                 break;
1044 
1045             case varTypeVariantList:
1046                 memContext = ((VariantVariantList *)this)->memContext;
1047                 varLstFree(((VariantVariantList *)this)->data);
1048                 break;
1049         }
1050 
1051         MEM_CONTEXT_BEGIN(memContext)
1052         {
1053             memFree(this);
1054         }
1055         MEM_CONTEXT_END();
1056     }
1057 
1058     FUNCTION_TEST_RETURN_VOID();
1059 }
1060