1 /***********************************************************************************************************************************
2 Command and Option Configuration
3 ***********************************************************************************************************************************/
4 #include "build.auto.h"
5 
6 #include <string.h>
7 
8 #include "common/debug.h"
9 #include "common/error.h"
10 #include "common/memContext.h"
11 #include "config/config.intern.h"
12 #include "config/parse.h"
13 
14 /***********************************************************************************************************************************
15 Data for the currently loaded configuration
16 ***********************************************************************************************************************************/
17 Config *configLocal = NULL;
18 
19 /**********************************************************************************************************************************/
20 void
cfgInit(Config * config)21 cfgInit(Config *config)
22 {
23     FUNCTION_TEST_BEGIN();
24         FUNCTION_TEST_PARAM_P(VOID, config);
25     FUNCTION_TEST_END();
26 
27     ASSERT(config != NULL);
28 
29     // Free the old context
30     if (configLocal != NULL)
31         memContextFree(configLocal->memContext);
32 
33     // Set config and move context to top so it persists for the life of the program
34     configLocal = config;
35     memContextMove(configLocal->memContext, memContextTop());
36 
37     FUNCTION_TEST_RETURN_VOID();
38 }
39 
40 /**********************************************************************************************************************************/
41 ConfigCommand
cfgCommand(void)42 cfgCommand(void)
43 {
44     FUNCTION_TEST_VOID();
45     FUNCTION_TEST_RETURN(configLocal == NULL ? cfgCmdNone : configLocal->command);
46 }
47 
48 ConfigCommandRole
cfgCommandRole(void)49 cfgCommandRole(void)
50 {
51     FUNCTION_TEST_VOID();
52     ASSERT(configLocal != NULL);
53     FUNCTION_TEST_RETURN(configLocal->commandRole);
54 }
55 
56 void
cfgCommandSet(ConfigCommand commandId,ConfigCommandRole commandRoleId)57 cfgCommandSet(ConfigCommand commandId, ConfigCommandRole commandRoleId)
58 {
59     FUNCTION_TEST_BEGIN();
60         FUNCTION_TEST_PARAM(ENUM, commandId);
61         FUNCTION_TEST_PARAM(ENUM, commandRoleId);
62     FUNCTION_TEST_END();
63 
64     ASSERT(configLocal != NULL);
65     ASSERT(commandId <= cfgCmdNone);
66 
67     configLocal->command = commandId;
68     configLocal->commandRole = commandRoleId;
69 
70     FUNCTION_TEST_RETURN_VOID();
71 }
72 
73 /**********************************************************************************************************************************/
74 bool
cfgCommandHelp(void)75 cfgCommandHelp(void)
76 {
77     FUNCTION_TEST_VOID();
78     ASSERT(configLocal != NULL);
79     FUNCTION_TEST_RETURN(configLocal->help);
80 }
81 
82 /**********************************************************************************************************************************/
83 VariantList *
cfgCommandJobRetry(void)84 cfgCommandJobRetry(void)
85 {
86     FUNCTION_TEST_VOID();
87 
88     ASSERT(configLocal != NULL);
89 
90     // Return NULL if no retries
91     unsigned int retryTotal = cfgOptionUInt(cfgOptJobRetry);
92 
93     if (retryTotal == 0)
94         FUNCTION_TEST_RETURN(NULL);
95 
96     // Build retry list
97     VariantList *result = varLstNew();
98 
99     for (unsigned int retryIdx = 0; retryIdx < cfgOptionUInt(cfgOptJobRetry); retryIdx++)
100         varLstAdd(result, varNewUInt64(retryIdx == 0 ? 0 : cfgOptionUInt64(cfgOptJobRetryInterval)));
101 
102     FUNCTION_TEST_RETURN(result);
103 }
104 
105 /**********************************************************************************************************************************/
106 const char *
cfgCommandName(void)107 cfgCommandName(void)
108 {
109     FUNCTION_TEST_VOID();
110 
111     ASSERT(configLocal != NULL);
112     ASSERT(configLocal->command < cfgCmdNone);
113 
114     FUNCTION_TEST_RETURN(cfgParseCommandName(configLocal->command));
115 }
116 
117 String *
cfgCommandRoleName(void)118 cfgCommandRoleName(void)
119 {
120     FUNCTION_TEST_VOID();
121 
122     FUNCTION_TEST_RETURN(cfgParseCommandRoleName(cfgCommand(), cfgCommandRole(), COLON_STR));
123 }
124 
125 /**********************************************************************************************************************************/
126 const StringList *
cfgCommandParam(void)127 cfgCommandParam(void)
128 {
129     FUNCTION_TEST_VOID();
130 
131     ASSERT(configLocal != NULL);
132 
133     if (configLocal->paramList == NULL)
134     {
135         MEM_CONTEXT_BEGIN(configLocal->memContext)
136         {
137             configLocal->paramList = strLstNew();
138         }
139         MEM_CONTEXT_END();
140     }
141 
142     FUNCTION_TEST_RETURN(configLocal->paramList);
143 }
144 
145 /**********************************************************************************************************************************/
146 const String *
cfgExe(void)147 cfgExe(void)
148 {
149     FUNCTION_TEST_VOID();
150     ASSERT(configLocal != NULL);
151     FUNCTION_TEST_RETURN(configLocal->exe);
152 }
153 
154 /**********************************************************************************************************************************/
155 bool
cfgLockRequired(void)156 cfgLockRequired(void)
157 {
158     FUNCTION_TEST_VOID();
159 
160     ASSERT(configLocal != NULL);
161     ASSERT(configLocal->command != cfgCmdNone);
162 
163     // Local roles never take a lock and the remote role has special logic for locking
164     FUNCTION_TEST_RETURN(
165         // If a lock is required for the command and the role is main
166         (configLocal->lockRequired && cfgCommandRole() == cfgCmdRoleMain) ||
167         // Or any command when the role is async
168         cfgCommandRole() == cfgCmdRoleAsync);
169 }
170 
171 /**********************************************************************************************************************************/
172 bool
cfgLockRemoteRequired(void)173 cfgLockRemoteRequired(void)
174 {
175     FUNCTION_TEST_VOID();
176 
177     ASSERT(configLocal != NULL);
178     ASSERT(configLocal->command != cfgCmdNone);
179 
180     FUNCTION_TEST_RETURN(configLocal->lockRemoteRequired);
181 }
182 
183 /**********************************************************************************************************************************/
184 LockType
cfgLockType(void)185 cfgLockType(void)
186 {
187     FUNCTION_TEST_VOID();
188 
189     ASSERT(configLocal != NULL);
190     ASSERT(configLocal->command != cfgCmdNone);
191 
192     FUNCTION_TEST_RETURN(configLocal->lockType);
193 }
194 
195 /**********************************************************************************************************************************/
196 bool
cfgLogFile(void)197 cfgLogFile(void)
198 {
199     FUNCTION_TEST_VOID();
200 
201     ASSERT(configLocal != NULL);
202     ASSERT(configLocal->command != cfgCmdNone);
203 
204     FUNCTION_TEST_RETURN(
205         // If the command always logs to a file
206         configLocal->logFile ||
207         // Or log-level-file was explicitly set as a param/env var
208         (cfgOptionValid(cfgOptLogLevelFile) && cfgOptionSource(cfgOptLogLevelFile) == cfgSourceParam) ||
209         // Or the role is async
210         cfgCommandRole() == cfgCmdRoleAsync);
211 }
212 
213 /**********************************************************************************************************************************/
214 LogLevel
cfgLogLevelDefault(void)215 cfgLogLevelDefault(void)
216 {
217     FUNCTION_TEST_VOID();
218 
219     ASSERT(configLocal != NULL);
220     ASSERT(configLocal->command != cfgCmdNone);
221 
222     FUNCTION_TEST_RETURN(configLocal->logLevelDefault);
223 }
224 
225 /**********************************************************************************************************************************/
226 bool
cfgOptionGroup(ConfigOption optionId)227 cfgOptionGroup(ConfigOption optionId)
228 {
229     FUNCTION_TEST_BEGIN();
230         FUNCTION_TEST_PARAM(ENUM, optionId);
231     FUNCTION_TEST_END();
232 
233     ASSERT(configLocal != NULL);
234     ASSERT(optionId < CFG_OPTION_TOTAL);
235 
236     FUNCTION_TEST_RETURN(configLocal->option[optionId].group);
237 }
238 
239 /**********************************************************************************************************************************/
240 unsigned int
cfgOptionGroupId(ConfigOption optionId)241 cfgOptionGroupId(ConfigOption optionId)
242 {
243     FUNCTION_TEST_BEGIN();
244         FUNCTION_TEST_PARAM(ENUM, optionId);
245     FUNCTION_TEST_END();
246 
247     ASSERT(configLocal != NULL);
248     ASSERT(optionId < CFG_OPTION_TOTAL);
249     ASSERT(configLocal->option[optionId].group);
250 
251     FUNCTION_TEST_RETURN(configLocal->option[optionId].groupId);
252 }
253 
254 /**********************************************************************************************************************************/
255 unsigned int
cfgOptionGroupIdxDefault(ConfigOptionGroup groupId)256 cfgOptionGroupIdxDefault(ConfigOptionGroup groupId)
257 {
258     FUNCTION_TEST_BEGIN();
259         FUNCTION_TEST_PARAM(ENUM, groupId);
260     FUNCTION_TEST_END();
261 
262     ASSERT(configLocal != NULL);
263     ASSERT(groupId < CFG_OPTION_GROUP_TOTAL);
264     ASSERT(configLocal->optionGroup[groupId].indexDefaultExists);
265 
266     FUNCTION_TEST_RETURN(configLocal->optionGroup[groupId].indexDefault);
267 }
268 
269 /**********************************************************************************************************************************/
270 unsigned int
cfgOptionGroupIdxToKey(ConfigOptionGroup groupId,unsigned int groupIdx)271 cfgOptionGroupIdxToKey(ConfigOptionGroup groupId, unsigned int groupIdx)
272 {
273     FUNCTION_TEST_BEGIN();
274         FUNCTION_TEST_PARAM(ENUM, groupId);
275         FUNCTION_TEST_PARAM(UINT, groupIdx);
276     FUNCTION_TEST_END();
277 
278     ASSERT(configLocal != NULL);
279     ASSERT(groupId < CFG_OPTION_GROUP_TOTAL);
280     ASSERT(groupIdx < configLocal->optionGroup[groupId].indexTotal);
281 
282     FUNCTION_TEST_RETURN(configLocal->optionGroup[groupId].indexMap[groupIdx] + 1);
283 }
284 
285 /**********************************************************************************************************************************/
286 unsigned int
cfgOptionKeyToIdx(ConfigOption optionId,unsigned int key)287 cfgOptionKeyToIdx(ConfigOption optionId, unsigned int key)
288 {
289     FUNCTION_TEST_BEGIN();
290         FUNCTION_TEST_PARAM(ENUM, optionId);
291         FUNCTION_TEST_PARAM(UINT, key);
292     FUNCTION_TEST_END();
293 
294     ASSERT(configLocal != NULL);
295     ASSERT(optionId < CFG_OPTION_TOTAL);
296 
297     unsigned int result = 0;
298 
299     // If then option is in a group then search for the key, else the index is 0
300     if (cfgOptionGroup(optionId))
301     {
302         unsigned int groupId = cfgOptionGroupId(optionId);
303 
304         // Seach the group for the key
305         for (; result < cfgOptionGroupIdxTotal(groupId); result++)
306         {
307             if (configLocal->optionGroup[groupId].indexMap[result] == key - 1)
308                 break;
309         }
310 
311         // Error when the key is not found
312         if (result == cfgOptionGroupIdxTotal(groupId))
313             THROW_FMT(AssertError, "key '%u' is not valid for '%s' option", key, configLocal->option[optionId].name);
314     }
315 
316     FUNCTION_TEST_RETURN(result);
317 }
318 
319 /**********************************************************************************************************************************/
320 unsigned int
cfgOptionGroupIdxTotal(ConfigOptionGroup groupId)321 cfgOptionGroupIdxTotal(ConfigOptionGroup groupId)
322 {
323     FUNCTION_TEST_BEGIN();
324         FUNCTION_TEST_PARAM(ENUM, groupId);
325     FUNCTION_TEST_END();
326 
327     ASSERT(configLocal != NULL);
328     ASSERT(groupId < CFG_OPTION_GROUP_TOTAL);
329 
330     FUNCTION_TEST_RETURN(configLocal->optionGroup[groupId].indexTotal);
331 }
332 
333 /**********************************************************************************************************************************/
334 bool
cfgOptionGroupValid(ConfigOptionGroup groupId)335 cfgOptionGroupValid(ConfigOptionGroup groupId)
336 {
337     FUNCTION_TEST_BEGIN();
338         FUNCTION_TEST_PARAM(ENUM, groupId);
339     FUNCTION_TEST_END();
340 
341     ASSERT(configLocal != NULL);
342     ASSERT(groupId < CFG_OPTION_GROUP_TOTAL);
343 
344     FUNCTION_TEST_RETURN(configLocal->optionGroup[groupId].valid);
345 }
346 
347 /**********************************************************************************************************************************/
348 unsigned int
cfgOptionIdxDefault(ConfigOption optionId)349 cfgOptionIdxDefault(ConfigOption optionId)
350 {
351     FUNCTION_TEST_BEGIN();
352         FUNCTION_TEST_PARAM(ENUM, optionId);
353     FUNCTION_TEST_END();
354 
355     ASSERT(configLocal != NULL);
356     ASSERT(optionId < CFG_OPTION_TOTAL);
357     ASSERT(
358         !configLocal->option[optionId].group || configLocal->optionGroup[configLocal->option[optionId].groupId].indexDefaultExists);
359 
360     FUNCTION_TEST_RETURN(
361         configLocal->option[optionId].group ? configLocal->optionGroup[configLocal->option[optionId].groupId].indexDefault : 0);
362 }
363 
364 /**********************************************************************************************************************************/
365 unsigned int
cfgOptionIdxTotal(ConfigOption optionId)366 cfgOptionIdxTotal(ConfigOption optionId)
367 {
368     FUNCTION_TEST_BEGIN();
369         FUNCTION_TEST_PARAM(ENUM, optionId);
370     FUNCTION_TEST_END();
371 
372     ASSERT(configLocal != NULL);
373     ASSERT(optionId < CFG_OPTION_TOTAL);
374 
375     FUNCTION_TEST_RETURN(
376         configLocal->option[optionId].group ? configLocal->optionGroup[configLocal->option[optionId].groupId].indexTotal : 1);
377 }
378 
379 /**********************************************************************************************************************************/
380 static Variant *
cfgOptionDefaultValue(ConfigOption optionId)381 cfgOptionDefaultValue(ConfigOption optionId)
382 {
383     FUNCTION_TEST_BEGIN();
384         FUNCTION_TEST_PARAM(ENUM, optionId);
385     FUNCTION_TEST_END();
386 
387     Variant *result;
388     Variant *defaultValue = varNewStrZ(cfgParseOptionDefault(cfgCommand(), optionId));
389 
390     switch (cfgParseOptionType(optionId))
391     {
392         case cfgOptTypeBoolean:
393             result = varNewBool(varBoolForce(defaultValue));
394             break;
395 
396         case cfgOptTypeInteger:
397         case cfgOptTypeSize:
398         case cfgOptTypeTime:
399             result = varNewInt64(varInt64Force(defaultValue));
400             break;
401 
402         case cfgOptTypePath:
403         case cfgOptTypeString:
404             result = varDup(defaultValue);
405             break;
406 
407         default:
408             THROW_FMT(AssertError, "default value not available for option type %u", cfgParseOptionType(optionId));
409     }
410 
411     FUNCTION_TEST_RETURN(result);
412 }
413 
414 const Variant *
cfgOptionDefault(ConfigOption optionId)415 cfgOptionDefault(ConfigOption optionId)
416 {
417     FUNCTION_TEST_BEGIN();
418         FUNCTION_TEST_PARAM(ENUM, optionId);
419     FUNCTION_TEST_END();
420 
421     ASSERT(configLocal != NULL);
422     ASSERT(optionId < CFG_OPTION_TOTAL);
423 
424     if (configLocal->option[optionId].defaultValue == NULL)
425     {
426         if (cfgParseOptionDefault(cfgCommand(), optionId) != NULL)
427         {
428             MEM_CONTEXT_BEGIN(configLocal->memContext)
429             {
430                 configLocal->option[optionId].defaultValue = cfgOptionDefaultValue(optionId);
431             }
432             MEM_CONTEXT_END();
433         }
434     }
435 
436     FUNCTION_TEST_RETURN(configLocal->option[optionId].defaultValue);
437 }
438 
439 void
cfgOptionDefaultSet(ConfigOption optionId,const Variant * defaultValue)440 cfgOptionDefaultSet(ConfigOption optionId, const Variant *defaultValue)
441 {
442     FUNCTION_TEST_BEGIN();
443         FUNCTION_TEST_PARAM(ENUM, optionId);
444         FUNCTION_TEST_PARAM(VARIANT, defaultValue);
445     FUNCTION_TEST_END();
446 
447     ASSERT(optionId < CFG_OPTION_TOTAL);
448     ASSERT(configLocal != NULL);
449     ASSERT(configLocal->option[optionId].valid);
450 
451     MEM_CONTEXT_BEGIN(configLocal->memContext)
452     {
453         // Set the default value
454         configLocal->option[optionId].defaultValue = varDup(defaultValue);
455 
456         // Copy the value to option indexes that are marked as default so the default can be retrieved quickly
457         for (unsigned int optionIdx = 0; optionIdx < cfgOptionIdxTotal(optionId); optionIdx++)
458         {
459             if (configLocal->option[optionId].index[optionIdx].source == cfgSourceDefault)
460             {
461                 configLocal->option[optionId].index[optionIdx].value = configLocal->option[optionId].defaultValue;
462                 configLocal->option[optionId].index[optionIdx].display = NULL;
463             }
464         }
465     }
466     MEM_CONTEXT_END();
467 
468     FUNCTION_TEST_RETURN_VOID();
469 }
470 
471 
472 /**********************************************************************************************************************************/
473 const String *
cfgOptionDisplayVar(const Variant * const value,const ConfigOptionType optionType)474 cfgOptionDisplayVar(const Variant *const value, const ConfigOptionType optionType)
475 {
476     FUNCTION_TEST_BEGIN();
477         FUNCTION_TEST_PARAM(VARIANT, value);
478         FUNCTION_TEST_PARAM(UINT, optionType);
479     FUNCTION_TEST_END();
480 
481     ASSERT(value != NULL);
482     ASSERT(optionType != cfgOptTypeHash && optionType != cfgOptTypeList);
483 
484     if (varType(value) == varTypeString)
485     {
486         FUNCTION_TEST_RETURN(varStr(value));
487     }
488     else if (optionType == cfgOptTypeBoolean)
489     {
490         FUNCTION_TEST_RETURN(varBool(value) ? TRUE_STR : FALSE_STR);
491     }
492     else if (optionType == cfgOptTypeTime)
493     {
494         FUNCTION_TEST_RETURN(strNewDbl((double)varInt64(value) / MSEC_PER_SEC));
495     }
496 
497     FUNCTION_TEST_RETURN(varStrForce(value));
498 }
499 
500 const String *
cfgOptionIdxDisplay(const ConfigOption optionId,const unsigned int optionIdx)501 cfgOptionIdxDisplay(const ConfigOption optionId, const unsigned int optionIdx)
502 {
503     FUNCTION_TEST_BEGIN();
504         FUNCTION_TEST_PARAM(ENUM, optionId);
505         FUNCTION_TEST_PARAM(UINT, optionIdx);
506     FUNCTION_TEST_END();
507 
508     ASSERT(optionId < CFG_OPTION_TOTAL);
509     ASSERT(configLocal != NULL);
510     ASSERT(
511         (!configLocal->option[optionId].group && optionIdx == 0) ||
512         (configLocal->option[optionId].group && optionIdx <
513             configLocal->optionGroup[configLocal->option[optionId].groupId].indexTotal));
514 
515     // Check that the option is valid for the current command
516     if (!cfgOptionValid(optionId))
517         THROW_FMT(AssertError, "option '%s' is not valid for the current command", cfgOptionIdxName(optionId, optionIdx));
518 
519     // If there is already a display value set then return that
520     ConfigOptionValue *const option = &configLocal->option[optionId].index[optionIdx];
521 
522     if (option->display != NULL)
523         FUNCTION_TEST_RETURN(option->display);
524 
525     // Generate the display value based on the type
526     MEM_CONTEXT_BEGIN(configLocal->memContext)
527     {
528         option->display = cfgOptionDisplayVar(option->value, cfgParseOptionType(optionId));
529     }
530     MEM_CONTEXT_END();
531 
532 
533     FUNCTION_TEST_RETURN(option->display);
534 }
535 
536 const String *
cfgOptionDisplay(const ConfigOption optionId)537 cfgOptionDisplay(const ConfigOption optionId)
538 {
539     FUNCTION_TEST_BEGIN();
540         FUNCTION_TEST_PARAM(ENUM, optionId);
541     FUNCTION_TEST_END();
542 
543     FUNCTION_TEST_RETURN(cfgOptionIdxDisplay(optionId, cfgOptionIdxDefault(optionId)));
544 }
545 
546 /**********************************************************************************************************************************/
547 String *
cfgOptionHostPort(ConfigOption optionId,unsigned int * port)548 cfgOptionHostPort(ConfigOption optionId, unsigned int *port)
549 {
550     FUNCTION_TEST_BEGIN();
551         FUNCTION_TEST_PARAM(ENUM, optionId);
552         FUNCTION_TEST_PARAM_P(UINT, port);
553     FUNCTION_TEST_END();
554 
555     FUNCTION_TEST_RETURN(cfgOptionIdxHostPort(optionId, cfgOptionIdxDefault(optionId), port));
556 }
557 
558 String *
cfgOptionIdxHostPort(ConfigOption optionId,unsigned int optionIdx,unsigned int * port)559 cfgOptionIdxHostPort(ConfigOption optionId, unsigned int optionIdx, unsigned int *port)
560 {
561     FUNCTION_TEST_BEGIN();
562         FUNCTION_TEST_PARAM(ENUM, optionId);
563         FUNCTION_TEST_PARAM(UINT, optionIdx);
564         FUNCTION_TEST_PARAM_P(UINT, port);
565     FUNCTION_TEST_END();
566 
567     ASSERT(optionId < CFG_OPTION_TOTAL);
568     ASSERT(configLocal != NULL);
569     ASSERT(
570         (!configLocal->option[optionId].group && optionIdx == 0) ||
571         (configLocal->option[optionId].group && optionIdx <
572             configLocal->optionGroup[configLocal->option[optionId].groupId].indexTotal));
573     ASSERT(port != NULL);
574 
575     String *result = NULL;
576 
577     // Proceed if option is valid and has a value
578     if (cfgOptionIdxTest(optionId, optionIdx))
579     {
580         MEM_CONTEXT_TEMP_BEGIN()
581         {
582             const String *host = cfgOptionIdxStr(optionId, optionIdx);
583 
584             // If the host contains a colon then it has a port appended
585             if (strChr(host, ':') != -1)
586             {
587                 const StringList *hostPart = strLstNewSplitZ(host, ":");
588 
589                 // More than one colon is invalid
590                 if (strLstSize(hostPart) > 2)
591                 {
592                     THROW_FMT(
593                         OptionInvalidError,
594                         "'%s' is not valid for option '%s'"
595                             "\nHINT: is more than one port specified?",
596                         strZ(host), cfgOptionIdxName(optionId, optionIdx));
597                 }
598 
599                 // Set the host
600                 MEM_CONTEXT_PRIOR_BEGIN()
601                 {
602                     result = strDup(strLstGet(hostPart, 0));
603                 }
604                 MEM_CONTEXT_PRIOR_END();
605 
606                 // Set the port and error if it is not a positive integer
607                 TRY_BEGIN()
608                 {
609                     *port = cvtZToUInt(strZ(strLstGet(hostPart, 1)));
610                 }
611                 CATCH(FormatError)
612                 {
613                     THROW_FMT(
614                         OptionInvalidError,
615                         "'%s' is not valid for option '%s'"
616                             "\nHINT: port is not a positive integer.",
617                         strZ(host), cfgOptionIdxName(optionId, optionIdx));
618                 }
619                 TRY_END();
620             }
621             // Else there is no port and just copy the host
622             else
623             {
624                 MEM_CONTEXT_PRIOR_BEGIN()
625                 {
626                     result = strDup(host);
627                 }
628                 MEM_CONTEXT_PRIOR_END();
629             }
630         }
631         MEM_CONTEXT_TEMP_END();
632     }
633 
634     FUNCTION_TEST_RETURN(result);
635 }
636 
637 /***********************************************************************************************************************************
638 Get option name by id
639 ***********************************************************************************************************************************/
640 const char *
cfgOptionName(ConfigOption optionId)641 cfgOptionName(ConfigOption optionId)
642 {
643     FUNCTION_TEST_BEGIN();
644         FUNCTION_TEST_PARAM(ENUM, optionId);
645     FUNCTION_TEST_END();
646 
647     ASSERT(optionId < CFG_OPTION_TOTAL);
648 
649     FUNCTION_TEST_RETURN(cfgOptionIdxName(optionId, cfgOptionIdxDefault(optionId)));
650 }
651 
652 const char *
cfgOptionIdxName(ConfigOption optionId,unsigned int optionIdx)653 cfgOptionIdxName(ConfigOption optionId, unsigned int optionIdx)
654 {
655     FUNCTION_TEST_BEGIN();
656         FUNCTION_TEST_PARAM(ENUM, optionId);
657         FUNCTION_TEST_PARAM(UINT, optionIdx);
658     FUNCTION_TEST_END();
659 
660     ASSERT(optionId < CFG_OPTION_TOTAL);
661     ASSERT(configLocal != NULL);
662     ASSERT(
663         (!configLocal->option[optionId].group && optionIdx == 0) ||
664         (configLocal->option[optionId].group && optionIdx <
665             configLocal->optionGroup[configLocal->option[optionId].groupId].indexTotal));
666 
667     if (configLocal->option[optionId].group)
668     {
669         // This is somewhat less than ideal since memory is being allocated with each call, rather than caching prior results. In
670         // practice the number of allocations should be quite small so we'll ignore this for now.
671         String *name = strNewFmt(
672             "%s%u%s", configLocal->optionGroup[configLocal->option[optionId].groupId].name,
673             configLocal->optionGroup[configLocal->option[optionId].groupId].indexMap[optionIdx] + 1,
674             configLocal->option[optionId].name + strlen(configLocal->optionGroup[configLocal->option[optionId].groupId].name));
675 
676         FUNCTION_TEST_RETURN(strZ(name));
677     }
678 
679     FUNCTION_TEST_RETURN(configLocal->option[optionId].name);
680 }
681 
682 /**********************************************************************************************************************************/
683 bool
cfgOptionNegate(ConfigOption optionId)684 cfgOptionNegate(ConfigOption optionId)
685 {
686     FUNCTION_TEST_BEGIN();
687         FUNCTION_TEST_PARAM(ENUM, optionId);
688     FUNCTION_TEST_END();
689 
690     FUNCTION_TEST_RETURN(cfgOptionIdxNegate(optionId, cfgOptionIdxDefault(optionId)));
691 }
692 
693 bool
cfgOptionIdxNegate(ConfigOption optionId,unsigned int optionIdx)694 cfgOptionIdxNegate(ConfigOption optionId, unsigned int optionIdx)
695 {
696     FUNCTION_TEST_BEGIN();
697         FUNCTION_TEST_PARAM(ENUM, optionId);
698         FUNCTION_TEST_PARAM(UINT, optionIdx);
699     FUNCTION_TEST_END();
700 
701     ASSERT(optionId < CFG_OPTION_TOTAL);
702     ASSERT(configLocal != NULL);
703     ASSERT(
704         (!configLocal->option[optionId].group && optionIdx == 0) ||
705         (configLocal->option[optionId].group && optionIdx <
706             configLocal->optionGroup[configLocal->option[optionId].groupId].indexTotal));
707 
708     FUNCTION_TEST_RETURN(configLocal->option[optionId].index[optionIdx].negate);
709 }
710 
711 /**********************************************************************************************************************************/
712 bool
cfgOptionReset(ConfigOption optionId)713 cfgOptionReset(ConfigOption optionId)
714 {
715     FUNCTION_TEST_BEGIN();
716         FUNCTION_TEST_PARAM(ENUM, optionId);
717     FUNCTION_TEST_END();
718 
719     FUNCTION_TEST_RETURN(cfgOptionIdxReset(optionId, cfgOptionIdxDefault(optionId)));
720 }
721 
722 bool
cfgOptionIdxReset(ConfigOption optionId,unsigned int optionIdx)723 cfgOptionIdxReset(ConfigOption optionId, unsigned int optionIdx)
724 {
725     FUNCTION_TEST_BEGIN();
726         FUNCTION_TEST_PARAM(ENUM, optionId);
727         FUNCTION_TEST_PARAM(UINT, optionIdx);
728     FUNCTION_TEST_END();
729 
730     ASSERT(optionId < CFG_OPTION_TOTAL);
731     ASSERT(configLocal != NULL);
732     ASSERT(
733         (!configLocal->option[optionId].group && optionIdx == 0) ||
734         (configLocal->option[optionId].group && optionIdx <
735             configLocal->optionGroup[configLocal->option[optionId].groupId].indexTotal));
736 
737     FUNCTION_TEST_RETURN(configLocal->option[optionId].index[optionIdx].reset);
738 }
739 
740 /**********************************************************************************************************************************/
741 // Helper to enforce contraints when getting options
742 static const Variant *
cfgOptionIdxInternal(ConfigOption optionId,unsigned int optionIdx,VariantType typeRequested,bool nullAllowed)743 cfgOptionIdxInternal(ConfigOption optionId, unsigned int optionIdx, VariantType typeRequested, bool nullAllowed)
744 {
745     FUNCTION_TEST_BEGIN();
746         FUNCTION_TEST_PARAM(ENUM, optionId);
747         FUNCTION_TEST_PARAM(UINT, optionIdx);
748         FUNCTION_TEST_PARAM(ENUM, typeRequested);
749         FUNCTION_TEST_PARAM(BOOL, nullAllowed);
750     FUNCTION_TEST_END();
751 
752     ASSERT(optionId < CFG_OPTION_TOTAL);
753     ASSERT(configLocal != NULL);
754     ASSERT(
755         (!configLocal->option[optionId].group && optionIdx == 0) ||
756         (configLocal->option[optionId].group && optionIdx <
757             configLocal->optionGroup[configLocal->option[optionId].groupId].indexTotal));
758 
759     // Check that the option is valid for the current command
760     if (!cfgOptionValid(optionId))
761         THROW_FMT(AssertError, "option '%s' is not valid for the current command", cfgOptionIdxName(optionId, optionIdx));
762 
763     // If the option is not NULL then check it is the requested type
764     const Variant *result = configLocal->option[optionId].index[optionIdx].value;
765 
766     if (result != NULL)
767     {
768         if (varType(result) != typeRequested)
769         {
770             THROW_FMT(
771                 AssertError, "option '%s' is type %u but %u was requested", cfgOptionIdxName(optionId, optionIdx), varType(result),
772                 typeRequested);
773         }
774     }
775     // Else check the option is allowed to be NULL
776     else if (!nullAllowed)
777         THROW_FMT(AssertError, "option '%s' is null but non-null was requested", cfgOptionIdxName(optionId, optionIdx));
778 
779     FUNCTION_TEST_RETURN(result);
780 }
781 
782 const Variant *
cfgOption(ConfigOption optionId)783 cfgOption(ConfigOption optionId)
784 {
785     FUNCTION_TEST_BEGIN();
786         FUNCTION_TEST_PARAM(ENUM, optionId);
787     FUNCTION_TEST_END();
788 
789     FUNCTION_TEST_RETURN(cfgOptionIdx(optionId, cfgOptionIdxDefault(optionId)));
790 }
791 
792 const Variant *
cfgOptionIdx(ConfigOption optionId,unsigned int optionIdx)793 cfgOptionIdx(ConfigOption optionId, unsigned int optionIdx)
794 {
795     FUNCTION_TEST_BEGIN();
796         FUNCTION_TEST_PARAM(ENUM, optionId);
797         FUNCTION_TEST_PARAM(UINT, optionIdx);
798     FUNCTION_TEST_END();
799 
800     ASSERT(configLocal != NULL);
801     ASSERT(
802         (!configLocal->option[optionId].group && optionIdx == 0) ||
803         (configLocal->option[optionId].group && optionIdx <
804             configLocal->optionGroup[configLocal->option[optionId].groupId].indexTotal));
805 
806     FUNCTION_TEST_RETURN(configLocal->option[optionId].index[optionIdx].value);
807 }
808 
809 bool
cfgOptionBool(ConfigOption optionId)810 cfgOptionBool(ConfigOption optionId)
811 {
812     FUNCTION_LOG_BEGIN(logLevelTrace);
813         FUNCTION_LOG_PARAM(ENUM, optionId);
814     FUNCTION_LOG_END();
815 
816     FUNCTION_LOG_RETURN(BOOL, varBool(cfgOptionIdxInternal(optionId, cfgOptionIdxDefault(optionId), varTypeBool, false)));
817 }
818 
819 bool
cfgOptionIdxBool(ConfigOption optionId,unsigned int optionIdx)820 cfgOptionIdxBool(ConfigOption optionId, unsigned int optionIdx)
821 {
822     FUNCTION_LOG_BEGIN(logLevelTrace);
823         FUNCTION_LOG_PARAM(ENUM, optionId);
824         FUNCTION_LOG_PARAM(UINT, optionIdx);
825     FUNCTION_LOG_END();
826 
827     FUNCTION_LOG_RETURN(BOOL, varBool(cfgOptionIdxInternal(optionId, optionIdx, varTypeBool, false)));
828 }
829 
830 int
cfgOptionInt(ConfigOption optionId)831 cfgOptionInt(ConfigOption optionId)
832 {
833     FUNCTION_LOG_BEGIN(logLevelTrace);
834         FUNCTION_LOG_PARAM(ENUM, optionId);
835     FUNCTION_LOG_END();
836 
837     FUNCTION_LOG_RETURN(INT, varIntForce(cfgOptionIdxInternal(optionId, cfgOptionIdxDefault(optionId), varTypeInt64, false)));
838 }
839 
840 int
cfgOptionIdxInt(ConfigOption optionId,unsigned int optionIdx)841 cfgOptionIdxInt(ConfigOption optionId, unsigned int optionIdx)
842 {
843     FUNCTION_LOG_BEGIN(logLevelTrace);
844         FUNCTION_LOG_PARAM(ENUM, optionId);
845         FUNCTION_LOG_PARAM(UINT, optionIdx);
846     FUNCTION_LOG_END();
847 
848     FUNCTION_LOG_RETURN(INT, varIntForce(cfgOptionIdxInternal(optionId, optionIdx, varTypeInt64, false)));
849 }
850 
851 int64_t
cfgOptionInt64(ConfigOption optionId)852 cfgOptionInt64(ConfigOption optionId)
853 {
854     FUNCTION_LOG_BEGIN(logLevelTrace);
855         FUNCTION_LOG_PARAM(ENUM, optionId);
856     FUNCTION_LOG_END();
857 
858     FUNCTION_LOG_RETURN(INT64, varInt64(cfgOptionIdxInternal(optionId, cfgOptionIdxDefault(optionId), varTypeInt64, false)));
859 }
860 
861 int64_t
cfgOptionIdxInt64(ConfigOption optionId,unsigned int optionIdx)862 cfgOptionIdxInt64(ConfigOption optionId, unsigned int optionIdx)
863 {
864     FUNCTION_LOG_BEGIN(logLevelTrace);
865         FUNCTION_LOG_PARAM(ENUM, optionId);
866         FUNCTION_LOG_PARAM(UINT, optionIdx);
867     FUNCTION_LOG_END();
868 
869     FUNCTION_LOG_RETURN(INT64, varInt64(cfgOptionIdxInternal(optionId, optionIdx, varTypeInt64, false)));
870 }
871 
872 unsigned int
cfgOptionUInt(ConfigOption optionId)873 cfgOptionUInt(ConfigOption optionId)
874 {
875     FUNCTION_LOG_BEGIN(logLevelTrace);
876         FUNCTION_LOG_PARAM(ENUM, optionId);
877     FUNCTION_LOG_END();
878 
879     FUNCTION_LOG_RETURN(UINT, varUIntForce(cfgOptionIdxInternal(optionId, cfgOptionIdxDefault(optionId), varTypeInt64, false)));
880 }
881 
882 unsigned int
cfgOptionIdxUInt(ConfigOption optionId,unsigned int optionIdx)883 cfgOptionIdxUInt(ConfigOption optionId, unsigned int optionIdx)
884 {
885     FUNCTION_LOG_BEGIN(logLevelTrace);
886         FUNCTION_LOG_PARAM(ENUM, optionId);
887         FUNCTION_LOG_PARAM(UINT, optionIdx);
888     FUNCTION_LOG_END();
889 
890     FUNCTION_LOG_RETURN(UINT, varUIntForce(cfgOptionIdxInternal(optionId, optionIdx, varTypeInt64, false)));
891 }
892 
893 uint64_t
cfgOptionUInt64(ConfigOption optionId)894 cfgOptionUInt64(ConfigOption optionId)
895 {
896     FUNCTION_LOG_BEGIN(logLevelTrace);
897         FUNCTION_LOG_PARAM(ENUM, optionId);
898     FUNCTION_LOG_END();
899 
900     FUNCTION_LOG_RETURN(UINT64, varUInt64Force(cfgOptionIdxInternal(optionId, cfgOptionIdxDefault(optionId), varTypeInt64, false)));
901 }
902 
903 uint64_t
cfgOptionIdxUInt64(ConfigOption optionId,unsigned int optionIdx)904 cfgOptionIdxUInt64(ConfigOption optionId, unsigned int optionIdx)
905 {
906     FUNCTION_LOG_BEGIN(logLevelTrace);
907         FUNCTION_LOG_PARAM(ENUM, optionId);
908         FUNCTION_LOG_PARAM(UINT, optionIdx);
909     FUNCTION_LOG_END();
910 
911     FUNCTION_LOG_RETURN(UINT64, varUInt64Force(cfgOptionIdxInternal(optionId, optionIdx, varTypeInt64, false)));
912 }
913 
914 const KeyValue *
cfgOptionKv(ConfigOption optionId)915 cfgOptionKv(ConfigOption optionId)
916 {
917     FUNCTION_LOG_BEGIN(logLevelTrace);
918         FUNCTION_LOG_PARAM(ENUM, optionId);
919     FUNCTION_LOG_END();
920 
921     FUNCTION_LOG_RETURN(KEY_VALUE, varKv(cfgOptionIdxInternal(optionId, cfgOptionIdxDefault(optionId), varTypeKeyValue, false)));
922 }
923 
924 const KeyValue *
cfgOptionIdxKv(ConfigOption optionId,unsigned int optionIdx)925 cfgOptionIdxKv(ConfigOption optionId, unsigned int optionIdx)
926 {
927     FUNCTION_LOG_BEGIN(logLevelTrace);
928         FUNCTION_LOG_PARAM(ENUM, optionId);
929         FUNCTION_LOG_PARAM(UINT, optionIdx);
930     FUNCTION_LOG_END();
931 
932     FUNCTION_LOG_RETURN(KEY_VALUE, varKv(cfgOptionIdxInternal(optionId, optionIdx, varTypeKeyValue, false)));
933 }
934 
935 const VariantList *
cfgOptionLst(ConfigOption optionId)936 cfgOptionLst(ConfigOption optionId)
937 {
938     FUNCTION_LOG_BEGIN(logLevelTrace);
939         FUNCTION_LOG_PARAM(ENUM, optionId);
940     FUNCTION_LOG_END();
941 
942     FUNCTION_LOG_RETURN_CONST(VARIANT_LIST, cfgOptionIdxLst(optionId, cfgOptionIdxDefault(optionId)));
943 }
944 
945 const VariantList *
cfgOptionIdxLst(ConfigOption optionId,unsigned int optionIdx)946 cfgOptionIdxLst(ConfigOption optionId, unsigned int optionIdx)
947 {
948     FUNCTION_LOG_BEGIN(logLevelTrace);
949         FUNCTION_LOG_PARAM(ENUM, optionId);
950         FUNCTION_LOG_PARAM(UINT, optionIdx);
951     FUNCTION_LOG_END();
952 
953     ASSERT(configLocal != NULL);
954 
955     const Variant *optionValue = cfgOptionIdxInternal(optionId, optionIdx, varTypeVariantList, true);
956 
957     if (optionValue == NULL)
958     {
959         MEM_CONTEXT_BEGIN(configLocal->memContext)
960         {
961             optionValue = varNewVarLst(varLstNew());
962             configLocal->option[optionId].index[optionIdx].value = optionValue;
963         }
964         MEM_CONTEXT_END();
965     }
966 
967     FUNCTION_LOG_RETURN(VARIANT_LIST, varVarLst(optionValue));
968 }
969 
970 const String *
cfgOptionStr(ConfigOption optionId)971 cfgOptionStr(ConfigOption optionId)
972 {
973     FUNCTION_LOG_BEGIN(logLevelTrace);
974         FUNCTION_LOG_PARAM(ENUM, optionId);
975     FUNCTION_LOG_END();
976 
977     FUNCTION_LOG_RETURN_CONST(STRING, varStr(cfgOptionIdxInternal(optionId, cfgOptionIdxDefault(optionId), varTypeString, false)));
978 }
979 
980 const String *
cfgOptionIdxStr(ConfigOption optionId,unsigned int optionIdx)981 cfgOptionIdxStr(ConfigOption optionId, unsigned int optionIdx)
982 {
983     FUNCTION_LOG_BEGIN(logLevelTrace);
984         FUNCTION_LOG_PARAM(ENUM, optionId);
985         FUNCTION_LOG_PARAM(UINT, optionIdx);
986     FUNCTION_LOG_END();
987 
988     FUNCTION_LOG_RETURN_CONST(STRING, varStr(cfgOptionIdxInternal(optionId, optionIdx, varTypeString, false)));
989 }
990 
991 const String *
cfgOptionStrNull(ConfigOption optionId)992 cfgOptionStrNull(ConfigOption optionId)
993 {
994     FUNCTION_LOG_BEGIN(logLevelTrace);
995         FUNCTION_LOG_PARAM(ENUM, optionId);
996     FUNCTION_LOG_END();
997 
998     FUNCTION_LOG_RETURN_CONST(STRING, varStr(cfgOptionIdxInternal(optionId, cfgOptionIdxDefault(optionId), varTypeString, true)));
999 }
1000 
1001 const String *
cfgOptionIdxStrNull(ConfigOption optionId,unsigned int optionIdx)1002 cfgOptionIdxStrNull(ConfigOption optionId, unsigned int optionIdx)
1003 {
1004     FUNCTION_LOG_BEGIN(logLevelTrace);
1005         FUNCTION_LOG_PARAM(ENUM, optionId);
1006         FUNCTION_LOG_PARAM(UINT, optionIdx);
1007     FUNCTION_LOG_END();
1008 
1009     FUNCTION_LOG_RETURN_CONST(STRING, varStr(cfgOptionIdxInternal(optionId, optionIdx, varTypeString, true)));
1010 }
1011 
1012 // Helper to convert option String values to StringIds. Some options need 6-bit encoding while most work fine with 5-bit encoding.
1013 // At some point the config parser will work with StringIds directly and this code can be removed, but for now it protects the
1014 // callers from this logic and hopefully means no changes to the callers when the parser is updated.
1015 static StringId
cfgOptionStrIdInternal(const ConfigOption optionId,const unsigned int optionIdx)1016 cfgOptionStrIdInternal(
1017     const ConfigOption optionId, const unsigned int optionIdx)
1018 {
1019     FUNCTION_TEST_BEGIN();
1020         FUNCTION_TEST_PARAM(ENUM, optionId);
1021         FUNCTION_TEST_PARAM(UINT, optionIdx);
1022     FUNCTION_TEST_END();
1023 
1024     const String *const value = varStr(cfgOptionIdxInternal(optionId, optionIdx, varTypeString, false));
1025     StringId result = 0;
1026 
1027     TRY_BEGIN()
1028     {
1029         result = strIdFromStr(stringIdBit5, value);
1030     }
1031     CATCH_ANY()
1032     {
1033         result = strIdFromStr(stringIdBit6, value);
1034     }
1035     TRY_END();
1036 
1037     FUNCTION_TEST_RETURN(result);
1038 }
1039 
1040 StringId
cfgOptionStrId(ConfigOption optionId)1041 cfgOptionStrId(ConfigOption optionId)
1042 {
1043     FUNCTION_LOG_BEGIN(logLevelTrace);
1044         FUNCTION_LOG_PARAM(ENUM, optionId);
1045     FUNCTION_LOG_END();
1046 
1047     FUNCTION_LOG_RETURN(STRING_ID, cfgOptionStrIdInternal(optionId, cfgOptionIdxDefault(optionId)));
1048 }
1049 
1050 StringId
cfgOptionIdxStrId(ConfigOption optionId,unsigned int optionIdx)1051 cfgOptionIdxStrId(ConfigOption optionId, unsigned int optionIdx)
1052 {
1053     FUNCTION_LOG_BEGIN(logLevelTrace);
1054         FUNCTION_LOG_PARAM(ENUM, optionId);
1055         FUNCTION_LOG_PARAM(UINT, optionIdx);
1056     FUNCTION_LOG_END();
1057 
1058     FUNCTION_LOG_RETURN(STRING_ID, cfgOptionStrIdInternal(optionId, optionIdx));
1059 }
1060 
1061 /**********************************************************************************************************************************/
1062 void
cfgOptionSet(ConfigOption optionId,ConfigSource source,const Variant * value)1063 cfgOptionSet(ConfigOption optionId, ConfigSource source, const Variant *value)
1064 {
1065     FUNCTION_TEST_BEGIN();
1066         FUNCTION_TEST_PARAM(ENUM, optionId);
1067         FUNCTION_TEST_PARAM(ENUM, source);
1068         FUNCTION_TEST_PARAM(VARIANT, value);
1069     FUNCTION_TEST_END();
1070 
1071     cfgOptionIdxSet(optionId, cfgOptionIdxDefault(optionId), source, value);
1072 
1073     FUNCTION_TEST_RETURN_VOID();
1074 }
1075 
1076 void
cfgOptionIdxSet(ConfigOption optionId,unsigned int optionIdx,ConfigSource source,const Variant * value)1077 cfgOptionIdxSet(ConfigOption optionId, unsigned int optionIdx, ConfigSource source, const Variant *value)
1078 {
1079     FUNCTION_TEST_BEGIN();
1080         FUNCTION_TEST_PARAM(ENUM, optionId);
1081         FUNCTION_TEST_PARAM(UINT, optionIdx);
1082         FUNCTION_TEST_PARAM(ENUM, source);
1083         FUNCTION_TEST_PARAM(VARIANT, value);
1084     FUNCTION_TEST_END();
1085 
1086     ASSERT(optionId < CFG_OPTION_TOTAL);
1087     ASSERT(configLocal != NULL);
1088     ASSERT(
1089         (!configLocal->option[optionId].group && optionIdx == 0) ||
1090         (configLocal->option[optionId].group && optionIdx <
1091             configLocal->optionGroup[configLocal->option[optionId].groupId].indexTotal));
1092 
1093     MEM_CONTEXT_BEGIN(configLocal->memContext)
1094     {
1095         // Set the source
1096         configLocal->option[optionId].index[optionIdx].source = source;
1097 
1098         // Only set value if it is not null
1099         if (value != NULL)
1100         {
1101             switch (cfgParseOptionType(optionId))
1102             {
1103                 case cfgOptTypeBoolean:
1104                 {
1105                     if (varType(value) == varTypeBool)
1106                         configLocal->option[optionId].index[optionIdx].value = varDup(value);
1107                     else
1108                         configLocal->option[optionId].index[optionIdx].value = varNewBool(varBoolForce(value));
1109 
1110                     break;
1111                 }
1112 
1113                 case cfgOptTypeInteger:
1114                 case cfgOptTypeSize:
1115                 case cfgOptTypeTime:
1116                 {
1117                     if (varType(value) == varTypeInt64)
1118                         configLocal->option[optionId].index[optionIdx].value = varDup(value);
1119                     else
1120                         configLocal->option[optionId].index[optionIdx].value = varNewInt64(varInt64Force(value));
1121 
1122                     break;
1123                 }
1124 
1125                 case cfgOptTypePath:
1126                 case cfgOptTypeString:
1127                 {
1128                     if (varType(value) == varTypeString)
1129                         configLocal->option[optionId].index[optionIdx].value = varDup(value);
1130                     else
1131                     {
1132                         THROW_FMT(
1133                             AssertError, "option '%s' must be set with String variant", cfgOptionIdxName(optionId, optionIdx));
1134                     }
1135 
1136                     break;
1137                 }
1138 
1139                 default:
1140                     THROW_FMT(AssertError, "set not available for option type %u", cfgParseOptionType(optionId));
1141             }
1142         }
1143         else
1144             configLocal->option[optionId].index[optionIdx].value = NULL;
1145 
1146         // Clear the display value, which will be generated when needed
1147         configLocal->option[optionId].index[optionIdx].display = NULL;
1148     }
1149     MEM_CONTEXT_END();
1150 
1151     FUNCTION_TEST_RETURN_VOID();
1152 }
1153 
1154 /**********************************************************************************************************************************/
1155 ConfigSource
cfgOptionSource(ConfigOption optionId)1156 cfgOptionSource(ConfigOption optionId)
1157 {
1158     FUNCTION_TEST_BEGIN();
1159         FUNCTION_TEST_PARAM(ENUM, optionId);
1160     FUNCTION_TEST_END();
1161 
1162     FUNCTION_TEST_RETURN(cfgOptionIdxSource(optionId, cfgOptionIdxDefault(optionId)));
1163 }
1164 
1165 ConfigSource
cfgOptionIdxSource(ConfigOption optionId,unsigned int optionIdx)1166 cfgOptionIdxSource(ConfigOption optionId, unsigned int optionIdx)
1167 {
1168     FUNCTION_TEST_BEGIN();
1169         FUNCTION_TEST_PARAM(ENUM, optionId);
1170         FUNCTION_TEST_PARAM(UINT, optionIdx);
1171     FUNCTION_TEST_END();
1172 
1173     ASSERT(optionId < CFG_OPTION_TOTAL);
1174     ASSERT(configLocal != NULL);
1175     ASSERT(
1176         (!configLocal->option[optionId].group && optionIdx == 0) ||
1177         (configLocal->option[optionId].group && optionIdx <
1178             configLocal->optionGroup[configLocal->option[optionId].groupId].indexTotal));
1179 
1180     FUNCTION_TEST_RETURN(configLocal->option[optionId].index[optionIdx].source);
1181 }
1182 
1183 /**********************************************************************************************************************************/
1184 bool
cfgOptionTest(ConfigOption optionId)1185 cfgOptionTest(ConfigOption optionId)
1186 {
1187     FUNCTION_TEST_BEGIN();
1188         FUNCTION_TEST_PARAM(ENUM, optionId);
1189     FUNCTION_TEST_END();
1190 
1191     FUNCTION_TEST_RETURN(cfgOptionIdxTest(optionId, cfgOptionIdxDefault(optionId)));
1192 }
1193 
1194 bool
cfgOptionIdxTest(ConfigOption optionId,unsigned int optionIdx)1195 cfgOptionIdxTest(ConfigOption optionId, unsigned int optionIdx)
1196 {
1197     FUNCTION_TEST_BEGIN();
1198         FUNCTION_TEST_PARAM(ENUM, optionId);
1199         FUNCTION_TEST_PARAM(UINT, optionIdx);
1200     FUNCTION_TEST_END();
1201 
1202     ASSERT(optionId < CFG_OPTION_TOTAL);
1203     ASSERT(configLocal != NULL);
1204     ASSERT(
1205         !cfgOptionValid(optionId) ||
1206         ((!configLocal->option[optionId].group && optionIdx == 0) ||
1207          (configLocal->option[optionId].group && optionIdx <
1208           configLocal->optionGroup[configLocal->option[optionId].groupId].indexTotal)));
1209 
1210     FUNCTION_TEST_RETURN(cfgOptionValid(optionId) && configLocal->option[optionId].index[optionIdx].value != NULL);
1211 }
1212 
1213 /**********************************************************************************************************************************/
1214 bool
cfgOptionValid(ConfigOption optionId)1215 cfgOptionValid(ConfigOption optionId)
1216 {
1217     FUNCTION_TEST_BEGIN();
1218         FUNCTION_TEST_PARAM(ENUM, optionId);
1219     FUNCTION_TEST_END();
1220 
1221     ASSERT(optionId < CFG_OPTION_TOTAL);
1222     ASSERT(configLocal != NULL);
1223 
1224     FUNCTION_TEST_RETURN(configLocal->option[optionId].valid);
1225 }
1226 
1227 void
cfgOptionInvalidate(ConfigOption optionId)1228 cfgOptionInvalidate(ConfigOption optionId)
1229 {
1230     FUNCTION_TEST_BEGIN();
1231         FUNCTION_TEST_PARAM(ENUM, optionId);
1232     FUNCTION_TEST_END();
1233 
1234     ASSERT(optionId < CFG_OPTION_TOTAL);
1235     ASSERT(configLocal != NULL);
1236 
1237     configLocal->option[optionId].valid = false;
1238 
1239     FUNCTION_TEST_RETURN_VOID();
1240 }
1241