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