diff --git a/build/lib/pgBackRestBuild/Config/BuildHelp.pm b/build/lib/pgBackRestBuild/Config/BuildHelp.pm index 2c3b74662..52308c105 100644 --- a/build/lib/pgBackRestBuild/Config/BuildHelp.pm +++ b/build/lib/pgBackRestBuild/Config/BuildHelp.pm @@ -20,7 +20,6 @@ use pgBackRestDoc::Common::String; use pgBackRestDoc::ProjectInfo; use pgBackRestBuild::Build::Common; -use pgBackRestBuild::Config::BuildParse; use pgBackRestBuild::Config::Data; #################################################################################################################################### diff --git a/build/lib/pgBackRestBuild/Config/BuildParse.pm b/build/lib/pgBackRestBuild/Config/BuildParse.pm deleted file mode 100644 index 2e5a0cbe5..000000000 --- a/build/lib/pgBackRestBuild/Config/BuildParse.pm +++ /dev/null @@ -1,630 +0,0 @@ -#################################################################################################################################### -# Auto-Generate Option Definition for Parsing with getopt_long(). -#################################################################################################################################### -package pgBackRestBuild::Config::BuildParse; - -use strict; -use warnings FATAL => qw(all); -use Carp qw(confess); -use English '-no_match_vars'; - -use Cwd qw(abs_path); -use Exporter qw(import); - our @EXPORT = qw(); -use File::Basename qw(dirname); -use Storable qw(dclone); - -use pgBackRestDoc::Common::Log; -use pgBackRestDoc::Common::String; -use pgBackRestDoc::ProjectInfo; - -use pgBackRestBuild::Build::Common; -use pgBackRestBuild::Config::Data; - -#################################################################################################################################### -# Constants -#################################################################################################################################### -use constant BLDLCL_FILE_DEFINE => 'parse'; - -use constant BLDLCL_DATA_COMMAND => '01-dataCommand'; -use constant BLDLCL_DATA_OPTION_GROUP => '01-dataOptionGroup'; -use constant BLDLCL_DATA_OPTION => '02-dataOption'; -use constant BLDLCL_DATA_OPTION_GETOPT => '03-dataOptionGetOpt'; -use constant BLDLCL_DATA_OPTION_RESOLVE => '04-dataOptionResolve'; - -#################################################################################################################################### -# Definitions for constants and data to build -#################################################################################################################################### -my $strSummary = 'Config Parse Rules'; - -my $rhBuild = -{ - &BLD_FILE => - { - &BLDLCL_FILE_DEFINE => - { - &BLD_SUMMARY => $strSummary, - - &BLD_DATA => - { - &BLDLCL_DATA_COMMAND => - { - &BLD_SUMMARY => 'Command parse data', - }, - - &BLDLCL_DATA_OPTION_GROUP => - { - &BLD_SUMMARY => 'Option group parse data', - }, - - &BLDLCL_DATA_OPTION => - { - &BLD_SUMMARY => 'Option parse data', - }, - - &BLDLCL_DATA_OPTION_GETOPT => - { - &BLD_SUMMARY => 'Option data for getopt_long()', - }, - - &BLDLCL_DATA_OPTION_RESOLVE => - { - &BLD_SUMMARY => 'Order for option parse resolution', - }, - }, - }, - }, -}; - -#################################################################################################################################### -# Generate enum names -#################################################################################################################################### -sub buildConfigCommandEnum -{ - return bldEnum('cfgCmd', shift) -} - -push @EXPORT, qw(buildConfigCommandEnum); - -sub buildConfigOptionEnum -{ - return bldEnum('cfgOpt', shift) -} - -push @EXPORT, qw(buildConfigOptionEnum); - -sub buildConfigOptionGroupEnum -{ - return bldEnum('cfgOptGrp', shift) -} - -push @EXPORT, qw(buildConfigOptionGroupEnum); - - -sub buildConfigDefineOptionTypeEnum -{ - return bldEnum('cfgOptType', shift); -} - -push @EXPORT, qw(buildConfigDefineOptionTypeEnum); - -sub buildConfigCommandRoleEnum -{ - return bldEnum('cfgCmdRole', shift); -} - -#################################################################################################################################### -# Helper functions for building optional option data -#################################################################################################################################### -sub renderAllowList -{ - my $ryAllowList = shift; - my $bCommandIndent = shift; - - my $strIndent = $bCommandIndent ? ' ' : ''; - - return - "${strIndent} PARSE_RULE_OPTION_OPTIONAL_ALLOW_LIST\n" . - "${strIndent} (\n" . - "${strIndent} " . join(",\n${strIndent} ", bldQuoteList($ryAllowList)) . - "\n" . - "${strIndent} ),\n"; -} - -sub renderDepend -{ - my $rhDepend = shift; - my $bCommandIndent = shift; - - my $strIndent = $bCommandIndent ? ' ' : ''; - - my $strDependOption = $rhDepend->{&CFGDEF_DEPEND_OPTION}; - my $ryDependList = $rhDepend->{&CFGDEF_DEPEND_LIST}; - - if (defined($ryDependList)) - { - my @stryQuoteList; - - foreach my $strItem (@{$ryDependList}) - { - push(@stryQuoteList, "\"${strItem}\""); - } - - return - "${strIndent} PARSE_RULE_OPTION_OPTIONAL_DEPEND_LIST\n" . - "${strIndent} (\n" . - "${strIndent} " . buildConfigOptionEnum($strDependOption) . ",\n" . - "${strIndent} " . join(",\n${strIndent} ", bldQuoteList($ryDependList)) . - "\n" . - "${strIndent} ),\n"; - } - - return - "${strIndent} PARSE_RULE_OPTION_OPTIONAL_DEPEND(" . buildConfigOptionEnum($strDependOption) . "),\n"; -} - -sub renderOptional -{ - my $rhOptional = shift; - my $bCommand = shift; - my $strCommand = shift; - my $strOption = shift; - - my $strIndent = $bCommand ? ' ' : ''; - my $strBuildSourceOptional; - my $bSingleLine = false; - - if (defined($rhOptional->{&CFGDEF_ALLOW_LIST})) - { - $strBuildSourceOptional .= - (defined($strBuildSourceOptional) && !$bSingleLine ? "\n" : '') . - renderAllowList($rhOptional->{&CFGDEF_ALLOW_LIST}, $bCommand); - - $bSingleLine = false; - } - - if (defined($rhOptional->{&CFGDEF_ALLOW_RANGE})) - { - my @fyRange = @{$rhOptional->{&CFGDEF_ALLOW_RANGE}}; - - my $iMultiplier = $rhOptional->{&CFGDEF_TYPE} eq CFGDEF_TYPE_TIME ? 1000 : 1; - - $strBuildSourceOptional = - (defined($strBuildSourceOptional) && !$bSingleLine ? "\n" : '') . - "${strIndent} PARSE_RULE_OPTION_OPTIONAL_ALLOW_RANGE(" . ($fyRange[0] * $iMultiplier) . ', ' . - ($fyRange[1] * $iMultiplier) . "),\n"; - - $bSingleLine = true; - } - - if (defined($rhOptional->{&CFGDEF_DEPEND})) - { - $strBuildSourceOptional .= - (defined($strBuildSourceOptional) && !$bSingleLine ? "\n" : '') . - renderDepend($rhOptional->{&CFGDEF_DEPEND}, $bCommand); - - $bSingleLine = defined($rhOptional->{&CFGDEF_DEPEND}{&CFGDEF_DEPEND_LIST}) ? false : true; - } - - if (defined($rhOptional->{&CFGDEF_DEFAULT})) - { - $strBuildSourceOptional .= - (defined($strBuildSourceOptional) && !$bSingleLine ? "\n" : '') . - "${strIndent} PARSE_RULE_OPTION_OPTIONAL_DEFAULT(" . - ($rhOptional->{&CFGDEF_DEFAULT_LITERAL} ? '' : '"') . - (defined($rhOptional->{&CFGDEF_TYPE}) && $rhOptional->{&CFGDEF_TYPE} eq CFGDEF_TYPE_TIME ? - $rhOptional->{&CFGDEF_DEFAULT} * 1000 : $rhOptional->{&CFGDEF_DEFAULT}) . - ($rhOptional->{&CFGDEF_DEFAULT_LITERAL} ? '' : '"') . - "),\n"; - - $bSingleLine = true; - } - - if ($bCommand && defined($rhOptional->{&CFGDEF_REQUIRED})) - { - $strBuildSourceOptional .= - (defined($strBuildSourceOptional) && !$bSingleLine ? "\n" : '') . - "${strIndent} PARSE_RULE_OPTION_OPTIONAL_REQUIRED(" . - ($rhOptional->{&CFGDEF_REQUIRED} ? 'true' : 'false') . "),\n"; - - $bSingleLine = true; - } - - return $strBuildSourceOptional; -} - -#################################################################################################################################### -# Build configuration constants and data -#################################################################################################################################### -sub buildConfigParse -{ - # Build command parse data - # ------------------------------------------------------------------------------------------------------------------------------ - my $rhCommandDefine = cfgDefineCommand(); - - my $strBuildSource = - "static const ParseRuleCommand parseRuleCommand[CFG_COMMAND_TOTAL] =\n" . - "{"; - - foreach my $strCommand (sort(keys(%{$rhCommandDefine}))) - { - my $rhCommand = $rhCommandDefine->{$strCommand}; - - # Build command data - $strBuildSource .= - "\n" . - " // " . (qw{-} x 125) . "\n" . - " PARSE_RULE_COMMAND\n" . - " (\n" . - " PARSE_RULE_COMMAND_NAME(\"${strCommand}\"),\n"; - - if ($rhCommand->{&CFGDEF_PARAMETER_ALLOWED}) - { - $strBuildSource .= - " PARSE_RULE_COMMAND_PARAMETER_ALLOWED(true),\n"; - } - - $strBuildSource .= - "\n" . - " PARSE_RULE_COMMAND_ROLE_VALID_LIST\n" . - " (\n"; - - foreach my $strCommandRole (sort(keys(%{$rhCommand->{&CFGDEF_COMMAND_ROLE}}))) - { - $strBuildSource .= - " PARSE_RULE_COMMAND_ROLE(" . buildConfigCommandRoleEnum($strCommandRole) . ")\n"; - } - - $strBuildSource .= - " ),\n"; - - $strBuildSource .= - " ),\n"; - }; - - $strBuildSource .= - "};\n"; - - $rhBuild->{&BLD_FILE}{&BLDLCL_FILE_DEFINE}{&BLD_DATA}{&BLDLCL_DATA_COMMAND}{&BLD_SOURCE} = $strBuildSource; - - # Build option group parse data - # ------------------------------------------------------------------------------------------------------------------------------ - my $rhOptionGroupDefine = cfgDefineOptionGroup(); - - $strBuildSource = - "static const ParseRuleOptionGroup parseRuleOptionGroup[CFG_OPTION_GROUP_TOTAL] =\n" . - "{"; - - foreach my $strGroup (sort(keys(%{$rhOptionGroupDefine}))) - { - $strBuildSource .= - "\n" . - " // " . (qw{-} x 125) . "\n" . - " PARSE_RULE_OPTION_GROUP\n" . - " (\n" . - " PARSE_RULE_OPTION_GROUP_NAME(\"" . $strGroup . "\"),\n" . - " ),\n"; - } - - $strBuildSource .= - "};\n"; - - $rhBuild->{&BLD_FILE}{&BLDLCL_FILE_DEFINE}{&BLD_DATA}{&BLDLCL_DATA_OPTION_GROUP}{&BLD_SOURCE} = $strBuildSource; - - # Build option parse data - # ------------------------------------------------------------------------------------------------------------------------------ - my $rhConfigDefine = cfgDefine(); - - $strBuildSource = - "static const ParseRuleOption parseRuleOption[CFG_OPTION_TOTAL] =\n" . - "{"; - - foreach my $strOption (sort(keys(%{$rhConfigDefine}))) - { - my $rhOption = $rhConfigDefine->{$strOption}; - - $strBuildSource .= - "\n" . - " // " . (qw{-} x 125) . "\n" . - " PARSE_RULE_OPTION\n" . - " (\n" . - " PARSE_RULE_OPTION_NAME(\"${strOption}\"),\n" . - " PARSE_RULE_OPTION_TYPE(" . buildConfigDefineOptionTypeEnum($rhOption->{&CFGDEF_TYPE}) . "),\n" . - " PARSE_RULE_OPTION_REQUIRED(" . ($rhOption->{&CFGDEF_REQUIRED} ? 'true' : 'false') . "),\n" . - " PARSE_RULE_OPTION_SECTION(cfgSection" . - (defined($rhOption->{&CFGDEF_SECTION}) ? ucfirst($rhOption->{&CFGDEF_SECTION}) : 'CommandLine') . - "),\n"; - - if ($rhOption->{&CFGDEF_SECURE}) - { - $strBuildSource .= - " PARSE_RULE_OPTION_SECURE(true),\n"; - } - - if ($rhOption->{&CFGDEF_TYPE} eq CFGDEF_TYPE_HASH || $rhOption->{&CFGDEF_TYPE} eq CFGDEF_TYPE_LIST) - { - $strBuildSource .= - " PARSE_RULE_OPTION_MULTI(true),\n"; - } - - # Build group info - # -------------------------------------------------------------------------------------------------------------------------- - if ($rhOption->{&CFGDEF_GROUP}) - { - $strBuildSource .= - " PARSE_RULE_OPTION_GROUP_MEMBER(true),\n" . - " PARSE_RULE_OPTION_GROUP_ID(" . buildConfigOptionGroupEnum($rhOption->{&CFGDEF_GROUP}) . "),\n"; - } - - # Build command role valid lists - #--------------------------------------------------------------------------------------------------------------------------- - my $strBuildSourceSub = ""; - - foreach my $strCommandRole (CFGCMD_ROLE_MAIN, CFGCMD_ROLE_ASYNC, CFGCMD_ROLE_LOCAL, CFGCMD_ROLE_REMOTE) - { - $strBuildSourceSub = ""; - - foreach my $strCommand (cfgDefineCommandList()) - { - if (defined($rhOption->{&CFGDEF_COMMAND}{$strCommand})) - { - if (defined($rhOption->{&CFGDEF_COMMAND}{$strCommand}{&CFGDEF_COMMAND_ROLE}{$strCommandRole})) - { - $strBuildSourceSub .= - " PARSE_RULE_OPTION_COMMAND(" . buildConfigCommandEnum($strCommand) . ")\n"; - } - } - } - - if ($strBuildSourceSub ne "") - { - $strBuildSource .= - "\n" . - " PARSE_RULE_OPTION_COMMAND_ROLE_" . uc($strCommandRole) . "_VALID_LIST\n" . - " (\n" . - $strBuildSourceSub . - " ),\n"; - } - } - - # Render optional data and command overrides - # -------------------------------------------------------------------------------------------------------------------------- - my $strBuildSourceOptional = renderOptional($rhOption, false); - - foreach my $strCommand (cfgDefineCommandList()) - { - my $strBuildSourceOptionalCommand; - my $rhCommand = $rhOption->{&CFGDEF_COMMAND}{$strCommand}; - $rhCommand->{&CFGDEF_TYPE} = $rhOption->{&CFGDEF_TYPE}; - - if (defined($rhCommand)) - { - $strBuildSourceOptionalCommand = renderOptional($rhCommand, true, $strCommand, $strOption); - - if (defined($strBuildSourceOptionalCommand)) - { - $strBuildSourceOptional .= - (defined($strBuildSourceOptional) ? "\n" : '') . - " PARSE_RULE_OPTION_OPTIONAL_COMMAND_OVERRIDE\n" . - " (\n" . - " PARSE_RULE_OPTION_OPTIONAL_COMMAND(" . buildConfigCommandEnum($strCommand) . "),\n" . - "\n" . - $strBuildSourceOptionalCommand . - " )\n"; - } - } - } - - if (defined($strBuildSourceOptional)) - { - $strBuildSource .= - "\n" . - " PARSE_RULE_OPTION_OPTIONAL_LIST\n" . - " (\n" . - $strBuildSourceOptional . - " ),\n"; - } - - $strBuildSource .= - " ),\n"; - } - - $strBuildSource .= - "};\n"; - - $rhBuild->{&BLD_FILE}{&BLDLCL_FILE_DEFINE}{&BLD_DATA}{&BLDLCL_DATA_OPTION}{&BLD_SOURCE} = $strBuildSource; - - # Build option list for getopt_long() - #------------------------------------------------------------------------------------------------------------------------------- - $strBuildSource = - "static const struct option optionList[] =\n" . - "{"; - - foreach my $strOption (sort(keys(%{$rhConfigDefine}))) - { - my $rhOption = $rhConfigDefine->{$strOption}; - my $strOptionEnum = buildConfigOptionEnum($strOption); - my $strOptionArg = ($rhOption->{&CFGDEF_TYPE} ne CFGDEF_TYPE_BOOLEAN ? " .has_arg = required_argument,\n" : ''); - my $strOptionPrefix = $rhConfigDefine->{$strOption}{&CFGDEF_PREFIX}; - - my @stryOptionName = ($strOption); - - if (defined($rhOption->{&CFGDEF_DEPRECATE})) - { - foreach my $strOptionNameAlt (sort(keys(%{$rhOption->{&CFGDEF_DEPRECATE}}))) - { - push(@stryOptionName, $strOptionNameAlt); - } - } - - $strBuildSource .= - "\n" . - " // ${strOption} option" . (@stryOptionName > 1 ? ' and deprecations' : '') . "\n" . - " // " . (qw{-} x 125) . "\n"; - - for (my $iOptionIdx = 1; $iOptionIdx <= $rhOption->{&CFGDEF_INDEX_TOTAL}; $iOptionIdx++) - { - for (my $iOptionNameIdx = 0; $iOptionNameIdx < @stryOptionName; $iOptionNameIdx++) - { - my $strOptionName = $stryOptionName[$iOptionNameIdx]; - my $rhNameAlt = $rhOption->{&CFGDEF_DEPRECATE}{$strOptionName}; - - # Skip alt name if it is not valid for this option index - if ($iOptionNameIdx > 0 && defined($rhNameAlt->{&CFGDEF_INDEX}) && $rhNameAlt->{&CFGDEF_INDEX} != $iOptionIdx) - { - next; - } - - # Generate output name - my $strOptionNameOut = $strOptionName; - my $strOptionConst; - - if (defined($strOptionPrefix)) - { - if ($iOptionNameIdx == 0) - { - $strOptionNameOut = - "${strOptionPrefix}${iOptionIdx}-" . substr($strOptionName, length($strOptionPrefix) + 1); - } - else - { - $strOptionNameOut =~ s/\?/$iOptionIdx/g; - } - } - - # Generate option value used for parsing (offset is added so options don't conflict with getopt_long return values) - my $strOptionFlag = 'PARSE_OPTION_FLAG |'; - - # Build option constant name if this is the current name for the option - if ($iOptionNameIdx == 0) - { - if (!$rhConfigDefine->{$strOption}{&CFGDEF_GROUP}) - { - $strOptionConst = "CFGOPT_" . uc($strOptionNameOut); - $strOptionConst =~ s/\-/_/g; - } - } - # Else use bare string and mark as deprecated - else - { - $strOptionFlag .= ' PARSE_DEPRECATE_FLAG |'; - } - - my $strOptionVal = - ($rhOption->{&CFGDEF_GROUP} ? "(" . ($iOptionIdx - 1) . " << PARSE_KEY_IDX_SHIFT) | " : '') . $strOptionEnum; - - # Add option - $strBuildSource .= - " {\n" . - " .name = \"${strOptionNameOut}\",\n" . - $strOptionArg . - " .val = ${strOptionFlag} ${strOptionVal},\n" . - " },\n"; - - # Add negation when defined - if ($rhOption->{&CFGDEF_NEGATE} && - !($iOptionNameIdx > 0 && defined($rhNameAlt->{&CFGDEF_NEGATE}) && !$rhNameAlt->{&CFGDEF_NEGATE})) - { - $strBuildSource .= - " {\n" . - " .name = \"no-${strOptionNameOut}\",\n" . - " .val = ${strOptionFlag} PARSE_NEGATE_FLAG | ${strOptionVal},\n" . - " },\n"; - } - - # Add reset when defined - if ($rhOption->{&CFGDEF_RESET} && - !($iOptionNameIdx > 0 && defined($rhNameAlt->{&CFGDEF_RESET}) && !$rhNameAlt->{&CFGDEF_RESET})) - { - $strBuildSource .= - " {\n" . - " .name = \"reset-${strOptionNameOut}\",\n" . - " .val = ${strOptionFlag} PARSE_RESET_FLAG | ${strOptionVal},\n" . - " },\n"; - } - } - } - } - - # The option list needs to be terminated or getopt_long will just keep on reading - $strBuildSource .= - " // Terminate option list\n" . - " {\n" . - " .name = NULL\n" . - " }\n" . - "};\n"; - - $rhBuild->{&BLD_FILE}{&BLDLCL_FILE_DEFINE}{&BLD_DATA}{&BLDLCL_DATA_OPTION_GETOPT}{&BLD_SOURCE} = $strBuildSource; - - # Build option resolve order list. This allows the option validation in C to take place in a single pass. - # - # Always process the stanza option first since confusing error message are produced if it is missing. - #------------------------------------------------------------------------------------------------------------------------------- - my @stryResolveOrder = (buildConfigOptionEnum(CFGOPT_STANZA)); - my $rhResolved = {&CFGOPT_STANZA => true}; - my $bAllResolved; - - do - { - # Assume that we will finish on this loop - $bAllResolved = true; - - # Loop through all options - foreach my $strOption (sort(keys(%{$rhConfigDefine}))) - { - my $bSkip = false; - - # Check the default depend - my $strOptionDepend = - ref($rhConfigDefine->{$strOption}{&CFGDEF_DEPEND}) eq 'HASH' ? - $rhConfigDefine->{$strOption}{&CFGDEF_DEPEND}{&CFGDEF_DEPEND_OPTION} : - $rhConfigDefine->{$strOption}{&CFGDEF_DEPEND}; - - if (defined($strOptionDepend) && !$rhResolved->{$strOptionDepend}) - { - # &log(WARN, "$strOptionDepend is not resolved"); - $bSkip = true; - } - - # Check the command depends - foreach my $strCommand (sort(keys(%{$rhConfigDefine->{$strOption}{&CFGDEF_COMMAND}}))) - { - my $strOptionDepend = - ref($rhConfigDefine->{$strOption}{&CFGDEF_COMMAND}{$strCommand}{&CFGDEF_DEPEND}) eq 'HASH' ? - $rhConfigDefine->{$strOption}{&CFGDEF_COMMAND}{$strCommand}{&CFGDEF_DEPEND}{&CFGDEF_DEPEND_OPTION} : - $rhConfigDefine->{$strOption}{&CFGDEF_COMMAND}{$strCommand}{&CFGDEF_DEPEND}; - - if (defined($strOptionDepend) && !$rhResolved->{$strOptionDepend}) - { - $bSkip = true; - } - } - - # If dependency was not found try again on the next loop - if ($bSkip) - { - $bAllResolved = false; - } - # Else add option to resolve order list - elsif (!$rhResolved->{$strOption}) - { - push(@stryResolveOrder, buildConfigOptionEnum($strOption)); - - $rhResolved->{$strOption} = true; - } - } - } - while (!$bAllResolved); - - $rhBuild->{&BLD_FILE}{&BLDLCL_FILE_DEFINE}{&BLD_DATA}{&BLDLCL_DATA_OPTION_RESOLVE}{&BLD_SOURCE} = - "static const ConfigOption optionResolveOrder[] =\n" . - "{\n" . - " " . join(",\n ", @stryResolveOrder) . ",\n" . - "};\n"; - - return $rhBuild; -} - -push @EXPORT, qw(buildConfigParse); - -1; diff --git a/src/Makefile.in b/src/Makefile.in index 2bf54b599..4df7d56e4 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -216,7 +216,7 @@ SRCS_BUILD_CONFIG = \ OBJS_BUILD_CONFIG = $(patsubst %.c,$(BUILDDIR)/%.o,$(SRCS_BUILD) $(SRCS_BUILD_CONFIG)) -build-config: $(OBJS_BUILD_CONFIG) build/config/config.yaml config/config.auto.h +build-config: $(OBJS_BUILD_CONFIG) build/config/config.yaml config/config.auto.h config/config.auto.c config/parse.auto.c $(CC) -o build-config $(OBJS_BUILD_CONFIG) $(LDFLAGS) $(LIBS) $(LIBS_BUILD) ./build-config $(VPATH) diff --git a/src/build/common/render.h b/src/build/common/render.h index 605010235..97a772db4 100644 --- a/src/build/common/render.h +++ b/src/build/common/render.h @@ -17,6 +17,10 @@ Block comments "****************************************************************************************************************************" \ "*******/" +#define COMMENT_SEPARATOR \ + " // ---------------------------------------------------------------------------------------------------------------------" \ + "--------" + /*********************************************************************************************************************************** Functions ***********************************************************************************************************************************/ diff --git a/src/build/config/main.c b/src/build/config/main.c index 3c880d4ec..eddb03e6e 100644 --- a/src/build/config/main.c +++ b/src/build/config/main.c @@ -15,6 +15,9 @@ main(int argListSize, const char *argList[]) // Check parameters CHECK(argListSize <= 2); + // Initialize logging + logInit(logLevelWarn, logLevelError, logLevelOff, false, 0, 1, false); + // If the path was specified const String *pathRepo; diff --git a/src/build/config/parse.c b/src/build/config/parse.c index b309d3577..02dc4ca9b 100644 --- a/src/build/config/parse.c +++ b/src/build/config/parse.c @@ -6,499 +6,1142 @@ Parse Configuration Yaml #include #include "common/log.h" +#include "common/type/convert.h" #include "storage/posix/storage.h" #include "build/common/yaml.h" #include "build/config/parse.h" -/**********************************************************************************************************************************/ +/*********************************************************************************************************************************** +Command role constants +***********************************************************************************************************************************/ +STRING_EXTERN(CMD_ROLE_ASYNC_STR, CMD_ROLE_ASYNC); +STRING_EXTERN(CMD_ROLE_LOCAL_STR, CMD_ROLE_LOCAL); +STRING_EXTERN(CMD_ROLE_MAIN_STR, CMD_ROLE_MAIN); +STRING_EXTERN(CMD_ROLE_REMOTE_STR, CMD_ROLE_REMOTE); + +/*********************************************************************************************************************************** +Command constants +***********************************************************************************************************************************/ +STRING_EXTERN(CMD_HELP_STR, CMD_HELP); +STRING_EXTERN(CMD_VERSION_STR, CMD_VERSION); + +/*********************************************************************************************************************************** +Option type constants +***********************************************************************************************************************************/ +STRING_EXTERN(OPT_TYPE_BOOLEAN_STR, OPT_TYPE_BOOLEAN); +STRING_EXTERN(OPT_TYPE_HASH_STR, OPT_TYPE_HASH); +STRING_EXTERN(OPT_TYPE_LIST_STR, OPT_TYPE_LIST); +STRING_EXTERN(OPT_TYPE_STRING_STR, OPT_TYPE_STRING); +STRING_EXTERN(OPT_TYPE_TIME_STR, OPT_TYPE_TIME); + +/*********************************************************************************************************************************** +Option constants +***********************************************************************************************************************************/ +STRING_EXTERN(OPT_STANZA_STR, OPT_STANZA); + +/*********************************************************************************************************************************** +Section constants +***********************************************************************************************************************************/ +STRING_EXTERN(SECTION_COMMAND_LINE_STR, SECTION_COMMAND_LINE); +STRING_EXTERN(SECTION_GLOBAL_STR, SECTION_GLOBAL); +STRING_EXTERN(SECTION_STANZA_STR, SECTION_STANZA); + +/*********************************************************************************************************************************** +Parse command list +***********************************************************************************************************************************/ +typedef struct BldCfgCommandRaw +{ + const String *const name; // See BldCfgCommand for comments + bool logFile; + const String *logLevelDefault; + bool lockRequired; + bool lockRemoteRequired; + const String *lockType; + bool parameterAllowed; + StringList *roleList; +} BldCfgCommandRaw; + +// Helper to parse command roles +static StringList * +bldCfgParseCommandRole(Yaml *const yaml) +{ + StringList *const result = strLstNew(); + + MEM_CONTEXT_TEMP_BEGIN() + { + yamlEventNextCheck(yaml, yamlEventTypeMapBegin); + YamlEvent commandRoleVal = yamlEventNext(yaml); + + if (commandRoleVal.type != yamlEventTypeMapEnd) + { + do + { + yamlEventCheck(commandRoleVal, yamlEventTypeScalar); + + strLstAdd(result, commandRoleVal.value); + + yamlEventNextCheck(yaml, yamlEventTypeMapBegin); + yamlEventNextCheck(yaml, yamlEventTypeMapEnd); + + commandRoleVal = yamlEventNext(yaml); + } + while (commandRoleVal.type != yamlEventTypeMapEnd); + } + } + MEM_CONTEXT_TEMP_END(); + + return result; +} + +static List * +bldCfgParseCommandList(Yaml *const yaml) +{ + List *const result = lstNewP(sizeof(BldCfgCommand), .comparator = lstComparatorStr); + + MEM_CONTEXT_TEMP_BEGIN() + { + yamlEventNextCheck(yaml, yamlEventTypeScalar); + yamlEventNextCheck(yaml, yamlEventTypeMapBegin); + + YamlEvent cmd = yamlEventNext(yaml); + + do + { + yamlEventCheck(cmd, yamlEventTypeScalar); + + BldCfgCommandRaw cmdRaw = + { + .name = cmd.value, + .logFile = true, + .logLevelDefault = strNewZ("info"), + .lockType = strNewZ("none"), + }; + + yamlEventNextCheck(yaml, yamlEventTypeMapBegin); + + YamlEvent cmdDef = yamlEventNext(yaml); + + if (cmdDef.type == yamlEventTypeScalar) + { + do + { + yamlEventCheck(cmdDef, yamlEventTypeScalar); + + if (strEqZ(cmdDef.value, "command-role")) + { + cmdRaw.roleList = bldCfgParseCommandRole(yaml); + } + else + { + YamlEvent cmdDefVal = yamlEventNextCheck(yaml, yamlEventTypeScalar); + + if (strEqZ(cmdDef.value, "internal")) + { + } + else if (strEqZ(cmdDef.value, "lock-type")) + { + cmdRaw.lockType = cmdDefVal.value; + } + else if (strEqZ(cmdDef.value, "lock-remote-required")) + { + cmdRaw.lockRemoteRequired = yamlBoolParse(cmdDefVal); + } + else if (strEqZ(cmdDef.value, "lock-required")) + { + cmdRaw.lockRequired = yamlBoolParse(cmdDefVal); + } + else if (strEqZ(cmdDef.value, "log-file")) + { + cmdRaw.logFile = yamlBoolParse(cmdDefVal); + } + else if (strEqZ(cmdDef.value, "log-level-default")) + { + cmdRaw.logLevelDefault = strLower(strDup(cmdDefVal.value)); + } + else if (strEqZ(cmdDef.value, "parameter-allowed")) + { + cmdRaw.parameterAllowed = strLower(strDup(cmdDefVal.value)); + } + else + THROW_FMT(FormatError, "unknown command definition '%s'", strZ(cmdDef.value)); + } + + cmdDef = yamlEventNext(yaml); + } + while (cmdDef.type != yamlEventTypeMapEnd); + } + else + yamlEventCheck(cmdDef, yamlEventTypeMapEnd); + + // Create role list if not defined + if (cmdRaw.roleList == NULL) + cmdRaw.roleList = strLstNew(); + + // Add main to the role list and resort + strLstAddIfMissing(cmdRaw.roleList, CMD_ROLE_MAIN_STR); + strLstSort(cmdRaw.roleList, sortOrderAsc); + + MEM_CONTEXT_BEGIN(lstMemContext(result)) + { + lstAdd( + result, + &(BldCfgCommand) + { + .name = strDup(cmdRaw.name), + .logFile = cmdRaw.logFile, + .logLevelDefault = strDup(cmdRaw.logLevelDefault), + .lockRequired = cmdRaw.lockRequired, + .lockRemoteRequired = cmdRaw.lockRemoteRequired, + .lockType = strDup(cmdRaw.lockType), + .parameterAllowed = cmdRaw.parameterAllowed, + .roleList = strLstDup(cmdRaw.roleList), + }); + } + MEM_CONTEXT_END(); + + cmd = yamlEventNext(yaml); + } + while (cmd.type != yamlEventTypeMapEnd); + + lstSort(result, sortOrderAsc); + } + MEM_CONTEXT_TEMP_END(); + + return result; +} + +/*********************************************************************************************************************************** +Parse option group list +***********************************************************************************************************************************/ +typedef struct BldCfgOptionGroupRaw +{ + const String *const name; // See BldCfgOptionGroup for comments + const Variant *indexTotal; +} BldCfgOptionGroupRaw; + +static List * +bldCfgParseOptionGroupList(Yaml *const yaml) +{ + List *const result = lstNewP(sizeof(BldCfgOptionGroup), .comparator = lstComparatorStr); + + MEM_CONTEXT_TEMP_BEGIN() + { + yamlEventNextCheck(yaml, yamlEventTypeScalar); + yamlEventNextCheck(yaml, yamlEventTypeMapBegin); + + YamlEvent optGrp = yamlEventNext(yaml); + + do + { + yamlEventCheck(optGrp, yamlEventTypeScalar); + BldCfgOptionGroupRaw optGrpRaw = {.name = optGrp.value}; + + yamlEventNextCheck(yaml, yamlEventTypeMapBegin); + + YamlEvent optGrpDef = yamlEventNext(yaml); + + do + { + yamlEventCheck(optGrpDef, yamlEventTypeScalar); + YamlEvent optGrpDefVal = yamlEventNextCheck(yaml, yamlEventTypeScalar); + + if (strEqZ(optGrpDef.value, "indexTotal")) + { + optGrpRaw.indexTotal = varNewUInt(cvtZToUInt(strZ(optGrpDefVal.value))); + } + else if (strEqZ(optGrpDef.value, "prefix")) + { + // ??? This is the same as the name so should be removed + } + else + THROW_FMT(FormatError, "unknown option group definition '%s'", strZ(optGrpDef.value)); + + optGrpDef = yamlEventNext(yaml); + } + while (optGrpDef.type != yamlEventTypeMapEnd); + + // indexTotal is required + if (optGrpRaw.indexTotal == NULL) + THROW_FMT(FormatError, "option group '%s' requires 'indexTotal'", strZ(optGrpRaw.name)); + + MEM_CONTEXT_BEGIN(lstMemContext(result)) + { + lstAdd(result, &(BldCfgOptionGroup){.name = strDup(optGrpRaw.name), .indexTotal = varUInt(optGrpRaw.indexTotal)}); + } + MEM_CONTEXT_END(); + + optGrp = yamlEventNext(yaml); + } + while (optGrp.type != yamlEventTypeMapEnd); + + lstSort(result, sortOrderAsc); + } + MEM_CONTEXT_TEMP_END(); + + return result; +} + +/*********************************************************************************************************************************** +Parse option list +***********************************************************************************************************************************/ +typedef struct BldCfgOptionDependRaw +{ + const String *option; // See BldCfgOptionDepend for comments + const StringList *valueList; +} BldCfgOptionDependRaw; + +typedef struct BldCfgOptionDeprecateRaw +{ + const String *name; // See BldCfgOptionDeprecate for comments + unsigned int index; + bool reset; +} BldCfgOptionDeprecateRaw; + +typedef struct BldCfgOptionCommandRaw +{ + const String *name; // See BldCfgOptionCommand for comments + const Variant *required; + const String *defaultValue; + const BldCfgOptionDependRaw *depend; + const StringList *allowList; + const StringList *roleList; +} BldCfgOptionCommandRaw; + +typedef struct BldCfgOptionRaw +{ + const String *name; // See BldCfgOption for comments + const String *type; + const String *section; + const Variant *required; + const Variant *negate; + bool reset; + const String *defaultValue; + bool defaultLiteral; + const String *group; + bool secure; + const BldCfgOptionDependRaw *depend; + const StringList *allowList; + const String *allowRangeMin; + const String *allowRangeMax; + const List *cmdList; + const StringList *cmdRoleList; + const List *deprecateList; +} BldCfgOptionRaw; + // Helper to parse allow list static const StringList * bldCfgParseAllowList(Yaml *const yaml, const List *const optList) { - YamlEvent allowListVal = yamlEventNext(yaml); + StringList *result = NULL; - // If allow list is defined - if (allowListVal.type == yamlEventTypeSeqBegin) + MEM_CONTEXT_TEMP_BEGIN() { YamlEvent allowListVal = yamlEventNext(yaml); - StringList *result = strLstNew(); - do + // If allow list is defined + if (allowListVal.type == yamlEventTypeSeqBegin) { - yamlEventCheck(allowListVal, yamlEventTypeScalar); - strLstAdd(result, allowListVal.value); + YamlEvent allowListVal = yamlEventNext(yaml); - allowListVal = yamlEventNext(yaml); + MEM_CONTEXT_PRIOR_BEGIN() + { + result = strLstNew(); + } + MEM_CONTEXT_PRIOR_END(); + + do + { + yamlEventCheck(allowListVal, yamlEventTypeScalar); + strLstAdd(result, allowListVal.value); + + allowListVal = yamlEventNext(yaml); + } + while (allowListVal.type != yamlEventTypeSeqEnd); } - while (allowListVal.type != yamlEventTypeSeqEnd); + else + { - strLstSort(result, sortOrderAsc); + // Else allow list is inherited + CHECK(optList != NULL); + yamlEventCheck(allowListVal, yamlEventTypeScalar); - return result; + const BldCfgOptionRaw *const optInherit = lstFind(optList, &allowListVal.value); + CHECK(optInherit != NULL); + + MEM_CONTEXT_PRIOR_BEGIN() + { + result = strLstDup(optInherit->allowList); + } + MEM_CONTEXT_PRIOR_END(); + } + + CHECK(result != NULL); } + MEM_CONTEXT_TEMP_END(); - // Else allow list is inherited - CHECK(optList != NULL); - yamlEventCheck(allowListVal, yamlEventTypeScalar); - - const BldCfgOption *const optInherit = lstFind(optList, &allowListVal.value); - CHECK(optInherit != NULL); - - return optInherit->allowList; + return result; } // Helper to parse allow range static void -bldCfgParseAllowRange(Yaml *const yaml) +bldCfgParseAllowRange(Yaml *const yaml, BldCfgOptionRaw *const opt) { - yamlEventNextCheck(yaml, yamlEventTypeSeqBegin); - - YamlEvent allowRangeVal = yamlEventNext(yaml); - - do + MEM_CONTEXT_TEMP_BEGIN() { - yamlEventCheck(allowRangeVal, yamlEventTypeScalar); + yamlEventNextCheck(yaml, yamlEventTypeSeqBegin); - allowRangeVal = yamlEventNext(yaml); - } - while (allowRangeVal.type != yamlEventTypeSeqEnd); -} + YamlEvent allowRangeMinVal = yamlEventNextCheck(yaml, yamlEventTypeScalar); + YamlEvent allowRangeMaxVal = yamlEventNextCheck(yaml, yamlEventTypeScalar); -// Helper to parse command roles -static void -bldCfgParseCommandRole(Yaml *const yaml) -{ - yamlEventNextCheck(yaml, yamlEventTypeMapBegin); - - YamlEvent commandRoleVal = yamlEventNext(yaml); - - if (commandRoleVal.type != yamlEventTypeMapEnd) - { - do + MEM_CONTEXT_PRIOR_BEGIN() { - yamlEventCheck(commandRoleVal, yamlEventTypeScalar); - yamlEventNextCheck(yaml, yamlEventTypeMapBegin); - yamlEventNextCheck(yaml, yamlEventTypeMapEnd); - - commandRoleVal = yamlEventNext(yaml); + opt->allowRangeMin = strDup(allowRangeMinVal.value); + opt->allowRangeMax = strDup(allowRangeMaxVal.value); } - while (commandRoleVal.type != yamlEventTypeMapEnd); + MEM_CONTEXT_PRIOR_END(); + + yamlEventNextCheck(yaml, yamlEventTypeSeqEnd); } + MEM_CONTEXT_TEMP_END(); } // Helper to parse depend -static void -bldCfgParseDepend(Yaml *const yaml) +static const BldCfgOptionDependRaw * +bldCfgParseDepend(Yaml *const yaml, const List *const optList) { - YamlEvent dependVal = yamlEventNext(yaml); + const BldCfgOptionDependRaw *result = NULL; - if (dependVal.type == yamlEventTypeMapBegin) + MEM_CONTEXT_TEMP_BEGIN() { - YamlEvent dependDef = yamlEventNext(yaml); + YamlEvent dependVal = yamlEventNext(yaml); - do + if (dependVal.type == yamlEventTypeMapBegin) { - yamlEventCheck(dependDef, yamlEventTypeScalar); + YamlEvent dependDef = yamlEventNext(yaml); + BldCfgOptionDependRaw optDependRaw = {0}; - if (strEqZ(dependDef.value, "list")) + do { - yamlEventNextCheck(yaml, yamlEventTypeSeqBegin); + yamlEventCheck(dependDef, yamlEventTypeScalar); - YamlEvent dependDefVal = yamlEventNext(yaml); - - do + if (strEqZ(dependDef.value, "list")) { - yamlEventCheck(dependDefVal, yamlEventTypeScalar); - dependDefVal = yamlEventNext(yaml); - } - while (dependDefVal.type != yamlEventTypeSeqEnd); - } - else - { - YamlEvent dependDefVal = yamlEventNext(yaml); - yamlEventCheck(dependDefVal, yamlEventTypeScalar); + yamlEventNextCheck(yaml, yamlEventTypeSeqBegin); + YamlEvent dependDefVal = yamlEventNext(yaml); - if (strEqZ(dependDef.value, "option")) - { + StringList *const valueList = strLstNew(); + + do + { + yamlEventCheck(dependDefVal, yamlEventTypeScalar); + + strLstAdd(valueList, dependDefVal.value); + + dependDefVal = yamlEventNext(yaml); + } + while (dependDefVal.type != yamlEventTypeSeqEnd); + + optDependRaw.valueList = valueList; } else - THROW_FMT(FormatError, "unknown depend definition '%s'", strZ(dependDef.value)); - } + { + YamlEvent dependDefVal = yamlEventNext(yaml); + yamlEventCheck(dependDefVal, yamlEventTypeScalar); - dependDef = yamlEventNext(yaml); + if (strEqZ(dependDef.value, "option")) + { + optDependRaw.option = dependDefVal.value; + } + else + THROW_FMT(FormatError, "unknown depend definition '%s'", strZ(dependDef.value)); + } + + dependDef = yamlEventNext(yaml); + } + while (dependDef.type != yamlEventTypeMapEnd); + + MEM_CONTEXT_PRIOR_BEGIN() + { + BldCfgOptionDependRaw *optDepend = memNew(sizeof(BldCfgOptionDependRaw)); + + *optDepend = (BldCfgOptionDependRaw) + { + .option = strDup(optDependRaw.option), + .valueList = strLstDup(optDependRaw.valueList) + }; + + result = optDepend; + } + MEM_CONTEXT_PRIOR_END(); + } + else + { + // Else depend is inherited + CHECK(optList != NULL); + yamlEventCheck(dependVal, yamlEventTypeScalar); + + const BldCfgOptionRaw *const optInherit = lstFind(optList, &dependVal.value); + + if (optInherit == NULL) + THROW_FMT(FormatError, "dependency inherited from option '%s' before it is defined", strZ(dependVal.value)); + + result = optInherit->depend; } - while (dependDef.type != yamlEventTypeMapEnd); } - else - yamlEventCheck(dependVal, yamlEventTypeScalar); + MEM_CONTEXT_TEMP_END(); + + return result; + +} + +// Helper to reconcile depend +static const BldCfgOptionDepend * +bldCfgParseDependReconcile(const BldCfgOptionDependRaw *const optDependRaw, const List *const optList) +{ + BldCfgOptionDepend *result = NULL; + + if (optDependRaw != NULL) + { + const BldCfgOption *const optDepend = lstFind(optList, &optDependRaw->option); + + if (optDepend == NULL) + THROW_FMT(FormatError, "dependency on undefined option '%s'", strZ(optDependRaw->option)); + + result = memNew(sizeof(BldCfgOptionDepend)); + + memcpy( + result, + &(BldCfgOptionDepend){.option = optDepend, .valueList = strLstDup(optDependRaw->valueList)}, + sizeof(BldCfgOptionDepend)); + } + + return result; } // Helper to parse deprecate -static void +static List * bldCfgParseOptionDeprecate(Yaml *const yaml) { - yamlEventNextCheck(yaml, yamlEventTypeMapBegin); + List *result = lstNewP(sizeof(BldCfgOptionCommandRaw), .comparator = lstComparatorStr); - YamlEvent optDeprecate = yamlEventNext(yaml); - - do + MEM_CONTEXT_TEMP_BEGIN() { - yamlEventCheck(optDeprecate, yamlEventTypeScalar); yamlEventNextCheck(yaml, yamlEventTypeMapBegin); - - YamlEvent optDeprecateDef = yamlEventNext(yaml); - - if (optDeprecateDef.type == yamlEventTypeScalar) - { - do - { - yamlEventCheck(optDeprecateDef, yamlEventTypeScalar); - yamlEventNextCheck(yaml, yamlEventTypeScalar); - - if (strEqZ(optDeprecateDef.value, "index")) - { - } - else if (strEqZ(optDeprecateDef.value, "reset")) - { - } - else - THROW_FMT(FormatError, "unknown deprecate definition '%s'", strZ(optDeprecateDef.value)); - - optDeprecateDef = yamlEventNext(yaml); - } - while (optDeprecateDef.type != yamlEventTypeMapEnd); - } - else - yamlEventCheck(optDeprecateDef, yamlEventTypeMapEnd); - - optDeprecate = yamlEventNext(yaml); - } - while (optDeprecate.type != yamlEventTypeMapEnd); -} - -// Helper to parse commands -static const List * -bldCfgParseOptionCommand(Yaml *const yaml, const List *const optList) -{ - YamlEvent optCmdVal = yamlEventNext(yaml); - - // If command list is defined - if (optCmdVal.type == yamlEventTypeMapBegin) - { - List *result = lstNewP(sizeof(BldCfgOptionCommand), .comparator = lstComparatorStr); - - YamlEvent optCmd = yamlEventNext(yaml); + YamlEvent optDeprecate = yamlEventNext(yaml); do { - yamlEventCheck(optCmd, yamlEventTypeScalar); - BldCfgOptionCommand optCmdData = {.name = optCmd.value}; + yamlEventCheck(optDeprecate, yamlEventTypeScalar); + BldCfgOptionDeprecateRaw optDeprecateRaw = {.name = optDeprecate.value, .reset = true}; yamlEventNextCheck(yaml, yamlEventTypeMapBegin); - YamlEvent optCmdDef = yamlEventNext(yaml); - if (optCmdDef.type == yamlEventTypeScalar) + YamlEvent optDeprecateDef = yamlEventNext(yaml); + + if (optDeprecateDef.type == yamlEventTypeScalar) { do { - yamlEventCheck(optCmdDef, yamlEventTypeScalar); + yamlEventCheck(optDeprecateDef, yamlEventTypeScalar); + YamlEvent optDeprecateDefVal = yamlEventNextCheck(yaml, yamlEventTypeScalar); - if (strEqZ(optCmdDef.value, "allow-list")) + if (strEqZ(optDeprecateDef.value, "index")) { - optCmdData.allowList = bldCfgParseAllowList(yaml, NULL); + optDeprecateRaw.index = cvtZToUInt(strZ(optDeprecateDefVal.value)); } - else if (strEqZ(optCmdDef.value, "command-role")) + else if (strEqZ(optDeprecateDef.value, "reset")) { - bldCfgParseCommandRole(yaml); - } - else if (strEqZ(optCmdDef.value, "depend")) - { - bldCfgParseDepend(yaml); + optDeprecateRaw.reset = yamlBoolParse(optDeprecateDefVal); } else - { - yamlEventNextCheck(yaml, yamlEventTypeScalar); + THROW_FMT(FormatError, "unknown deprecate definition '%s'", strZ(optDeprecateDef.value)); - if (strEqZ(optCmdDef.value, "default")) - { - } - else if (strEqZ(optCmdDef.value, "internal")) - { - } - else if (strEqZ(optCmdDef.value, "required")) - { - } - else - THROW_FMT(FormatError, "unknown option command definition '%s'", strZ(optCmdDef.value)); - } - - optCmdDef = yamlEventNext(yaml); + optDeprecateDef = yamlEventNext(yaml); } - while (optCmdDef.type != yamlEventTypeMapEnd); + while (optDeprecateDef.type != yamlEventTypeMapEnd); } else - yamlEventCheck(optCmdDef, yamlEventTypeMapEnd); + yamlEventCheck(optDeprecateDef, yamlEventTypeMapEnd); - lstAdd(result, &optCmdData); + MEM_CONTEXT_PRIOR_BEGIN() + { + lstAdd( + result, + &(BldCfgOptionDeprecate) + { + .name = strDup(optDeprecateRaw.name), + .index = optDeprecateRaw.index, + .reset = optDeprecateRaw.reset, + }); + } + MEM_CONTEXT_PRIOR_END(); - optCmd = yamlEventNext(yaml); + optDeprecate = yamlEventNext(yaml); } - while (optCmd.type != yamlEventTypeMapEnd); + while (optDeprecate.type != yamlEventTypeMapEnd); lstSort(result, sortOrderAsc); - - return result; } + MEM_CONTEXT_TEMP_END(); - // Else command list is inherited - CHECK(optList != NULL); - yamlEventCheck(optCmdVal, yamlEventTypeScalar); - - const BldCfgOption *const optInherit = lstFind(optList, &optCmdVal.value); - CHECK(optInherit != NULL); - - return optInherit->cmdList; + return result; } +// Helper to reconcile deprecate +static List * +bldCfgParseOptionDeprecateReconcile(const List *const optDeprecateRawList) +{ + List *result = NULL; + + if (optDeprecateRawList != NULL) + { + result = lstNewP(sizeof(BldCfgOptionDeprecate), .comparator = lstComparatorStr); + + for (unsigned int optDeprecateRawIdx = 0; optDeprecateRawIdx < lstSize(optDeprecateRawList); optDeprecateRawIdx++) + { + const BldCfgOptionDeprecateRaw *const optDeprecateRaw = lstGet(optDeprecateRawList, optDeprecateRawIdx); + + lstAdd( + result, + &(BldCfgOptionDeprecate) + { + .name = strDup(optDeprecateRaw->name), + .index = optDeprecateRaw->index, + .reset = optDeprecateRaw->reset, + }); + } + } + + return result; +} + +// Helper to parse the option command list +static const List * +bldCfgParseOptionCommandList(Yaml *const yaml, const List *const optList) +{ + const List *result = NULL; + + MEM_CONTEXT_TEMP_BEGIN() + { + YamlEvent optCmdVal = yamlEventNext(yaml); + + // If command list is defined + if (optCmdVal.type == yamlEventTypeMapBegin) + { + List *const optCmdRawList = lstNewP(sizeof(BldCfgOptionCommandRaw), .comparator = lstComparatorStr); + + YamlEvent optCmd = yamlEventNext(yaml); + + do + { + yamlEventCheck(optCmd, yamlEventTypeScalar); + BldCfgOptionCommandRaw optCmdRaw = {.name = optCmd.value}; + + yamlEventNextCheck(yaml, yamlEventTypeMapBegin); + YamlEvent optCmdDef = yamlEventNext(yaml); + + if (optCmdDef.type == yamlEventTypeScalar) + { + do + { + yamlEventCheck(optCmdDef, yamlEventTypeScalar); + + if (strEqZ(optCmdDef.value, "allow-list")) + { + optCmdRaw.allowList = bldCfgParseAllowList(yaml, NULL); + } + else if (strEqZ(optCmdDef.value, "command-role")) + { + optCmdRaw.roleList = bldCfgParseCommandRole(yaml); + } + else if (strEqZ(optCmdDef.value, "depend")) + { + MEM_CONTEXT_BEGIN(lstMemContext(optCmdRawList)) + { + optCmdRaw.depend = bldCfgParseDepend(yaml, optList); + } + MEM_CONTEXT_END(); + } + else + { + YamlEvent optCmdDefVal = yamlEventNextCheck(yaml, yamlEventTypeScalar); + + if (strEqZ(optCmdDef.value, "default")) + { + // If an override to inheritance + if (strEqZ(optCmdDefVal.value, "~")) + { + optCmdRaw.defaultValue = NULL; + } + // Else set the value + else + optCmdRaw.defaultValue = optCmdDefVal.value; + } + else if (strEqZ(optCmdDef.value, "internal")) + { + } + else if (strEqZ(optCmdDef.value, "required")) + { + optCmdRaw.required = varNewBool(yamlBoolParse(optCmdDefVal)); + } + else + THROW_FMT(FormatError, "unknown option command definition '%s'", strZ(optCmdDef.value)); + } + + optCmdDef = yamlEventNext(yaml); + } + while (optCmdDef.type != yamlEventTypeMapEnd); + } + else + yamlEventCheck(optCmdDef, yamlEventTypeMapEnd); + + MEM_CONTEXT_BEGIN(lstMemContext(optCmdRawList)) + { + lstAdd( + optCmdRawList, + &(BldCfgOptionCommandRaw) + { + .name = strDup(optCmdRaw.name), + .required = varDup(optCmdRaw.required), + .defaultValue = strDup(optCmdRaw.defaultValue), + .depend = optCmdRaw.depend, + .allowList = strLstDup(optCmdRaw.allowList), + .roleList = strLstDup(optCmdRaw.roleList), + }); + } + MEM_CONTEXT_END(); + + optCmd = yamlEventNext(yaml); + } + while (optCmd.type != yamlEventTypeMapEnd); + + lstSort(optCmdRawList, sortOrderAsc); + + result = lstMove(optCmdRawList, memContextPrior()); + } + // Else command list is inherited + else + { + CHECK(optList != NULL); + yamlEventCheck(optCmdVal, yamlEventTypeScalar); + + const BldCfgOptionRaw *const optInherit = lstFind(optList, &optCmdVal.value); + CHECK(optInherit != NULL); + + result = optInherit->cmdList; + } + } + MEM_CONTEXT_TEMP_END(); + + return result; +} + +static List * +bldCfgParseOptionList(Yaml *const yaml, const List *const cmdList, const List *const optGrpList) +{ + List *const result = lstNewP(sizeof(BldCfgOption), .comparator = lstComparatorStr); + + MEM_CONTEXT_TEMP_BEGIN() + { + List *const optListRaw = lstNewP(sizeof(BldCfgOptionRaw), .comparator = lstComparatorStr); + + // Parse raw + // ------------------------------------------------------------------------------------------------------------------------- + yamlEventNextCheck(yaml, yamlEventTypeScalar); + yamlEventNextCheck(yaml, yamlEventTypeMapBegin); + + YamlEvent opt = yamlEventNext(yaml); + + do + { + yamlEventCheck(opt, yamlEventTypeScalar); + BldCfgOptionRaw optRaw = {.name = opt.value, .required = BOOL_TRUE_VAR}; + bool inheritFound = false; + + yamlEventNextCheck(yaml, yamlEventTypeMapBegin); + + YamlEvent optDef = yamlEventNext(yaml); + + do + { + yamlEventCheck(optDef, yamlEventTypeScalar); + + if (strEqZ(optDef.value, "allow-list")) + { + optRaw.allowList = bldCfgParseAllowList(yaml, optListRaw); + } + else if (strEqZ(optDef.value, "allow-range")) + { + bldCfgParseAllowRange(yaml, &optRaw); + } + else if (strEqZ(optDef.value, "command")) + { + optRaw.cmdList = bldCfgParseOptionCommandList(yaml, optListRaw); + } + else if (strEqZ(optDef.value, "command-role")) + { + optRaw.cmdRoleList = bldCfgParseCommandRole(yaml); + } + else if (strEqZ(optDef.value, "depend")) + { + optRaw.depend = bldCfgParseDepend(yaml, optListRaw); + } + else if (strEqZ(optDef.value, "deprecate")) + { + optRaw.deprecateList = bldCfgParseOptionDeprecate(yaml); + } + else + { + YamlEvent optDefVal = yamlEventNextCheck(yaml, yamlEventTypeScalar); + + if (strEqZ(optDef.value, "default")) + { + // If an override to inheritance + if (strEqZ(optDefVal.value, "~")) + { + optRaw.defaultValue = NULL; + } + // Else set the value + else + optRaw.defaultValue = optDefVal.value; + } + else if (strEqZ(optDef.value, "default-literal")) + { + optRaw.defaultLiteral = yamlBoolParse(optDefVal); + } + else if (strEqZ(optDef.value, "group")) + { + optRaw.group = optDefVal.value; + + if (!lstExists(optGrpList, &optRaw.group)) + THROW_FMT(FormatError, "option '%s' has invalid group '%s'", strZ(optRaw.name), strZ(optRaw.group)); + } + else if (strEqZ(optDef.value, "inherit")) + { + const BldCfgOptionRaw *const optInherit = lstFind(optListRaw, &optDefVal.value); + CHECK(optInherit != NULL); + + optRaw = *optInherit; + optRaw.name = opt.value; + + // Deprecations cannot be inherited + optRaw.deprecateList = NULL; + + inheritFound = true; + } + else if (strEqZ(optDef.value, "internal")) + { + } + else if (strEqZ(optDef.value, "negate")) + { + optRaw.negate = varNewBool(yamlBoolParse(optDefVal)); + } + else if (strEqZ(optDef.value, "required")) + { + optRaw.required = varNewBool(yamlBoolParse(optDefVal)); + } + else if (strEqZ(optDef.value, "section")) + { + optRaw.section = optDefVal.value; + } + else if (strEqZ(optDef.value, "secure")) + { + optRaw.secure = yamlBoolParse(optDefVal); + } + else if (strEqZ(optDef.value, "type")) + { + optRaw.type = optDefVal.value; + } + else + THROW_FMT(FormatError, "unknown option definition '%s'", strZ(optDef.value)); + } + + optDef = yamlEventNext(yaml); + } + while (optDef.type != yamlEventTypeMapEnd); + + // Type is required + if (optRaw.type == NULL) + THROW_FMT(FormatError, "option '%s' requires 'type'", strZ(optRaw.name)); + + // Set defaults if not inherited + if (!inheritFound) + { + // Section defaults to command line + if (optRaw.section == NULL) + optRaw.section = SECTION_COMMAND_LINE_STR; + + // Set negate default if not defined + if (optRaw.negate == NULL) + { + optRaw.negate = varNewBool( + strEq(optRaw.type, OPT_TYPE_BOOLEAN_STR) && !strEq(optRaw.section, SECTION_COMMAND_LINE_STR)); + } + + // Build default command list if not defined + if (optRaw.cmdList == NULL) + { + List *optCmdList = lstNewP(sizeof(BldCfgOptionCommandRaw), .comparator = lstComparatorStr); + + for (unsigned int cmdIdx = 0; cmdIdx < lstSize(cmdList); cmdIdx++) + { + const BldCfgCommand *const cmd = lstGet(cmdList, cmdIdx); + + if (!strEq(cmd->name, CMD_HELP_STR) && !strEq(cmd->name, CMD_VERSION_STR)) + lstAdd(optCmdList, &(BldCfgOptionCommandRaw){.name = cmd->name}); + } + + lstSort(optCmdList, sortOrderAsc); + optRaw.cmdList = optCmdList; + } + } + + // Set reset + optRaw.reset = !strEq(optRaw.section, SECTION_COMMAND_LINE_STR); + + lstAdd(optListRaw, &optRaw); + + opt = yamlEventNext(yaml); + } + while (opt.type != yamlEventTypeMapEnd); + + lstSort(optListRaw, sortOrderAsc); + + // Copy option list to result + // ------------------------------------------------------------------------------------------------------------------------- + for (unsigned int optRawIdx = 0; optRawIdx < lstSize(optListRaw); optRawIdx++) + { + const BldCfgOptionRaw *const optRaw = lstGet(optListRaw, optRawIdx); + + MEM_CONTEXT_BEGIN(lstMemContext(result)) + { + lstAdd( + result, + &(BldCfgOption) + { + .name = strDup(optRaw->name), + .type = strDup(optRaw->type), + .section = strDup(optRaw->section), + .required = varBool(optRaw->required), + .negate = varBool(optRaw->negate), + .reset = optRaw->reset, + .defaultValue = strDup(optRaw->defaultValue), + .defaultLiteral = optRaw->defaultLiteral, + .group = strDup(optRaw->group), + .secure = optRaw->secure, + .allowList = strLstDup(optRaw->allowList), + .allowRangeMin = strDup(optRaw->allowRangeMin), + .allowRangeMax = strDup(optRaw->allowRangeMax), + .cmdRoleList = strLstDup(optRaw->cmdRoleList), // Is this used? + .deprecateList = bldCfgParseOptionDeprecateReconcile(optRaw->deprecateList), + }); + } + MEM_CONTEXT_END(); + } + + // Reconcile option list + // ------------------------------------------------------------------------------------------------------------------------- + for (unsigned int optRawIdx = 0; optRawIdx < lstSize(optListRaw); optRawIdx++) + { + const BldCfgOptionRaw *const optRaw = lstGet(optListRaw, optRawIdx); + + // Reconcile option command list roles + List *const cmdOptList = lstNewP(sizeof(BldCfgOptionCommand), .comparator = lstComparatorStr); + + for (unsigned int optCmdRawIdx = 0; optCmdRawIdx < lstSize(optRaw->cmdList); optCmdRawIdx++) + { + BldCfgOptionCommandRaw optCmd = *(BldCfgOptionCommandRaw *)lstGet(optRaw->cmdList, optCmdRawIdx); + + // Lookup command + const BldCfgCommand *const cmd = lstFind(cmdList, &optCmd.name); + + if (cmd == NULL) + { + THROW_FMT( + FormatError, "invalid command '%s' in option '%s' command list", strZ(optCmd.name), strZ(optRaw->name)); + } + + // Default required to option required if not defined + if (optCmd.required == NULL) + optCmd.required = optRaw->required; + + // Default command role list if not defined + if (optCmd.roleList == NULL) + { + // Use option list as default if defined. It will need to be filtered against roles valid for each command + if (optRaw->cmdRoleList != NULL) + { + StringList *const roleList = strLstNew(); + + for (unsigned int cmdRoleIdx = 0; cmdRoleIdx < strLstSize(optRaw->cmdRoleList); cmdRoleIdx++) + { + const String *role = strLstGet(optRaw->cmdRoleList, cmdRoleIdx); + + if (strLstExists(cmd->roleList, role)) + strLstAdd(roleList, role); + } + + optCmd.roleList = roleList; + } + // Else use option command list + else + optCmd.roleList = cmd->roleList; + } + + CHECK(optCmd.roleList != NULL); + + MEM_CONTEXT_BEGIN(lstMemContext(cmdOptList)) + { + lstAdd( + cmdOptList, + &(BldCfgOptionCommand) + { + .name = strDup(optCmd.name), + .required = varBool(optCmd.required), + .defaultValue = strDup(optCmd.defaultValue), + .depend = bldCfgParseDependReconcile(optCmd.depend, result), + .allowList = strLstDup(optCmd.allowList), + .roleList = strLstDup(optCmd.roleList), + }); + } + MEM_CONTEXT_END(); + } + + const BldCfgOption *const opt = lstGet(result, optRawIdx); + CHECK(strEq(opt->name, optRaw->name)); + + // Assigning to const pointers this way is definitely cheating, but since we allocated the memory and know exactly where + // it is so this is the easiest way to avoid a lot of indirection due to the dependency of BldCfgOptionDepend on + // BldCfgOption. This would be completely unacceptable in production code but feels OK in this context. + MEM_CONTEXT_BEGIN(lstMemContext(result)) + { + *((List **)&opt->cmdList) = lstMove(cmdOptList, memContextCurrent()); + *((const BldCfgOptionDepend **)&opt->depend) = bldCfgParseDependReconcile(optRaw->depend, result); + } + MEM_CONTEXT_END(); + } + } + MEM_CONTEXT_TEMP_END(); + + return result; +} + +/*********************************************************************************************************************************** +Build option resolve order list +***********************************************************************************************************************************/ +static List * +bldCfgParseOptionResolveList(const List *const optList) +{ + List *const result = lstNewP(sizeof(BldCfgOption *), .comparator = lstComparatorStr); + + // The stanza option will always be resolved first since errors can be confusing when it is missing. That means it must exist + // and cannot have any depedencies. + // ----------------------------------------------------------------------------------------------------------------------------- + const BldCfgOption *const optStanza = lstFind(optList, &OPT_STANZA_STR); + + if (optStanza == NULL) + THROW(FormatError, "option '" OPT_STANZA "' must exist"); + + if (optStanza->depend != NULL) + THROW(FormatError, "option '" OPT_STANZA "' may not depend on other option"); + + for (unsigned int optCmdIdx = 0; optCmdIdx < lstSize(optStanza->cmdList); optCmdIdx++) + { + const BldCfgOptionCommand *const optStanzaCmd = lstGet(optStanza->cmdList, optCmdIdx); + + if (optStanzaCmd->depend != NULL) + THROW_FMT(FormatError, "option '" OPT_STANZA "' command '%s' may not depend on other option", strZ(optStanzaCmd->name)); + } + + // Determine resolve order + // ----------------------------------------------------------------------------------------------------------------------------- + StringList *const optResolveList = strLstNew(); + strLstAdd(optResolveList, OPT_STANZA_STR); + + do + { + // Was at least one option resolved in the loop? + bool resolved = false; + + for (unsigned int optIdx = 0; optIdx < lstSize(optList); optIdx++) + { + const BldCfgOption *const opt = lstGet(optList, optIdx); + + // If the option has already been resolved then continue + if (strLstExists(optResolveList, opt->name)) + continue; + + // If the option dependency has not been resolved then continue + if (opt->depend != NULL && !strLstExists(optResolveList, opt->depend->option->name)) + continue; + + // If the option command dependency has not been resolved then continue + unsigned int optCmdIdx = 0; + + for (; optCmdIdx < lstSize(opt->cmdList); optCmdIdx++) + { + const BldCfgOptionCommand *const optCmd = lstGet(opt->cmdList, optCmdIdx); + + if (optCmd->depend != NULL && !strLstExists(optResolveList, optCmd->depend->option->name)) + break; + } + + if (optCmdIdx < lstSize(opt->cmdList)) + continue; + + // Option dependencies have been resolved + strLstAdd(optResolveList, opt->name); + resolved = true; + } + + // If nothing was resolved in the loop then there may be a circular reference + if (!resolved) + { + // Find the options that were not resolved + StringList *const unresolvedList = strLstNew(); + + for (unsigned int optIdx = 0; optIdx < lstSize(optList); optIdx++) + { + const BldCfgOption *const opt = lstGet(optList, optIdx); + + if (!strLstExists(optResolveList, opt->name)) + strLstAdd(unresolvedList, opt->name); + } + + THROW_FMT( + FormatError, + "unable to resolve dependencies for option(s) '%s'\n" + "HINT: are there circular dependencies?", + strZ(strLstJoin(unresolvedList, ", "))); + } + } + while (strLstSize(optResolveList) != lstSize(optList)); + + // Copy resolved list + for (unsigned int optResolveIdx = 0; optResolveIdx < strLstSize(optResolveList); optResolveIdx++) + { + const String *const optName = strLstGet(optResolveList, optResolveIdx); + const BldCfgOption *const opt = lstFind(optList, &optName); + lstAdd(result, &opt); + } + + return result; +} + +/**********************************************************************************************************************************/ BldCfg bldCfgParse(const Storage *const storageRepo) { - BldCfg result = - { - .commandList = lstNewP(sizeof(BldCfgCommand), .comparator = lstComparatorStr), - .optGrpList = lstNewP(sizeof(BldCfgOptionGroup), .comparator = lstComparatorStr), - .optList = lstNewP(sizeof(BldCfgOption), .comparator = lstComparatorStr), - }; - // Initialize yaml Yaml *const yaml = yamlNew(storageGetP(storageNewReadP(storageRepo, STRDEF("src/build/config/config.yaml")))); yamlEventNextCheck(yaml, yamlEventTypeMapBegin); - // Parse commands - // ----------------------------------------------------------------------------------------------------------------------------- - yamlEventNextCheck(yaml, yamlEventTypeScalar); - yamlEventNextCheck(yaml, yamlEventTypeMapBegin); + // Parse configuration + const List *const cmdList = bldCfgParseCommandList(yaml); + const List *const optGrpList = bldCfgParseOptionGroupList(yaml); + const List *const optList = bldCfgParseOptionList(yaml, cmdList, optGrpList); + const List *const optResolveList = bldCfgParseOptionResolveList(optList); - YamlEvent cmd = yamlEventNext(yaml); - - do - { - yamlEventCheck(cmd, yamlEventTypeScalar); - - BldCfgCommand cmdData = - { - .name = cmd.value, - .logFile = true, - .logLevelDefault = strNewZ("info"), - .lockType = strNewZ("none"), - }; - - yamlEventNextCheck(yaml, yamlEventTypeMapBegin); - - YamlEvent cmdDef = yamlEventNext(yaml); - - if (cmdDef.type == yamlEventTypeScalar) - { - do - { - yamlEventCheck(cmdDef, yamlEventTypeScalar); - - if (strEqZ(cmdDef.value, "command-role")) - { - bldCfgParseCommandRole(yaml); - } - else - { - YamlEvent cmdDefVal = yamlEventNextCheck(yaml, yamlEventTypeScalar); - - if (strEqZ(cmdDef.value, "internal")) - { - } - else if (strEqZ(cmdDef.value, "lock-type")) - { - cmdData.lockType = cmdDefVal.value; - } - else if (strEqZ(cmdDef.value, "lock-remote-required")) - { - cmdData.lockRemoteRequired = yamlBoolParse(cmdDefVal); - } - else if (strEqZ(cmdDef.value, "lock-required")) - { - cmdData.lockRequired = yamlBoolParse(cmdDefVal); - } - else if (strEqZ(cmdDef.value, "log-file")) - { - cmdData.logFile = yamlBoolParse(cmdDefVal); - } - else if (strEqZ(cmdDef.value, "log-level-default")) - { - cmdData.logLevelDefault = strLower(strDup(cmdDefVal.value)); - } - else if (strEqZ(cmdDef.value, "parameter-allowed")) - { - } - else - THROW_FMT(FormatError, "unknown command definition '%s'", strZ(cmdDef.value)); - } - - cmdDef = yamlEventNext(yaml); - } - while (cmdDef.type != yamlEventTypeMapEnd); - } - else - yamlEventCheck(cmdDef, yamlEventTypeMapEnd); - - lstAdd(result.commandList, &cmdData); - - cmd = yamlEventNext(yaml); - } - while (cmd.type != yamlEventTypeMapEnd); - - lstSort(result.commandList, sortOrderAsc); - - // Parse option groups - // ----------------------------------------------------------------------------------------------------------------------------- - yamlEventNextCheck(yaml, yamlEventTypeScalar); - yamlEventNextCheck(yaml, yamlEventTypeMapBegin); - - YamlEvent optGrp = yamlEventNext(yaml); - - do - { - yamlEventCheck(optGrp, yamlEventTypeScalar); - BldCfgOptionGroup optGrpData = {.name = optGrp.value}; - - yamlEventNextCheck(yaml, yamlEventTypeMapBegin); - - YamlEvent optGrpDef = yamlEventNext(yaml); - - do - { - yamlEventCheck(optGrpDef, yamlEventTypeScalar); - yamlEventNextCheck(yaml, yamlEventTypeScalar); - - if (strEqZ(optGrpDef.value, "indexTotal")) - { - } - else if (strEqZ(optGrpDef.value, "prefix")) - { - } - else - THROW_FMT(FormatError, "unknown option group definition '%s'", strZ(optGrpDef.value)); - - optGrpDef = yamlEventNext(yaml); - } - while (optGrpDef.type != yamlEventTypeMapEnd); - - lstAdd(result.optGrpList, &optGrpData); - - optGrp = yamlEventNext(yaml); - } - while (optGrp.type != yamlEventTypeMapEnd); - - lstSort(result.optGrpList, sortOrderAsc); - - // Parse options - // ----------------------------------------------------------------------------------------------------------------------------- - yamlEventNextCheck(yaml, yamlEventTypeScalar); - yamlEventNextCheck(yaml, yamlEventTypeMapBegin); - - YamlEvent opt = yamlEventNext(yaml); - - do - { - yamlEventCheck(opt, yamlEventTypeScalar); - BldCfgOption optData = {.name = opt.value}; - - yamlEventNextCheck(yaml, yamlEventTypeMapBegin); - - YamlEvent optDef = yamlEventNext(yaml); - - do - { - yamlEventCheck(optDef, yamlEventTypeScalar); - - if (strEqZ(optDef.value, "allow-list")) - { - optData.allowList = bldCfgParseAllowList(yaml, result.optList); - } - else if (strEqZ(optDef.value, "allow-range")) - { - bldCfgParseAllowRange(yaml); - } - else if (strEqZ(optDef.value, "command")) - { - optData.cmdList = bldCfgParseOptionCommand(yaml, result.optList); - } - else if (strEqZ(optDef.value, "command-role")) - { - bldCfgParseCommandRole(yaml); - } - else if (strEqZ(optDef.value, "depend")) - { - bldCfgParseDepend(yaml); - } - else if (strEqZ(optDef.value, "deprecate")) - { - bldCfgParseOptionDeprecate(yaml); - } - else - { - YamlEvent optDefVal = yamlEventNextCheck(yaml, yamlEventTypeScalar); - - if (strEqZ(optDef.value, "default")) - { - } - else if (strEqZ(optDef.value, "default-literal")) - { - } - else if (strEqZ(optDef.value, "group")) - { - optData.group = optDefVal.value; - } - else if (strEqZ(optDef.value, "inherit")) - { - const BldCfgOption *const optInherit = lstFind(result.optList, &optDefVal.value); - CHECK(optInherit != NULL); - - optData = *optInherit; - optData.name = opt.value; - } - else if (strEqZ(optDef.value, "internal")) - { - } - else if (strEqZ(optDef.value, "negate")) - { - } - else if (strEqZ(optDef.value, "required")) - { - } - else if (strEqZ(optDef.value, "section")) - { - } - else if (strEqZ(optDef.value, "secure")) - { - } - else if (strEqZ(optDef.value, "type")) - { - optData.type = optDefVal.value; - } - else - THROW_FMT(FormatError, "unknown option definition '%s'", strZ(optDef.value)); - } - - optDef = yamlEventNext(yaml); - } - while (optDef.type != yamlEventTypeMapEnd); - - lstAdd(result.optList, &optData); - - opt = yamlEventNext(yaml); - } - while (opt.type != yamlEventTypeMapEnd); - - lstSort(result.optList, sortOrderAsc); - - return result; + return (BldCfg){.cmdList = cmdList, .optGrpList = optGrpList, .optList = optList, .optResolveList = optResolveList}; } diff --git a/src/build/config/parse.h b/src/build/config/parse.h index 2968f8d5d..deacd45f5 100644 --- a/src/build/config/parse.h +++ b/src/build/config/parse.h @@ -4,44 +4,131 @@ Parse Configuration Yaml #ifndef BUILD_CONFIG_PARSE_H #define BUILD_CONFIG_PARSE_H +#include "common/type/stringList.h" + +/*********************************************************************************************************************************** +Command role constants +***********************************************************************************************************************************/ +#define CMD_ROLE_ASYNC "async" + STRING_DECLARE(CMD_ROLE_ASYNC_STR); +#define CMD_ROLE_LOCAL "local" + STRING_DECLARE(CMD_ROLE_LOCAL_STR); +#define CMD_ROLE_MAIN "main" + STRING_DECLARE(CMD_ROLE_MAIN_STR); +#define CMD_ROLE_REMOTE "remote" + STRING_DECLARE(CMD_ROLE_REMOTE_STR); + +/*********************************************************************************************************************************** +Command constants +***********************************************************************************************************************************/ +#define CMD_HELP "help" + STRING_DECLARE(CMD_HELP_STR); +#define CMD_VERSION "version" + STRING_DECLARE(CMD_VERSION_STR); + +/*********************************************************************************************************************************** +Option type constants +***********************************************************************************************************************************/ +#define OPT_TYPE_BOOLEAN "boolean" + STRING_DECLARE(OPT_TYPE_BOOLEAN_STR); +#define OPT_TYPE_HASH "hash" + STRING_DECLARE(OPT_TYPE_HASH_STR); +#define OPT_TYPE_LIST "list" + STRING_DECLARE(OPT_TYPE_LIST_STR); +#define OPT_TYPE_STRING "string" + STRING_DECLARE(OPT_TYPE_STRING_STR); +#define OPT_TYPE_TIME "time" + STRING_DECLARE(OPT_TYPE_TIME_STR); + +/*********************************************************************************************************************************** +Option constants +***********************************************************************************************************************************/ +#define OPT_STANZA "stanza" + STRING_DECLARE(OPT_STANZA_STR); + +/*********************************************************************************************************************************** +Section constants +***********************************************************************************************************************************/ +#define SECTION_COMMAND_LINE "command-line" + STRING_DECLARE(SECTION_COMMAND_LINE_STR); +#define SECTION_GLOBAL "global" + STRING_DECLARE(SECTION_GLOBAL_STR); +#define SECTION_STANZA "stanza" + STRING_DECLARE(SECTION_STANZA_STR); + /*********************************************************************************************************************************** Types ***********************************************************************************************************************************/ typedef struct BldCfgCommand { - const String *name; // Name - bool logFile; // Does the command write automatically to a log file? - const String *logLevelDefault; // Default log level - bool lockRequired; // Is a lock required - bool lockRemoteRequired; // Is a remote lock required? - const String *lockType; // Lock type + const String *const name; // Name + const bool logFile; // Does the command write automatically to a log file? + const String *const logLevelDefault; // Default log level + const bool lockRequired; // Is a lock required + const bool lockRemoteRequired; // Is a remote lock required? + const String *const lockType; // Lock type + const bool parameterAllowed; // Are command line parameters allowed? + const StringList *const roleList; // Roles valid for the command } BldCfgCommand; typedef struct BldCfgOptionGroup { - const String *name; // Name + const String *const name; // Name + const unsigned int indexTotal; // Total indexes for option } BldCfgOptionGroup; +typedef struct BldCfgOption BldCfgOption; // Forward declaration + +typedef struct BldCfgOptionDepend +{ + const BldCfgOption *const option; // Option dependency is on + const StringList *const valueList; // Allowed value list +} BldCfgOptionDepend; + +typedef struct BldCfgOptionDeprecate +{ + const String *const name; // Deprecated option name + const unsigned int index; // Option index to deprecate + const bool reset; // Does the deprecated option allow reset +} BldCfgOptionDeprecate; + typedef struct BldCfgOptionCommand { - const String *name; // Name - const StringList *allowList; // Allowed value list + const String *const name; // Name + const bool required; // Is the option required? + const String *const defaultValue; // Default value, if any + const BldCfgOptionDepend *const depend; // Dependency, if any + const StringList *const allowList; // Allowed value list + const StringList *const roleList; // Roles valid for the command } BldCfgOptionCommand; -typedef struct BldCfgOption +struct BldCfgOption { - const String *name; // Name - const String *type; // Option type, e.g. integer - const String *group; // Option group, if any - const StringList *allowList; // Allowed value list - const List *cmdList; // Command override list -} BldCfgOption; + const String *const name; // Name + const String *const type; // Option type, e.g. integer + const String *const section; // Option section, i.e. stanza or global + const bool required; // Is the option required? + const bool negate; // Can the option be negated? + const bool reset; // Can the option be reset? + const String *const defaultValue; // Default value, if any + const bool defaultLiteral; // Should default be interpreted literally, i.e. not a string + const String *const group; // Option group, if any + const bool secure; // Does the option contain a secret? + const BldCfgOptionDepend *const depend; // Dependency, if any + const StringList *const allowList; // Allowed value list + const String *const allowRangeMin; // Allow range min, if any + const String *const allowRangeMax; // Allow range max, if any + const List *const cmdList; // Command override list + const StringList *const cmdRoleList; // Roles valid for the option + const List *const deprecateList; // List of option deprecations +}; typedef struct BldCfg { - List *commandList; // Command list - List *optGrpList; // Option group list - List *optList; // Option list + const List *const cmdList; // Command list + const List *const optGrpList; // Option group list + const List *const optList; // Option list + const List *const optResolveList; // Option list in resolved dependency order } BldCfg; /*********************************************************************************************************************************** diff --git a/src/build/config/render.c b/src/build/config/render.c index 900b35570..ca1c9bcd0 100644 --- a/src/build/config/render.c +++ b/src/build/config/render.c @@ -73,18 +73,20 @@ bldEnumOpt(const String *const value) return bldEnum("cfgOpt", value); } -/**********************************************************************************************************************************/ -void -bldCfgRender(const Storage *const storageRepo, const BldCfg bldCfg) +/*********************************************************************************************************************************** +Render config.auto.h +***********************************************************************************************************************************/ +#define CONFIG_MODULE "config" +#define CONFIG_AUTO_COMMENT "Command and Option Configuration" + +static void +bldCfgRenderConfigAutoH(const Storage *const storageRepo, const BldCfg bldCfg) { - // Build Header - // ----------------------------------------------------------------------------------------------------------------------------- - const String *const header = bldHeader("config", "Command and Option Configuration"); String *config = strNewFmt( "%s" "#ifndef CONFIG_CONFIG_AUTO_H\n" "#define CONFIG_CONFIG_AUTO_H\n", - strZ(header)); + strZ(bldHeader(CONFIG_MODULE, CONFIG_AUTO_COMMENT))); // Command constants // ----------------------------------------------------------------------------------------------------------------------------- @@ -95,18 +97,14 @@ bldCfgRender(const Storage *const storageRepo, const BldCfg bldCfg) "Command constants\n" COMMENT_BLOCK_END "\n"); - unsigned int cmdTotal = 0; - - for (unsigned int cmdIdx = 0; cmdIdx < lstSize(bldCfg.commandList); cmdIdx++) + for (unsigned int cmdIdx = 0; cmdIdx < lstSize(bldCfg.cmdList); cmdIdx++) { - const BldCfgCommand *const cmd = lstGet(bldCfg.commandList, cmdIdx); + const BldCfgCommand *const cmd = lstGet(bldCfg.cmdList, cmdIdx); strCatFmt(config, "%s\n", strZ(bldDefineRender(bldConst("CFGCMD", cmd->name), strNewFmt("\"%s\"", strZ(cmd->name))))); - - cmdTotal++; } - strCatFmt(config, "\n%s\n", strZ(bldDefineRender(STRDEF("CFG_COMMAND_TOTAL"), strNewFmt("%u", cmdTotal)))); + strCatFmt(config, "\n%s\n", strZ(bldDefineRender(STRDEF("CFG_COMMAND_TOTAL"), strNewFmt("%u", lstSize(bldCfg.cmdList))))); // Option group constants // ----------------------------------------------------------------------------------------------------------------------------- @@ -117,12 +115,7 @@ bldCfgRender(const Storage *const storageRepo, const BldCfg bldCfg) "Option group constants\n" COMMENT_BLOCK_END "\n"); - unsigned int optGrpTotal = 0; - - for (unsigned int optGrpIdx = 0; optGrpIdx < lstSize(bldCfg.optGrpList); optGrpIdx++) - optGrpTotal++; - - strCatFmt(config, "%s\n", strZ(bldDefineRender(STRDEF("CFG_OPTION_GROUP_TOTAL"), strNewFmt("%u", optGrpTotal)))); + strCatFmt(config, "%s\n", strZ(bldDefineRender(STRDEF("CFG_OPTION_GROUP_TOTAL"), strNewFmt("%u", lstSize(bldCfg.optGrpList))))); // Option constants // ----------------------------------------------------------------------------------------------------------------------------- @@ -133,19 +126,15 @@ bldCfgRender(const Storage *const storageRepo, const BldCfg bldCfg) "Option constants\n" COMMENT_BLOCK_END "\n"); - unsigned int optTotal = 0; - for (unsigned int optIdx = 0; optIdx < lstSize(bldCfg.optList); optIdx++) { const BldCfgOption *const opt = lstGet(bldCfg.optList, optIdx); if (opt->group == NULL) strCatFmt(config, "%s\n", strZ(bldDefineRender(bldConst("CFGOPT", opt->name), strNewFmt("\"%s\"", strZ(opt->name))))); - - optTotal++; } - strCatFmt(config, "\n%s\n", strZ(bldDefineRender(STRDEF("CFG_OPTION_TOTAL"), strNewFmt("%u", optTotal)))); + strCatFmt(config, "\n%s\n", strZ(bldDefineRender(STRDEF("CFG_OPTION_TOTAL"), strNewFmt("%u", lstSize(bldCfg.optList))))); // Option value constants // ----------------------------------------------------------------------------------------------------------------------------- @@ -172,17 +161,14 @@ bldCfgRender(const Storage *const storageRepo, const BldCfg bldCfg) strLstAddIfMissing(allowList, strLstGet(opt->allowList, allowListIdx)); } - if (opt->cmdList != NULL) + for (unsigned int optCmdListIdx = 0; optCmdListIdx < lstSize(opt->cmdList); optCmdListIdx++) { - for (unsigned int optCmdListIdx = 0; optCmdListIdx < lstSize(opt->cmdList); optCmdListIdx++) - { - BldCfgOptionCommand *optCmd = lstGet(opt->cmdList, optCmdListIdx); + BldCfgOptionCommand *optCmd = lstGet(opt->cmdList, optCmdListIdx); - if (optCmd->allowList != NULL) - { - for (unsigned int allowListIdx = 0; allowListIdx < strLstSize(optCmd->allowList); allowListIdx++) - strLstAddIfMissing(allowList, strLstGet(optCmd->allowList, allowListIdx)); - } + if (optCmd->allowList != NULL) + { + for (unsigned int allowListIdx = 0; allowListIdx < strLstSize(optCmd->allowList); allowListIdx++) + strLstAddIfMissing(allowList, strLstGet(optCmd->allowList, allowListIdx)); } } @@ -224,9 +210,9 @@ bldCfgRender(const Storage *const storageRepo, const BldCfg bldCfg) "typedef enum\n" "{\n"); - for (unsigned int cmdIdx = 0; cmdIdx < lstSize(bldCfg.commandList); cmdIdx++) + for (unsigned int cmdIdx = 0; cmdIdx < lstSize(bldCfg.cmdList); cmdIdx++) { - const BldCfgCommand *const cmd = lstGet(bldCfg.commandList, cmdIdx); + const BldCfgCommand *const cmd = lstGet(bldCfg.cmdList, cmdIdx); strCatFmt(config, " %s,\n", strZ(bldEnumCmd(cmd->name))); } @@ -288,22 +274,30 @@ bldCfgRender(const Storage *const storageRepo, const BldCfg bldCfg) "#endif\n"); bldPut(storageRepo, "src/config/config.auto.h", BUFSTR(config)); +} - // Build C +/*********************************************************************************************************************************** +Render config.auto.c +***********************************************************************************************************************************/ +static void +bldCfgRenderConfigAutoC(const Storage *const storageRepo, const BldCfg bldCfg) +{ + String *const config = bldHeader(CONFIG_MODULE, CONFIG_AUTO_COMMENT); + + // Command data // ----------------------------------------------------------------------------------------------------------------------------- - config = strNewFmt( - "%s" + strCatZ( + config, "\n" COMMENT_BLOCK_BEGIN "\n" "Command data\n" COMMENT_BLOCK_END "\n" "static const ConfigCommandData configCommandData[CFG_COMMAND_TOTAL] = CONFIG_COMMAND_LIST\n" - "(\n", - strZ(header)); + "(\n"); - for (unsigned int cmdIdx = 0; cmdIdx < lstSize(bldCfg.commandList); cmdIdx++) + for (unsigned int cmdIdx = 0; cmdIdx < lstSize(bldCfg.cmdList); cmdIdx++) { - const BldCfgCommand *const cmd = lstGet(bldCfg.commandList, cmdIdx); + const BldCfgCommand *const cmd = lstGet(bldCfg.cmdList, cmdIdx); if (cmdIdx != 0) strCatZ(config, "\n"); @@ -328,5 +322,571 @@ bldCfgRender(const Storage *const storageRepo, const BldCfg bldCfg) config, ")\n"); + // Write to storage + // ----------------------------------------------------------------------------------------------------------------------------- bldPut(storageRepo, "src/config/config.auto.c", BUFSTR(config)); } + +/*********************************************************************************************************************************** +Render parse.auto.c +***********************************************************************************************************************************/ +#define PARSE_AUTO_COMMENT "Config Parse Rules" + +static void +bldCfgRenderLf(String *const config, const bool lf) +{ + if (lf) + strCatZ(config, "\n"); +} + +static const String * +bldCfgRenderValue(const String *const type, const String *const value) +{ + // Translate boolean values + if (strEq(type, OPT_TYPE_BOOLEAN_STR)) + { + if (strEq(value, FALSE_STR)) + return ZERO_STR; + + CHECK(strEq(value, TRUE_STR)); + return strNewZ("1"); + } + // Translate time values + else if (strEq(type, OPT_TYPE_TIME_STR)) + return strNewFmt("%" PRId64, (int64_t)(cvtZToDouble(strZ(value)) * 1000)); + + return value; +} + +// Helper to render allow list +static bool +bldCfgRenderAllowList(String *const config, const StringList *const allowList, const bool command) +{ + if (allowList != NULL) + { + const char *indent = command ? " " : " "; + + strCatFmt( + config, + "%sPARSE_RULE_OPTION_OPTIONAL_ALLOW_LIST\n" + "%s(\n", + indent, indent); + + for (unsigned int allowIdx = 0; allowIdx < strLstSize(allowList); allowIdx++) + { + strCatFmt( + config, + "%s \"%s\"%s\n", + indent, strZ(strLstGet(allowList, allowIdx)), + allowIdx < strLstSize(allowList) - 1 ? "," : ""); + } + + strCatFmt(config, "%s),\n", indent); + + return true; + } + + return false; +} + +// Helper to render default +static bool +bldCfgRenderDefault( + String *const config, const String *const type, const String *const defaultValue, + const bool defaultLiteral, const bool command, bool multi) +{ + if (defaultValue != NULL) + { + const char *indent = command ? " " : " "; + + bldCfgRenderLf(config, multi); + + strCatFmt( + config, + "%sPARSE_RULE_OPTION_OPTIONAL_DEFAULT(%s%s%s),\n", + indent, defaultLiteral ? "" : "\"", strZ(bldCfgRenderValue(type, defaultValue)), defaultLiteral ? "" : "\""); + + return false; + } + + return multi; +} + +// Helper to render depend +static bool +bldCfgRenderDepend(String *const config, const BldCfgOptionDepend *const depend, const bool command, const bool multi) +{ + if (depend != NULL) + { + const char *indent = command ? " " : " "; + + bldCfgRenderLf(config, multi); + + if (depend->valueList != NULL) + { + strCatFmt( + config, + "%sPARSE_RULE_OPTION_OPTIONAL_DEPEND_LIST\n" + "%s(\n" + "%s %s,\n", + indent, indent, indent, strZ(bldEnum("cfgOpt", depend->option->name))); + + for (unsigned int valueIdx = 0; valueIdx < strLstSize(depend->valueList); valueIdx++) + { + strCatFmt( + config, "%s \"%s\"%s\n", indent, + strZ(bldCfgRenderValue(depend->option->type, strLstGet(depend->valueList, valueIdx))), + valueIdx < strLstSize(depend->valueList) - 1 ? "," : ""); + } + + strCatFmt(config, "%s),\n", indent); + + return true; + } + else + { + strCatFmt( + config, + "%sPARSE_RULE_OPTION_OPTIONAL_DEPEND(%s),\n", + indent, strZ(bldEnum("cfgOpt", depend->option->name))); + + return false; + } + } + + return multi; +} + +static void +bldCfgRenderParseAutoC(const Storage *const storageRepo, const BldCfg bldCfg) +{ + String *const config = bldHeader(CONFIG_MODULE, PARSE_AUTO_COMMENT); + + // Command parse rules + // ----------------------------------------------------------------------------------------------------------------------------- + strCatFmt( + config, + "\n" + COMMENT_BLOCK_BEGIN "\n" + "Command parse data\n" + COMMENT_BLOCK_END "\n" + "static const ParseRuleCommand parseRuleCommand[CFG_COMMAND_TOTAL] =\n" + "{\n"); + + for (unsigned int cmdIdx = 0; cmdIdx < lstSize(bldCfg.cmdList); cmdIdx++) + { + const BldCfgCommand *const cmd = lstGet(bldCfg.cmdList, cmdIdx); + + bldCfgRenderLf(config, cmdIdx != 0); + + strCatFmt( + config, + COMMENT_SEPARATOR "\n" + " PARSE_RULE_COMMAND\n" + " (\n" + " PARSE_RULE_COMMAND_NAME(\"%s\"),\n", + strZ(cmd->name)); + + if (cmd->parameterAllowed) + strCatZ(config, " PARSE_RULE_COMMAND_PARAMETER_ALLOWED(true),\n"); + + strCatFmt( + config, + "\n" + " PARSE_RULE_COMMAND_ROLE_VALID_LIST\n" + " (\n"); + + for (unsigned int cmdRoleIdx = 0; cmdRoleIdx < strLstSize(cmd->roleList); cmdRoleIdx++) + { + strCatFmt( + config, + " PARSE_RULE_COMMAND_ROLE(%s)\n", + strZ(bldEnum("cfgCmdRole", strLstGet(cmd->roleList, cmdRoleIdx)))); + } + + strCatZ( + config, + " ),\n" + " ),\n"); + } + + strCatZ( + config, + "};\n"); + + // Option group rules + // ----------------------------------------------------------------------------------------------------------------------------- + strCatFmt( + config, + "\n" + COMMENT_BLOCK_BEGIN "\n" + "Option group parse data\n" + COMMENT_BLOCK_END "\n" + "static const ParseRuleOptionGroup parseRuleOptionGroup[CFG_OPTION_GROUP_TOTAL] =\n" + "{\n"); + + for (unsigned int optGrpIdx = 0; optGrpIdx < lstSize(bldCfg.optGrpList); optGrpIdx++) + { + const BldCfgOptionGroup *const optGrp = lstGet(bldCfg.optGrpList, optGrpIdx); + + bldCfgRenderLf(config, optGrpIdx != 0); + + strCatFmt( + config, + COMMENT_SEPARATOR "\n" + " PARSE_RULE_OPTION_GROUP\n" + " (\n" + " PARSE_RULE_OPTION_GROUP_NAME(\"%s\"),\n" + " ),\n", + strZ(optGrp->name)); + } + + strCatZ( + config, + "};\n"); + + // Option rules + // ----------------------------------------------------------------------------------------------------------------------------- + strCatFmt( + config, + "\n" + COMMENT_BLOCK_BEGIN "\n" + "Option parse data\n" + COMMENT_BLOCK_END "\n" + "static const ParseRuleOption parseRuleOption[CFG_OPTION_TOTAL] =\n" + "{\n"); + + StringList *const cmdRoleAllList = strLstNew(); + strLstAdd(cmdRoleAllList, CMD_ROLE_MAIN_STR); + strLstAdd(cmdRoleAllList, CMD_ROLE_ASYNC_STR); + strLstAdd(cmdRoleAllList, CMD_ROLE_LOCAL_STR); + strLstAdd(cmdRoleAllList, CMD_ROLE_REMOTE_STR); + + for (unsigned int optIdx = 0; optIdx < lstSize(bldCfg.optList); optIdx++) + { + const BldCfgOption *const opt = lstGet(bldCfg.optList, optIdx); + + bldCfgRenderLf(config, optIdx != 0); + + strCatFmt( + config, + COMMENT_SEPARATOR "\n" + " PARSE_RULE_OPTION\n" + " (\n" + " PARSE_RULE_OPTION_NAME(\"%s\"),\n" + " PARSE_RULE_OPTION_TYPE(%s),\n" + " PARSE_RULE_OPTION_REQUIRED(%s),\n" + " PARSE_RULE_OPTION_SECTION(%s),\n", + strZ(opt->name), strZ(bldEnum("cfgOptType", opt->type)), cvtBoolToConstZ(opt->required), + strZ(bldEnum("cfgSection", opt->section))); + + if (opt->secure) + strCatZ(config, " PARSE_RULE_OPTION_SECURE(true),\n"); + + if (strEq(opt->type, OPT_TYPE_HASH_STR) || strEq(opt->type, OPT_TYPE_LIST_STR)) + strCatZ(config, " PARSE_RULE_OPTION_MULTI(true),\n"); + + if (opt->group != NULL) + { + strCatFmt( + config, + " PARSE_RULE_OPTION_GROUP_MEMBER(true),\n" + " PARSE_RULE_OPTION_GROUP_ID(%s),\n", + strZ(bldEnum("cfgOptGrp", opt->group))); + } + + // Build command role valid lists + for (unsigned int cmdRoleAllIdx = 0; cmdRoleAllIdx < strLstSize(cmdRoleAllList); cmdRoleAllIdx++) + { + String *const configRole = strNew(); + + const String *const cmdRole = strLstGet(cmdRoleAllList, cmdRoleAllIdx); + + for (unsigned int optCmdIdx = 0; optCmdIdx < lstSize(opt->cmdList); optCmdIdx++) + { + BldCfgOptionCommand *const optCmd = lstGet(opt->cmdList, optCmdIdx); + + if (strLstExists(optCmd->roleList, cmdRole)) + { + strCatFmt( + configRole, + " PARSE_RULE_OPTION_COMMAND(%s)\n", strZ(bldEnum("cfgCmd", optCmd->name))); + } + } + + if (!strEmpty(configRole)) + { + strCatFmt( + config, + "\n" + " PARSE_RULE_OPTION_COMMAND_ROLE_%s_VALID_LIST\n" + " (\n" + "%s" + " ),\n", + strZ(strUpper(strDup(cmdRole))), strZ(configRole)); + } + } + + // Build optional data + String *const configOptional = strNew(); + + if (opt->allowRangeMin != NULL) + { + CHECK(opt->allowRangeMax != NULL); + + const String *allowRangeMin = opt->allowRangeMin; + const String *allowRangeMax = opt->allowRangeMax; + + if (strEq(opt->type, OPT_TYPE_TIME_STR)) + { + allowRangeMin = strNewFmt("%" PRId64, (int64_t)(cvtZToDouble(strZ(allowRangeMin)) * 1000)); + allowRangeMax = strNewFmt("%" PRId64, (int64_t)(cvtZToDouble(strZ(allowRangeMax)) * 1000)); + } + + strCatFmt( + configOptional, + " PARSE_RULE_OPTION_OPTIONAL_ALLOW_RANGE(%s, %s),\n", + strZ(allowRangeMin), strZ(allowRangeMax)); + } + + bool multi = bldCfgRenderAllowList(configOptional, opt->allowList, false); + multi = bldCfgRenderDepend(configOptional, opt->depend, false, multi); + multi = bldCfgRenderDefault(configOptional, opt->type, opt->defaultValue, opt->defaultLiteral, false, multi); + + // Build optional data for commands + for (unsigned int optCmdIdx = 0; optCmdIdx < lstSize(opt->cmdList); optCmdIdx++) + { + BldCfgOptionCommand *const optCmd = lstGet(opt->cmdList, optCmdIdx); + String *const configCommand = strNew(); + + bool multi = bldCfgRenderAllowList(configCommand, optCmd->allowList, true); + multi = bldCfgRenderDepend(configCommand, optCmd->depend, true, multi); + multi = bldCfgRenderDefault(configCommand, opt->type, optCmd->defaultValue, false, true, multi); + + if (optCmd->required != opt->required) + { + bldCfgRenderLf(configCommand, multi); + + strCatFmt( + configCommand, + " PARSE_RULE_OPTION_OPTIONAL_REQUIRED(%s),\n", + cvtBoolToConstZ(optCmd->required)); + } + + if (!strEmpty(configCommand)) + { + bldCfgRenderLf(configOptional, !strEmpty(configOptional)); + + strCatFmt( + configOptional, + " PARSE_RULE_OPTION_OPTIONAL_COMMAND_OVERRIDE\n" + " (\n" + " PARSE_RULE_OPTION_OPTIONAL_COMMAND(%s),\n" + "\n" + "%s" + " )\n", + strZ(bldEnum("cfgCmd", optCmd->name)), strZ(configCommand)); + } + } + + // Add optional data + if (!strEmpty(configOptional)) + { + strCatFmt( + config, + "\n" + " PARSE_RULE_OPTION_OPTIONAL_LIST\n" + " (\n" + "%s" + " ),\n", + strZ(configOptional)); + } + + strCatZ(config, " ),\n"); + } + + strCatZ( + config, + "};\n"); + + // Option data for getopt_long() + // ----------------------------------------------------------------------------------------------------------------------------- + strCatFmt( + config, + "\n" + COMMENT_BLOCK_BEGIN "\n" + "Option data for getopt_long()\n" + COMMENT_BLOCK_END "\n" + "static const struct option optionList[] =\n" + "{\n"); + + for (unsigned int optIdx = 0; optIdx < lstSize(bldCfg.optList); optIdx++) + { + const BldCfgOption *const opt = lstGet(bldCfg.optList, optIdx); + + // Determine if the option is indexed + unsigned int indexTotal = 1; + const BldCfgOptionGroup *optGrp = NULL; + + if (opt->group != NULL) + { + optGrp = lstFind(bldCfg.optGrpList, &opt->group); + CHECK(optGrp != NULL); + + indexTotal = optGrp->indexTotal; + } + + bldCfgRenderLf(config, optIdx != 0); + + strCatFmt( + config, + " // %s option%s\n" + COMMENT_SEPARATOR "\n", + strZ(opt->name), opt->deprecateList != NULL ? " and deprecations" : ""); + + for (unsigned int index = 0; index < indexTotal; index++) + { + const String *optName = opt->name; + const String *optShift = EMPTY_STR; + + // Generate indexed name + if (optGrp != NULL) + { + optName = strNewFmt("%s%u%s", strZ(optGrp->name), index + 1, strZ(strSub(optName, strSize(optGrp->name)))); + optShift = strNewFmt(" | (%u << PARSE_KEY_IDX_SHIFT)", index); + } + + strCatFmt( + config, + " {\n" + " .name = \"%s\",\n" + "%s" + " .val = PARSE_OPTION_FLAG%s | %s,\n" + " },\n", + strZ(optName), + strEq(opt->type, OPT_TYPE_BOOLEAN_STR) ? "" : " .has_arg = required_argument,\n", strZ(optShift), + strZ(bldEnum("cfgOpt", opt->name))); + + if (opt->negate) + { + strCatFmt( + config, + " {\n" + " .name = \"no-%s\",\n" + " .val = PARSE_OPTION_FLAG | PARSE_NEGATE_FLAG%s | %s,\n" + " },\n", + strZ(optName), strZ(optShift), strZ(bldEnum("cfgOpt", opt->name))); + } + + if (opt->reset) + { + strCatFmt( + config, + " {\n" + " .name = \"reset-%s\",\n" + " .val = PARSE_OPTION_FLAG | PARSE_RESET_FLAG%s | %s,\n" + " },\n", + strZ(optName), strZ(optShift), strZ(bldEnum("cfgOpt", opt->name))); + } + + if (opt->deprecateList != 0) + { + for (unsigned int deprecateIdx = 0; deprecateIdx < lstSize(opt->deprecateList); deprecateIdx++) + { + const BldCfgOptionDeprecate *const deprecate = lstGet(opt->deprecateList, deprecateIdx); + const String *deprecateName = deprecate->name; + + // Skip the deprecation if it does not apply to this index + if (deprecate->index > 0 && deprecate->index != index + 1) + continue; + + // Generate name if deprecation applies to all indexes + int deprecateIndexPos = strChr(deprecateName, '?'); + + if (deprecateIndexPos != -1) + { + CHECK(optGrp != NULL); + + deprecateName = strNewFmt( + "%s%u%s", strZ(strSubN(deprecateName, 0, (size_t)deprecateIndexPos)), index + 1, + strZ(strSub(deprecateName, (size_t)deprecateIndexPos + 1))); + } + + strCatFmt( + config, + " {\n" + " .name = \"%s\",\n" + "%s" + " .val = PARSE_OPTION_FLAG | PARSE_DEPRECATE_FLAG%s | %s,\n" + " },\n", + strZ(deprecateName), + strEq(opt->type, OPT_TYPE_BOOLEAN_STR) ? "" : " .has_arg = required_argument,\n", strZ(optShift), + strZ(bldEnum("cfgOpt", opt->name))); + + if (opt->negate) + { + strCatFmt( + config, + " {\n" + " .name = \"no-%s\",\n" + " .val = PARSE_OPTION_FLAG | PARSE_DEPRECATE_FLAG | PARSE_NEGATE_FLAG%s | %s,\n" + " },\n", + strZ(deprecateName), strZ(optShift), strZ(bldEnum("cfgOpt", opt->name))); + } + + if (opt->reset && deprecate->reset) + { + strCatFmt( + config, + " {\n" + " .name = \"reset-%s\",\n" + " .val = PARSE_OPTION_FLAG | PARSE_DEPRECATE_FLAG | PARSE_RESET_FLAG%s | %s,\n" + " },\n", + strZ(deprecateName), strZ(optShift), strZ(bldEnum("cfgOpt", opt->name))); + } + } + } + } + } + + strCatZ( + config, + " // Terminate option list\n" + " {\n" + " .name = NULL\n" + " }\n" + "};\n"); + + // Order for option parse resolution + // ----------------------------------------------------------------------------------------------------------------------------- + strCatFmt( + config, + "\n" + COMMENT_BLOCK_BEGIN "\n" + "Order for option parse resolution\n" + COMMENT_BLOCK_END "\n" + "static const ConfigOption optionResolveOrder[] =\n" + "{\n"); + + // Render resolve order + for (unsigned int optResolveIdx = 0; optResolveIdx < lstSize(bldCfg.optResolveList); optResolveIdx++) + { + strCatFmt( + config, " %s,\n", strZ(bldEnum("cfgOpt", (*(BldCfgOption **)lstGet(bldCfg.optResolveList, optResolveIdx))->name))); + } + + strCatZ(config, "};\n"); + + // Write to storage + // ----------------------------------------------------------------------------------------------------------------------------- + bldPut(storageRepo, "src/config/parse.auto.c", BUFSTR(config)); +} + +/**********************************************************************************************************************************/ +void +bldCfgRender(const Storage *const storageRepo, const BldCfg bldCfg) +{ + bldCfgRenderConfigAutoH(storageRepo, bldCfg); + bldCfgRenderConfigAutoC(storageRepo, bldCfg); + bldCfgRenderParseAutoC(storageRepo, bldCfg); +} diff --git a/src/config/parse.auto.c b/src/config/parse.auto.c index aa1ad2c2e..72e73f62e 100644 --- a/src/config/parse.auto.c +++ b/src/config/parse.auto.c @@ -1,7 +1,7 @@ /*********************************************************************************************************************************** Config Parse Rules -Automatically generated by Build.pm -- do not modify directly. +Automatically generated by 'make build-config' -- do not modify directly. ***********************************************************************************************************************************/ /*********************************************************************************************************************************** diff --git a/test/code-count/file-type.yaml b/test/code-count/file-type.yaml index 76f567a50..a8fff444c 100644 --- a/test/code-count/file-type.yaml +++ b/test/code-count/file-type.yaml @@ -11,18 +11,10 @@ build/lib/pgBackRestBuild/Build/Common.pm: class: build type: perl -build/lib/pgBackRestBuild/Config/Build.pm: - class: build - type: perl - build/lib/pgBackRestBuild/Config/BuildHelp.pm: class: build type: perl -build/lib/pgBackRestBuild/Config/BuildParse.pm: - class: build - type: perl - build/lib/pgBackRestBuild/Config/Data.pm: class: build type: perl diff --git a/test/src/module/build/configTest.c b/test/src/module/build/configTest.c index 60bcb241d..62ee51665 100644 --- a/test/src/module/build/configTest.c +++ b/test/src/module/build/configTest.c @@ -46,10 +46,19 @@ testRun(void) TEST_ERROR(bldCfgParse(storageTest), FormatError, "unknown option group definition 'bogus'"); + HRN_STORAGE_PUT_Z( + storageTest, "src/build/config/config.yaml", + TEST_COMMAND_VALID + "optionGroup:\n" + " repo: \n" + " prefix: test\n"); + + TEST_ERROR(bldCfgParse(storageTest), FormatError, "option group 'repo' requires 'indexTotal'"); + #define TEST_OPTION_GROUP_VALID \ "optionGroup:\n" \ " repo:\n" \ - " prefix: repo\n" \ + " indexTotal: 2\n" \ "\n" // ------------------------------------------------------------------------------------------------------------------------- @@ -65,6 +74,16 @@ testRun(void) TEST_ERROR(bldCfgParse(storageTest), FormatError, "unknown option definition 'bogus'"); + HRN_STORAGE_PUT_Z( + storageTest, "src/build/config/config.yaml", + TEST_COMMAND_VALID + TEST_OPTION_GROUP_VALID + "option:\n" + " config:\n" + " section: global\n"); + + TEST_ERROR(bldCfgParse(storageTest), FormatError, "option 'config' requires 'type'"); + HRN_STORAGE_PUT_Z( storageTest, "src/build/config/config.yaml", TEST_COMMAND_VALID @@ -99,6 +118,112 @@ testRun(void) TEST_ERROR(bldCfgParse(storageTest), FormatError, "unknown option command definition 'bogus'"); + HRN_STORAGE_PUT_Z( + storageTest, "src/build/config/config.yaml", + TEST_COMMAND_VALID + TEST_OPTION_GROUP_VALID + "option:\n" + " config:\n" + " depend: bogus\n"); + + TEST_ERROR(bldCfgParse(storageTest), FormatError, "dependency inherited from option 'bogus' before it is defined"); + + HRN_STORAGE_PUT_Z( + storageTest, "src/build/config/config.yaml", + TEST_COMMAND_VALID + TEST_OPTION_GROUP_VALID + "option:\n" + " config:\n" + " type: string\n" + " command:\n" + " bogus: {}\n"); + + TEST_ERROR(bldCfgParse(storageTest), FormatError, "invalid command 'bogus' in option 'config' command list"); + + HRN_STORAGE_PUT_Z( + storageTest, "src/build/config/config.yaml", + TEST_COMMAND_VALID + TEST_OPTION_GROUP_VALID + "option:\n" + " config:\n" + " type: string\n" + " depend:\n" + " option: bogus\n"); + + TEST_ERROR(bldCfgParse(storageTest), FormatError, "dependency on undefined option 'bogus'"); + + HRN_STORAGE_PUT_Z( + storageTest, "src/build/config/config.yaml", + TEST_COMMAND_VALID + TEST_OPTION_GROUP_VALID + "option:\n" + " config:\n" + " type: string\n" + " group: bogus\n"); + + TEST_ERROR(bldCfgParse(storageTest), FormatError, "option 'config' has invalid group 'bogus'"); + + HRN_STORAGE_PUT_Z( + storageTest, "src/build/config/config.yaml", + TEST_COMMAND_VALID + TEST_OPTION_GROUP_VALID + "option:\n" + " stanza:\n" + " type: string\n" + " config:\n" + " type: string\n" + " depend:\n" + " option: online\n" + " online:\n" + " type: boolean\n" + " depend:\n" + " option: config\n"); + + TEST_ERROR( + bldCfgParse(storageTest), FormatError, + "unable to resolve dependencies for option(s) 'config, online'\n" + "HINT: are there circular dependencies?"); + + HRN_STORAGE_PUT_Z( + storageTest, "src/build/config/config.yaml", + TEST_COMMAND_VALID + TEST_OPTION_GROUP_VALID + "option:\n" + " config:\n" + " type: string\n"); + + TEST_ERROR(bldCfgParse(storageTest), FormatError, "option 'stanza' must exist"); + + HRN_STORAGE_PUT_Z( + storageTest, "src/build/config/config.yaml", + TEST_COMMAND_VALID + TEST_OPTION_GROUP_VALID + "option:\n" + " config:\n" + " type: string\n" + " stanza:\n" + " type: string\n" + " depend:\n" + " option: config\n"); + + TEST_ERROR(bldCfgParse(storageTest), FormatError, "option 'stanza' may not depend on other option"); + + HRN_STORAGE_PUT_Z( + storageTest, "src/build/config/config.yaml", + TEST_COMMAND_VALID + TEST_OPTION_GROUP_VALID + "option:\n" + " config:\n" + " type: string\n" + " stanza:\n" + " type: string\n" + " command:\n" + " archive-get:\n" + " depend:\n" + " option: config\n"); + + TEST_ERROR(bldCfgParse(storageTest), FormatError, "option 'stanza' command 'archive-get' may not depend on other option"); + // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("parse and render config"); @@ -126,19 +251,31 @@ testRun(void) "\n" " help: {}\n" "\n" + " version: {}\n" + "\n" "optionGroup:\n" " pg:\n" - " indexTotal: 8\n" + " indexTotal: 2\n" " prefix: pg\n" " repo:\n" - " indexTotal: 4\n" + " indexTotal: 2\n" " prefix: repo\n" "\n" "option:\n" + " timeout:\n" + " type: time\n" + " default: 10\n" + " allow-range: [5, 50]\n" + "\n" " compress-type:\n" " section: global\n" " type: string\n" " default: gz\n" + " command:\n" + " backup: {}\n" + " archive-get:\n" + " depend:\n" + " option: config\n" " command-role: {}\n" " deprecate:\n" " compress: {}\n" @@ -155,7 +292,7 @@ testRun(void) " inherit: compress-level\n" " internal: true\n" " secure: true\n" - " default: 3\n" + " default: ~\n" " depend:\n" " option: compress-type\n" " list:\n" @@ -166,7 +303,7 @@ testRun(void) " type: string\n" " default: CFGOPTDEF_CONFIG_PATH \"/\" PROJECT_CONFIG_FILE\n" " default-literal: true\n" - " negate: y\n" + " negate: true\n" "\n" " log-level-console:\n" " section: global\n" @@ -197,17 +334,53 @@ testRun(void) " - warn\n" " command-role:\n" " main: {}\n" + " help: {}\n" + " archive-get:\n" + " default: ~\n" + "\n" + " stanza:\n" + " type: list\n" + " command:\n" " archive-get: {}\n" + " backup: {}\n" + "\n" + " online:\n" + " type: boolean\n" + " default: true\n" + " command:\n" + " backup: {}\n" + " command-role:\n" + " main: {}\n" + " deprecate:\n" + " online-old: {}\n" + "\n" + " backup-standby:\n" + " section: global\n" + " type: boolean\n" + " default: false\n" + " depend:\n" + " option: online\n" + " command:\n" + " backup: {}\n" + " command-role:\n" + " async: {}\n" + " main: {}\n" + " deprecate:\n" + " backup-standby-old: {}\n" "\n" " pg-path:\n" + " section: stanza\n" " group: pg\n" - " type: path\n" + " type: hash\n" " deprecate:\n" " db-path: {index: 1, reset: false}\n" " db?-path: {reset: false}\n"); TEST_RESULT_VOID(bldCfgRender(storageTest, bldCfgParse(storageTest)), "parse and render"); + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("check config.auto.h"); + TEST_STORAGE_GET( storageTest, "src/config/config.auto.h", @@ -225,8 +398,9 @@ testRun(void) "#define CFGCMD_ARCHIVE_GET \"archive-get\"\n" "#define CFGCMD_BACKUP \"backup\"\n" "#define CFGCMD_HELP \"help\"\n" + "#define CFGCMD_VERSION \"version\"\n" "\n" - "#define CFG_COMMAND_TOTAL 3\n" + "#define CFG_COMMAND_TOTAL 4\n" "\n" COMMENT_BLOCK_BEGIN "\n" "Option group constants\n" @@ -236,14 +410,18 @@ testRun(void) COMMENT_BLOCK_BEGIN "\n" "Option constants\n" COMMENT_BLOCK_END "\n" + "#define CFGOPT_BACKUP_STANDBY \"backup-standby\"\n" "#define CFGOPT_COMPRESS_LEVEL \"compress-level\"\n" "#define CFGOPT_COMPRESS_LEVEL_NETWORK \"compress-level-network\"\n" "#define CFGOPT_COMPRESS_TYPE \"compress-type\"\n" "#define CFGOPT_CONFIG \"config\"\n" "#define CFGOPT_LOG_LEVEL_CONSOLE \"log-level-console\"\n" "#define CFGOPT_LOG_LEVEL_FILE \"log-level-file\"\n" + "#define CFGOPT_ONLINE \"online\"\n" + "#define CFGOPT_STANZA \"stanza\"\n" + "#define CFGOPT_TIMEOUT \"timeout\"\n" "\n" - "#define CFG_OPTION_TOTAL 7\n" + "#define CFG_OPTION_TOTAL 11\n" "\n" COMMENT_BLOCK_BEGIN "\n" "Option value constants\n" @@ -274,6 +452,7 @@ testRun(void) " cfgCmdArchiveGet,\n" " cfgCmdBackup,\n" " cfgCmdHelp,\n" + " cfgCmdVersion,\n" " cfgCmdNone,\n" "} ConfigCommand;\n" "\n" @@ -291,17 +470,780 @@ testRun(void) COMMENT_BLOCK_END "\n" "typedef enum\n" "{\n" + " cfgOptBackupStandby,\n" " cfgOptCompressLevel,\n" " cfgOptCompressLevelNetwork,\n" " cfgOptCompressType,\n" " cfgOptConfig,\n" " cfgOptLogLevelConsole,\n" " cfgOptLogLevelFile,\n" + " cfgOptOnline,\n" " cfgOptPgPath,\n" + " cfgOptStanza,\n" + " cfgOptTimeout,\n" "} ConfigOption;\n" "\n" - "#endif\n" - ); + "#endif\n"); + + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("check config.auto.c"); + + TEST_STORAGE_GET( + storageTest, + "src/config/config.auto.c", + COMMENT_BLOCK_BEGIN "\n" + "Command and Option Configuration\n" + "\n" + "Automatically generated by 'make build-config' -- do not modify directly.\n" + COMMENT_BLOCK_END "\n" + "\n" + COMMENT_BLOCK_BEGIN "\n" + "Command data\n" + COMMENT_BLOCK_END "\n" + "static const ConfigCommandData configCommandData[CFG_COMMAND_TOTAL] = CONFIG_COMMAND_LIST\n" + "(\n" + " CONFIG_COMMAND\n" + " (\n" + " CONFIG_COMMAND_NAME(CFGCMD_ARCHIVE_GET)\n" + "\n" + " CONFIG_COMMAND_LOG_FILE(false)\n" + " CONFIG_COMMAND_LOG_LEVEL_DEFAULT(logLevelDebug)\n" + " CONFIG_COMMAND_LOCK_REQUIRED(false)\n" + " CONFIG_COMMAND_LOCK_REMOTE_REQUIRED(false)\n" + " CONFIG_COMMAND_LOCK_TYPE(lockTypeArchive)\n" + " )\n" + "\n" + " CONFIG_COMMAND\n" + " (\n" + " CONFIG_COMMAND_NAME(CFGCMD_BACKUP)\n" + "\n" + " CONFIG_COMMAND_LOG_FILE(true)\n" + " CONFIG_COMMAND_LOG_LEVEL_DEFAULT(logLevelInfo)\n" + " CONFIG_COMMAND_LOCK_REQUIRED(true)\n" + " CONFIG_COMMAND_LOCK_REMOTE_REQUIRED(true)\n" + " CONFIG_COMMAND_LOCK_TYPE(lockTypeBackup)\n" + " )\n" + "\n" + " CONFIG_COMMAND\n" + " (\n" + " CONFIG_COMMAND_NAME(CFGCMD_HELP)\n" + "\n" + " CONFIG_COMMAND_LOG_FILE(true)\n" + " CONFIG_COMMAND_LOG_LEVEL_DEFAULT(logLevelInfo)\n" + " CONFIG_COMMAND_LOCK_REQUIRED(false)\n" + " CONFIG_COMMAND_LOCK_REMOTE_REQUIRED(false)\n" + " CONFIG_COMMAND_LOCK_TYPE(lockTypeNone)\n" + " )\n" + "\n" + " CONFIG_COMMAND\n" + " (\n" + " CONFIG_COMMAND_NAME(CFGCMD_VERSION)\n" + "\n" + " CONFIG_COMMAND_LOG_FILE(true)\n" + " CONFIG_COMMAND_LOG_LEVEL_DEFAULT(logLevelInfo)\n" + " CONFIG_COMMAND_LOCK_REQUIRED(false)\n" + " CONFIG_COMMAND_LOCK_REMOTE_REQUIRED(false)\n" + " CONFIG_COMMAND_LOCK_TYPE(lockTypeNone)\n" + " )\n" + ")\n"); + + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("check parse.auto.c"); + + TEST_STORAGE_GET( + storageTest, + "src/config/parse.auto.c", + COMMENT_BLOCK_BEGIN "\n" + "Config Parse Rules\n" + "\n" + "Automatically generated by 'make build-config' -- do not modify directly.\n" + COMMENT_BLOCK_END "\n" + "\n" + COMMENT_BLOCK_BEGIN "\n" + "Command parse data\n" + COMMENT_BLOCK_END "\n" + "static const ParseRuleCommand parseRuleCommand[CFG_COMMAND_TOTAL] =\n" + "{\n" + COMMENT_SEPARATOR "\n" + " PARSE_RULE_COMMAND\n" + " (\n" + " PARSE_RULE_COMMAND_NAME(\"archive-get\"),\n" + " PARSE_RULE_COMMAND_PARAMETER_ALLOWED(true),\n" + "\n" + " PARSE_RULE_COMMAND_ROLE_VALID_LIST\n" + " (\n" + " PARSE_RULE_COMMAND_ROLE(cfgCmdRoleAsync)\n" + " PARSE_RULE_COMMAND_ROLE(cfgCmdRoleLocal)\n" + " PARSE_RULE_COMMAND_ROLE(cfgCmdRoleMain)\n" + " PARSE_RULE_COMMAND_ROLE(cfgCmdRoleRemote)\n" + " ),\n" + " ),\n" + "\n" + COMMENT_SEPARATOR "\n" + " PARSE_RULE_COMMAND\n" + " (\n" + " PARSE_RULE_COMMAND_NAME(\"backup\"),\n" + "\n" + " PARSE_RULE_COMMAND_ROLE_VALID_LIST\n" + " (\n" + " PARSE_RULE_COMMAND_ROLE(cfgCmdRoleLocal)\n" + " PARSE_RULE_COMMAND_ROLE(cfgCmdRoleMain)\n" + " PARSE_RULE_COMMAND_ROLE(cfgCmdRoleRemote)\n" + " ),\n" + " ),\n" + "\n" + COMMENT_SEPARATOR "\n" + " PARSE_RULE_COMMAND\n" + " (\n" + " PARSE_RULE_COMMAND_NAME(\"help\"),\n" + "\n" + " PARSE_RULE_COMMAND_ROLE_VALID_LIST\n" + " (\n" + " PARSE_RULE_COMMAND_ROLE(cfgCmdRoleMain)\n" + " ),\n" + " ),\n" + "\n" + COMMENT_SEPARATOR "\n" + " PARSE_RULE_COMMAND\n" + " (\n" + " PARSE_RULE_COMMAND_NAME(\"version\"),\n" + "\n" + " PARSE_RULE_COMMAND_ROLE_VALID_LIST\n" + " (\n" + " PARSE_RULE_COMMAND_ROLE(cfgCmdRoleMain)\n" + " ),\n" + " ),\n" + "};\n" + "\n" + COMMENT_BLOCK_BEGIN "\n" + "Option group parse data\n" + COMMENT_BLOCK_END "\n" + "static const ParseRuleOptionGroup parseRuleOptionGroup[CFG_OPTION_GROUP_TOTAL] =\n" + "{\n" + COMMENT_SEPARATOR "\n" + " PARSE_RULE_OPTION_GROUP\n" + " (\n" + " PARSE_RULE_OPTION_GROUP_NAME(\"pg\"),\n" + " ),\n" + "\n" + COMMENT_SEPARATOR "\n" + " PARSE_RULE_OPTION_GROUP\n" + " (\n" + " PARSE_RULE_OPTION_GROUP_NAME(\"repo\"),\n" + " ),\n" + "};\n" + "\n" + COMMENT_BLOCK_BEGIN "\n" + "Option parse data\n" + COMMENT_BLOCK_END "\n" + "static const ParseRuleOption parseRuleOption[CFG_OPTION_TOTAL] =\n" + "{\n" + COMMENT_SEPARATOR "\n" + " PARSE_RULE_OPTION\n" + " (\n" + " PARSE_RULE_OPTION_NAME(\"backup-standby\"),\n" + " PARSE_RULE_OPTION_TYPE(cfgOptTypeBoolean),\n" + " PARSE_RULE_OPTION_REQUIRED(true),\n" + " PARSE_RULE_OPTION_SECTION(cfgSectionGlobal),\n" + "\n" + " PARSE_RULE_OPTION_COMMAND_ROLE_MAIN_VALID_LIST\n" + " (\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdBackup)\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_OPTIONAL_LIST\n" + " (\n" + " PARSE_RULE_OPTION_OPTIONAL_DEPEND(cfgOptOnline),\n" + " PARSE_RULE_OPTION_OPTIONAL_DEFAULT(\"0\"),\n" + " ),\n" + " ),\n" + "\n" + COMMENT_SEPARATOR "\n" + " PARSE_RULE_OPTION\n" + " (\n" + " PARSE_RULE_OPTION_NAME(\"compress-level\"),\n" + " PARSE_RULE_OPTION_TYPE(cfgOptTypeInteger),\n" + " PARSE_RULE_OPTION_REQUIRED(false),\n" + " PARSE_RULE_OPTION_SECTION(cfgSectionGlobal),\n" + "\n" + " PARSE_RULE_OPTION_COMMAND_ROLE_MAIN_VALID_LIST\n" + " (\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdBackup)\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_COMMAND_ROLE_ASYNC_VALID_LIST\n" + " (\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_COMMAND_ROLE_LOCAL_VALID_LIST\n" + " (\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdBackup)\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_COMMAND_ROLE_REMOTE_VALID_LIST\n" + " (\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdBackup)\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_OPTIONAL_LIST\n" + " (\n" + " PARSE_RULE_OPTION_OPTIONAL_ALLOW_RANGE(0, 9),\n" + "\n" + " PARSE_RULE_OPTION_OPTIONAL_COMMAND_OVERRIDE\n" + " (\n" + " PARSE_RULE_OPTION_OPTIONAL_COMMAND(cfgCmdArchiveGet),\n" + "\n" + " PARSE_RULE_OPTION_OPTIONAL_DEPEND(cfgOptConfig),\n" + " )\n" + " ),\n" + " ),\n" + "\n" + COMMENT_SEPARATOR "\n" + " PARSE_RULE_OPTION\n" + " (\n" + " PARSE_RULE_OPTION_NAME(\"compress-level-network\"),\n" + " PARSE_RULE_OPTION_TYPE(cfgOptTypeInteger),\n" + " PARSE_RULE_OPTION_REQUIRED(false),\n" + " PARSE_RULE_OPTION_SECTION(cfgSectionGlobal),\n" + " PARSE_RULE_OPTION_SECURE(true),\n" + "\n" + " PARSE_RULE_OPTION_COMMAND_ROLE_MAIN_VALID_LIST\n" + " (\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdBackup)\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_COMMAND_ROLE_ASYNC_VALID_LIST\n" + " (\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_COMMAND_ROLE_LOCAL_VALID_LIST\n" + " (\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdBackup)\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_COMMAND_ROLE_REMOTE_VALID_LIST\n" + " (\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdBackup)\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_OPTIONAL_LIST\n" + " (\n" + " PARSE_RULE_OPTION_OPTIONAL_ALLOW_RANGE(0, 9),\n" + " PARSE_RULE_OPTION_OPTIONAL_DEPEND_LIST\n" + " (\n" + " cfgOptCompressType,\n" + " \"none\",\n" + " \"gz\"\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_OPTIONAL_COMMAND_OVERRIDE\n" + " (\n" + " PARSE_RULE_OPTION_OPTIONAL_COMMAND(cfgCmdArchiveGet),\n" + "\n" + " PARSE_RULE_OPTION_OPTIONAL_DEPEND(cfgOptConfig),\n" + " )\n" + " ),\n" + " ),\n" + "\n" + COMMENT_SEPARATOR "\n" + " PARSE_RULE_OPTION\n" + " (\n" + " PARSE_RULE_OPTION_NAME(\"compress-type\"),\n" + " PARSE_RULE_OPTION_TYPE(cfgOptTypeString),\n" + " PARSE_RULE_OPTION_REQUIRED(true),\n" + " PARSE_RULE_OPTION_SECTION(cfgSectionGlobal),\n" + "\n" + " PARSE_RULE_OPTION_OPTIONAL_LIST\n" + " (\n" + " PARSE_RULE_OPTION_OPTIONAL_DEFAULT(\"gz\"),\n" + "\n" + " PARSE_RULE_OPTION_OPTIONAL_COMMAND_OVERRIDE\n" + " (\n" + " PARSE_RULE_OPTION_OPTIONAL_COMMAND(cfgCmdArchiveGet),\n" + "\n" + " PARSE_RULE_OPTION_OPTIONAL_DEPEND(cfgOptConfig),\n" + " )\n" + " ),\n" + " ),\n" + "\n" + COMMENT_SEPARATOR "\n" + " PARSE_RULE_OPTION\n" + " (\n" + " PARSE_RULE_OPTION_NAME(\"config\"),\n" + " PARSE_RULE_OPTION_TYPE(cfgOptTypeString),\n" + " PARSE_RULE_OPTION_REQUIRED(true),\n" + " PARSE_RULE_OPTION_SECTION(cfgSectionCommandLine),\n" + "\n" + " PARSE_RULE_OPTION_COMMAND_ROLE_MAIN_VALID_LIST\n" + " (\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdBackup)\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_COMMAND_ROLE_ASYNC_VALID_LIST\n" + " (\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_COMMAND_ROLE_LOCAL_VALID_LIST\n" + " (\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdBackup)\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_COMMAND_ROLE_REMOTE_VALID_LIST\n" + " (\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdBackup)\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_OPTIONAL_LIST\n" + " (\n" + " PARSE_RULE_OPTION_OPTIONAL_DEFAULT(CFGOPTDEF_CONFIG_PATH \"/\" PROJECT_CONFIG_FILE),\n" + " ),\n" + " ),\n" + "\n" + COMMENT_SEPARATOR "\n" + " PARSE_RULE_OPTION\n" + " (\n" + " PARSE_RULE_OPTION_NAME(\"log-level-console\"),\n" + " PARSE_RULE_OPTION_TYPE(cfgOptTypeString),\n" + " PARSE_RULE_OPTION_REQUIRED(true),\n" + " PARSE_RULE_OPTION_SECTION(cfgSectionGlobal),\n" + "\n" + " PARSE_RULE_OPTION_COMMAND_ROLE_MAIN_VALID_LIST\n" + " (\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdBackup)\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_COMMAND_ROLE_ASYNC_VALID_LIST\n" + " (\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_COMMAND_ROLE_LOCAL_VALID_LIST\n" + " (\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdBackup)\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_COMMAND_ROLE_REMOTE_VALID_LIST\n" + " (\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdBackup)\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_OPTIONAL_LIST\n" + " (\n" + " PARSE_RULE_OPTION_OPTIONAL_ALLOW_LIST\n" + " (\n" + " \"off\",\n" + " \"error\",\n" + " \"warn\",\n" + " \"debug1\"\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_OPTIONAL_DEFAULT(\"warn\"),\n" + " ),\n" + " ),\n" + "\n" + COMMENT_SEPARATOR "\n" + " PARSE_RULE_OPTION\n" + " (\n" + " PARSE_RULE_OPTION_NAME(\"log-level-file\"),\n" + " PARSE_RULE_OPTION_TYPE(cfgOptTypeString),\n" + " PARSE_RULE_OPTION_REQUIRED(true),\n" + " PARSE_RULE_OPTION_SECTION(cfgSectionGlobal),\n" + "\n" + " PARSE_RULE_OPTION_COMMAND_ROLE_MAIN_VALID_LIST\n" + " (\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdBackup)\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdHelp)\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_COMMAND_ROLE_ASYNC_VALID_LIST\n" + " (\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_COMMAND_ROLE_LOCAL_VALID_LIST\n" + " (\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_COMMAND_ROLE_REMOTE_VALID_LIST\n" + " (\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_OPTIONAL_LIST\n" + " (\n" + " PARSE_RULE_OPTION_OPTIONAL_ALLOW_LIST\n" + " (\n" + " \"off\",\n" + " \"error\",\n" + " \"warn\",\n" + " \"debug1\"\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_OPTIONAL_DEFAULT(\"info\"),\n" + "\n" + " PARSE_RULE_OPTION_OPTIONAL_COMMAND_OVERRIDE\n" + " (\n" + " PARSE_RULE_OPTION_OPTIONAL_COMMAND(cfgCmdBackup),\n" + "\n" + " PARSE_RULE_OPTION_OPTIONAL_ALLOW_LIST\n" + " (\n" + " \"off\",\n" + " \"warn\"\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_OPTIONAL_DEPEND_LIST\n" + " (\n" + " cfgOptLogLevelConsole,\n" + " \"warn\"\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_OPTIONAL_DEFAULT(\"warn\"),\n" + " PARSE_RULE_OPTION_OPTIONAL_REQUIRED(false),\n" + " )\n" + " ),\n" + " ),\n" + "\n" + COMMENT_SEPARATOR "\n" + " PARSE_RULE_OPTION\n" + " (\n" + " PARSE_RULE_OPTION_NAME(\"online\"),\n" + " PARSE_RULE_OPTION_TYPE(cfgOptTypeBoolean),\n" + " PARSE_RULE_OPTION_REQUIRED(true),\n" + " PARSE_RULE_OPTION_SECTION(cfgSectionCommandLine),\n" + "\n" + " PARSE_RULE_OPTION_COMMAND_ROLE_MAIN_VALID_LIST\n" + " (\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdBackup)\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_OPTIONAL_LIST\n" + " (\n" + " PARSE_RULE_OPTION_OPTIONAL_DEFAULT(\"1\"),\n" + " ),\n" + " ),\n" + "\n" + COMMENT_SEPARATOR "\n" + " PARSE_RULE_OPTION\n" + " (\n" + " PARSE_RULE_OPTION_NAME(\"pg-path\"),\n" + " PARSE_RULE_OPTION_TYPE(cfgOptTypeHash),\n" + " PARSE_RULE_OPTION_REQUIRED(true),\n" + " PARSE_RULE_OPTION_SECTION(cfgSectionStanza),\n" + " PARSE_RULE_OPTION_MULTI(true),\n" + " PARSE_RULE_OPTION_GROUP_MEMBER(true),\n" + " PARSE_RULE_OPTION_GROUP_ID(cfgOptGrpPg),\n" + "\n" + " PARSE_RULE_OPTION_COMMAND_ROLE_MAIN_VALID_LIST\n" + " (\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdBackup)\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_COMMAND_ROLE_ASYNC_VALID_LIST\n" + " (\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_COMMAND_ROLE_LOCAL_VALID_LIST\n" + " (\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdBackup)\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_COMMAND_ROLE_REMOTE_VALID_LIST\n" + " (\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdBackup)\n" + " ),\n" + " ),\n" + "\n" + COMMENT_SEPARATOR "\n" + " PARSE_RULE_OPTION\n" + " (\n" + " PARSE_RULE_OPTION_NAME(\"stanza\"),\n" + " PARSE_RULE_OPTION_TYPE(cfgOptTypeList),\n" + " PARSE_RULE_OPTION_REQUIRED(true),\n" + " PARSE_RULE_OPTION_SECTION(cfgSectionCommandLine),\n" + " PARSE_RULE_OPTION_MULTI(true),\n" + "\n" + " PARSE_RULE_OPTION_COMMAND_ROLE_MAIN_VALID_LIST\n" + " (\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdBackup)\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_COMMAND_ROLE_ASYNC_VALID_LIST\n" + " (\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_COMMAND_ROLE_LOCAL_VALID_LIST\n" + " (\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdBackup)\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_COMMAND_ROLE_REMOTE_VALID_LIST\n" + " (\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdBackup)\n" + " ),\n" + " ),\n" + "\n" + COMMENT_SEPARATOR "\n" + " PARSE_RULE_OPTION\n" + " (\n" + " PARSE_RULE_OPTION_NAME(\"timeout\"),\n" + " PARSE_RULE_OPTION_TYPE(cfgOptTypeTime),\n" + " PARSE_RULE_OPTION_REQUIRED(true),\n" + " PARSE_RULE_OPTION_SECTION(cfgSectionCommandLine),\n" + "\n" + " PARSE_RULE_OPTION_COMMAND_ROLE_MAIN_VALID_LIST\n" + " (\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdBackup)\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_COMMAND_ROLE_ASYNC_VALID_LIST\n" + " (\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_COMMAND_ROLE_LOCAL_VALID_LIST\n" + " (\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdBackup)\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_COMMAND_ROLE_REMOTE_VALID_LIST\n" + " (\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n" + " PARSE_RULE_OPTION_COMMAND(cfgCmdBackup)\n" + " ),\n" + "\n" + " PARSE_RULE_OPTION_OPTIONAL_LIST\n" + " (\n" + " PARSE_RULE_OPTION_OPTIONAL_ALLOW_RANGE(5000, 50000),\n" + " PARSE_RULE_OPTION_OPTIONAL_DEFAULT(\"10000\"),\n" + " ),\n" + " ),\n" + "};\n" + "\n" + COMMENT_BLOCK_BEGIN "\n" + "Option data for getopt_long()\n" + COMMENT_BLOCK_END "\n" + "static const struct option optionList[] =\n" + "{\n" + " // backup-standby option and deprecations\n" + COMMENT_SEPARATOR "\n" + " {\n" + " .name = \"backup-standby\",\n" + " .val = PARSE_OPTION_FLAG | cfgOptBackupStandby,\n" + " },\n" + " {\n" + " .name = \"no-backup-standby\",\n" + " .val = PARSE_OPTION_FLAG | PARSE_NEGATE_FLAG | cfgOptBackupStandby,\n" + " },\n" + " {\n" + " .name = \"reset-backup-standby\",\n" + " .val = PARSE_OPTION_FLAG | PARSE_RESET_FLAG | cfgOptBackupStandby,\n" + " },\n" + " {\n" + " .name = \"backup-standby-old\",\n" + " .val = PARSE_OPTION_FLAG | PARSE_DEPRECATE_FLAG | cfgOptBackupStandby,\n" + " },\n" + " {\n" + " .name = \"no-backup-standby-old\",\n" + " .val = PARSE_OPTION_FLAG | PARSE_DEPRECATE_FLAG | PARSE_NEGATE_FLAG | cfgOptBackupStandby,\n" + " },\n" + " {\n" + " .name = \"reset-backup-standby-old\",\n" + " .val = PARSE_OPTION_FLAG | PARSE_DEPRECATE_FLAG | PARSE_RESET_FLAG | cfgOptBackupStandby,\n" + " },\n" + "\n" + " // compress-level option\n" + COMMENT_SEPARATOR "\n" + " {\n" + " .name = \"compress-level\",\n" + " .has_arg = required_argument,\n" + " .val = PARSE_OPTION_FLAG | cfgOptCompressLevel,\n" + " },\n" + " {\n" + " .name = \"reset-compress-level\",\n" + " .val = PARSE_OPTION_FLAG | PARSE_RESET_FLAG | cfgOptCompressLevel,\n" + " },\n" + "\n" + " // compress-level-network option\n" + COMMENT_SEPARATOR "\n" + " {\n" + " .name = \"compress-level-network\",\n" + " .has_arg = required_argument,\n" + " .val = PARSE_OPTION_FLAG | cfgOptCompressLevelNetwork,\n" + " },\n" + " {\n" + " .name = \"reset-compress-level-network\",\n" + " .val = PARSE_OPTION_FLAG | PARSE_RESET_FLAG | cfgOptCompressLevelNetwork,\n" + " },\n" + "\n" + " // compress-type option and deprecations\n" + COMMENT_SEPARATOR "\n" + " {\n" + " .name = \"compress-type\",\n" + " .has_arg = required_argument,\n" + " .val = PARSE_OPTION_FLAG | cfgOptCompressType,\n" + " },\n" + " {\n" + " .name = \"reset-compress-type\",\n" + " .val = PARSE_OPTION_FLAG | PARSE_RESET_FLAG | cfgOptCompressType,\n" + " },\n" + " {\n" + " .name = \"compress\",\n" + " .has_arg = required_argument,\n" + " .val = PARSE_OPTION_FLAG | PARSE_DEPRECATE_FLAG | cfgOptCompressType,\n" + " },\n" + " {\n" + " .name = \"reset-compress\",\n" + " .val = PARSE_OPTION_FLAG | PARSE_DEPRECATE_FLAG | PARSE_RESET_FLAG | cfgOptCompressType,\n" + " },\n" + "\n" + " // config option\n" + COMMENT_SEPARATOR "\n" + " {\n" + " .name = \"config\",\n" + " .has_arg = required_argument,\n" + " .val = PARSE_OPTION_FLAG | cfgOptConfig,\n" + " },\n" + " {\n" + " .name = \"no-config\",\n" + " .val = PARSE_OPTION_FLAG | PARSE_NEGATE_FLAG | cfgOptConfig,\n" + " },\n" + "\n" + " // log-level-console option\n" + COMMENT_SEPARATOR "\n" + " {\n" + " .name = \"log-level-console\",\n" + " .has_arg = required_argument,\n" + " .val = PARSE_OPTION_FLAG | cfgOptLogLevelConsole,\n" + " },\n" + " {\n" + " .name = \"reset-log-level-console\",\n" + " .val = PARSE_OPTION_FLAG | PARSE_RESET_FLAG | cfgOptLogLevelConsole,\n" + " },\n" + "\n" + " // log-level-file option\n" + COMMENT_SEPARATOR "\n" + " {\n" + " .name = \"log-level-file\",\n" + " .has_arg = required_argument,\n" + " .val = PARSE_OPTION_FLAG | cfgOptLogLevelFile,\n" + " },\n" + " {\n" + " .name = \"reset-log-level-file\",\n" + " .val = PARSE_OPTION_FLAG | PARSE_RESET_FLAG | cfgOptLogLevelFile,\n" + " },\n" + "\n" + " // online option and deprecations\n" + COMMENT_SEPARATOR "\n" + " {\n" + " .name = \"online\",\n" + " .val = PARSE_OPTION_FLAG | cfgOptOnline,\n" + " },\n" + " {\n" + " .name = \"online-old\",\n" + " .val = PARSE_OPTION_FLAG | PARSE_DEPRECATE_FLAG | cfgOptOnline,\n" + " },\n" + "\n" + " // pg-path option and deprecations\n" + COMMENT_SEPARATOR "\n" + " {\n" + " .name = \"pg1-path\",\n" + " .has_arg = required_argument,\n" + " .val = PARSE_OPTION_FLAG | (0 << PARSE_KEY_IDX_SHIFT) | cfgOptPgPath,\n" + " },\n" + " {\n" + " .name = \"reset-pg1-path\",\n" + " .val = PARSE_OPTION_FLAG | PARSE_RESET_FLAG | (0 << PARSE_KEY_IDX_SHIFT) | cfgOptPgPath,\n" + " },\n" + " {\n" + " .name = \"db-path\",\n" + " .has_arg = required_argument,\n" + " .val = PARSE_OPTION_FLAG | PARSE_DEPRECATE_FLAG | (0 << PARSE_KEY_IDX_SHIFT) | cfgOptPgPath,\n" + " },\n" + " {\n" + " .name = \"db1-path\",\n" + " .has_arg = required_argument,\n" + " .val = PARSE_OPTION_FLAG | PARSE_DEPRECATE_FLAG | (0 << PARSE_KEY_IDX_SHIFT) | cfgOptPgPath,\n" + " },\n" + " {\n" + " .name = \"pg2-path\",\n" + " .has_arg = required_argument,\n" + " .val = PARSE_OPTION_FLAG | (1 << PARSE_KEY_IDX_SHIFT) | cfgOptPgPath,\n" + " },\n" + " {\n" + " .name = \"reset-pg2-path\",\n" + " .val = PARSE_OPTION_FLAG | PARSE_RESET_FLAG | (1 << PARSE_KEY_IDX_SHIFT) | cfgOptPgPath,\n" + " },\n" + " {\n" + " .name = \"db2-path\",\n" + " .has_arg = required_argument,\n" + " .val = PARSE_OPTION_FLAG | PARSE_DEPRECATE_FLAG | (1 << PARSE_KEY_IDX_SHIFT) | cfgOptPgPath,\n" + " },\n" + "\n" + " // stanza option\n" + COMMENT_SEPARATOR "\n" + " {\n" + " .name = \"stanza\",\n" + " .has_arg = required_argument,\n" + " .val = PARSE_OPTION_FLAG | cfgOptStanza,\n" + " },\n" + "\n" + " // timeout option\n" + COMMENT_SEPARATOR "\n" + " {\n" + " .name = \"timeout\",\n" + " .has_arg = required_argument,\n" + " .val = PARSE_OPTION_FLAG | cfgOptTimeout,\n" + " },\n" + " // Terminate option list\n" + " {\n" + " .name = NULL\n" + " }\n" + "};\n" + "\n" + COMMENT_BLOCK_BEGIN "\n" + "Order for option parse resolution\n" + COMMENT_BLOCK_END "\n" + "static const ConfigOption optionResolveOrder[] =\n" + "{\n" + " cfgOptStanza,\n" + " cfgOptConfig,\n" + " cfgOptLogLevelConsole,\n" + " cfgOptLogLevelFile,\n" + " cfgOptOnline,\n" + " cfgOptPgPath,\n" + " cfgOptTimeout,\n" + " cfgOptBackupStandby,\n" + " cfgOptCompressLevel,\n" + " cfgOptCompressType,\n" + " cfgOptCompressLevelNetwork,\n" + "};\n"); } FUNCTION_HARNESS_RETURN_VOID(); diff --git a/test/test.pl b/test/test.pl index a9cf2778c..d8b271248 100755 --- a/test/test.pl +++ b/test/test.pl @@ -37,7 +37,6 @@ use pgBackRestDoc::ProjectInfo; use pgBackRestBuild::Build; use pgBackRestBuild::Build::Common; use pgBackRestBuild::Config::BuildHelp; -use pgBackRestBuild::Config::BuildParse; use pgBackRestBuild::Error::Build; use pgBackRestBuild::Error::Data; @@ -532,12 +531,6 @@ eval &BLD_PATH => 'command/help', }, - 'configParse' => - { - &BLD_DATA => buildConfigParse(), - &BLD_PATH => 'config', - }, - 'error' => { &BLD_DATA => buildError(),