You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-07-15 01:04:37 +02:00
Move all parse-related rules to parse module.
Data required for parsing was spread between the config and defined modules, mostly for historical reasons because the same data was used by Perl. Requiring all the parse rules to be accessed with function interfaces makes the code more complicated and new rules harder to implement. Instead, move the data to the parse module so in the most complex cases no interface functions are needed. This reduces the total amount of code and paves the way for more complex parse rules.
This commit is contained in:
@ -35,9 +35,7 @@ use constant BLDLCL_CONSTANT_OPTION_TOTAL => 'CFG_OPTI
|
||||
|
||||
use constant BLDLCL_DATA_COMMAND_CONSTANT => '01-commandConstant';
|
||||
use constant BLDLCL_DATA_COMMAND => '02-command';
|
||||
use constant BLDLCL_DATA_OPTION_GROUP => '03-optionGroup';
|
||||
use constant BLDLCL_DATA_OPTION_CONSTANT => '04-optionConstant';
|
||||
use constant BLDLCL_DATA_OPTION => '05-option';
|
||||
|
||||
use constant BLDLCL_ENUM_COMMAND => '01-enumCommand';
|
||||
use constant BLDLCL_ENUM_OPTION_GROUP => '02-enumOptionGroup';
|
||||
@ -107,20 +105,10 @@ my $rhBuild =
|
||||
&BLD_SUMMARY => 'Command data',
|
||||
},
|
||||
|
||||
&BLDLCL_DATA_OPTION_GROUP =>
|
||||
{
|
||||
&BLD_SUMMARY => 'Option group data',
|
||||
},
|
||||
|
||||
&BLDLCL_DATA_OPTION_CONSTANT =>
|
||||
{
|
||||
&BLD_SUMMARY => 'Option constants',
|
||||
},
|
||||
|
||||
&BLDLCL_DATA_OPTION =>
|
||||
{
|
||||
&BLD_SUMMARY => 'Option data',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -163,7 +151,7 @@ sub buildConfig
|
||||
my $iCommandTotal = 0;
|
||||
|
||||
my $strBuildSource =
|
||||
'static ConfigCommandData configCommandData[' . BLDLCL_CONSTANT_COMMAND_TOTAL . "] = CONFIG_COMMAND_LIST\n" .
|
||||
'static const ConfigCommandData configCommandData[' . BLDLCL_CONSTANT_COMMAND_TOTAL . "] = CONFIG_COMMAND_LIST\n" .
|
||||
"(";
|
||||
my $strBuildSourceConstant = '';
|
||||
|
||||
@ -192,7 +180,6 @@ sub buildConfig
|
||||
" CONFIG_COMMAND_LOCK_REMOTE_REQUIRED(" .
|
||||
($rhCommand->{&CFGDEF_LOCK_REMOTE_REQUIRED} ? 'true' : 'false') . ")\n" .
|
||||
" CONFIG_COMMAND_LOCK_TYPE(lockType" . ucfirst(lc($rhCommand->{&CFGDEF_LOCK_TYPE})) . ")\n" .
|
||||
" CONFIG_COMMAND_PARAMETER_ALLOWED(" . ($rhCommand->{&CFGDEF_PARAMETER_ALLOWED} ? 'true' : 'false') . ")\n" .
|
||||
" )\n";
|
||||
|
||||
$rhBuild->{&BLD_FILE}{&BLDLCL_FILE_CONFIG}{&BLD_CONSTANT_GROUP}{&BLDLCL_CONSTANT_COMMAND}{&BLD_CONSTANT}
|
||||
@ -227,31 +214,17 @@ sub buildConfig
|
||||
$rhEnum = $rhBuild->{&BLD_FILE}{&BLDLCL_FILE_CONFIG}{&BLD_ENUM}{&BLDLCL_ENUM_OPTION_GROUP};
|
||||
my $iGroupTotal = 0;
|
||||
|
||||
$strBuildSource =
|
||||
'static ConfigOptionGroupData configOptionGroupData[' . BLDLCL_CONSTANT_OPTION_GROUP_TOTAL . "] = \n" .
|
||||
"{";
|
||||
|
||||
foreach my $strGroup (sort(keys(%{$rhOptionGroupDefine})))
|
||||
{
|
||||
my $strGroupEnum = buildConfigOptionGroupEnum($strGroup);
|
||||
push(@{$rhEnum->{&BLD_LIST}}, $strGroupEnum);
|
||||
|
||||
$strBuildSource .=
|
||||
"\n" .
|
||||
" // ${strGroupEnum}\n" .
|
||||
" //" . (qw{-} x 126) . "\n" .
|
||||
" {\n" .
|
||||
" .name = \"" . $strGroup . "\"\n" .
|
||||
" },\n";
|
||||
|
||||
$iGroupTotal++;
|
||||
}
|
||||
|
||||
$strBuildSource .=
|
||||
"};\n";
|
||||
|
||||
$rhBuild->{&BLD_FILE}{&BLDLCL_FILE_CONFIG}{&BLD_DATA}{&BLDLCL_DATA_OPTION_GROUP}{&BLD_SOURCE} = $strBuildSource;
|
||||
|
||||
# Set option total constant
|
||||
$rhBuild->{&BLD_FILE}{&BLDLCL_FILE_CONFIG}{&BLD_CONSTANT_GROUP}{&BLDLCL_CONSTANT_OPTION_GROUP}{&BLD_CONSTANT}
|
||||
{&BLDLCL_CONSTANT_OPTION_GROUP_TOTAL}{&BLD_CONSTANT_VALUE} = $iGroupTotal;
|
||||
@ -263,16 +236,10 @@ sub buildConfig
|
||||
$rhEnum = $rhBuild->{&BLD_FILE}{&BLDLCL_FILE_CONFIG}{&BLD_ENUM}{&BLDLCL_ENUM_OPTION};
|
||||
my $iOptionTotal = 0;
|
||||
|
||||
$strBuildSource =
|
||||
'static ConfigOptionData configOptionData[' . BLDLCL_CONSTANT_OPTION_TOTAL . "] = CONFIG_OPTION_LIST\n" .
|
||||
"(";
|
||||
$strBuildSourceConstant = '';
|
||||
|
||||
foreach my $strOption (sort(keys(%{$rhConfigDefine})))
|
||||
{
|
||||
my $iOptionIndexTotal = $rhConfigDefine->{$strOption}{&CFGDEF_INDEX_TOTAL};
|
||||
my $strOptionPrefix = $rhConfigDefine->{$strOption}{&CFGDEF_PREFIX};
|
||||
|
||||
# Build C enum
|
||||
my $strOptionEnum = buildConfigOptionEnum($strOption);
|
||||
push(@{$rhEnum->{&BLD_LIST}}, $strOptionEnum);
|
||||
@ -282,26 +249,6 @@ sub buildConfig
|
||||
$strOptionConst = "CFGOPT_" . uc($strOption);
|
||||
$strOptionConst =~ s/\-/_/g;
|
||||
|
||||
# Add option data
|
||||
$strBuildSource .=
|
||||
"\n" .
|
||||
" //" . (qw{-} x 126) . "\n" .
|
||||
" CONFIG_OPTION\n" .
|
||||
" (\n" .
|
||||
" CONFIG_OPTION_NAME(\"${strOption}\")\n";
|
||||
|
||||
if ($rhConfigDefine->{$strOption}{&CFGDEF_GROUP})
|
||||
{
|
||||
$strBuildSource .=
|
||||
" CONFIG_OPTION_GROUP(true)\n" .
|
||||
" CONFIG_OPTION_GROUP_ID(" . buildConfigOptionGroupEnum($rhConfigDefine->{$strOption}{&CFGDEF_GROUP}) .
|
||||
")\n";
|
||||
}
|
||||
|
||||
$strBuildSource .=
|
||||
" )\n";
|
||||
|
||||
|
||||
if (!$rhConfigDefine->{$strOption}{&CFGDEF_GROUP})
|
||||
{
|
||||
$rhBuild->{&BLD_FILE}{&BLDLCL_FILE_CONFIG}{&BLD_CONSTANT_GROUP}{&BLDLCL_CONSTANT_OPTION}{&BLD_CONSTANT}
|
||||
@ -314,10 +261,6 @@ sub buildConfig
|
||||
$iOptionTotal += 1;
|
||||
}
|
||||
|
||||
$strBuildSource .=
|
||||
")\n";
|
||||
|
||||
$rhBuild->{&BLD_FILE}{&BLDLCL_FILE_CONFIG}{&BLD_DATA}{&BLDLCL_DATA_OPTION}{&BLD_SOURCE} = $strBuildSource;
|
||||
$rhBuild->{&BLD_FILE}{&BLDLCL_FILE_CONFIG}{&BLD_DATA}{&BLDLCL_DATA_OPTION_CONSTANT}{&BLD_SOURCE} = $strBuildSourceConstant;
|
||||
|
||||
# Add an LF to the last option constant so there's whitespace before the total
|
||||
|
@ -1,342 +0,0 @@
|
||||
####################################################################################################################################
|
||||
# Auto-Generate Command and Option Configuration Definition Enums, Constants and Data
|
||||
####################################################################################################################################
|
||||
package pgBackRestBuild::Config::BuildDefine;
|
||||
|
||||
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::DocConfig;
|
||||
use pgBackRestDoc::Common::DocRender;
|
||||
use pgBackRestDoc::Common::Log;
|
||||
use pgBackRestDoc::Common::String;
|
||||
use pgBackRestDoc::ProjectInfo;
|
||||
|
||||
use pgBackRestBuild::Build::Common;
|
||||
use pgBackRestBuild::Config::Build;
|
||||
use pgBackRestBuild::Config::Data;
|
||||
|
||||
####################################################################################################################################
|
||||
# Constants
|
||||
####################################################################################################################################
|
||||
use constant BLDLCL_FILE_DEFINE => 'define';
|
||||
|
||||
use constant BLDLCL_DATA_COMMAND => '01-dataCommand';
|
||||
use constant BLDLCL_DATA_OPTION => '02-dataOption';
|
||||
|
||||
use constant BLDLCL_ENUM_OPTION_TYPE => '02-enumOptionType';
|
||||
|
||||
####################################################################################################################################
|
||||
# Definitions for constants and data to build
|
||||
####################################################################################################################################
|
||||
my $strSummary = 'Command and Option Definition';
|
||||
|
||||
my $rhBuild =
|
||||
{
|
||||
&BLD_FILE =>
|
||||
{
|
||||
&BLDLCL_FILE_DEFINE =>
|
||||
{
|
||||
&BLD_SUMMARY => $strSummary,
|
||||
|
||||
&BLD_ENUM =>
|
||||
{
|
||||
&BLDLCL_ENUM_OPTION_TYPE =>
|
||||
{
|
||||
&BLD_SUMMARY => 'Option type define',
|
||||
&BLD_NAME => 'ConfigDefineOptionType',
|
||||
},
|
||||
},
|
||||
|
||||
&BLD_DATA =>
|
||||
{
|
||||
&BLDLCL_DATA_COMMAND =>
|
||||
{
|
||||
&BLD_SUMMARY => 'Command define data',
|
||||
},
|
||||
|
||||
&BLDLCL_DATA_OPTION =>
|
||||
{
|
||||
&BLD_SUMMARY => 'Option define data',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
####################################################################################################################################
|
||||
# Generate enum names
|
||||
####################################################################################################################################
|
||||
sub buildConfigDefineOptionTypeEnum
|
||||
{
|
||||
return bldEnum('cfgDefOptType', shift);
|
||||
}
|
||||
|
||||
push @EXPORT, qw(buildConfigDefineOptionTypeEnum);
|
||||
|
||||
####################################################################################################################################
|
||||
# Helper functions for building optional option data
|
||||
####################################################################################################################################
|
||||
sub renderAllowList
|
||||
{
|
||||
my $ryAllowList = shift;
|
||||
my $bCommandIndent = shift;
|
||||
|
||||
my $strIndent = $bCommandIndent ? ' ' : '';
|
||||
|
||||
return
|
||||
"${strIndent} CFGDEFDATA_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} CFGDEFDATA_OPTION_OPTIONAL_DEPEND_LIST\n" .
|
||||
"${strIndent} (\n" .
|
||||
"${strIndent} " . buildConfigOptionEnum($strDependOption) . ",\n" .
|
||||
"${strIndent} " . join(",\n${strIndent} ", bldQuoteList($ryDependList)) .
|
||||
"\n" .
|
||||
"${strIndent} )\n";
|
||||
}
|
||||
|
||||
return
|
||||
"${strIndent} CFGDEFDATA_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} CFGDEFDATA_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} CFGDEFDATA_OPTION_OPTIONAL_DEFAULT(\"" .
|
||||
(defined($rhOptional->{&CFGDEF_TYPE}) && $rhOptional->{&CFGDEF_TYPE} eq CFGDEF_TYPE_TIME ?
|
||||
$rhOptional->{&CFGDEF_DEFAULT} * 1000 : $rhOptional->{&CFGDEF_DEFAULT}) .
|
||||
"\")\n";
|
||||
|
||||
$bSingleLine = true;
|
||||
}
|
||||
|
||||
if ($bCommand && defined($rhOptional->{&CFGDEF_REQUIRED}))
|
||||
{
|
||||
$strBuildSourceOptional .=
|
||||
(defined($strBuildSourceOptional) && !$bSingleLine ? "\n" : '') .
|
||||
"${strIndent} CFGDEFDATA_OPTION_OPTIONAL_REQUIRED(" .
|
||||
($rhOptional->{&CFGDEF_REQUIRED} ? 'true' : 'false') . ")\n";
|
||||
|
||||
$bSingleLine = true;
|
||||
}
|
||||
|
||||
return $strBuildSourceOptional;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Build configuration constants and data
|
||||
####################################################################################################################################
|
||||
sub buildConfigDefine
|
||||
{
|
||||
# Build command constants and data
|
||||
#-------------------------------------------------------------------------------------------------------------------------------
|
||||
my $strBuildSource =
|
||||
"static ConfigDefineCommandData configDefineCommandData[] = CFGDEFDATA_COMMAND_LIST\n" .
|
||||
"(";
|
||||
|
||||
foreach my $strCommand (cfgDefineCommandList())
|
||||
{
|
||||
# Build command data
|
||||
$strBuildSource .=
|
||||
"\n" .
|
||||
" CFGDEFDATA_COMMAND\n" .
|
||||
" (\n" .
|
||||
" CFGDEFDATA_COMMAND_NAME(\"${strCommand}\")\n" .
|
||||
" )\n";
|
||||
};
|
||||
|
||||
$strBuildSource .=
|
||||
")\n";
|
||||
|
||||
$rhBuild->{&BLD_FILE}{&BLDLCL_FILE_DEFINE}{&BLD_DATA}{&BLDLCL_DATA_COMMAND}{&BLD_SOURCE} = $strBuildSource;
|
||||
|
||||
# Build option type constants
|
||||
#-------------------------------------------------------------------------------------------------------------------------------
|
||||
my $rhEnum = $rhBuild->{&BLD_FILE}{&BLDLCL_FILE_DEFINE}{&BLD_ENUM}{&BLDLCL_ENUM_OPTION_TYPE};
|
||||
|
||||
foreach my $strOptionType (cfgDefineOptionTypeList())
|
||||
{
|
||||
# Build C enum
|
||||
my $strOptionTypeEnum = buildConfigDefineOptionTypeEnum($strOptionType);
|
||||
push(@{$rhEnum->{&BLD_LIST}}, $strOptionTypeEnum);
|
||||
};
|
||||
|
||||
# Build option constants and data
|
||||
#-------------------------------------------------------------------------------------------------------------------------------
|
||||
my $rhConfigDefine = cfgDefine();
|
||||
|
||||
$strBuildSource =
|
||||
"static ConfigDefineOptionData configDefineOptionData[] = CFGDEFDATA_OPTION_LIST\n" .
|
||||
"(";
|
||||
|
||||
foreach my $strOption (sort(keys(%{$rhConfigDefine})))
|
||||
{
|
||||
# Build option data
|
||||
my $rhOption = $rhConfigDefine->{$strOption};
|
||||
|
||||
my $strOptionPrefix = $rhOption->{&CFGDEF_PREFIX};
|
||||
|
||||
$strBuildSource .=
|
||||
"\n" .
|
||||
" // " . (qw{-} x 125) . "\n" .
|
||||
" CFGDEFDATA_OPTION\n" .
|
||||
" (\n";
|
||||
|
||||
my $bRequired = $rhOption->{&CFGDEF_REQUIRED};
|
||||
|
||||
$strBuildSource .=
|
||||
" CFGDEFDATA_OPTION_NAME(\"${strOption}\")\n" .
|
||||
" CFGDEFDATA_OPTION_REQUIRED(" . ($bRequired ? 'true' : 'false') . ")\n" .
|
||||
" CFGDEFDATA_OPTION_SECTION(cfgDefSection" .
|
||||
(defined($rhOption->{&CFGDEF_SECTION}) ? ucfirst($rhOption->{&CFGDEF_SECTION}) : 'CommandLine') .
|
||||
")\n" .
|
||||
" CFGDEFDATA_OPTION_TYPE(" . buildConfigDefineOptionTypeEnum($rhOption->{&CFGDEF_TYPE}) . ")\n" .
|
||||
"\n" .
|
||||
" CFGDEFDATA_OPTION_SECURE(" . ($rhOption->{&CFGDEF_SECURE} ? 'true' : 'false') . ")\n";
|
||||
|
||||
$strBuildSource .=
|
||||
"\n" .
|
||||
" CFGDEFDATA_OPTION_COMMAND_LIST\n" .
|
||||
" (\n";
|
||||
|
||||
foreach my $strCommand (cfgDefineCommandList())
|
||||
{
|
||||
if (defined($rhOption->{&CFGDEF_COMMAND}{$strCommand}))
|
||||
{
|
||||
$strBuildSource .=
|
||||
" CFGDEFDATA_OPTION_COMMAND(" . buildConfigCommandEnum($strCommand) . ")\n";
|
||||
}
|
||||
}
|
||||
|
||||
$strBuildSource .=
|
||||
" )\n";
|
||||
|
||||
# Render optional data
|
||||
my $strBuildSourceOptional = renderOptional($rhOption, false);
|
||||
|
||||
# Render command overrides
|
||||
foreach my $strCommand (cfgDefineCommandList())
|
||||
{
|
||||
my $strBuildSourceOptionalCommand;
|
||||
my $rhCommand = $rhOption->{&CFGDEF_COMMAND}{$strCommand};
|
||||
|
||||
if (defined($rhCommand))
|
||||
{
|
||||
$strBuildSourceOptionalCommand = renderOptional($rhCommand, true, $strCommand, $strOption);
|
||||
|
||||
if (defined($strBuildSourceOptionalCommand))
|
||||
{
|
||||
$strBuildSourceOptional .=
|
||||
(defined($strBuildSourceOptional) ? "\n" : '') .
|
||||
" CFGDEFDATA_OPTION_OPTIONAL_COMMAND_OVERRIDE\n" .
|
||||
" (\n" .
|
||||
" CFGDEFDATA_OPTION_OPTIONAL_COMMAND(" . buildConfigCommandEnum($strCommand) . ")\n" .
|
||||
"\n" .
|
||||
$strBuildSourceOptionalCommand .
|
||||
" )\n";
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
if (defined($strBuildSourceOptional))
|
||||
{
|
||||
$strBuildSource .=
|
||||
"\n" .
|
||||
" CFGDEFDATA_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;
|
||||
|
||||
return $rhBuild;
|
||||
}
|
||||
|
||||
push @EXPORT, qw(buildConfigDefine);
|
||||
|
||||
1;
|
@ -27,13 +27,18 @@ use pgBackRestBuild::Config::Data;
|
||||
####################################################################################################################################
|
||||
use constant BLDLCL_FILE_DEFINE => 'parse';
|
||||
|
||||
use constant BLDLCL_DATA_OPTION => '01-dataOption';
|
||||
use constant BLDLCL_DATA_OPTION_RESOLVE => '01-dataOptionResolve';
|
||||
use constant BLDLCL_ENUM_OPTION_TYPE => '01-enumOptionType';
|
||||
|
||||
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 = 'Option Parse Definition';
|
||||
my $strSummary = 'Config Parse Rules';
|
||||
|
||||
my $rhBuild =
|
||||
{
|
||||
@ -43,13 +48,37 @@ my $rhBuild =
|
||||
{
|
||||
&BLD_SUMMARY => $strSummary,
|
||||
|
||||
&BLD_ENUM =>
|
||||
{
|
||||
&BLDLCL_ENUM_OPTION_TYPE =>
|
||||
{
|
||||
&BLD_SUMMARY => 'Option type',
|
||||
&BLD_NAME => 'ConfigOptionType',
|
||||
},
|
||||
},
|
||||
|
||||
&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',
|
||||
@ -59,16 +88,326 @@ my $rhBuild =
|
||||
},
|
||||
};
|
||||
|
||||
####################################################################################################################################
|
||||
# Generate enum names
|
||||
####################################################################################################################################
|
||||
sub buildConfigDefineOptionTypeEnum
|
||||
{
|
||||
return bldEnum('cfgOptType', shift);
|
||||
}
|
||||
|
||||
push @EXPORT, qw(buildConfigDefineOptionTypeEnum);
|
||||
|
||||
####################################################################################################################################
|
||||
# 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(\"" .
|
||||
(defined($rhOptional->{&CFGDEF_TYPE}) && $rhOptional->{&CFGDEF_TYPE} eq CFGDEF_TYPE_TIME ?
|
||||
$rhOptional->{&CFGDEF_DEFAULT} * 1000 : $rhOptional->{&CFGDEF_DEFAULT}) .
|
||||
"\"),\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 option parse list
|
||||
#-------------------------------------------------------------------------------------------------------------------------------
|
||||
my $rhConfigDefine = cfgDefine();
|
||||
# Build option type enum
|
||||
# ------------------------------------------------------------------------------------------------------------------------------
|
||||
my $rhEnum = $rhBuild->{&BLD_FILE}{&BLDLCL_FILE_DEFINE}{&BLD_ENUM}{&BLDLCL_ENUM_OPTION_TYPE};
|
||||
|
||||
foreach my $strOptionType (cfgDefineOptionTypeList())
|
||||
{
|
||||
# Build C enum
|
||||
my $strOptionTypeEnum = buildConfigDefineOptionTypeEnum($strOptionType);
|
||||
push(@{$rhEnum->{&BLD_LIST}}, $strOptionTypeEnum);
|
||||
};
|
||||
|
||||
# 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 126) . "\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";
|
||||
};
|
||||
|
||||
$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 126) . "\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 default list
|
||||
# --------------------------------------------------------------------------------------------------------------------------
|
||||
my $strBuildSourceSub = "";
|
||||
|
||||
foreach my $strCommand (cfgDefineCommandList())
|
||||
{
|
||||
if (defined($rhOption->{&CFGDEF_COMMAND}{$strCommand}))
|
||||
{
|
||||
$strBuildSourceSub .=
|
||||
" PARSE_RULE_OPTION_COMMAND(" . buildConfigCommandEnum($strCommand) . ")\n";
|
||||
}
|
||||
}
|
||||
|
||||
if ($strBuildSourceSub ne "")
|
||||
{
|
||||
$strBuildSource .=
|
||||
"\n" .
|
||||
" PARSE_RULE_OPTION_COMMAND_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};
|
||||
|
||||
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" .
|
||||
"{";
|
||||
|
||||
@ -186,7 +525,7 @@ sub buildConfigParse
|
||||
" }\n" .
|
||||
"};\n";
|
||||
|
||||
$rhBuild->{&BLD_FILE}{&BLDLCL_FILE_DEFINE}{&BLD_DATA}{&BLDLCL_DATA_OPTION}{&BLD_SOURCE} = $strBuildSource;
|
||||
$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.
|
||||
#
|
||||
|
@ -117,7 +117,6 @@ SRCS = \
|
||||
common/user.c \
|
||||
common/wait.c \
|
||||
config/config.c \
|
||||
config/define.c \
|
||||
config/exec.c \
|
||||
config/load.c \
|
||||
config/parse.c \
|
||||
|
@ -13,7 +13,7 @@ Common Command Routines
|
||||
#include "common/time.h"
|
||||
#include "common/type/json.h"
|
||||
#include "config/config.intern.h"
|
||||
#include "config/define.h"
|
||||
#include "config/parse.h"
|
||||
#include "version.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
@ -76,7 +76,7 @@ cmdOption(void)
|
||||
// Skip the option if not valid for this command. Generally only one command runs at a time, but sometimes
|
||||
// commands are chained together (e.g. backup and expire) and the second command may not use all the options of
|
||||
// the first command. Displaying them is harmless but might cause confusion.
|
||||
if (!cfgOptionValid(optionId) || !cfgDefOptionValid(cfgCommand(), optionId))
|
||||
if (!cfgOptionValid(optionId) || !cfgParseOptionValid(cfgCommand(), optionId))
|
||||
continue;
|
||||
|
||||
// Loop through option indexes
|
||||
@ -94,10 +94,10 @@ cmdOption(void)
|
||||
else if (cfgOptionIdxSource(optionId, optionIdx) != cfgSourceDefault)
|
||||
{
|
||||
// Don't show redacted options
|
||||
if (cfgDefOptionSecure(optionId))
|
||||
if (cfgParseOptionSecure(optionId))
|
||||
strCatFmt(cmdOptionStr, " --%s=<redacted>", cfgOptionIdxName(optionId, optionIdx));
|
||||
// Output boolean option
|
||||
else if (cfgDefOptionType(optionId) == cfgDefOptTypeBoolean)
|
||||
else if (cfgParseOptionType(optionId) == cfgOptTypeBoolean)
|
||||
strCatFmt(cmdOptionStr, " --%s", cfgOptionIdxName(optionId, optionIdx));
|
||||
// Output other options
|
||||
else
|
||||
@ -105,7 +105,7 @@ cmdOption(void)
|
||||
StringList *valueList = NULL;
|
||||
|
||||
// Generate the values of hash options
|
||||
if (cfgDefOptionType(optionId) == cfgDefOptTypeHash)
|
||||
if (cfgParseOptionType(optionId) == cfgOptTypeHash)
|
||||
{
|
||||
valueList = strLstNew();
|
||||
|
||||
@ -122,12 +122,12 @@ cmdOption(void)
|
||||
}
|
||||
}
|
||||
// Generate values for list options
|
||||
else if (cfgDefOptionType(optionId) == cfgDefOptTypeList)
|
||||
else if (cfgParseOptionType(optionId) == cfgOptTypeList)
|
||||
{
|
||||
valueList = strLstNewVarLst(cfgOptionIdxLst(optionId, optionIdx));
|
||||
}
|
||||
// Generate time value
|
||||
else if (cfgDefOptionType(optionId) == cfgDefOptTypeTime)
|
||||
else if (cfgParseOptionType(optionId) == cfgOptTypeTime)
|
||||
{
|
||||
valueList = strLstNew();
|
||||
strLstAdd(
|
||||
|
@ -12,7 +12,6 @@ Help Command
|
||||
#include "common/memContext.h"
|
||||
#include "common/type/pack.h"
|
||||
#include "config/config.h"
|
||||
#include "config/define.h"
|
||||
#include "config/parse.h"
|
||||
#include "version.h"
|
||||
|
||||
@ -81,7 +80,7 @@ helpRenderText(const String *text, size_t indent, bool indentFirst, size_t lengt
|
||||
Helper function for helpRender() to output values as strings
|
||||
***********************************************************************************************************************************/
|
||||
static const String *
|
||||
helpRenderValue(const Variant *value, ConfigDefineOptionType type)
|
||||
helpRenderValue(const Variant *value, ConfigOptionType type)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelTrace);
|
||||
FUNCTION_LOG_PARAM(VARIANT, value);
|
||||
@ -134,7 +133,7 @@ helpRenderValue(const Variant *value, ConfigDefineOptionType type)
|
||||
|
||||
result = resultTemp;
|
||||
}
|
||||
else if (type == cfgDefOptTypeTime)
|
||||
else if (type == cfgOptTypeTime)
|
||||
result = cvtDoubleToStr((double)varInt64(value) / MSEC_PER_SEC);
|
||||
else
|
||||
result = varStrForce(value);
|
||||
@ -326,7 +325,7 @@ helpRender(void)
|
||||
|
||||
for (unsigned int optionId = 0; optionId < CFG_OPTION_TOTAL; optionId++)
|
||||
{
|
||||
if (cfgDefOptionValid(commandId, optionId) && !optionData[optionId].internal)
|
||||
if (cfgParseOptionValid(commandId, optionId) && !optionData[optionId].internal)
|
||||
{
|
||||
const String *section = optionData[optionId].section;
|
||||
|
||||
@ -339,8 +338,8 @@ helpRender(void)
|
||||
|
||||
kvAdd(optionKv, VARSTR(section), VARINT((int)optionId));
|
||||
|
||||
if (strlen(cfgDefOptionName(optionId)) > optionSizeMax)
|
||||
optionSizeMax = strlen(cfgDefOptionName(optionId));
|
||||
if (strlen(cfgParseOptionName(optionId)) > optionSizeMax)
|
||||
optionSizeMax = strlen(cfgParseOptionName(optionId));
|
||||
}
|
||||
}
|
||||
|
||||
@ -365,18 +364,18 @@ helpRender(void)
|
||||
strNewN(strZ(optionData[optionId].summary), strSize(optionData[optionId].summary) - 1));
|
||||
|
||||
// Ouput current and default values if they exist
|
||||
const String *defaultValue = helpRenderValue(cfgOptionDefault(optionId), cfgDefOptionType(optionId));
|
||||
const String *defaultValue = helpRenderValue(cfgOptionDefault(optionId), cfgParseOptionType(optionId));
|
||||
const String *value = NULL;
|
||||
|
||||
if (cfgOptionSource(optionId) != cfgSourceDefault)
|
||||
value = helpRenderValue(cfgOption(optionId), cfgDefOptionType(optionId));
|
||||
value = helpRenderValue(cfgOption(optionId), cfgParseOptionType(optionId));
|
||||
|
||||
if (value != NULL || defaultValue != NULL)
|
||||
{
|
||||
strCatZ(summary, " [");
|
||||
|
||||
if (value != NULL)
|
||||
strCatFmt(summary, "current=%s", cfgDefOptionSecure(optionId) ? "<redacted>" : strZ(value));
|
||||
strCatFmt(summary, "current=%s", cfgParseOptionSecure(optionId) ? "<redacted>" : strZ(value));
|
||||
|
||||
if (defaultValue != NULL)
|
||||
{
|
||||
@ -392,7 +391,7 @@ helpRender(void)
|
||||
// Output option help
|
||||
strCatFmt(
|
||||
result, " --%s%*s%s\n",
|
||||
cfgDefOptionName(optionId), (int)(optionSizeMax - strlen(cfgDefOptionName(optionId)) + 2), "",
|
||||
cfgParseOptionName(optionId), (int)(optionSizeMax - strlen(cfgParseOptionName(optionId)) + 2), "",
|
||||
strZ(helpRenderText(summary, optionSizeMax + 6, false, CONSOLE_WIDTH)));
|
||||
}
|
||||
}
|
||||
@ -414,7 +413,7 @@ helpRender(void)
|
||||
|
||||
if (!option.found)
|
||||
{
|
||||
int optionId = cfgDefOptionId(strZ(optionName));
|
||||
int optionId = cfgParseOptionId(strZ(optionName));
|
||||
|
||||
if (optionId == -1)
|
||||
THROW_FMT(OptionInvalidError, "option '%s' is not valid for command '%s'", strZ(optionName), commandName);
|
||||
@ -430,23 +429,23 @@ helpRender(void)
|
||||
"%s\n"
|
||||
"\n"
|
||||
"%s\n",
|
||||
cfgDefOptionName(option.id),
|
||||
cfgParseOptionName(option.id),
|
||||
strZ(helpRenderText(optionData[option.id].summary, 0, true, CONSOLE_WIDTH)),
|
||||
strZ(helpRenderText(optionData[option.id].description, 0, true, CONSOLE_WIDTH)));
|
||||
|
||||
// Ouput current and default values if they exist
|
||||
const String *defaultValue = helpRenderValue(cfgOptionDefault(option.id), cfgDefOptionType(option.id));
|
||||
const String *defaultValue = helpRenderValue(cfgOptionDefault(option.id), cfgParseOptionType(option.id));
|
||||
const String *value = NULL;
|
||||
|
||||
if (cfgOptionSource(option.id) != cfgSourceDefault)
|
||||
value = helpRenderValue(cfgOption(option.id), cfgDefOptionType(option.id));
|
||||
value = helpRenderValue(cfgOption(option.id), cfgParseOptionType(option.id));
|
||||
|
||||
if (value != NULL || defaultValue != NULL)
|
||||
{
|
||||
strCat(result, LF_STR);
|
||||
|
||||
if (value != NULL)
|
||||
strCatFmt(result, "current: %s\n", cfgDefOptionSecure(option.id) ? "<redacted>" : strZ(value));
|
||||
strCatFmt(result, "current: %s\n", cfgParseOptionSecure(option.id) ? "<redacted>" : strZ(value));
|
||||
|
||||
if (defaultValue != NULL)
|
||||
strCatFmt(result, "default: %s\n", strZ(defaultValue));
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -9,7 +9,7 @@ Command and Option Configuration
|
||||
#include "common/error.h"
|
||||
#include "common/memContext.h"
|
||||
#include "config/config.intern.h"
|
||||
#include "config/define.h"
|
||||
#include "config/parse.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Map command names to ids and vice versa
|
||||
@ -24,8 +24,6 @@ typedef struct ConfigCommandData
|
||||
|
||||
bool logFile:1;
|
||||
unsigned int logLevelDefault:4;
|
||||
|
||||
bool parameterAllowed:1;
|
||||
} ConfigCommandData;
|
||||
|
||||
#define CONFIG_COMMAND_LIST(...) \
|
||||
@ -46,39 +44,6 @@ typedef struct ConfigCommandData
|
||||
.logLevelDefault = logLevelDefaultParam,
|
||||
#define CONFIG_COMMAND_NAME(nameParam) \
|
||||
.name = nameParam,
|
||||
#define CONFIG_COMMAND_PARAMETER_ALLOWED(parameterAllowedParam) \
|
||||
.parameterAllowed = parameterAllowedParam,
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Option group data
|
||||
***********************************************************************************************************************************/
|
||||
typedef struct ConfigOptionGroupData
|
||||
{
|
||||
const char *name; // All options in the group must be prefixed with this name
|
||||
} ConfigOptionGroupData;
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Map options names and indexes to option definitions
|
||||
***********************************************************************************************************************************/
|
||||
typedef struct ConfigOptionData
|
||||
{
|
||||
const char *name; // Option name
|
||||
bool group:1; // Is the option in a group?
|
||||
unsigned int groupId:1; // Group id if option is in a group
|
||||
} ConfigOptionData;
|
||||
|
||||
#define CONFIG_OPTION_LIST(...) \
|
||||
{__VA_ARGS__};
|
||||
|
||||
#define CONFIG_OPTION(...) \
|
||||
{__VA_ARGS__},
|
||||
|
||||
#define CONFIG_OPTION_NAME(nameParam) \
|
||||
.name = nameParam,
|
||||
#define CONFIG_OPTION_GROUP(groupParam) \
|
||||
.group = groupParam,
|
||||
#define CONFIG_OPTION_GROUP_ID(groupIdParam) \
|
||||
.groupId = groupIdParam,
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Include the automatically generated configuration data
|
||||
@ -367,19 +332,6 @@ cfgLogLevelDefault(void)
|
||||
FUNCTION_TEST_RETURN((LogLevel)configCommandData[cfgCommand()].logLevelDefault);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
bool
|
||||
cfgCommandParameterAllowed(ConfigCommand commandId)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(ENUM, commandId);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(commandId < cfgCmdNone);
|
||||
|
||||
FUNCTION_TEST_RETURN(configCommandData[commandId].parameterAllowed);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
bool
|
||||
cfgOptionGroup(ConfigOption optionId)
|
||||
@ -388,9 +340,10 @@ cfgOptionGroup(ConfigOption optionId)
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(configLocal != NULL);
|
||||
ASSERT(optionId < CFG_OPTION_TOTAL);
|
||||
|
||||
FUNCTION_TEST_RETURN(configOptionData[optionId].group);
|
||||
FUNCTION_TEST_RETURN(configLocal->option[optionId].group);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
@ -401,10 +354,11 @@ cfgOptionGroupId(ConfigOption optionId)
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(configLocal != NULL);
|
||||
ASSERT(optionId < CFG_OPTION_TOTAL);
|
||||
ASSERT(configOptionData[optionId].group);
|
||||
ASSERT(configLocal->option[optionId].group);
|
||||
|
||||
FUNCTION_TEST_RETURN(configOptionData[optionId].groupId);
|
||||
FUNCTION_TEST_RETURN(configLocal->option[optionId].groupId);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
@ -465,7 +419,7 @@ cfgOptionKeyToIdx(ConfigOption optionId, unsigned int key)
|
||||
|
||||
// Error when the key is not found
|
||||
if (result == cfgOptionGroupIdxTotal(groupId))
|
||||
THROW_FMT(AssertError, "key '%u' is not valid for '%s' option", key, configOptionData[optionId].name);
|
||||
THROW_FMT(AssertError, "key '%u' is not valid for '%s' option", key, configLocal->option[optionId].name);
|
||||
}
|
||||
|
||||
FUNCTION_TEST_RETURN(result);
|
||||
@ -511,7 +465,7 @@ cfgOptionIdxDefault(ConfigOption optionId)
|
||||
ASSERT(optionId < CFG_OPTION_TOTAL);
|
||||
|
||||
FUNCTION_TEST_RETURN(
|
||||
configOptionData[optionId].group ? configLocal->optionGroup[configOptionData[optionId].groupId].indexDefault : 0);
|
||||
configLocal->option[optionId].group ? configLocal->optionGroup[configLocal->option[optionId].groupId].indexDefault : 0);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
@ -526,7 +480,7 @@ cfgOptionIdxTotal(ConfigOption optionId)
|
||||
ASSERT(optionId < CFG_OPTION_TOTAL);
|
||||
|
||||
FUNCTION_TEST_RETURN(
|
||||
configOptionData[optionId].group ? configLocal->optionGroup[configOptionData[optionId].groupId].indexTotal : 1);
|
||||
configLocal->option[optionId].group ? configLocal->optionGroup[configLocal->option[optionId].groupId].indexTotal : 1);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
@ -538,31 +492,31 @@ cfgOptionDefaultValue(ConfigOption optionId)
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
Variant *result;
|
||||
Variant *defaultValue = varNewStrZ(cfgDefOptionDefault(cfgCommand(), optionId));
|
||||
Variant *defaultValue = varNewStrZ(cfgParseOptionDefault(cfgCommand(), optionId));
|
||||
|
||||
switch (cfgDefOptionType(optionId))
|
||||
switch (cfgParseOptionType(optionId))
|
||||
{
|
||||
case cfgDefOptTypeBoolean:
|
||||
case cfgOptTypeBoolean:
|
||||
{
|
||||
result = varNewBool(varBoolForce(defaultValue));
|
||||
break;
|
||||
}
|
||||
|
||||
case cfgDefOptTypeInteger:
|
||||
case cfgDefOptTypeSize:
|
||||
case cfgDefOptTypeTime:
|
||||
case cfgOptTypeInteger:
|
||||
case cfgOptTypeSize:
|
||||
case cfgOptTypeTime:
|
||||
{
|
||||
result = varNewInt64(varInt64Force(defaultValue));
|
||||
break;
|
||||
}
|
||||
|
||||
case cfgDefOptTypePath:
|
||||
case cfgDefOptTypeString:
|
||||
case cfgOptTypePath:
|
||||
case cfgOptTypeString:
|
||||
result = varDup(defaultValue);
|
||||
break;
|
||||
|
||||
default:
|
||||
THROW_FMT(AssertError, "default value not available for option type %d", cfgDefOptionType(optionId));
|
||||
THROW_FMT(AssertError, "default value not available for option type %u", cfgParseOptionType(optionId));
|
||||
}
|
||||
|
||||
FUNCTION_TEST_RETURN(result);
|
||||
@ -580,7 +534,7 @@ cfgOptionDefault(ConfigOption optionId)
|
||||
|
||||
if (configLocal->option[optionId].defaultValue == NULL)
|
||||
{
|
||||
if (cfgDefOptionDefault(cfgCommand(), optionId) != NULL)
|
||||
if (cfgParseOptionDefault(cfgCommand(), optionId) != NULL)
|
||||
{
|
||||
MEM_CONTEXT_BEGIN(configLocal->memContext)
|
||||
{
|
||||
@ -646,8 +600,9 @@ cfgOptionIdxHostPort(ConfigOption optionId, unsigned int optionIdx, unsigned int
|
||||
ASSERT(optionId < CFG_OPTION_TOTAL);
|
||||
ASSERT(configLocal != NULL);
|
||||
ASSERT(
|
||||
(!configOptionData[optionId].group && optionIdx == 0) ||
|
||||
(configOptionData[optionId].group && optionIdx < configLocal->optionGroup[configOptionData[optionId].groupId].indexTotal));
|
||||
(!configLocal->option[optionId].group && optionIdx == 0) ||
|
||||
(configLocal->option[optionId].group && optionIdx <
|
||||
configLocal->optionGroup[configLocal->option[optionId].groupId].indexTotal));
|
||||
ASSERT(port != NULL);
|
||||
|
||||
String *result = NULL;
|
||||
@ -727,33 +682,6 @@ cfgOptionName(ConfigOption optionId)
|
||||
FUNCTION_TEST_RETURN(cfgOptionIdxName(optionId, cfgOptionIdxDefault(optionId)));
|
||||
}
|
||||
|
||||
const char *
|
||||
cfgOptionKeyIdxName(ConfigOption optionId, unsigned int keyIdx)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_PARAM(UINT, keyIdx);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(optionId < CFG_OPTION_TOTAL);
|
||||
ASSERT((!configOptionData[optionId].group && keyIdx == 0) || configOptionData[optionId].group);
|
||||
|
||||
// If the option is in a group then construct the name
|
||||
if (configOptionData[optionId].group)
|
||||
{
|
||||
// This is somewhat less than ideal since memory is being allocated with each call, rather than caching prior results. In
|
||||
// practice the number of allocations should be quite small so we'll ignore this for now.
|
||||
String *name = strNewFmt(
|
||||
"%s%u%s", configOptionGroupData[configOptionData[optionId].groupId].name, keyIdx + 1,
|
||||
configOptionData[optionId].name + strlen(configOptionGroupData[configOptionData[optionId].groupId].name));
|
||||
|
||||
FUNCTION_TEST_RETURN(strZ(name));
|
||||
}
|
||||
|
||||
// Else return the stored name
|
||||
FUNCTION_TEST_RETURN(configOptionData[optionId].name);
|
||||
}
|
||||
|
||||
const char *
|
||||
cfgOptionIdxName(ConfigOption optionId, unsigned int optionIdx)
|
||||
{
|
||||
@ -765,16 +693,23 @@ cfgOptionIdxName(ConfigOption optionId, unsigned int optionIdx)
|
||||
ASSERT(optionId < CFG_OPTION_TOTAL);
|
||||
ASSERT(configLocal != NULL);
|
||||
ASSERT(
|
||||
(!configOptionData[optionId].group && optionIdx == 0) ||
|
||||
(configOptionData[optionId].group && optionIdx < configLocal->optionGroup[configOptionData[optionId].groupId].indexTotal));
|
||||
(!configLocal->option[optionId].group && optionIdx == 0) ||
|
||||
(configLocal->option[optionId].group && optionIdx <
|
||||
configLocal->optionGroup[configLocal->option[optionId].groupId].indexTotal));
|
||||
|
||||
if (configOptionData[optionId].group)
|
||||
if (configLocal->option[optionId].group)
|
||||
{
|
||||
FUNCTION_TEST_RETURN(
|
||||
cfgOptionKeyIdxName(optionId, configLocal->optionGroup[configOptionData[optionId].groupId].indexMap[optionIdx]));
|
||||
// This is somewhat less than ideal since memory is being allocated with each call, rather than caching prior results. In
|
||||
// practice the number of allocations should be quite small so we'll ignore this for now.
|
||||
String *name = strNewFmt(
|
||||
"%s%u%s", configLocal->optionGroup[configLocal->option[optionId].groupId].name,
|
||||
configLocal->optionGroup[configLocal->option[optionId].groupId].indexMap[optionIdx] + 1,
|
||||
configLocal->option[optionId].name + strlen(configLocal->optionGroup[configLocal->option[optionId].groupId].name));
|
||||
|
||||
FUNCTION_TEST_RETURN(strZ(name));
|
||||
}
|
||||
|
||||
FUNCTION_TEST_RETURN(configOptionData[optionId].name);
|
||||
FUNCTION_TEST_RETURN(configLocal->option[optionId].name);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
@ -799,8 +734,9 @@ cfgOptionIdxNegate(ConfigOption optionId, unsigned int optionIdx)
|
||||
ASSERT(optionId < CFG_OPTION_TOTAL);
|
||||
ASSERT(configLocal != NULL);
|
||||
ASSERT(
|
||||
(!configOptionData[optionId].group && optionIdx == 0) ||
|
||||
(configOptionData[optionId].group && optionIdx < configLocal->optionGroup[configOptionData[optionId].groupId].indexTotal));
|
||||
(!configLocal->option[optionId].group && optionIdx == 0) ||
|
||||
(configLocal->option[optionId].group && optionIdx <
|
||||
configLocal->optionGroup[configLocal->option[optionId].groupId].indexTotal));
|
||||
|
||||
FUNCTION_TEST_RETURN(configLocal->option[optionId].index[optionIdx].negate);
|
||||
}
|
||||
@ -827,8 +763,9 @@ cfgOptionIdxReset(ConfigOption optionId, unsigned int optionIdx)
|
||||
ASSERT(optionId < CFG_OPTION_TOTAL);
|
||||
ASSERT(configLocal != NULL);
|
||||
ASSERT(
|
||||
(!configOptionData[optionId].group && optionIdx == 0) ||
|
||||
(configOptionData[optionId].group && optionIdx < configLocal->optionGroup[configOptionData[optionId].groupId].indexTotal));
|
||||
(!configLocal->option[optionId].group && optionIdx == 0) ||
|
||||
(configLocal->option[optionId].group && optionIdx <
|
||||
configLocal->optionGroup[configLocal->option[optionId].groupId].indexTotal));
|
||||
|
||||
FUNCTION_TEST_RETURN(configLocal->option[optionId].index[optionIdx].reset);
|
||||
}
|
||||
@ -848,8 +785,9 @@ cfgOptionIdxInternal(ConfigOption optionId, unsigned int optionIdx, VariantType
|
||||
ASSERT(optionId < CFG_OPTION_TOTAL);
|
||||
ASSERT(configLocal != NULL);
|
||||
ASSERT(
|
||||
(!configOptionData[optionId].group && optionIdx == 0) ||
|
||||
(configOptionData[optionId].group && optionIdx < configLocal->optionGroup[configOptionData[optionId].groupId].indexTotal));
|
||||
(!configLocal->option[optionId].group && optionIdx == 0) ||
|
||||
(configLocal->option[optionId].group && optionIdx <
|
||||
configLocal->optionGroup[configLocal->option[optionId].groupId].indexTotal));
|
||||
|
||||
// Check that the option is valid for the current command
|
||||
if (!cfgOptionValid(optionId))
|
||||
@ -894,8 +832,9 @@ cfgOptionIdx(ConfigOption optionId, unsigned int optionIdx)
|
||||
|
||||
ASSERT(configLocal != NULL);
|
||||
ASSERT(
|
||||
(!configOptionData[optionId].group && optionIdx == 0) ||
|
||||
(configOptionData[optionId].group && optionIdx < configLocal->optionGroup[configOptionData[optionId].groupId].indexTotal));
|
||||
(!configLocal->option[optionId].group && optionIdx == 0) ||
|
||||
(configLocal->option[optionId].group && optionIdx <
|
||||
configLocal->optionGroup[configLocal->option[optionId].groupId].indexTotal));
|
||||
|
||||
FUNCTION_TEST_RETURN(configLocal->option[optionId].index[optionIdx].value);
|
||||
}
|
||||
@ -1131,8 +1070,9 @@ cfgOptionIdxSet(ConfigOption optionId, unsigned int optionIdx, ConfigSource sour
|
||||
ASSERT(optionId < CFG_OPTION_TOTAL);
|
||||
ASSERT(configLocal != NULL);
|
||||
ASSERT(
|
||||
(!configOptionData[optionId].group && optionIdx == 0) ||
|
||||
(configOptionData[optionId].group && optionIdx < configLocal->optionGroup[configOptionData[optionId].groupId].indexTotal));
|
||||
(!configLocal->option[optionId].group && optionIdx == 0) ||
|
||||
(configLocal->option[optionId].group && optionIdx <
|
||||
configLocal->optionGroup[configLocal->option[optionId].groupId].indexTotal));
|
||||
|
||||
MEM_CONTEXT_BEGIN(configLocal->memContext)
|
||||
{
|
||||
@ -1142,9 +1082,9 @@ cfgOptionIdxSet(ConfigOption optionId, unsigned int optionIdx, ConfigSource sour
|
||||
// Only set value if it is not null
|
||||
if (value != NULL)
|
||||
{
|
||||
switch (cfgDefOptionType(optionId))
|
||||
switch (cfgParseOptionType(optionId))
|
||||
{
|
||||
case cfgDefOptTypeBoolean:
|
||||
case cfgOptTypeBoolean:
|
||||
{
|
||||
if (varType(value) == varTypeBool)
|
||||
configLocal->option[optionId].index[optionIdx].value = varDup(value);
|
||||
@ -1154,9 +1094,9 @@ cfgOptionIdxSet(ConfigOption optionId, unsigned int optionIdx, ConfigSource sour
|
||||
break;
|
||||
}
|
||||
|
||||
case cfgDefOptTypeInteger:
|
||||
case cfgDefOptTypeSize:
|
||||
case cfgDefOptTypeTime:
|
||||
case cfgOptTypeInteger:
|
||||
case cfgOptTypeSize:
|
||||
case cfgOptTypeTime:
|
||||
{
|
||||
if (varType(value) == varTypeInt64)
|
||||
configLocal->option[optionId].index[optionIdx].value = varDup(value);
|
||||
@ -1166,8 +1106,8 @@ cfgOptionIdxSet(ConfigOption optionId, unsigned int optionIdx, ConfigSource sour
|
||||
break;
|
||||
}
|
||||
|
||||
case cfgDefOptTypePath:
|
||||
case cfgDefOptTypeString:
|
||||
case cfgOptTypePath:
|
||||
case cfgOptTypeString:
|
||||
{
|
||||
if (varType(value) == varTypeString)
|
||||
configLocal->option[optionId].index[optionIdx].value = varDup(value);
|
||||
@ -1181,7 +1121,7 @@ cfgOptionIdxSet(ConfigOption optionId, unsigned int optionIdx, ConfigSource sour
|
||||
}
|
||||
|
||||
default:
|
||||
THROW_FMT(AssertError, "set not available for option type %d", cfgDefOptionType(optionId));
|
||||
THROW_FMT(AssertError, "set not available for option type %u", cfgParseOptionType(optionId));
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -1214,8 +1154,9 @@ cfgOptionIdxSource(ConfigOption optionId, unsigned int optionIdx)
|
||||
ASSERT(optionId < CFG_OPTION_TOTAL);
|
||||
ASSERT(configLocal != NULL);
|
||||
ASSERT(
|
||||
(!configOptionData[optionId].group && optionIdx == 0) ||
|
||||
(configOptionData[optionId].group && optionIdx < configLocal->optionGroup[configOptionData[optionId].groupId].indexTotal));
|
||||
(!configLocal->option[optionId].group && optionIdx == 0) ||
|
||||
(configLocal->option[optionId].group && optionIdx <
|
||||
configLocal->optionGroup[configLocal->option[optionId].groupId].indexTotal));
|
||||
|
||||
FUNCTION_TEST_RETURN(configLocal->option[optionId].index[optionIdx].source);
|
||||
}
|
||||
@ -1242,8 +1183,9 @@ cfgOptionIdxTest(ConfigOption optionId, unsigned int optionIdx)
|
||||
ASSERT(optionId < CFG_OPTION_TOTAL);
|
||||
ASSERT(configLocal != NULL);
|
||||
ASSERT(
|
||||
(!configOptionData[optionId].group && optionIdx == 0) ||
|
||||
(configOptionData[optionId].group && optionIdx < configLocal->optionGroup[configOptionData[optionId].groupId].indexTotal));
|
||||
(!configLocal->option[optionId].group && optionIdx == 0) ||
|
||||
(configLocal->option[optionId].group && optionIdx <
|
||||
configLocal->optionGroup[configLocal->option[optionId].groupId].indexTotal));
|
||||
|
||||
FUNCTION_TEST_RETURN(cfgOptionValid(optionId) && configLocal->option[optionId].index[optionIdx].value != NULL);
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ config/parse.c sets the command and options and determines which options are val
|
||||
#include "common/lock.h"
|
||||
#include "common/log.h"
|
||||
#include "common/type/stringList.h"
|
||||
|
||||
#include "config/config.auto.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
@ -87,9 +86,6 @@ LogLevel cfgLogLevelDefault(void);
|
||||
// Command parameters, if any
|
||||
const StringList *cfgCommandParam(void);
|
||||
|
||||
// Does this command allow parameters?
|
||||
bool cfgCommandParameterAllowed(ConfigCommand commandId);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Option Group Functions
|
||||
***********************************************************************************************************************************/
|
||||
|
@ -43,6 +43,7 @@ typedef struct Config
|
||||
// Group options that are related together to allow valid and test checks across all options in the group
|
||||
struct
|
||||
{
|
||||
const char *name; // Name
|
||||
bool valid; // Is option group valid for the current command?
|
||||
unsigned int indexTotal; // Total number of indexes with values in option group
|
||||
unsigned int indexDefault; // Default index (usually 0)
|
||||
@ -52,7 +53,10 @@ typedef struct Config
|
||||
// Option data
|
||||
struct
|
||||
{
|
||||
const char *name; // Name
|
||||
bool valid; // Is option valid for current command?
|
||||
bool group; // In a group?
|
||||
unsigned int groupId; // Id if in a group
|
||||
const Variant *defaultValue; // Default value
|
||||
ConfigOptionValue *index; // List of indexed values (only 1 unless the option is indexed)
|
||||
} option[CFG_OPTION_TOTAL];
|
||||
@ -76,10 +80,6 @@ unsigned int cfgOptionGroupId(ConfigOption optionId);
|
||||
/***********************************************************************************************************************************
|
||||
Option Functions
|
||||
***********************************************************************************************************************************/
|
||||
// Get the option name using the key index -- i.e. the key that was used during configuration - 1, e.g. to get pg2-host pass 1 to
|
||||
// keyIdx.
|
||||
const char *cfgOptionKeyIdxName(ConfigOption optionId, unsigned int keyIdx);
|
||||
|
||||
// Convert the key used in the original configuration to a group index. This is used when an option key must be translated into the
|
||||
// local group index, e.g. during parsing or when getting the value of specific options from a remote.
|
||||
unsigned int cfgOptionKeyToIdx(ConfigOption optionId, unsigned int key);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,596 +0,0 @@
|
||||
/***********************************************************************************************************************************
|
||||
Command and Option Configuration Definition
|
||||
***********************************************************************************************************************************/
|
||||
#include "build.auto.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/error.h"
|
||||
#include "config/define.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Define global section name
|
||||
***********************************************************************************************************************************/
|
||||
STRING_EXTERN(CFGDEF_SECTION_GLOBAL_STR, CFGDEF_SECTION_GLOBAL);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Map command names to ids and vice versa.
|
||||
***********************************************************************************************************************************/
|
||||
typedef struct ConfigDefineCommandData
|
||||
{
|
||||
const char *name; // Command name
|
||||
} ConfigDefineCommandData;
|
||||
|
||||
// Command macros are intended to make the command definitions easy to read and to produce good diffs.
|
||||
//----------------------------------------------------------------------------------------------------------------------------------
|
||||
#define CFGDEFDATA_COMMAND_LIST(...) \
|
||||
{__VA_ARGS__};
|
||||
|
||||
#define CFGDEFDATA_COMMAND(...) \
|
||||
{__VA_ARGS__},
|
||||
|
||||
#define CFGDEFDATA_COMMAND_NAME(nameParam) \
|
||||
.name = nameParam,
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Define how an option is parsed and interacts with other options.
|
||||
***********************************************************************************************************************************/
|
||||
typedef struct ConfigDefineOptionData
|
||||
{
|
||||
const char *name; // Option name
|
||||
unsigned int type:3; // Option type (e.g. string, int, boolean, etc.)
|
||||
unsigned int section:2; // Config section (e.g. global, stanza, cmd-line)
|
||||
bool required:1; // Is the option required?
|
||||
bool secure:1; // Does the option need to be redacted on logs and cmd-line?
|
||||
unsigned int commandValid:20; // Bitmap for commands that the option is valid for
|
||||
|
||||
const void **data; // Optional data and command overrides
|
||||
} ConfigDefineOptionData;
|
||||
|
||||
// Option macros are intended to make the command definitions easy to read and to produce good diffs.
|
||||
//----------------------------------------------------------------------------------------------------------------------------------
|
||||
#define CFGDEFDATA_OPTION_LIST(...) \
|
||||
{__VA_ARGS__};
|
||||
|
||||
#define CFGDEFDATA_OPTION(...) \
|
||||
{__VA_ARGS__},
|
||||
|
||||
#define CFGDEFDATA_OPTION_NAME(nameParam) \
|
||||
.name = nameParam,
|
||||
#define CFGDEFDATA_OPTION_REQUIRED(requiredParam) \
|
||||
.required = requiredParam,
|
||||
#define CFGDEFDATA_OPTION_SECTION(sectionParam) \
|
||||
.section = sectionParam,
|
||||
#define CFGDEFDATA_OPTION_SECURE(secureParam) \
|
||||
.secure = secureParam,
|
||||
#define CFGDEFDATA_OPTION_TYPE(typeParam) \
|
||||
.type = typeParam,
|
||||
|
||||
// Define additional types of data that can be associated with an option. Because these types are rare they are not give dedicated
|
||||
// fields and are instead packed into an array which is read at runtime. This may seem inefficient but they are only accessed a
|
||||
// single time during parse so space efficiency is more important than performance.
|
||||
//----------------------------------------------------------------------------------------------------------------------------------
|
||||
typedef enum
|
||||
{
|
||||
configDefDataTypeEnd, // Indicates there is no more data
|
||||
configDefDataTypeAllowList,
|
||||
configDefDataTypeAllowRange,
|
||||
configDefDataTypeCommand,
|
||||
configDefDataTypeDefault,
|
||||
configDefDataTypeDepend,
|
||||
configDefDataTypeRequired,
|
||||
} ConfigDefineDataType;
|
||||
|
||||
#define CFGDATA_OPTION_OPTIONAL_PUSH_LIST(type, size, data, ...) \
|
||||
(const void *)((uint32_t)type << 24 | (uint32_t)size << 16 | (uint32_t)data), __VA_ARGS__
|
||||
|
||||
#define CFGDATA_OPTION_OPTIONAL_PUSH(type, size, data) \
|
||||
(const void *)((uint32_t)type << 24 | (uint32_t)size << 16 | (uint32_t)data)
|
||||
|
||||
#define CFGDEFDATA_OPTION_COMMAND_LIST(...) \
|
||||
.commandValid = 0 __VA_ARGS__,
|
||||
|
||||
#define CFGDEFDATA_OPTION_COMMAND(commandParam) \
|
||||
| (1 << commandParam)
|
||||
|
||||
#define CFGDEFDATA_OPTION_OPTIONAL_LIST(...) \
|
||||
.data = (const void *[]){__VA_ARGS__ NULL},
|
||||
|
||||
#define CFGDEFDATA_OPTION_OPTIONAL_DEFAULT(defaultValue) \
|
||||
CFGDATA_OPTION_OPTIONAL_PUSH_LIST(configDefDataTypeDefault, 1, 0, defaultValue),
|
||||
|
||||
#define CFGDEFDATA_OPTION_OPTIONAL_ALLOW_LIST(...) \
|
||||
CFGDATA_OPTION_OPTIONAL_PUSH_LIST( \
|
||||
configDefDataTypeAllowList, sizeof((const char *[]){__VA_ARGS__}) / sizeof(const char *), 0, __VA_ARGS__),
|
||||
|
||||
#define CFGDEFDATA_OPTION_OPTIONAL_ALLOW_RANGE(rangeMinParam, rangeMaxParam) \
|
||||
CFGDATA_OPTION_OPTIONAL_PUSH_LIST( \
|
||||
configDefDataTypeAllowRange, 4, 0, \
|
||||
(const void *)(intptr_t)(int32_t)((int64_t)rangeMinParam >> 32), \
|
||||
(const void *)(intptr_t)(int32_t)((int64_t)rangeMinParam & 0xFFFFFFFF), \
|
||||
(const void *)(intptr_t)(int32_t)((int64_t)rangeMaxParam >> 32), \
|
||||
(const void *)(intptr_t)(int32_t)((int64_t)rangeMaxParam & 0xFFFFFFFF)),
|
||||
|
||||
#define CFGDEFDATA_OPTION_OPTIONAL_DEPEND(optionDepend) \
|
||||
CFGDATA_OPTION_OPTIONAL_PUSH(configDefDataTypeDepend, 0, optionDepend),
|
||||
|
||||
#define CFGDEFDATA_OPTION_OPTIONAL_DEPEND_LIST(optionDepend, ...) \
|
||||
CFGDATA_OPTION_OPTIONAL_PUSH_LIST( \
|
||||
configDefDataTypeDepend, sizeof((const char *[]){__VA_ARGS__}) / sizeof(const char *), optionDepend, __VA_ARGS__),
|
||||
|
||||
#define CFGDEFDATA_OPTION_OPTIONAL_COMMAND_OVERRIDE(...) \
|
||||
__VA_ARGS__
|
||||
|
||||
#define CFGDEFDATA_OPTION_OPTIONAL_COMMAND(command) \
|
||||
CFGDATA_OPTION_OPTIONAL_PUSH(configDefDataTypeCommand, 0, command),
|
||||
|
||||
#define CFGDEFDATA_OPTION_OPTIONAL_REQUIRED(commandOptionRequired) \
|
||||
CFGDATA_OPTION_OPTIONAL_PUSH(configDefDataTypeRequired, 0, commandOptionRequired),
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Include the automatically generated configuration data.
|
||||
***********************************************************************************************************************************/
|
||||
#include "config/define.auto.c"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Find optional data for a command and option.
|
||||
***********************************************************************************************************************************/
|
||||
static void
|
||||
cfgDefDataFind(
|
||||
ConfigDefineDataType typeFind, ConfigCommand commandId, const void **dataList, bool *dataDefFound, int *dataDef,
|
||||
const void ***dataDefList, unsigned int *dataDefListSize)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(ENUM, typeFind);
|
||||
FUNCTION_TEST_PARAM(ENUM, commandId);
|
||||
FUNCTION_TEST_PARAM_PP(VOID, dataList);
|
||||
FUNCTION_TEST_PARAM_P(BOOL, dataDefFound);
|
||||
FUNCTION_TEST_PARAM_P(INT, dataDef);
|
||||
FUNCTION_TEST_PARAM_PP(VOID, dataDefList);
|
||||
FUNCTION_TEST_PARAM_P(UINT, dataDefListSize);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(dataDefFound != NULL);
|
||||
ASSERT(dataDef != NULL);
|
||||
ASSERT(dataDefList != NULL);
|
||||
ASSERT(dataDefListSize != NULL);
|
||||
|
||||
*dataDefFound = false;
|
||||
|
||||
// Only proceed if there is data
|
||||
if (dataList != NULL)
|
||||
{
|
||||
ConfigDefineDataType type;
|
||||
unsigned int offset = 0;
|
||||
unsigned int size;
|
||||
int data;
|
||||
unsigned int commandCurrent = UINT_MAX;
|
||||
|
||||
// Loop through all data
|
||||
do
|
||||
{
|
||||
// Extract data
|
||||
type = (ConfigDefineDataType)(((uintptr_t)dataList[offset] >> 24) & 0xFF);
|
||||
size = ((uintptr_t)dataList[offset] >> 16) & 0xFF;
|
||||
data = (uintptr_t)dataList[offset] & 0xFFFF;
|
||||
|
||||
// If a command block then set the current command
|
||||
if (type == configDefDataTypeCommand)
|
||||
{
|
||||
// If data was not found in the expected command then there's nothing more to look for
|
||||
if (commandCurrent == commandId)
|
||||
break;
|
||||
|
||||
// Set the current command
|
||||
commandCurrent = (unsigned int)data;
|
||||
}
|
||||
// Only find type if not in a command block yet or in the expected command
|
||||
else if (type == typeFind && (commandCurrent == UINT_MAX || commandCurrent == commandId))
|
||||
{
|
||||
// Store the data found
|
||||
*dataDefFound = true;
|
||||
*dataDef = data;
|
||||
*dataDefList = &dataList[offset + 1];
|
||||
*dataDefListSize = size;
|
||||
|
||||
// If found in the expected command block then nothing more to look for
|
||||
if (commandCurrent == commandId)
|
||||
break;
|
||||
}
|
||||
|
||||
offset += size + 1;
|
||||
}
|
||||
while (type != configDefDataTypeEnd);
|
||||
}
|
||||
|
||||
FUNCTION_TEST_RETURN_VOID();
|
||||
}
|
||||
|
||||
#define CONFIG_DEFINE_DATA_FIND(commandId, optionId, type) \
|
||||
bool dataDefFound = false; \
|
||||
int dataDef = 0; \
|
||||
unsigned int dataDefListSize = 0; \
|
||||
const void **dataDefList = NULL; \
|
||||
\
|
||||
cfgDefDataFind( \
|
||||
type, commandId, configDefineOptionData[optionId].data, &dataDefFound, &dataDef, &dataDefList, &dataDefListSize);
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
unsigned int
|
||||
cfgDefCommandTotal(void)
|
||||
{
|
||||
FUNCTION_TEST_VOID();
|
||||
FUNCTION_TEST_RETURN(sizeof(configDefineCommandData) / sizeof(ConfigDefineCommandData));
|
||||
}
|
||||
|
||||
unsigned int
|
||||
cfgDefOptionTotal(void)
|
||||
{
|
||||
FUNCTION_TEST_VOID();
|
||||
FUNCTION_TEST_RETURN(sizeof(configDefineOptionData) / sizeof(ConfigDefineOptionData));
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
bool
|
||||
cfgDefOptionAllowList(ConfigCommand commandId, ConfigOption optionId)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(ENUM, commandId);
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(commandId < cfgDefCommandTotal());
|
||||
ASSERT(optionId < cfgDefOptionTotal());
|
||||
|
||||
CONFIG_DEFINE_DATA_FIND(commandId, optionId, configDefDataTypeAllowList);
|
||||
|
||||
FUNCTION_TEST_RETURN(dataDefFound);
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
cfgDefOptionAllowListValueTotal(ConfigCommand commandId, ConfigOption optionId)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(ENUM, commandId);
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(commandId < cfgDefCommandTotal());
|
||||
ASSERT(optionId < cfgDefOptionTotal());
|
||||
|
||||
CONFIG_DEFINE_DATA_FIND(commandId, optionId, configDefDataTypeAllowList);
|
||||
|
||||
FUNCTION_TEST_RETURN(dataDefListSize);
|
||||
}
|
||||
|
||||
static const char *
|
||||
cfgDefOptionAllowListValue(ConfigCommand commandId, ConfigOption optionId, unsigned int valueId)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(ENUM, commandId);
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_PARAM(UINT, valueId);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(commandId < cfgDefCommandTotal());
|
||||
ASSERT(optionId < cfgDefOptionTotal());
|
||||
ASSERT(valueId < cfgDefOptionAllowListValueTotal(commandId, optionId));
|
||||
|
||||
CONFIG_DEFINE_DATA_FIND(commandId, optionId, configDefDataTypeAllowList);
|
||||
|
||||
FUNCTION_TEST_RETURN((char *)dataDefList[valueId]);
|
||||
}
|
||||
|
||||
// Check if the value matches a value in the allow list
|
||||
bool
|
||||
cfgDefOptionAllowListValueValid(ConfigCommand commandId, ConfigOption optionId, const char *value)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(ENUM, commandId);
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_PARAM(STRINGZ, value);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(commandId < cfgDefCommandTotal());
|
||||
ASSERT(optionId < cfgDefOptionTotal());
|
||||
ASSERT(value != NULL);
|
||||
|
||||
bool result = false;
|
||||
|
||||
for (unsigned int valueIdx = 0; valueIdx < cfgDefOptionAllowListValueTotal(commandId, optionId); valueIdx++)
|
||||
{
|
||||
if (strcmp(value, cfgDefOptionAllowListValue(commandId, optionId, valueIdx)) == 0)
|
||||
result = true;
|
||||
}
|
||||
|
||||
FUNCTION_TEST_RETURN(result);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
bool
|
||||
cfgDefOptionAllowRange(ConfigCommand commandId, ConfigOption optionId)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(ENUM, commandId);
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(commandId < cfgDefCommandTotal());
|
||||
ASSERT(optionId < cfgDefOptionTotal());
|
||||
|
||||
CONFIG_DEFINE_DATA_FIND(commandId, optionId, configDefDataTypeAllowRange);
|
||||
|
||||
FUNCTION_TEST_RETURN(dataDefFound);
|
||||
}
|
||||
|
||||
int64_t
|
||||
cfgDefOptionAllowRangeMax(ConfigCommand commandId, ConfigOption optionId)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(ENUM, commandId);
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(commandId < cfgDefCommandTotal());
|
||||
ASSERT(optionId < cfgDefOptionTotal());
|
||||
|
||||
CONFIG_DEFINE_DATA_FIND(commandId, optionId, configDefDataTypeAllowRange);
|
||||
|
||||
FUNCTION_TEST_RETURN((int64_t)(intptr_t)dataDefList[2] << 32 | (int64_t)(intptr_t)dataDefList[3]);
|
||||
}
|
||||
|
||||
int64_t
|
||||
cfgDefOptionAllowRangeMin(ConfigCommand commandId, ConfigOption optionId)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(ENUM, commandId);
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(commandId < cfgDefCommandTotal());
|
||||
ASSERT(optionId < cfgDefOptionTotal());
|
||||
|
||||
CONFIG_DEFINE_DATA_FIND(commandId, optionId, configDefDataTypeAllowRange);
|
||||
|
||||
FUNCTION_TEST_RETURN((int64_t)(intptr_t)dataDefList[0] << 32 | (int64_t)(intptr_t)dataDefList[1]);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
const char *
|
||||
cfgDefOptionDefault(ConfigCommand commandId, ConfigOption optionId)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(ENUM, commandId);
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(commandId < cfgDefCommandTotal());
|
||||
ASSERT(optionId < cfgDefOptionTotal());
|
||||
|
||||
CONFIG_DEFINE_DATA_FIND(commandId, optionId, configDefDataTypeDefault);
|
||||
|
||||
char *result = NULL;
|
||||
|
||||
if (dataDefFound)
|
||||
result = (char *)dataDefList[0];
|
||||
|
||||
FUNCTION_TEST_RETURN(result);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
bool
|
||||
cfgDefOptionDepend(ConfigCommand commandId, ConfigOption optionId)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(ENUM, commandId);
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(commandId < cfgDefCommandTotal());
|
||||
ASSERT(optionId < cfgDefOptionTotal());
|
||||
|
||||
CONFIG_DEFINE_DATA_FIND(commandId, optionId, configDefDataTypeDepend);
|
||||
|
||||
FUNCTION_TEST_RETURN(dataDefFound);
|
||||
}
|
||||
|
||||
ConfigOption
|
||||
cfgDefOptionDependOption(ConfigCommand commandId, ConfigOption optionId)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(ENUM, commandId);
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(commandId < cfgDefCommandTotal());
|
||||
ASSERT(optionId < cfgDefOptionTotal());
|
||||
|
||||
CONFIG_DEFINE_DATA_FIND(commandId, optionId, configDefDataTypeDepend);
|
||||
|
||||
FUNCTION_TEST_RETURN((ConfigOption)dataDef);
|
||||
}
|
||||
|
||||
const char *
|
||||
cfgDefOptionDependValue(ConfigCommand commandId, ConfigOption optionId, unsigned int valueId)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(ENUM, commandId);
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_PARAM(UINT, valueId);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(commandId < cfgDefCommandTotal());
|
||||
ASSERT(optionId < cfgDefOptionTotal());
|
||||
ASSERT(valueId < cfgDefOptionDependValueTotal(commandId, optionId));
|
||||
|
||||
CONFIG_DEFINE_DATA_FIND(commandId, optionId, configDefDataTypeDepend);
|
||||
|
||||
FUNCTION_TEST_RETURN((char *)dataDefList[valueId]);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
cfgDefOptionDependValueTotal(ConfigCommand commandId, ConfigOption optionId)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(ENUM, commandId);
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(commandId < cfgDefCommandTotal());
|
||||
ASSERT(optionId < cfgDefOptionTotal());
|
||||
|
||||
CONFIG_DEFINE_DATA_FIND(commandId, optionId, configDefDataTypeDepend);
|
||||
|
||||
FUNCTION_TEST_RETURN(dataDefListSize);
|
||||
}
|
||||
|
||||
// Check if the value matches a value in the allow list
|
||||
bool
|
||||
cfgDefOptionDependValueValid(ConfigCommand commandId, ConfigOption optionId, const char *value)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(ENUM, commandId);
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_PARAM(STRINGZ, value);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(commandId < cfgDefCommandTotal());
|
||||
ASSERT(optionId < cfgDefOptionTotal());
|
||||
ASSERT(value != NULL);
|
||||
|
||||
bool result = false;
|
||||
|
||||
for (unsigned int valueIdx = 0; valueIdx < cfgDefOptionDependValueTotal(commandId, optionId); valueIdx++)
|
||||
{
|
||||
if (strcmp(value, cfgDefOptionDependValue(commandId, optionId, valueIdx)) == 0)
|
||||
result = true;
|
||||
}
|
||||
|
||||
FUNCTION_TEST_RETURN(result);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
int
|
||||
cfgDefOptionId(const char *optionName)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(STRINGZ, optionName);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(optionName != NULL);
|
||||
|
||||
int result = -1;
|
||||
|
||||
for (ConfigOption optionId = 0; optionId < cfgDefOptionTotal(); optionId++)
|
||||
if (strcmp(optionName, configDefineOptionData[optionId].name) == 0)
|
||||
result = optionId;
|
||||
|
||||
FUNCTION_TEST_RETURN(result);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
bool
|
||||
cfgDefOptionMulti(ConfigOption optionId)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(optionId < cfgDefOptionTotal());
|
||||
|
||||
FUNCTION_TEST_RETURN(
|
||||
configDefineOptionData[optionId].type == cfgDefOptTypeHash ||
|
||||
configDefineOptionData[optionId].type == cfgDefOptTypeList);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
const char *
|
||||
cfgDefOptionName(ConfigOption optionId)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(optionId < cfgDefOptionTotal());
|
||||
|
||||
FUNCTION_TEST_RETURN(configDefineOptionData[optionId].name);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
bool
|
||||
cfgDefOptionSecure(ConfigOption optionId)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(optionId < cfgDefOptionTotal());
|
||||
|
||||
FUNCTION_TEST_RETURN(configDefineOptionData[optionId].secure);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
bool
|
||||
cfgDefOptionRequired(ConfigCommand commandId, ConfigOption optionId)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(ENUM, commandId);
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(commandId < cfgDefCommandTotal());
|
||||
ASSERT(optionId < cfgDefOptionTotal());
|
||||
|
||||
CONFIG_DEFINE_DATA_FIND(commandId, optionId, configDefDataTypeRequired);
|
||||
|
||||
bool result = configDefineOptionData[optionId].required;
|
||||
|
||||
if (dataDefFound)
|
||||
result = (bool)dataDef;
|
||||
|
||||
FUNCTION_TEST_RETURN(result);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
ConfigDefSection
|
||||
cfgDefOptionSection(ConfigOption optionId)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(optionId < cfgDefOptionTotal());
|
||||
|
||||
FUNCTION_TEST_RETURN(configDefineOptionData[optionId].section);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
int
|
||||
cfgDefOptionType(ConfigOption optionId)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(optionId < cfgDefOptionTotal());
|
||||
|
||||
FUNCTION_TEST_RETURN(configDefineOptionData[optionId].type);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
bool
|
||||
cfgDefOptionValid(ConfigCommand commandId, ConfigOption optionId)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(ENUM, commandId);
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(commandId < cfgDefCommandTotal());
|
||||
ASSERT(optionId < cfgDefOptionTotal());
|
||||
|
||||
FUNCTION_TEST_RETURN(configDefineOptionData[optionId].commandValid & (1 << commandId));
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
/***********************************************************************************************************************************
|
||||
Command and Option Configuration Definition
|
||||
***********************************************************************************************************************************/
|
||||
#ifndef CONFIG_DEFINE_H
|
||||
#define CONFIG_DEFINE_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Section enum - defines which sections of the config an option can appear in
|
||||
***********************************************************************************************************************************/
|
||||
typedef enum
|
||||
{
|
||||
cfgDefSectionCommandLine, // command-line only
|
||||
cfgDefSectionGlobal, // command-line or in any config section
|
||||
cfgDefSectionStanza, // command-line or in any config stanza section
|
||||
} ConfigDefSection;
|
||||
|
||||
#include "common/type/string.h"
|
||||
#include "config/config.auto.h"
|
||||
#include "config/define.auto.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Define global section name
|
||||
***********************************************************************************************************************************/
|
||||
#define CFGDEF_SECTION_GLOBAL "global"
|
||||
STRING_DECLARE(CFGDEF_SECTION_GLOBAL_STR);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Functions
|
||||
***********************************************************************************************************************************/
|
||||
// Command total
|
||||
unsigned int cfgDefCommandTotal(void);
|
||||
|
||||
// Option allow lists
|
||||
bool cfgDefOptionAllowList(ConfigCommand commandId, ConfigOption optionId);
|
||||
bool cfgDefOptionAllowListValueValid(ConfigCommand commandId, ConfigOption optionId, const char *value);
|
||||
|
||||
// Allow range
|
||||
bool cfgDefOptionAllowRange(ConfigCommand commandId, ConfigOption optionId);
|
||||
int64_t cfgDefOptionAllowRangeMax(ConfigCommand commandId, ConfigOption optionId);
|
||||
int64_t cfgDefOptionAllowRangeMin(ConfigCommand commandId, ConfigOption optionId);
|
||||
|
||||
// Default value for the option
|
||||
const char *cfgDefOptionDefault(ConfigCommand commandId, ConfigOption optionId);
|
||||
|
||||
// Dependencies and depend lists
|
||||
bool cfgDefOptionDepend(ConfigCommand commandId, ConfigOption optionId);
|
||||
ConfigOption cfgDefOptionDependOption(ConfigCommand commandId, ConfigOption optionId);
|
||||
unsigned int cfgDefOptionDependValueTotal(ConfigCommand commandId, ConfigOption optionId);
|
||||
bool cfgDefOptionDependValueValid(ConfigCommand commandId, ConfigOption optionId, const char *value);
|
||||
const char *cfgDefOptionDependValue(ConfigCommand commandId, ConfigOption optionId, unsigned int valueId);
|
||||
|
||||
// Option id by name
|
||||
int cfgDefOptionId(const char *optionName);
|
||||
|
||||
// Does the option accept multiple values?
|
||||
bool cfgDefOptionMulti(ConfigOption optionId);
|
||||
|
||||
// Name of the option
|
||||
const char *cfgDefOptionName(ConfigOption optionId);
|
||||
|
||||
// Is the option required
|
||||
bool cfgDefOptionRequired(ConfigCommand commandId, ConfigOption optionId);
|
||||
|
||||
// Get option section
|
||||
ConfigDefSection cfgDefOptionSection(ConfigOption optionId);
|
||||
|
||||
// Does the option need to be protected from showing up in logs, command lines, etc?
|
||||
bool cfgDefOptionSecure(ConfigOption optionId);
|
||||
|
||||
// Option total
|
||||
unsigned int cfgDefOptionTotal(void);
|
||||
|
||||
// Get option data type
|
||||
int cfgDefOptionType(ConfigOption optionId);
|
||||
|
||||
// Is the option valid for the command?
|
||||
bool cfgDefOptionValid(ConfigCommand commandId, ConfigOption optionId);
|
||||
|
||||
#endif
|
@ -7,9 +7,9 @@ Exec Configuration
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/log.h"
|
||||
#include "config/define.h"
|
||||
#include "config/config.intern.h"
|
||||
#include "config/exec.h"
|
||||
#include "config/parse.h"
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
StringList *
|
||||
@ -35,7 +35,7 @@ cfgExecParam(ConfigCommand commandId, ConfigCommandRole commandRoleId, const Key
|
||||
// Skip the option if it is not valid for the original/specified command or if is secure. Also skip repo1-cipher-type
|
||||
// because there's no point of passing it if the other process doesn't have access to repo1-cipher-pass. There is
|
||||
// probably a better way to do this last part...
|
||||
if (!cfgDefOptionValid(commandId, optionId) || cfgDefOptionSecure(optionId) || optionId == cfgOptRepoCipherType)
|
||||
if (!cfgParseOptionValid(commandId, optionId) || cfgParseOptionSecure(optionId) || optionId == cfgOptRepoCipherType)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -109,7 +109,7 @@ cfgExecParam(ConfigCommand commandId, ConfigCommandRole commandRoleId, const Key
|
||||
{
|
||||
valueList = strLstNewVarLst(varVarLst(value));
|
||||
}
|
||||
else if (cfgDefOptionType(optionId) == cfgDefOptTypeTime)
|
||||
else if (cfgParseOptionType(optionId) == cfgOptTypeTime)
|
||||
{
|
||||
valueList = strLstNew();
|
||||
strLstAdd(valueList, cvtDoubleToStr((double)varInt64(value) / MSEC_PER_SEC));
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,24 +1,24 @@
|
||||
/***********************************************************************************************************************************
|
||||
Command and Option Definition
|
||||
Config Parse Rules
|
||||
|
||||
Automatically generated by Build.pm -- do not modify directly.
|
||||
***********************************************************************************************************************************/
|
||||
#ifndef CONFIG_DEFINE_AUTO_H
|
||||
#define CONFIG_DEFINE_AUTO_H
|
||||
#ifndef CONFIG_PARSE_AUTO_H
|
||||
#define CONFIG_PARSE_AUTO_H
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Option type define enum
|
||||
Option type enum
|
||||
***********************************************************************************************************************************/
|
||||
typedef enum
|
||||
{
|
||||
cfgDefOptTypeBoolean,
|
||||
cfgDefOptTypeHash,
|
||||
cfgDefOptTypeInteger,
|
||||
cfgDefOptTypeList,
|
||||
cfgDefOptTypePath,
|
||||
cfgDefOptTypeSize,
|
||||
cfgDefOptTypeString,
|
||||
cfgDefOptTypeTime,
|
||||
} ConfigDefineOptionType;
|
||||
cfgOptTypeBoolean,
|
||||
cfgOptTypeHash,
|
||||
cfgOptTypeInteger,
|
||||
cfgOptTypeList,
|
||||
cfgOptTypePath,
|
||||
cfgOptTypeSize,
|
||||
cfgOptTypeString,
|
||||
cfgOptTypeTime,
|
||||
} ConfigOptionType;
|
||||
|
||||
#endif
|
@ -15,11 +15,25 @@ Command and Option Parse
|
||||
#include "common/memContext.h"
|
||||
#include "common/regExp.h"
|
||||
#include "config/config.intern.h"
|
||||
#include "config/define.h"
|
||||
#include "config/parse.h"
|
||||
#include "storage/helper.h"
|
||||
#include "version.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Define global section name
|
||||
***********************************************************************************************************************************/
|
||||
#define CFGDEF_SECTION_GLOBAL "global"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Section enum - defines which sections of the config an option can appear in
|
||||
***********************************************************************************************************************************/
|
||||
typedef enum
|
||||
{
|
||||
cfgSectionCommandLine, // Command-line only
|
||||
cfgSectionGlobal, // Command-line or in any config section
|
||||
cfgSectionStanza, // Command-line or in any config stanza section
|
||||
} ConfigSection;
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Standard config file name and old default path and name
|
||||
***********************************************************************************************************************************/
|
||||
@ -70,10 +84,228 @@ Parse option flags
|
||||
#define PARSE_KEY_IDX_MASK 0xFF
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Include automatically generated data structure for getopt_long()
|
||||
Define how a command is parsed
|
||||
***********************************************************************************************************************************/
|
||||
typedef struct ParseRuleCommand
|
||||
{
|
||||
const char *name; // Name
|
||||
bool parameterAllowed:1; // Command-line parameters are allowed
|
||||
} ParseRuleCommand;
|
||||
|
||||
// Macros used to define parse rules in parse.auto.c in a format that diffs well
|
||||
#define PARSE_RULE_COMMAND(...) \
|
||||
{__VA_ARGS__}
|
||||
|
||||
#define PARSE_RULE_COMMAND_NAME(nameParam) \
|
||||
.name = nameParam
|
||||
|
||||
#define PARSE_RULE_COMMAND_PARAMETER_ALLOWED(parameterAllowedParam) \
|
||||
.parameterAllowed = parameterAllowedParam
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Define how an option group is parsed
|
||||
***********************************************************************************************************************************/
|
||||
typedef struct ParseRuleOptionGroup
|
||||
{
|
||||
const char *name; // All options in the group must be prefixed with this name
|
||||
} ParseRuleOptionGroup;
|
||||
|
||||
// Macros used to define parse rules in parse.auto.c in a format that diffs well
|
||||
#define PARSE_RULE_OPTION_GROUP(...) \
|
||||
{__VA_ARGS__}
|
||||
|
||||
#define PARSE_RULE_OPTION_GROUP_NAME(nameParam) \
|
||||
.name = nameParam
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Define how an option is parsed and interacts with other options
|
||||
***********************************************************************************************************************************/
|
||||
typedef struct ParseRuleOption
|
||||
{
|
||||
const char *name; // Name
|
||||
unsigned int type:3; // e.g. string, int, boolean
|
||||
bool required:1; // Is the option required?
|
||||
unsigned int section:2; // e.g. global, stanza, cmd-line
|
||||
bool secure:1; // Needs to be redacted in logs and cmd-line?
|
||||
bool multi:1; // Can be specified multiple times?
|
||||
bool group:1; // In a group?
|
||||
unsigned int groupId:1; // Id if in a group
|
||||
uint64_t commandValid:CFG_COMMAND_TOTAL; // Valid for the command?
|
||||
|
||||
const void **data; // Optional data and command overrides
|
||||
} ParseRuleOption;
|
||||
|
||||
// Define additional types of data that can be associated with an option. Because these types are rare they are not give dedicated
|
||||
// fields and are instead packed into an array which is read at runtime. This may seem inefficient but they are only accessed a
|
||||
// single time during parse so space efficiency is more important than performance.
|
||||
typedef enum
|
||||
{
|
||||
parseRuleOptionDataTypeEnd, // Indicates there is no more data
|
||||
parseRuleOptionDataTypeAllowList,
|
||||
parseRuleOptionDataTypeAllowRange,
|
||||
parseRuleOptionDataTypeCommand,
|
||||
parseRuleOptionDataTypeDefault,
|
||||
parseRuleOptionDataTypeDepend,
|
||||
parseRuleOptionDataTypeRequired,
|
||||
} ParseRuleOptionDataType;
|
||||
|
||||
// Macros used to define parse rules in parse.auto.c in a format that diffs well
|
||||
#define PARSE_RULE_OPTION(...) \
|
||||
{__VA_ARGS__}
|
||||
|
||||
#define PARSE_RULE_OPTION_NAME(nameParam) \
|
||||
.name = nameParam
|
||||
|
||||
#define PARSE_RULE_OPTION_TYPE(typeParam) \
|
||||
.type = typeParam
|
||||
|
||||
#define PARSE_RULE_OPTION_REQUIRED(requiredParam) \
|
||||
.required = requiredParam
|
||||
|
||||
#define PARSE_RULE_OPTION_SECTION(sectionParam) \
|
||||
.section = sectionParam
|
||||
|
||||
#define PARSE_RULE_OPTION_SECURE(secureParam) \
|
||||
.secure = secureParam
|
||||
|
||||
#define PARSE_RULE_OPTION_MULTI(typeMulti) \
|
||||
.multi = typeMulti
|
||||
|
||||
#define PARSE_RULE_OPTION_GROUP_MEMBER(groupParam) \
|
||||
.group = groupParam
|
||||
|
||||
#define PARSE_RULE_OPTION_GROUP_ID(groupIdParam) \
|
||||
.groupId = groupIdParam
|
||||
|
||||
#define PARSE_RULE_OPTION_COMMAND_LIST(...) \
|
||||
.commandValid = 0 __VA_ARGS__
|
||||
|
||||
#define PARSE_RULE_OPTION_COMMAND(commandParam) \
|
||||
| (1 << commandParam)
|
||||
|
||||
#define PARSE_RULE_OPTION_OPTIONAL_PUSH_LIST(type, size, data, ...) \
|
||||
(const void *)((uint32_t)type << 24 | (uint32_t)size << 16 | (uint32_t)data), __VA_ARGS__
|
||||
|
||||
#define PARSE_RULE_OPTION_OPTIONAL_LIST(...) \
|
||||
.data = (const void *[]){__VA_ARGS__ NULL}
|
||||
|
||||
#define PARSE_RULE_OPTION_OPTIONAL_PUSH(type, size, data) \
|
||||
(const void *)((uint32_t)type << 24 | (uint32_t)size << 16 | (uint32_t)data)
|
||||
|
||||
#define PARSE_RULE_OPTION_OPTIONAL_COMMAND_OVERRIDE(...) \
|
||||
__VA_ARGS__
|
||||
|
||||
#define PARSE_RULE_OPTION_OPTIONAL_COMMAND(command) \
|
||||
PARSE_RULE_OPTION_OPTIONAL_PUSH(parseRuleOptionDataTypeCommand, 0, command)
|
||||
|
||||
#define PARSE_RULE_OPTION_OPTIONAL_ALLOW_LIST(...) \
|
||||
PARSE_RULE_OPTION_OPTIONAL_PUSH_LIST( \
|
||||
parseRuleOptionDataTypeAllowList, sizeof((const char *[]){__VA_ARGS__}) / sizeof(const char *), 0, __VA_ARGS__)
|
||||
|
||||
#define PARSE_RULE_OPTION_OPTIONAL_ALLOW_RANGE(rangeMinParam, rangeMaxParam) \
|
||||
PARSE_RULE_OPTION_OPTIONAL_PUSH_LIST( \
|
||||
parseRuleOptionDataTypeAllowRange, 4, 0, \
|
||||
(const void *)(intptr_t)(int32_t)((int64_t)rangeMinParam >> 32), \
|
||||
(const void *)(intptr_t)(int32_t)((int64_t)rangeMinParam & 0xFFFFFFFF), \
|
||||
(const void *)(intptr_t)(int32_t)((int64_t)rangeMaxParam >> 32), \
|
||||
(const void *)(intptr_t)(int32_t)((int64_t)rangeMaxParam & 0xFFFFFFFF))
|
||||
|
||||
#define PARSE_RULE_OPTION_OPTIONAL_DEFAULT(defaultParam) \
|
||||
PARSE_RULE_OPTION_OPTIONAL_PUSH_LIST(parseRuleOptionDataTypeDefault, 1, 0, defaultParam)
|
||||
|
||||
#define PARSE_RULE_OPTION_OPTIONAL_DEPEND(optionDepend) \
|
||||
PARSE_RULE_OPTION_OPTIONAL_PUSH(parseRuleOptionDataTypeDepend, 0, optionDepend)
|
||||
|
||||
#define PARSE_RULE_OPTION_OPTIONAL_DEPEND_LIST(optionDepend, ...) \
|
||||
PARSE_RULE_OPTION_OPTIONAL_PUSH_LIST( \
|
||||
parseRuleOptionDataTypeDepend, sizeof((const char *[]){__VA_ARGS__}) / sizeof(const char *), optionDepend, __VA_ARGS__)
|
||||
|
||||
#define PARSE_RULE_OPTION_OPTIONAL_REQUIRED(requiredParam) \
|
||||
PARSE_RULE_OPTION_OPTIONAL_PUSH(parseRuleOptionDataTypeRequired, 0, requiredParam)
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Include automatically generated parse data
|
||||
***********************************************************************************************************************************/
|
||||
#include "config/parse.auto.c"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Find optional data for a command and option
|
||||
***********************************************************************************************************************************/
|
||||
// Extract an int64 from optional data list
|
||||
#define PARSE_RULE_DATA_INT64(data, index) \
|
||||
((int64_t)(intptr_t)data.list[index] << 32 | (int64_t)(intptr_t)data.list[index + 1])
|
||||
|
||||
// Extracted option data
|
||||
typedef struct ParseRuleOptionData
|
||||
{
|
||||
bool found; // Was the data found?
|
||||
int data; // Data value
|
||||
unsigned int listSize; // Data list size
|
||||
const void **list; // Data list
|
||||
} ParseRuleOptionData;
|
||||
|
||||
static ParseRuleOptionData
|
||||
parseRuleOptionDataFind(ParseRuleOptionDataType typeFind, ConfigCommand commandId, ConfigOption optionId)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(ENUM, typeFind);
|
||||
FUNCTION_TEST_PARAM(ENUM, commandId);
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ParseRuleOptionData result = {0};
|
||||
|
||||
const void **dataList = parseRuleOption[optionId].data;
|
||||
|
||||
// Only proceed if there is data
|
||||
if (dataList != NULL)
|
||||
{
|
||||
ParseRuleOptionDataType type;
|
||||
unsigned int offset = 0;
|
||||
unsigned int size;
|
||||
int data;
|
||||
unsigned int commandCurrent = UINT_MAX;
|
||||
|
||||
// Loop through all data
|
||||
do
|
||||
{
|
||||
// Extract data
|
||||
type = (ParseRuleOptionDataType)(((uintptr_t)dataList[offset] >> 24) & 0xFF);
|
||||
size = ((uintptr_t)dataList[offset] >> 16) & 0xFF;
|
||||
data = (uintptr_t)dataList[offset] & 0xFFFF;
|
||||
|
||||
// If a command block then set the current command
|
||||
if (type == parseRuleOptionDataTypeCommand)
|
||||
{
|
||||
// If data was not found in the expected command then there's nothing more to look for
|
||||
if (commandCurrent == commandId)
|
||||
break;
|
||||
|
||||
// Set the current command
|
||||
commandCurrent = (unsigned int)data;
|
||||
}
|
||||
// Only find type if not in a command block yet or in the expected command
|
||||
else if (type == typeFind && (commandCurrent == UINT_MAX || commandCurrent == commandId))
|
||||
{
|
||||
// Store the data found
|
||||
result.found = true;
|
||||
result.data = data;
|
||||
result.listSize = size;
|
||||
result.list = &dataList[offset + 1];
|
||||
|
||||
// If found in the expected command block then nothing more to look for
|
||||
if (commandCurrent == commandId)
|
||||
break;
|
||||
}
|
||||
|
||||
offset += size + 1;
|
||||
}
|
||||
while (type != parseRuleOptionDataTypeEnd);
|
||||
}
|
||||
|
||||
FUNCTION_TEST_RETURN(result);
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Struct to hold options parsed from the command line
|
||||
***********************************************************************************************************************************/
|
||||
@ -111,7 +343,7 @@ parseOptionIdxValue(ParseOption *optionList, unsigned int optionId, unsigned int
|
||||
if (optionKeyIdx >= optionList[optionId].indexListTotal)
|
||||
{
|
||||
// If the option is in a group
|
||||
if (cfgOptionGroup(optionId))
|
||||
if (parseRuleOption[optionId].group)
|
||||
{
|
||||
unsigned int optionOffset = 0;
|
||||
|
||||
@ -194,6 +426,145 @@ cfgParseOption(const String *optionName)
|
||||
FUNCTION_TEST_RETURN((CfgParseOptionResult){0});
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
const char *
|
||||
cfgParseOptionDefault(ConfigCommand commandId, ConfigOption optionId)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(ENUM, commandId);
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(commandId < CFG_COMMAND_TOTAL);
|
||||
ASSERT(optionId < CFG_OPTION_TOTAL);
|
||||
|
||||
ParseRuleOptionData data = parseRuleOptionDataFind(parseRuleOptionDataTypeDefault, commandId, optionId);
|
||||
|
||||
if (data.found)
|
||||
FUNCTION_TEST_RETURN((const char *)data.list[0]);
|
||||
|
||||
FUNCTION_TEST_RETURN(NULL);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
int
|
||||
cfgParseOptionId(const char *optionName)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(STRINGZ, optionName);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(optionName != NULL);
|
||||
|
||||
int result = -1;
|
||||
|
||||
for (ConfigOption optionId = 0; optionId < CFG_OPTION_TOTAL; optionId++)
|
||||
if (strcmp(optionName, parseRuleOption[optionId].name) == 0)
|
||||
result = optionId;
|
||||
|
||||
FUNCTION_TEST_RETURN(result);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
const char *
|
||||
cfgParseOptionName(ConfigOption optionId)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(optionId < CFG_OPTION_TOTAL);
|
||||
|
||||
FUNCTION_TEST_RETURN(parseRuleOption[optionId].name);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
const char *
|
||||
cfgParseOptionKeyIdxName(ConfigOption optionId, unsigned int keyIdx)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_PARAM(UINT, keyIdx);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(optionId < CFG_OPTION_TOTAL);
|
||||
ASSERT((!parseRuleOption[optionId].group && keyIdx == 0) || parseRuleOption[optionId].group);
|
||||
|
||||
// If the option is in a group then construct the name
|
||||
if (parseRuleOption[optionId].group)
|
||||
{
|
||||
String *name = strNewFmt(
|
||||
"%s%u%s", parseRuleOptionGroup[parseRuleOption[optionId].groupId].name, keyIdx + 1,
|
||||
parseRuleOption[optionId].name + strlen(parseRuleOptionGroup[parseRuleOption[optionId].groupId].name));
|
||||
|
||||
FUNCTION_TEST_RETURN(strZ(name));
|
||||
}
|
||||
|
||||
// Else return the stored name
|
||||
FUNCTION_TEST_RETURN(parseRuleOption[optionId].name);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
bool
|
||||
cfgParseOptionRequired(ConfigCommand commandId, ConfigOption optionId)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(ENUM, commandId);
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(commandId < CFG_COMMAND_TOTAL);
|
||||
ASSERT(optionId < CFG_OPTION_TOTAL);
|
||||
|
||||
ParseRuleOptionData data = parseRuleOptionDataFind(parseRuleOptionDataTypeRequired, commandId, optionId);
|
||||
|
||||
if (data.found)
|
||||
FUNCTION_TEST_RETURN((bool)data.data);
|
||||
|
||||
FUNCTION_TEST_RETURN(parseRuleOption[optionId].required);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
bool
|
||||
cfgParseOptionSecure(ConfigOption optionId)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(optionId < CFG_OPTION_TOTAL);
|
||||
|
||||
FUNCTION_TEST_RETURN(parseRuleOption[optionId].secure);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
ConfigOptionType
|
||||
cfgParseOptionType(ConfigOption optionId)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(optionId < CFG_OPTION_TOTAL);
|
||||
|
||||
FUNCTION_TEST_RETURN(parseRuleOption[optionId].type);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
bool
|
||||
cfgParseOptionValid(ConfigCommand commandId, ConfigOption optionId)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(ENUM, commandId);
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(commandId < CFG_COMMAND_TOTAL);
|
||||
ASSERT(optionId < CFG_OPTION_TOTAL);
|
||||
|
||||
FUNCTION_TEST_RETURN(parseRuleOption[optionId].commandValid & (1 << commandId));
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Generate multiplier based on character
|
||||
***********************************************************************************************************************************/
|
||||
@ -621,14 +992,14 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
ASSERT(option.id < CFG_OPTION_TOTAL);
|
||||
|
||||
// Error if this option is secure and cannot be passed on the command line
|
||||
if (cfgDefOptionSecure(option.id))
|
||||
if (cfgParseOptionSecure(option.id))
|
||||
{
|
||||
THROW_FMT(
|
||||
OptionInvalidError,
|
||||
"option '%s' is not allowed on the command-line\n"
|
||||
"HINT: this option could expose secrets in the process list.\n"
|
||||
"HINT: specify the option in a configuration file or an environment variable instead.",
|
||||
cfgOptionKeyIdxName(option.id, option.keyIdx));
|
||||
cfgParseOptionKeyIdxName(option.id, option.keyIdx));
|
||||
}
|
||||
|
||||
// If the option has not been found yet then set it
|
||||
@ -659,7 +1030,7 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
{
|
||||
THROW_FMT(
|
||||
OptionInvalidError, "option '%s' is negated multiple times",
|
||||
cfgOptionKeyIdxName(option.id, option.keyIdx));
|
||||
cfgParseOptionKeyIdxName(option.id, option.keyIdx));
|
||||
}
|
||||
|
||||
// Make sure option is not reset more than once. Same justification as negate.
|
||||
@ -667,7 +1038,7 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
{
|
||||
THROW_FMT(
|
||||
OptionInvalidError, "option '%s' is reset multiple times",
|
||||
cfgOptionKeyIdxName(option.id, option.keyIdx));
|
||||
cfgParseOptionKeyIdxName(option.id, option.keyIdx));
|
||||
}
|
||||
|
||||
// Don't allow an option to be both negated and reset
|
||||
@ -675,7 +1046,7 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
{
|
||||
THROW_FMT(
|
||||
OptionInvalidError, "option '%s' cannot be negated and reset",
|
||||
cfgOptionKeyIdxName(option.id, option.keyIdx));
|
||||
cfgParseOptionKeyIdxName(option.id, option.keyIdx));
|
||||
}
|
||||
|
||||
// Don't allow an option to be both set and negated
|
||||
@ -683,7 +1054,7 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
{
|
||||
THROW_FMT(
|
||||
OptionInvalidError, "option '%s' cannot be set and negated",
|
||||
cfgOptionKeyIdxName(option.id, option.keyIdx));
|
||||
cfgParseOptionKeyIdxName(option.id, option.keyIdx));
|
||||
}
|
||||
|
||||
// Don't allow an option to be both set and reset
|
||||
@ -691,11 +1062,11 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
{
|
||||
THROW_FMT(
|
||||
OptionInvalidError, "option '%s' cannot be set and reset",
|
||||
cfgOptionKeyIdxName(option.id, option.keyIdx));
|
||||
cfgParseOptionKeyIdxName(option.id, option.keyIdx));
|
||||
}
|
||||
|
||||
// Add the argument
|
||||
if (optionList[optionListIdx].has_arg == required_argument && cfgDefOptionMulti(option.id))
|
||||
if (optionList[optionListIdx].has_arg == required_argument && parseRuleOption[option.id].multi)
|
||||
{
|
||||
strLstAdd(optionValue->valueList, strNew(optarg));
|
||||
}
|
||||
@ -704,7 +1075,7 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
{
|
||||
THROW_FMT(
|
||||
OptionInvalidError, "option '%s' cannot be set multiple times",
|
||||
cfgOptionKeyIdxName(option.id, option.keyIdx));
|
||||
cfgParseOptionKeyIdxName(option.id, option.keyIdx));
|
||||
}
|
||||
}
|
||||
|
||||
@ -728,7 +1099,7 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
}
|
||||
|
||||
// Error when parameters found but the command does not allow parameters
|
||||
if (config->paramList != NULL && !config->help && !cfgCommandParameterAllowed(config->command))
|
||||
if (config->paramList != NULL && !config->help && !parseRuleCommand[config->command].parameterAllowed)
|
||||
THROW(ParamInvalidError, "command does not allow parameters");
|
||||
|
||||
// Enable logging (except for local and remote commands) so config file warnings will be output
|
||||
@ -784,7 +1155,7 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
}
|
||||
|
||||
// Continue if the option is not valid for this command
|
||||
if (!cfgDefOptionValid(config->command, option.id))
|
||||
if (!cfgParseOptionValid(config->command, option.id))
|
||||
continue;
|
||||
|
||||
if (strSize(value) == 0)
|
||||
@ -800,7 +1171,7 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
optionValue->source = cfgSourceConfig;
|
||||
|
||||
// Convert boolean to string
|
||||
if (cfgDefOptionType(option.id) == cfgDefOptTypeBoolean)
|
||||
if (cfgParseOptionType(option.id) == cfgOptTypeBoolean)
|
||||
{
|
||||
if (strEqZ(value, "n"))
|
||||
optionValue->negate = true;
|
||||
@ -808,7 +1179,7 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
THROW_FMT(OptionInvalidValueError, "environment boolean option '%s' must be 'y' or 'n'", strZ(key));
|
||||
}
|
||||
// Else split list/hash into separate values
|
||||
else if (cfgDefOptionMulti(option.id))
|
||||
else if (parseRuleOption[option.id].multi)
|
||||
{
|
||||
optionValue->valueList = strLstNewSplitZ(value, ":");
|
||||
}
|
||||
@ -825,8 +1196,8 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
// Load the configuration file(s)
|
||||
String *configString = cfgFileLoad(
|
||||
parseOptionList, STR(cfgDefOptionDefault(config->command, cfgOptConfig)),
|
||||
STR(cfgDefOptionDefault(config->command, cfgOptConfigIncludePath)), PGBACKREST_CONFIG_ORIG_PATH_FILE_STR);
|
||||
parseOptionList, STR(cfgParseOptionDefault(config->command, cfgOptConfig)),
|
||||
STR(cfgParseOptionDefault(config->command, cfgOptConfigIncludePath)), PGBACKREST_CONFIG_ORIG_PATH_FILE_STR);
|
||||
|
||||
if (configString != NULL)
|
||||
{
|
||||
@ -848,7 +1219,7 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
}
|
||||
|
||||
strLstAdd(sectionList, strNewFmt(CFGDEF_SECTION_GLOBAL ":%s", cfgCommandName(config->command)));
|
||||
strLstAdd(sectionList, CFGDEF_SECTION_GLOBAL_STR);
|
||||
strLstAddZ(sectionList, CFGDEF_SECTION_GLOBAL);
|
||||
|
||||
// Loop through sections to search for options
|
||||
for (unsigned int sectionIdx = 0; sectionIdx < strLstSize(sectionList); sectionIdx++)
|
||||
@ -885,7 +1256,7 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
}
|
||||
|
||||
// Warn if this option should be command-line only
|
||||
if (cfgDefOptionSection(option.id) == cfgDefSectionCommandLine)
|
||||
if (parseRuleOption[option.id].section == cfgSectionCommandLine)
|
||||
{
|
||||
LOG_WARN_FMT("configuration file contains command-line only option '%s'", strZ(key));
|
||||
continue;
|
||||
@ -905,7 +1276,7 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
kvPut(optionFound, optionFoundKey, VARSTR(key));
|
||||
|
||||
// Continue if the option is not valid for this command
|
||||
if (!cfgDefOptionValid(config->command, option.id))
|
||||
if (!cfgParseOptionValid(config->command, option.id))
|
||||
{
|
||||
// Warn if it is in a command section
|
||||
if (sectionIdx % 2 == 0)
|
||||
@ -920,7 +1291,8 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
}
|
||||
|
||||
// Continue if stanza option is in a global section
|
||||
if (cfgDefOptionSection(option.id) == cfgDefSectionStanza && strBeginsWithZ(section, CFGDEF_SECTION_GLOBAL))
|
||||
if (parseRuleOption[option.id].section == cfgSectionStanza &&
|
||||
strBeginsWithZ(section, CFGDEF_SECTION_GLOBAL))
|
||||
{
|
||||
LOG_WARN_FMT(
|
||||
"configuration file contains stanza-only option '%s' in global section '%s'", strZ(key),
|
||||
@ -941,11 +1313,11 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
if (iniSectionKeyIsList(ini, section, key))
|
||||
{
|
||||
// Error if the option cannot be specified multiple times
|
||||
if (!cfgDefOptionMulti(option.id))
|
||||
if (!parseRuleOption[option.id].multi)
|
||||
{
|
||||
THROW_FMT(
|
||||
OptionInvalidError, "option '%s' cannot be set multiple times",
|
||||
cfgOptionKeyIdxName(option.id, option.keyIdx));
|
||||
cfgParseOptionKeyIdxName(option.id, option.keyIdx));
|
||||
}
|
||||
|
||||
optionValue->valueList = iniGetList(ini, section, key);
|
||||
@ -962,7 +1334,7 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
strZ(key));
|
||||
}
|
||||
|
||||
if (cfgDefOptionType(option.id) == cfgDefOptTypeBoolean)
|
||||
if (cfgParseOptionType(option.id) == cfgOptTypeBoolean)
|
||||
{
|
||||
if (strEqZ(value, "n"))
|
||||
optionValue->negate = true;
|
||||
@ -987,10 +1359,15 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
|
||||
for (unsigned int optionId = 0; optionId < CFG_OPTION_TOTAL; optionId++)
|
||||
{
|
||||
// Always assign name since it may be needed for error messages
|
||||
config->option[optionId].name = parseRuleOption[optionId].name;
|
||||
|
||||
// Is the option valid for this command?
|
||||
if (cfgDefOptionValid(config->command, optionId))
|
||||
if (cfgParseOptionValid(config->command, optionId))
|
||||
{
|
||||
config->option[optionId].valid = true;
|
||||
config->option[optionId].group = parseRuleOption[optionId].group;
|
||||
config->option[optionId].groupId = parseRuleOption[optionId].groupId;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -998,7 +1375,7 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
if (parseOptionList[optionId].indexList != NULL)
|
||||
{
|
||||
THROW_FMT(
|
||||
OptionInvalidError, "option '%s' not valid for command '%s'", cfgDefOptionName(optionId),
|
||||
OptionInvalidError, "option '%s' not valid for command '%s'", cfgParseOptionName(optionId),
|
||||
cfgCommandName(config->command));
|
||||
}
|
||||
|
||||
@ -1007,9 +1384,9 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
}
|
||||
|
||||
// If the option is in a group
|
||||
if (cfgOptionGroup(optionId))
|
||||
if (parseRuleOption[optionId].group)
|
||||
{
|
||||
unsigned int groupId = cfgOptionGroupId(optionId);
|
||||
unsigned int groupId = parseRuleOption[optionId].groupId;
|
||||
|
||||
config->optionGroup[groupId].valid = true;
|
||||
|
||||
@ -1033,6 +1410,9 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
// Write the indexes into the group in order
|
||||
for (unsigned int groupId = 0; groupId < CFG_OPTION_GROUP_TOTAL; groupId++)
|
||||
{
|
||||
// Set group name
|
||||
config->optionGroup[groupId].name = parseRuleOptionGroup[groupId].name;
|
||||
|
||||
// Skip the group if it is not valid
|
||||
if (!config->optionGroup[groupId].valid)
|
||||
continue;
|
||||
@ -1080,8 +1460,8 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
continue;
|
||||
|
||||
// Determine the option index total. For options that are not indexed the index total is 1.
|
||||
bool optionGroup = cfgOptionGroup(optionId);
|
||||
unsigned int optionGroupId = optionGroup ? cfgOptionGroupId(optionId) : UINT_MAX;
|
||||
bool optionGroup = parseRuleOption[optionId].group;
|
||||
unsigned int optionGroupId = optionGroup ? parseRuleOption[optionId].groupId : UINT_MAX;
|
||||
unsigned int optionListIndexTotal = optionGroup ? config->optionGroup[optionGroupId].indexTotal : 1;
|
||||
|
||||
MEM_CONTEXT_BEGIN(config->memContext)
|
||||
@ -1091,7 +1471,7 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
MEM_CONTEXT_END();
|
||||
|
||||
// Loop through the option indexes
|
||||
ConfigDefineOptionType optionDefType = cfgDefOptionType(optionId);
|
||||
ConfigOptionType optionType = cfgParseOptionType(optionId);
|
||||
|
||||
for (unsigned int optionListIdx = 0; optionListIdx < optionListIndexTotal; optionListIdx++)
|
||||
{
|
||||
@ -1107,7 +1487,7 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
|
||||
// Is the value set for this option?
|
||||
bool optionSet =
|
||||
parseOptionValue->found && (optionDefType == cfgDefOptTypeBoolean || !parseOptionValue->negate) &&
|
||||
parseOptionValue->found && (optionType == cfgOptTypeBoolean || !parseOptionValue->negate) &&
|
||||
!parseOptionValue->reset;
|
||||
|
||||
// Initialize option value and set negate and reset flag
|
||||
@ -1115,18 +1495,19 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
|
||||
// Check option dependencies
|
||||
bool dependResolved = true;
|
||||
ParseRuleOptionData depend = parseRuleOptionDataFind(parseRuleOptionDataTypeDepend, config->command, optionId);
|
||||
|
||||
if (cfgDefOptionDepend(config->command, optionId))
|
||||
if (depend.found)
|
||||
{
|
||||
ConfigOption dependOptionId = cfgDefOptionDependOption(config->command, optionId);
|
||||
ConfigDefineOptionType dependOptionDefType = cfgDefOptionType(dependOptionId);
|
||||
ConfigOption dependOptionId = (ConfigOption)depend.data;
|
||||
ConfigOptionType dependOptionType = cfgParseOptionType(dependOptionId);
|
||||
|
||||
// Get the depend option value
|
||||
const Variant *dependValue = config->option[dependOptionId].index[optionListIdx].value;
|
||||
|
||||
if (dependValue != NULL)
|
||||
{
|
||||
if (dependOptionDefType == cfgDefOptTypeBoolean)
|
||||
if (dependOptionType == cfgOptTypeBoolean)
|
||||
{
|
||||
if (varBool(dependValue))
|
||||
dependValue = OPTION_VALUE_1;
|
||||
@ -1146,13 +1527,23 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
{
|
||||
THROW_FMT(
|
||||
OptionInvalidError, "option '%s' not valid without option '%s'",
|
||||
cfgOptionKeyIdxName(optionId, optionKeyIdx), cfgOptionKeyIdxName(dependOptionId, optionKeyIdx));
|
||||
cfgParseOptionKeyIdxName(optionId, optionKeyIdx),
|
||||
cfgParseOptionKeyIdxName(dependOptionId, optionKeyIdx));
|
||||
}
|
||||
}
|
||||
// If a depend list exists, make sure the value is in the list
|
||||
else if (cfgDefOptionDependValueTotal(config->command, optionId) > 0)
|
||||
else if (depend.listSize > 0)
|
||||
{
|
||||
dependResolved = cfgDefOptionDependValueValid(config->command, optionId, strZ(varStr(dependValue)));
|
||||
dependResolved = false;
|
||||
|
||||
for (unsigned int listIdx = 0; listIdx < depend.listSize; listIdx++)
|
||||
{
|
||||
if (strEqZ(varStr(dependValue), (const char *)depend.list[listIdx]))
|
||||
{
|
||||
dependResolved = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If depend not resolved and option value is set on the command-line then error. It's OK to have
|
||||
// unresolved options in the config file because they may be there for another command. For instance,
|
||||
@ -1161,29 +1552,28 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
if (!dependResolved && optionSet && parseOptionValue->source == cfgSourceParam)
|
||||
{
|
||||
// Get the depend option name
|
||||
const String *dependOptionName = STR(cfgOptionKeyIdxName(dependOptionId, optionKeyIdx));
|
||||
const String *dependOptionName = STR(cfgParseOptionKeyIdxName(dependOptionId, optionKeyIdx));
|
||||
|
||||
// Build the list of possible depend values
|
||||
StringList *dependValueList = strLstNew();
|
||||
|
||||
for (unsigned int listIdx = 0;
|
||||
listIdx < cfgDefOptionDependValueTotal(config->command, optionId); listIdx++)
|
||||
for (unsigned int listIdx = 0; listIdx < depend.listSize; listIdx++)
|
||||
{
|
||||
const char *dependValue = cfgDefOptionDependValue(config->command, optionId, listIdx);
|
||||
const char *dependValue = (const char *)depend.list[listIdx];
|
||||
|
||||
// Build list based on depend option type
|
||||
if (dependOptionDefType == cfgDefOptTypeBoolean)
|
||||
if (dependOptionType == cfgOptTypeBoolean)
|
||||
{
|
||||
// Boolean outputs depend option name as no-* when false
|
||||
if (strcmp(dependValue, ZERO_Z) == 0)
|
||||
{
|
||||
dependOptionName =
|
||||
strNewFmt("no-%s", cfgOptionKeyIdxName(dependOptionId, optionKeyIdx));
|
||||
strNewFmt("no-%s", cfgParseOptionKeyIdxName(dependOptionId, optionKeyIdx));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(dependOptionDefType == cfgDefOptTypePath || dependOptionDefType == cfgDefOptTypeString);
|
||||
ASSERT(dependOptionType == cfgOptTypePath || dependOptionType == cfgOptTypeString);
|
||||
strLstAdd(dependValueList, strNewFmt("'%s'", dependValue));
|
||||
}
|
||||
}
|
||||
@ -1202,7 +1592,7 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
strZ(
|
||||
strNewFmt(
|
||||
"option '%s' not valid without option '%s'%s",
|
||||
cfgOptionKeyIdxName(optionId, optionKeyIdx), strZ(dependOptionName),
|
||||
cfgParseOptionKeyIdxName(optionId, optionKeyIdx), strZ(dependOptionName),
|
||||
strZ(errorValue))));
|
||||
}
|
||||
}
|
||||
@ -1216,11 +1606,11 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
{
|
||||
configOptionValue->source = parseOptionValue->source;
|
||||
|
||||
if (optionDefType == cfgDefOptTypeBoolean)
|
||||
if (optionType == cfgOptTypeBoolean)
|
||||
{
|
||||
configOptionValue->value = !parseOptionValue->negate ? BOOL_TRUE_VAR : BOOL_FALSE_VAR;
|
||||
}
|
||||
else if (optionDefType == cfgDefOptTypeHash)
|
||||
else if (optionType == cfgOptTypeHash)
|
||||
{
|
||||
Variant *value = NULL;
|
||||
|
||||
@ -1242,7 +1632,7 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
THROW_FMT(
|
||||
OptionInvalidError, "key/value '%s' not valid for '%s' option",
|
||||
strZ(strLstGet(parseOptionValue->valueList, listIdx)),
|
||||
cfgOptionKeyIdxName(optionId, optionKeyIdx));
|
||||
cfgParseOptionKeyIdxName(optionId, optionKeyIdx));
|
||||
}
|
||||
|
||||
kvPut(keyValue, VARSTR(strNewN(pair, (size_t)(equal - pair))), VARSTRZ(equal + 1));
|
||||
@ -1250,7 +1640,7 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
|
||||
configOptionValue->value = value;
|
||||
}
|
||||
else if (optionDefType == cfgDefOptTypeList)
|
||||
else if (optionType == cfgOptTypeList)
|
||||
{
|
||||
MEM_CONTEXT_BEGIN(config->memContext)
|
||||
{
|
||||
@ -1264,15 +1654,15 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
const String *valueAllow = value;
|
||||
|
||||
// If a numeric type check that the value is valid
|
||||
if (optionDefType == cfgDefOptTypeInteger || optionDefType == cfgDefOptTypeSize ||
|
||||
optionDefType == cfgDefOptTypeTime)
|
||||
if (optionType == cfgOptTypeInteger || optionType == cfgOptTypeSize ||
|
||||
optionType == cfgOptTypeTime)
|
||||
{
|
||||
int64_t valueInt64 = 0;
|
||||
|
||||
// Check that the value can be converted
|
||||
TRY_BEGIN()
|
||||
{
|
||||
if (optionDefType == cfgDefOptTypeInteger)
|
||||
if (optionType == cfgOptTypeInteger)
|
||||
{
|
||||
MEM_CONTEXT_BEGIN(config->memContext)
|
||||
{
|
||||
@ -1282,7 +1672,7 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
|
||||
valueInt64 = varInt64(configOptionValue->value);
|
||||
}
|
||||
else if (optionDefType == cfgDefOptTypeSize)
|
||||
else if (optionType == cfgOptTypeSize)
|
||||
{
|
||||
MEM_CONTEXT_BEGIN(config->memContext)
|
||||
{
|
||||
@ -1295,7 +1685,7 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(optionDefType == cfgDefOptTypeTime);
|
||||
ASSERT(optionType == cfgOptTypeTime);
|
||||
|
||||
MEM_CONTEXT_BEGIN(config->memContext)
|
||||
{
|
||||
@ -1311,18 +1701,21 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
{
|
||||
THROW_FMT(
|
||||
OptionInvalidValueError, "'%s' is not valid for '%s' option", strZ(value),
|
||||
cfgOptionKeyIdxName(optionId, optionKeyIdx));
|
||||
cfgParseOptionKeyIdxName(optionId, optionKeyIdx));
|
||||
}
|
||||
TRY_END();
|
||||
|
||||
// Check value range
|
||||
if (cfgDefOptionAllowRange(config->command, optionId) &&
|
||||
(valueInt64 < cfgDefOptionAllowRangeMin(config->command, optionId) ||
|
||||
valueInt64 > cfgDefOptionAllowRangeMax(config->command, optionId)))
|
||||
ParseRuleOptionData allowRange = parseRuleOptionDataFind(
|
||||
parseRuleOptionDataTypeAllowRange, config->command, optionId);
|
||||
|
||||
if (allowRange.found &&
|
||||
(valueInt64 < PARSE_RULE_DATA_INT64(allowRange, 0) ||
|
||||
valueInt64 > PARSE_RULE_DATA_INT64(allowRange, 2)))
|
||||
{
|
||||
THROW_FMT(
|
||||
OptionInvalidValueError, "'%s' is out of range for '%s' option", strZ(value),
|
||||
cfgOptionKeyIdxName(optionId, optionKeyIdx));
|
||||
cfgParseOptionKeyIdxName(optionId, optionKeyIdx));
|
||||
}
|
||||
}
|
||||
// Else if path make sure it is valid
|
||||
@ -1333,17 +1726,17 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
{
|
||||
THROW_FMT(
|
||||
OptionInvalidValueError, "'%s' must be >= 1 character for '%s' option", strZ(value),
|
||||
cfgOptionKeyIdxName(optionId, optionKeyIdx));
|
||||
cfgParseOptionKeyIdxName(optionId, optionKeyIdx));
|
||||
}
|
||||
|
||||
if (optionDefType == cfgDefOptTypePath)
|
||||
if (optionType == cfgOptTypePath)
|
||||
{
|
||||
// Make sure it starts with /
|
||||
if (!strBeginsWithZ(value, "/"))
|
||||
{
|
||||
THROW_FMT(
|
||||
OptionInvalidValueError, "'%s' must begin with / for '%s' option", strZ(value),
|
||||
cfgOptionKeyIdxName(optionId, optionKeyIdx));
|
||||
cfgParseOptionKeyIdxName(optionId, optionKeyIdx));
|
||||
}
|
||||
|
||||
// Make sure there are no occurrences of //
|
||||
@ -1351,7 +1744,7 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
{
|
||||
THROW_FMT(
|
||||
OptionInvalidValueError, "'%s' cannot contain // for '%s' option", strZ(value),
|
||||
cfgOptionKeyIdxName(optionId, optionKeyIdx));
|
||||
cfgParseOptionKeyIdxName(optionId, optionKeyIdx));
|
||||
}
|
||||
|
||||
// If the path ends with a / we'll strip it off (unless the value is just /)
|
||||
@ -1367,12 +1760,25 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
}
|
||||
|
||||
// If the option has an allow list then check it
|
||||
if (cfgDefOptionAllowList(config->command, optionId) &&
|
||||
!cfgDefOptionAllowListValueValid(config->command, optionId, strZ(valueAllow)))
|
||||
ParseRuleOptionData allowList = parseRuleOptionDataFind(
|
||||
parseRuleOptionDataTypeAllowList, config->command, optionId);
|
||||
|
||||
if (allowList.found)
|
||||
{
|
||||
THROW_FMT(
|
||||
OptionInvalidValueError, "'%s' is not allowed for '%s' option", strZ(value),
|
||||
cfgOptionKeyIdxName(optionId, optionKeyIdx));
|
||||
unsigned int listIdx = 0;
|
||||
|
||||
for (; listIdx < allowList.listSize; listIdx++)
|
||||
{
|
||||
if (strEqZ(valueAllow, (const char *)allowList.list[listIdx]))
|
||||
break;
|
||||
}
|
||||
|
||||
if (listIdx == allowList.listSize)
|
||||
{
|
||||
THROW_FMT(
|
||||
OptionInvalidValueError, "'%s' is not allowed for '%s' option", strZ(value),
|
||||
cfgParseOptionKeyIdxName(optionId, optionKeyIdx));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1382,7 +1788,7 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
else
|
||||
{
|
||||
// Get the default value for this option
|
||||
const char *value = cfgDefOptionDefault(config->command, optionId);
|
||||
const char *value = cfgParseOptionDefault(config->command, optionId);
|
||||
|
||||
// If the option has a default
|
||||
if (value != NULL)
|
||||
@ -1392,15 +1798,15 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
// This would typically be a switch but since not all cases are covered it would require a
|
||||
// separate function which does not seem worth it. The eventual plan is to have all the defaults
|
||||
// represented as constants so they can be assigned directly without creating variants.
|
||||
if (optionDefType == cfgDefOptTypeBoolean)
|
||||
if (optionType == cfgOptTypeBoolean)
|
||||
configOptionValue->value = strcmp(value, ONE_Z) == 0 ? BOOL_TRUE_VAR : BOOL_FALSE_VAR;
|
||||
else if (optionDefType == cfgDefOptTypePath || optionDefType == cfgDefOptTypeString)
|
||||
else if (optionType == cfgOptTypePath || optionType == cfgOptTypeString)
|
||||
configOptionValue->value = varNewStrZ(value);
|
||||
else
|
||||
{
|
||||
ASSERT(
|
||||
optionDefType == cfgDefOptTypeInteger || optionDefType == cfgDefOptTypeSize ||
|
||||
optionDefType == cfgDefOptTypeTime);
|
||||
optionType == cfgOptTypeInteger || optionType == cfgOptTypeSize ||
|
||||
optionType == cfgOptTypeTime);
|
||||
|
||||
configOptionValue->value = varNewInt64(cvtZToInt64(value));
|
||||
}
|
||||
@ -1408,16 +1814,16 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
|
||||
MEM_CONTEXT_END();
|
||||
}
|
||||
// Else error if option is required and help was not requested
|
||||
else if (cfgDefOptionRequired(config->command, optionId) && !config->help)
|
||||
else if (cfgParseOptionRequired(config->command, optionId) && !config->help)
|
||||
{
|
||||
const char *hint = "";
|
||||
|
||||
if (cfgDefOptionSection(optionId) == cfgDefSectionStanza)
|
||||
if (parseRuleOption[optionId].section == cfgSectionStanza)
|
||||
hint = "\nHINT: does this stanza exist?";
|
||||
|
||||
THROW_FMT(
|
||||
OptionRequiredError, "%s command requires option: %s%s", cfgCommandName(config->command),
|
||||
cfgOptionKeyIdxName(optionId, optionKeyIdx), hint);
|
||||
cfgParseOptionKeyIdxName(optionId, optionKeyIdx), hint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ Parse Configuration
|
||||
#define CONFIG_PARSE_H
|
||||
|
||||
#include "config/config.h"
|
||||
#include "config/parse.auto.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Functions
|
||||
@ -25,4 +26,28 @@ typedef struct CfgParseOptionResult
|
||||
|
||||
CfgParseOptionResult cfgParseOption(const String *optionName);
|
||||
|
||||
// Default value for the option
|
||||
const char *cfgParseOptionDefault(ConfigCommand commandId, ConfigOption optionId);
|
||||
|
||||
// Option id from name
|
||||
int cfgParseOptionId(const char *optionName);
|
||||
|
||||
// Option name from id
|
||||
const char *cfgParseOptionName(ConfigOption optionId);
|
||||
|
||||
// Option name from id and key
|
||||
const char *cfgParseOptionKeyIdxName(ConfigOption optionId, unsigned int keyIdx);
|
||||
|
||||
// Does the option need to be protected from showing up in logs, command lines, etc?
|
||||
bool cfgParseOptionSecure(ConfigOption optionId);
|
||||
|
||||
// Option data type
|
||||
ConfigOptionType cfgParseOptionType(ConfigOption optionId);
|
||||
|
||||
// Is the option required?
|
||||
bool cfgParseOptionRequired(ConfigCommand commandId, ConfigOption optionId);
|
||||
|
||||
// Is the option valid for the command?
|
||||
bool cfgParseOptionValid(ConfigCommand commandId, ConfigOption optionId);
|
||||
|
||||
#endif
|
||||
|
@ -10,8 +10,8 @@ Protocol Helper
|
||||
#include "common/exec.h"
|
||||
#include "common/memContext.h"
|
||||
#include "config/config.intern.h"
|
||||
#include "config/define.h"
|
||||
#include "config/exec.h"
|
||||
#include "config/parse.h"
|
||||
#include "config/protocol.h"
|
||||
#include "postgres/version.h"
|
||||
#include "protocol/helper.h"
|
||||
@ -341,8 +341,8 @@ protocolRemoteParam(ProtocolStorageType protocolStorageType, unsigned int hostId
|
||||
cfgOptionIdxSource(optConfigPath, hostIdx) != cfgSourceDefault ? VARSTR(cfgOptionIdxStr(optConfigPath, hostIdx)) : NULL);
|
||||
|
||||
// Update/remove repo/pg options that are sent to the remote
|
||||
const String *repoHostPrefix = STR(cfgDefOptionName(cfgOptRepoHost));
|
||||
const String *pgHostPrefix = STR(cfgDefOptionName(cfgOptPgHost));
|
||||
const String *repoHostPrefix = STR(cfgParseOptionName(cfgOptRepoHost));
|
||||
const String *pgHostPrefix = STR(cfgParseOptionName(cfgOptPgHost));
|
||||
|
||||
for (ConfigOption optionId = 0; optionId < CFG_OPTION_TOTAL; optionId++)
|
||||
{
|
||||
@ -350,7 +350,7 @@ protocolRemoteParam(ProtocolStorageType protocolStorageType, unsigned int hostId
|
||||
if (!cfgOptionGroup(optionId))
|
||||
continue;
|
||||
|
||||
const String *optionDefName = STR(cfgDefOptionName(optionId));
|
||||
const String *optionDefName = STR(cfgParseOptionName(optionId));
|
||||
unsigned int groupId = cfgOptionGroupId(optionId);
|
||||
bool remove = false;
|
||||
bool skipHostZero = false;
|
||||
@ -370,7 +370,7 @@ protocolRemoteParam(ProtocolStorageType protocolStorageType, unsigned int hostId
|
||||
// Remove unrequired/defaulted pg options when the remote type is repo since they won't be used
|
||||
if (protocolStorageType == protocolStorageTypeRepo)
|
||||
{
|
||||
remove = !cfgDefOptionRequired(cfgCommand(), optionId) || cfgDefOptionDefault(cfgCommand(), optionId) != NULL;
|
||||
remove = !cfgParseOptionRequired(cfgCommand(), optionId) || cfgParseOptionDefault(cfgCommand(), optionId) != NULL;
|
||||
}
|
||||
// The remote is not expecting to see host settings so it could get confused about the locality of pg, i.e. local or
|
||||
// remote.
|
||||
@ -410,7 +410,7 @@ protocolRemoteParam(ProtocolStorageType protocolStorageType, unsigned int hostId
|
||||
kvPut(
|
||||
optionReplace,
|
||||
protocolStorageType == protocolStorageTypeRepo ?
|
||||
VARSTRZ(cfgOptionIdxName(cfgOptRepoLocal, hostIdx)) : VARSTRZ(cfgOptionKeyIdxName(cfgOptPgLocal, 0)),
|
||||
VARSTRZ(cfgOptionIdxName(cfgOptRepoLocal, hostIdx)) : VARSTRZ(cfgParseOptionKeyIdxName(cfgOptPgLocal, 0)),
|
||||
BOOL_TRUE_VAR);
|
||||
|
||||
// Set default to make it explicit which host will be used on the remote
|
||||
|
@ -9,7 +9,6 @@ Storage Helper
|
||||
#include "common/io/io.h"
|
||||
#include "common/memContext.h"
|
||||
#include "common/regExp.h"
|
||||
#include "config/define.h"
|
||||
#include "config/config.h"
|
||||
#include "protocol/helper.h"
|
||||
#include "storage/azure/storage.h"
|
||||
|
@ -15,7 +15,7 @@ build/lib/pgBackRestBuild/Config/Build.pm:
|
||||
class: build
|
||||
type: perl
|
||||
|
||||
build/lib/pgBackRestBuild/Config/BuildDefine.pm:
|
||||
build/lib/pgBackRestBuild/Config/BuildHelp.pm:
|
||||
class: build
|
||||
type: perl
|
||||
|
||||
@ -1171,22 +1171,6 @@ src/config/config.intern.h:
|
||||
class: core
|
||||
type: c/h
|
||||
|
||||
src/config/define.auto.c:
|
||||
class: core/auto
|
||||
type: c
|
||||
|
||||
src/config/define.auto.h:
|
||||
class: core/auto
|
||||
type: c/h
|
||||
|
||||
src/config/define.c:
|
||||
class: core
|
||||
type: c
|
||||
|
||||
src/config/define.h:
|
||||
class: core
|
||||
type: c/h
|
||||
|
||||
src/config/exec.c:
|
||||
class: core
|
||||
type: c
|
||||
@ -1207,6 +1191,10 @@ src/config/parse.auto.c:
|
||||
class: core/auto
|
||||
type: c
|
||||
|
||||
src/config/parse.auto.h:
|
||||
class: core/auto
|
||||
type: c/h
|
||||
|
||||
src/config/parse.c:
|
||||
class: core
|
||||
type: c
|
||||
@ -2091,10 +2079,6 @@ test/src/module/common/waitTest.c:
|
||||
class: test/module
|
||||
type: c
|
||||
|
||||
test/src/module/config/defineTest.c:
|
||||
class: test/module
|
||||
type: c
|
||||
|
||||
test/src/module/config/execTest.c:
|
||||
class: test/module
|
||||
type: c
|
||||
|
@ -363,17 +363,9 @@ unit:
|
||||
- name: config
|
||||
|
||||
test:
|
||||
# ----------------------------------------------------------------------------------------------------------------------------
|
||||
- name: define
|
||||
total: 1
|
||||
|
||||
coverage:
|
||||
config/define: full
|
||||
config/define.auto: noCode
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------------------------------
|
||||
- name: parse
|
||||
total: 5
|
||||
total: 6
|
||||
|
||||
coverage:
|
||||
config/config: full
|
||||
|
@ -11,7 +11,6 @@ Harness for Loading Test Configurations
|
||||
#include "common/harnessTest.h"
|
||||
|
||||
#include "config/config.intern.h"
|
||||
#include "config/define.h"
|
||||
#include "config/load.h"
|
||||
#include "config/parse.h"
|
||||
#include "storage/helper.h"
|
||||
@ -59,11 +58,11 @@ harnessCfgLoadRole(ConfigCommand commandId, ConfigCommandRole commandRoleId, con
|
||||
StringList *argList = strLstDup(argListParam);
|
||||
|
||||
// Set log path if valid
|
||||
if (cfgDefOptionValid(commandId, cfgOptLogPath))
|
||||
if (cfgParseOptionValid(commandId, cfgOptLogPath))
|
||||
strLstInsert(argList, 0, strNewFmt("--" CFGOPT_LOG_PATH "=%s", testDataPath()));
|
||||
|
||||
// Set lock path if valid
|
||||
if (cfgDefOptionValid(commandId, cfgOptLockPath))
|
||||
if (cfgParseOptionValid(commandId, cfgOptLockPath))
|
||||
strLstInsert(argList, 0, strNewFmt("--" CFGOPT_LOCK_PATH "=%s/lock", testDataPath()));
|
||||
|
||||
// Insert the command so it does not interfere with parameters
|
||||
@ -139,7 +138,7 @@ hrnCfgArgRawZ(StringList *argList, ConfigOption optionId, const char *value)
|
||||
void
|
||||
hrnCfgArgKeyRawZ(StringList *argList, ConfigOption optionId, unsigned optionKey, const char *value)
|
||||
{
|
||||
strLstAdd(argList, strNewFmt("--%s=%s", cfgOptionKeyIdxName(optionId, optionKey - 1), value));
|
||||
strLstAdd(argList, strNewFmt("--%s=%s", cfgParseOptionKeyIdxName(optionId, optionKey - 1), value));
|
||||
}
|
||||
|
||||
void
|
||||
@ -151,7 +150,7 @@ hrnCfgArgRawBool(StringList *argList, ConfigOption optionId, bool value)
|
||||
void
|
||||
hrnCfgArgKeyRawBool(StringList *argList, ConfigOption optionId, unsigned optionKey, bool value)
|
||||
{
|
||||
strLstAdd(argList, strNewFmt("--%s%s", value ? "" : "no-", cfgOptionKeyIdxName(optionId, optionKey - 1)));
|
||||
strLstAdd(argList, strNewFmt("--%s%s", value ? "" : "no-", cfgParseOptionKeyIdxName(optionId, optionKey - 1)));
|
||||
}
|
||||
|
||||
void
|
||||
@ -163,7 +162,7 @@ hrnCfgArgRawNegate(StringList *argList, ConfigOption optionId)
|
||||
void
|
||||
hrnCfgArgKeyRawNegate(StringList *argList, ConfigOption optionId, unsigned optionKey)
|
||||
{
|
||||
strLstAdd(argList, strNewFmt("--no-%s", cfgOptionKeyIdxName(optionId, optionKey - 1)));
|
||||
strLstAdd(argList, strNewFmt("--no-%s", cfgParseOptionKeyIdxName(optionId, optionKey - 1)));
|
||||
}
|
||||
|
||||
void
|
||||
@ -175,7 +174,7 @@ hrnCfgArgRawReset(StringList *argList, ConfigOption optionId)
|
||||
void
|
||||
hrnCfgArgKeyRawReset(StringList *argList, ConfigOption optionId, unsigned optionKey)
|
||||
{
|
||||
strLstAdd(argList, strNewFmt("--reset-%s", cfgOptionKeyIdxName(optionId, optionKey - 1)));
|
||||
strLstAdd(argList, strNewFmt("--reset-%s", cfgParseOptionKeyIdxName(optionId, optionKey - 1)));
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
@ -200,7 +199,7 @@ hrnCfgEnvRawZ(ConfigOption optionId, const char *value)
|
||||
void
|
||||
hrnCfgEnvKeyRawZ(ConfigOption optionId, unsigned optionKey, const char *value)
|
||||
{
|
||||
setenv(strZ(strNewFmt(HRN_PGBACKREST_ENV "%s", cfgOptionKeyIdxName(optionId, optionKey - 1))), value, true);
|
||||
setenv(strZ(strNewFmt(HRN_PGBACKREST_ENV "%s", cfgParseOptionKeyIdxName(optionId, optionKey - 1))), value, true);
|
||||
}
|
||||
|
||||
void
|
||||
@ -212,5 +211,5 @@ hrnCfgEnvRemoveRaw(ConfigOption optionId)
|
||||
void
|
||||
hrnCfgEnvKeyRemoveRaw(ConfigOption optionId, unsigned optionKey)
|
||||
{
|
||||
unsetenv(strZ(strNewFmt(HRN_PGBACKREST_ENV "%s", cfgOptionKeyIdxName(optionId, optionKey - 1))));
|
||||
unsetenv(strZ(strNewFmt(HRN_PGBACKREST_ENV "%s", cfgParseOptionKeyIdxName(optionId, optionKey - 1))));
|
||||
}
|
||||
|
@ -71,11 +71,11 @@ testRun(void)
|
||||
// *****************************************************************************************************************************
|
||||
if (testBegin("helpRenderValue()"))
|
||||
{
|
||||
TEST_RESULT_STR_Z(helpRenderValue(varNewBool(true), cfgDefOptTypeBoolean), "y", "boolean y");
|
||||
TEST_RESULT_STR_Z(helpRenderValue(varNewBool(false), cfgDefOptTypeBoolean), "n", "boolean n");
|
||||
TEST_RESULT_STR_Z(helpRenderValue(varNewStrZ("test-string"), cfgDefOptTypeString), "test-string", "string");
|
||||
TEST_RESULT_STR_Z(helpRenderValue(varNewInt64(1234), cfgDefOptTypeInteger), "1234", "int");
|
||||
TEST_RESULT_STR_Z(helpRenderValue(varNewInt64(1234000), cfgDefOptTypeTime), "1234", "time");
|
||||
TEST_RESULT_STR_Z(helpRenderValue(varNewBool(true), cfgOptTypeBoolean), "y", "boolean y");
|
||||
TEST_RESULT_STR_Z(helpRenderValue(varNewBool(false), cfgOptTypeBoolean), "n", "boolean n");
|
||||
TEST_RESULT_STR_Z(helpRenderValue(varNewStrZ("test-string"), cfgOptTypeString), "test-string", "string");
|
||||
TEST_RESULT_STR_Z(helpRenderValue(varNewInt64(1234), cfgOptTypeInteger), "1234", "int");
|
||||
TEST_RESULT_STR_Z(helpRenderValue(varNewInt64(1234000), cfgOptTypeTime), "1234", "time");
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************************
|
||||
|
@ -1,107 +0,0 @@
|
||||
/***********************************************************************************************************************************
|
||||
Test Configuration Command and Option Definition
|
||||
***********************************************************************************************************************************/
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Test run
|
||||
***********************************************************************************************************************************/
|
||||
void
|
||||
testRun(void)
|
||||
{
|
||||
FUNCTION_HARNESS_VOID();
|
||||
|
||||
// Static tests against known values -- these may break as options change so will need to be kept up to date. The tests have
|
||||
// generally been selected to favor values that are not expected to change but adjustments are welcome as long as the type of
|
||||
// test is not drastically changed.
|
||||
// *****************************************************************************************************************************
|
||||
if (testBegin("check known values"))
|
||||
{
|
||||
TEST_RESULT_Z(cfgDefOptionName(cfgOptConfig), "config", "option name");
|
||||
|
||||
TEST_RESULT_INT(cfgDefOptionId("repo-host"), cfgOptRepoHost, "define id");
|
||||
TEST_RESULT_INT(cfgDefOptionId(BOGUS_STR), -1, "invalid define id");
|
||||
|
||||
TEST_RESULT_BOOL(cfgDefOptionAllowList(cfgCmdBackup, cfgOptLogLevelConsole), true, "allow list valid");
|
||||
TEST_RESULT_BOOL(cfgDefOptionAllowList(cfgCmdBackup, cfgOptPgHost), false, "allow list not valid");
|
||||
TEST_RESULT_BOOL(cfgDefOptionAllowList(cfgCmdBackup, cfgOptType), true, "command allow list valid");
|
||||
|
||||
TEST_RESULT_INT(cfgDefOptionAllowListValueTotal(cfgCmdBackup, cfgOptChecksumPage), 0, "allow list total = 0");
|
||||
|
||||
TEST_RESULT_INT(cfgDefOptionAllowListValueTotal(cfgCmdBackup, cfgOptType), 3, "allow list total");
|
||||
|
||||
TEST_RESULT_Z(cfgDefOptionAllowListValue(cfgCmdBackup, cfgOptType, 0), "full", "allow list value 0");
|
||||
TEST_RESULT_Z(cfgDefOptionAllowListValue(cfgCmdBackup, cfgOptType, 1), "diff", "allow list value 1");
|
||||
TEST_RESULT_Z(cfgDefOptionAllowListValue(cfgCmdBackup, cfgOptType, 2), "incr", "allow list value 2");
|
||||
TEST_ERROR(
|
||||
cfgDefOptionAllowListValue(cfgCmdBackup, cfgOptType, 3), AssertError,
|
||||
"assertion 'valueId < cfgDefOptionAllowListValueTotal(commandId, optionId)' failed");
|
||||
|
||||
TEST_RESULT_BOOL(
|
||||
cfgDefOptionAllowListValueValid(cfgCmdBackup, cfgOptType, "diff"), true, "allow list value valid");
|
||||
TEST_RESULT_BOOL(
|
||||
cfgDefOptionAllowListValueValid(cfgCmdBackup, cfgOptType, BOGUS_STR), false, "allow list value not valid");
|
||||
|
||||
TEST_RESULT_BOOL(cfgDefOptionAllowRange(cfgCmdBackup, cfgOptCompressLevel), true, "range allowed");
|
||||
TEST_RESULT_BOOL(cfgDefOptionAllowRange(cfgCmdBackup, cfgOptRepoHost), false, "range not allowed");
|
||||
|
||||
TEST_RESULT_INT(cfgDefOptionAllowRangeMin(cfgCmdBackup, cfgOptDbTimeout), 100, "range min");
|
||||
TEST_RESULT_INT(cfgDefOptionAllowRangeMax(cfgCmdBackup, cfgOptCompressLevel), 9, "range max");
|
||||
TEST_RESULT_INT(cfgDefOptionAllowRangeMin(cfgCmdArchivePush, cfgOptArchivePushQueueMax), 0, "range min");
|
||||
TEST_RESULT_INT(cfgDefOptionAllowRangeMax(cfgCmdArchivePush, cfgOptArchivePushQueueMax), 4503599627370496, "range max");
|
||||
|
||||
TEST_ERROR(
|
||||
cfgDefOptionDefault(cfgDefCommandTotal(), cfgOptCompressLevel), AssertError,
|
||||
"assertion 'commandId < cfgDefCommandTotal()' failed");
|
||||
TEST_ERROR(cfgDefOptionDefault(
|
||||
cfgCmdBackup, cfgDefOptionTotal()), AssertError,
|
||||
"assertion 'optionId < cfgDefOptionTotal()' failed");
|
||||
TEST_RESULT_Z(cfgDefOptionDefault(cfgCmdRestore, cfgOptType), "default", "command default exists");
|
||||
TEST_RESULT_Z(cfgDefOptionDefault(cfgCmdBackup, cfgOptRepoHost), NULL, "default does not exist");
|
||||
|
||||
TEST_RESULT_BOOL(cfgDefOptionDepend(cfgCmdRestore, cfgOptRepoS3Key), true, "has depend option");
|
||||
TEST_RESULT_BOOL(cfgDefOptionDepend(cfgCmdRestore, cfgOptType), false, "does not have depend option");
|
||||
|
||||
TEST_RESULT_INT(cfgDefOptionDependOption(cfgCmdBackup, cfgOptPgHostUser), cfgOptPgHost, "depend option id");
|
||||
TEST_RESULT_INT(cfgDefOptionDependOption(cfgCmdBackup, cfgOptRepoHostCmd), cfgOptRepoHost, "depend option id");
|
||||
|
||||
TEST_RESULT_INT(cfgDefOptionDependValueTotal(cfgCmdRestore, cfgOptTarget), 3, "depend option value total");
|
||||
TEST_RESULT_Z(cfgDefOptionDependValue(cfgCmdRestore, cfgOptTarget, 0), "name", "depend option value 0");
|
||||
TEST_RESULT_Z(cfgDefOptionDependValue(cfgCmdRestore, cfgOptTarget, 1), "time", "depend option value 1");
|
||||
TEST_RESULT_Z(cfgDefOptionDependValue(cfgCmdRestore, cfgOptTarget, 2), "xid", "depend option value 2");
|
||||
TEST_ERROR(
|
||||
cfgDefOptionDependValue(cfgCmdRestore, cfgOptTarget, 3), AssertError,
|
||||
"assertion 'valueId < cfgDefOptionDependValueTotal(commandId, optionId)' failed");
|
||||
|
||||
TEST_RESULT_BOOL(
|
||||
cfgDefOptionDependValueValid(cfgCmdRestore, cfgOptTarget, "time"), true, "depend option value valid");
|
||||
TEST_RESULT_BOOL(
|
||||
cfgDefOptionDependValueValid(cfgCmdRestore, cfgOptTarget, BOGUS_STR), false, "depend option value not valid");
|
||||
|
||||
TEST_RESULT_BOOL(cfgDefOptionMulti(cfgOptRecoveryOption), true, "recovery-option is multi");
|
||||
TEST_RESULT_BOOL(cfgDefOptionMulti(cfgOptDbInclude), true, "db-include is multi");
|
||||
TEST_RESULT_BOOL(cfgDefOptionMulti(cfgOptStartFast), false, "start-fast is not multi");
|
||||
|
||||
TEST_RESULT_BOOL(cfgDefOptionRequired(cfgCmdBackup, cfgOptConfig), true, "option required");
|
||||
TEST_RESULT_BOOL(cfgDefOptionRequired(cfgCmdBackup, cfgOptForce), true, "option required");
|
||||
TEST_RESULT_BOOL(cfgDefOptionRequired(cfgCmdRestore, cfgOptRepoHost), false, "option not required");
|
||||
TEST_RESULT_BOOL(cfgDefOptionRequired(cfgCmdInfo, cfgOptStanza), false, "command option not required");
|
||||
|
||||
TEST_RESULT_INT(cfgDefOptionSection(cfgOptRepoS3Key), cfgDefSectionGlobal, "global section");
|
||||
TEST_RESULT_INT(cfgDefOptionSection(cfgOptPgPath), cfgDefSectionStanza, "stanza section");
|
||||
TEST_RESULT_INT(cfgDefOptionSection(cfgOptType), cfgDefSectionCommandLine, "command line only");
|
||||
|
||||
TEST_RESULT_BOOL(cfgDefOptionSecure(cfgOptRepoS3Key), true, "option secure");
|
||||
TEST_RESULT_BOOL(cfgDefOptionSecure(cfgOptRepoHost), false, "option not secure");
|
||||
|
||||
TEST_RESULT_INT(cfgDefOptionType(cfgOptType), cfgDefOptTypeString, "string type");
|
||||
TEST_RESULT_INT(cfgDefOptionType(cfgOptDelta), cfgDefOptTypeBoolean, "boolean type");
|
||||
|
||||
TEST_ERROR(
|
||||
cfgDefOptionValid(cfgCmdInfo, cfgDefOptionTotal()), AssertError,
|
||||
"assertion 'optionId < cfgDefOptionTotal()' failed");
|
||||
TEST_RESULT_BOOL(cfgDefOptionValid(cfgCmdBackup, cfgOptType), true, "option valid");
|
||||
TEST_RESULT_BOOL(cfgDefOptionValid(cfgCmdInfo, cfgOptType), false, "option not valid");
|
||||
}
|
||||
|
||||
FUNCTION_HARNESS_RESULT_VOID();
|
||||
}
|
@ -38,6 +38,14 @@ testRun(void)
|
||||
{
|
||||
FUNCTION_HARNESS_VOID();
|
||||
|
||||
// *****************************************************************************************************************************
|
||||
if (testBegin("size"))
|
||||
{
|
||||
TEST_TITLE("check size of parse structures");
|
||||
|
||||
TEST_RESULT_UINT(sizeof(ParseRuleOption), TEST_64BIT() ? 24 : 12, "ParseRuleOption size");
|
||||
}
|
||||
|
||||
// Config functions that are not tested with parse
|
||||
// *****************************************************************************************************************************
|
||||
if (testBegin("cfg*()"))
|
||||
@ -45,6 +53,11 @@ testRun(void)
|
||||
TEST_TITLE("config command defaults to none before cfgInit()");
|
||||
|
||||
TEST_RESULT_UINT(cfgCommand(), cfgCmdNone, "command is none");
|
||||
|
||||
TEST_TITLE("parse option name to id");
|
||||
|
||||
TEST_RESULT_INT(cfgParseOptionId(BOGUS_STR), -1, "invalid option");
|
||||
TEST_RESULT_INT(cfgParseOptionId(CFGOPT_STANZA), cfgOptStanza, "valid option");
|
||||
}
|
||||
|
||||
// config and config-include-path options
|
||||
@ -146,9 +159,9 @@ testRun(void)
|
||||
strZ(strNewFmt("%s/global-backup.confsave", strZ(configIncludePath))));
|
||||
|
||||
// Set up defaults
|
||||
String *backupCmdDefConfigValue = strNew(cfgDefOptionDefault(cfgCommandId(TEST_COMMAND_BACKUP), cfgOptConfig));
|
||||
String *backupCmdDefConfigValue = strNew(cfgParseOptionDefault(cfgCommandId(TEST_COMMAND_BACKUP), cfgOptConfig));
|
||||
String *backupCmdDefConfigInclPathValue = strNew(
|
||||
cfgDefOptionDefault(cfgCommandId(TEST_COMMAND_BACKUP), cfgOptConfigIncludePath));
|
||||
cfgParseOptionDefault(cfgCommandId(TEST_COMMAND_BACKUP), cfgOptConfigIncludePath));
|
||||
String *oldConfigDefault = strNewFmt("%s%s", testPath(), PGBACKREST_CONFIG_ORIG_PATH_FILE);
|
||||
|
||||
// Create the option structure and initialize with 0
|
||||
@ -1241,7 +1254,7 @@ testRun(void)
|
||||
"%s=/path/to/db2\n"
|
||||
"pg3-host=ignore\n"
|
||||
"recovery-option=c=d\n",
|
||||
cfgOptionKeyIdxName(cfgOptPgHost, 1), cfgOptionKeyIdxName(cfgOptPgPath, 1))));
|
||||
cfgParseOptionKeyIdxName(cfgOptPgHost, 1), cfgParseOptionKeyIdxName(cfgOptPgPath, 1))));
|
||||
|
||||
TEST_RESULT_VOID(configParse(strLstSize(argList), strLstPtr(argList), false), TEST_COMMAND_BACKUP " command");
|
||||
harnessLogResult(
|
||||
|
@ -36,7 +36,6 @@ use pgBackRestDoc::ProjectInfo;
|
||||
use pgBackRestBuild::Build;
|
||||
use pgBackRestBuild::Build::Common;
|
||||
use pgBackRestBuild::Config::Build;
|
||||
use pgBackRestBuild::Config::BuildDefine;
|
||||
use pgBackRestBuild::Config::BuildHelp;
|
||||
use pgBackRestBuild::Config::BuildParse;
|
||||
use pgBackRestBuild::Error::Build;
|
||||
@ -580,12 +579,6 @@ eval
|
||||
&BLD_PATH => 'command/help',
|
||||
},
|
||||
|
||||
'configDefine' =>
|
||||
{
|
||||
&BLD_DATA => buildConfigDefine(),
|
||||
&BLD_PATH => 'config',
|
||||
},
|
||||
|
||||
'configParse' =>
|
||||
{
|
||||
&BLD_DATA => buildConfigParse(),
|
||||
|
Reference in New Issue
Block a user