1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2024-12-12 10:04:14 +02:00

Complete migration of config code generation to C.

This was started in c5ae047e but did not include generation of parse.auto.c.

The parser has also been improved with better errors and multiple passes to reduce dependency on ordering and produce and cleaner output.

Option order resolution now includes cycle detection.
This commit is contained in:
David Steele 2021-07-28 19:59:23 -04:00
parent 7517c5fef8
commit f3f0c64a78
12 changed files with 2715 additions and 1122 deletions

View File

@ -20,7 +20,6 @@ use pgBackRestDoc::Common::String;
use pgBackRestDoc::ProjectInfo;
use pgBackRestBuild::Build::Common;
use pgBackRestBuild::Config::BuildParse;
use pgBackRestBuild::Config::Data;
####################################################################################################################################

View File

@ -1,630 +0,0 @@
####################################################################################################################################
# Auto-Generate Option Definition for Parsing with getopt_long().
####################################################################################################################################
package pgBackRestBuild::Config::BuildParse;
use strict;
use warnings FATAL => qw(all);
use Carp qw(confess);
use English '-no_match_vars';
use Cwd qw(abs_path);
use Exporter qw(import);
our @EXPORT = qw();
use File::Basename qw(dirname);
use Storable qw(dclone);
use pgBackRestDoc::Common::Log;
use pgBackRestDoc::Common::String;
use pgBackRestDoc::ProjectInfo;
use pgBackRestBuild::Build::Common;
use pgBackRestBuild::Config::Data;
####################################################################################################################################
# Constants
####################################################################################################################################
use constant BLDLCL_FILE_DEFINE => 'parse';
use constant BLDLCL_DATA_COMMAND => '01-dataCommand';
use constant BLDLCL_DATA_OPTION_GROUP => '01-dataOptionGroup';
use constant BLDLCL_DATA_OPTION => '02-dataOption';
use constant BLDLCL_DATA_OPTION_GETOPT => '03-dataOptionGetOpt';
use constant BLDLCL_DATA_OPTION_RESOLVE => '04-dataOptionResolve';
####################################################################################################################################
# Definitions for constants and data to build
####################################################################################################################################
my $strSummary = 'Config Parse Rules';
my $rhBuild =
{
&BLD_FILE =>
{
&BLDLCL_FILE_DEFINE =>
{
&BLD_SUMMARY => $strSummary,
&BLD_DATA =>
{
&BLDLCL_DATA_COMMAND =>
{
&BLD_SUMMARY => 'Command parse data',
},
&BLDLCL_DATA_OPTION_GROUP =>
{
&BLD_SUMMARY => 'Option group parse data',
},
&BLDLCL_DATA_OPTION =>
{
&BLD_SUMMARY => 'Option parse data',
},
&BLDLCL_DATA_OPTION_GETOPT =>
{
&BLD_SUMMARY => 'Option data for getopt_long()',
},
&BLDLCL_DATA_OPTION_RESOLVE =>
{
&BLD_SUMMARY => 'Order for option parse resolution',
},
},
},
},
};
####################################################################################################################################
# Generate enum names
####################################################################################################################################
sub buildConfigCommandEnum
{
return bldEnum('cfgCmd', shift)
}
push @EXPORT, qw(buildConfigCommandEnum);
sub buildConfigOptionEnum
{
return bldEnum('cfgOpt', shift)
}
push @EXPORT, qw(buildConfigOptionEnum);
sub buildConfigOptionGroupEnum
{
return bldEnum('cfgOptGrp', shift)
}
push @EXPORT, qw(buildConfigOptionGroupEnum);
sub buildConfigDefineOptionTypeEnum
{
return bldEnum('cfgOptType', shift);
}
push @EXPORT, qw(buildConfigDefineOptionTypeEnum);
sub buildConfigCommandRoleEnum
{
return bldEnum('cfgCmdRole', shift);
}
####################################################################################################################################
# Helper functions for building optional option data
####################################################################################################################################
sub renderAllowList
{
my $ryAllowList = shift;
my $bCommandIndent = shift;
my $strIndent = $bCommandIndent ? ' ' : '';
return
"${strIndent} PARSE_RULE_OPTION_OPTIONAL_ALLOW_LIST\n" .
"${strIndent} (\n" .
"${strIndent} " . join(",\n${strIndent} ", bldQuoteList($ryAllowList)) .
"\n" .
"${strIndent} ),\n";
}
sub renderDepend
{
my $rhDepend = shift;
my $bCommandIndent = shift;
my $strIndent = $bCommandIndent ? ' ' : '';
my $strDependOption = $rhDepend->{&CFGDEF_DEPEND_OPTION};
my $ryDependList = $rhDepend->{&CFGDEF_DEPEND_LIST};
if (defined($ryDependList))
{
my @stryQuoteList;
foreach my $strItem (@{$ryDependList})
{
push(@stryQuoteList, "\"${strItem}\"");
}
return
"${strIndent} PARSE_RULE_OPTION_OPTIONAL_DEPEND_LIST\n" .
"${strIndent} (\n" .
"${strIndent} " . buildConfigOptionEnum($strDependOption) . ",\n" .
"${strIndent} " . join(",\n${strIndent} ", bldQuoteList($ryDependList)) .
"\n" .
"${strIndent} ),\n";
}
return
"${strIndent} PARSE_RULE_OPTION_OPTIONAL_DEPEND(" . buildConfigOptionEnum($strDependOption) . "),\n";
}
sub renderOptional
{
my $rhOptional = shift;
my $bCommand = shift;
my $strCommand = shift;
my $strOption = shift;
my $strIndent = $bCommand ? ' ' : '';
my $strBuildSourceOptional;
my $bSingleLine = false;
if (defined($rhOptional->{&CFGDEF_ALLOW_LIST}))
{
$strBuildSourceOptional .=
(defined($strBuildSourceOptional) && !$bSingleLine ? "\n" : '') .
renderAllowList($rhOptional->{&CFGDEF_ALLOW_LIST}, $bCommand);
$bSingleLine = false;
}
if (defined($rhOptional->{&CFGDEF_ALLOW_RANGE}))
{
my @fyRange = @{$rhOptional->{&CFGDEF_ALLOW_RANGE}};
my $iMultiplier = $rhOptional->{&CFGDEF_TYPE} eq CFGDEF_TYPE_TIME ? 1000 : 1;
$strBuildSourceOptional =
(defined($strBuildSourceOptional) && !$bSingleLine ? "\n" : '') .
"${strIndent} PARSE_RULE_OPTION_OPTIONAL_ALLOW_RANGE(" . ($fyRange[0] * $iMultiplier) . ', ' .
($fyRange[1] * $iMultiplier) . "),\n";
$bSingleLine = true;
}
if (defined($rhOptional->{&CFGDEF_DEPEND}))
{
$strBuildSourceOptional .=
(defined($strBuildSourceOptional) && !$bSingleLine ? "\n" : '') .
renderDepend($rhOptional->{&CFGDEF_DEPEND}, $bCommand);
$bSingleLine = defined($rhOptional->{&CFGDEF_DEPEND}{&CFGDEF_DEPEND_LIST}) ? false : true;
}
if (defined($rhOptional->{&CFGDEF_DEFAULT}))
{
$strBuildSourceOptional .=
(defined($strBuildSourceOptional) && !$bSingleLine ? "\n" : '') .
"${strIndent} PARSE_RULE_OPTION_OPTIONAL_DEFAULT(" .
($rhOptional->{&CFGDEF_DEFAULT_LITERAL} ? '' : '"') .
(defined($rhOptional->{&CFGDEF_TYPE}) && $rhOptional->{&CFGDEF_TYPE} eq CFGDEF_TYPE_TIME ?
$rhOptional->{&CFGDEF_DEFAULT} * 1000 : $rhOptional->{&CFGDEF_DEFAULT}) .
($rhOptional->{&CFGDEF_DEFAULT_LITERAL} ? '' : '"') .
"),\n";
$bSingleLine = true;
}
if ($bCommand && defined($rhOptional->{&CFGDEF_REQUIRED}))
{
$strBuildSourceOptional .=
(defined($strBuildSourceOptional) && !$bSingleLine ? "\n" : '') .
"${strIndent} PARSE_RULE_OPTION_OPTIONAL_REQUIRED(" .
($rhOptional->{&CFGDEF_REQUIRED} ? 'true' : 'false') . "),\n";
$bSingleLine = true;
}
return $strBuildSourceOptional;
}
####################################################################################################################################
# Build configuration constants and data
####################################################################################################################################
sub buildConfigParse
{
# Build command parse data
# ------------------------------------------------------------------------------------------------------------------------------
my $rhCommandDefine = cfgDefineCommand();
my $strBuildSource =
"static const ParseRuleCommand parseRuleCommand[CFG_COMMAND_TOTAL] =\n" .
"{";
foreach my $strCommand (sort(keys(%{$rhCommandDefine})))
{
my $rhCommand = $rhCommandDefine->{$strCommand};
# Build command data
$strBuildSource .=
"\n" .
" // " . (qw{-} x 125) . "\n" .
" PARSE_RULE_COMMAND\n" .
" (\n" .
" PARSE_RULE_COMMAND_NAME(\"${strCommand}\"),\n";
if ($rhCommand->{&CFGDEF_PARAMETER_ALLOWED})
{
$strBuildSource .=
" PARSE_RULE_COMMAND_PARAMETER_ALLOWED(true),\n";
}
$strBuildSource .=
"\n" .
" PARSE_RULE_COMMAND_ROLE_VALID_LIST\n" .
" (\n";
foreach my $strCommandRole (sort(keys(%{$rhCommand->{&CFGDEF_COMMAND_ROLE}})))
{
$strBuildSource .=
" PARSE_RULE_COMMAND_ROLE(" . buildConfigCommandRoleEnum($strCommandRole) . ")\n";
}
$strBuildSource .=
" ),\n";
$strBuildSource .=
" ),\n";
};
$strBuildSource .=
"};\n";
$rhBuild->{&BLD_FILE}{&BLDLCL_FILE_DEFINE}{&BLD_DATA}{&BLDLCL_DATA_COMMAND}{&BLD_SOURCE} = $strBuildSource;
# Build option group parse data
# ------------------------------------------------------------------------------------------------------------------------------
my $rhOptionGroupDefine = cfgDefineOptionGroup();
$strBuildSource =
"static const ParseRuleOptionGroup parseRuleOptionGroup[CFG_OPTION_GROUP_TOTAL] =\n" .
"{";
foreach my $strGroup (sort(keys(%{$rhOptionGroupDefine})))
{
$strBuildSource .=
"\n" .
" // " . (qw{-} x 125) . "\n" .
" PARSE_RULE_OPTION_GROUP\n" .
" (\n" .
" PARSE_RULE_OPTION_GROUP_NAME(\"" . $strGroup . "\"),\n" .
" ),\n";
}
$strBuildSource .=
"};\n";
$rhBuild->{&BLD_FILE}{&BLDLCL_FILE_DEFINE}{&BLD_DATA}{&BLDLCL_DATA_OPTION_GROUP}{&BLD_SOURCE} = $strBuildSource;
# Build option parse data
# ------------------------------------------------------------------------------------------------------------------------------
my $rhConfigDefine = cfgDefine();
$strBuildSource =
"static const ParseRuleOption parseRuleOption[CFG_OPTION_TOTAL] =\n" .
"{";
foreach my $strOption (sort(keys(%{$rhConfigDefine})))
{
my $rhOption = $rhConfigDefine->{$strOption};
$strBuildSource .=
"\n" .
" // " . (qw{-} x 125) . "\n" .
" PARSE_RULE_OPTION\n" .
" (\n" .
" PARSE_RULE_OPTION_NAME(\"${strOption}\"),\n" .
" PARSE_RULE_OPTION_TYPE(" . buildConfigDefineOptionTypeEnum($rhOption->{&CFGDEF_TYPE}) . "),\n" .
" PARSE_RULE_OPTION_REQUIRED(" . ($rhOption->{&CFGDEF_REQUIRED} ? 'true' : 'false') . "),\n" .
" PARSE_RULE_OPTION_SECTION(cfgSection" .
(defined($rhOption->{&CFGDEF_SECTION}) ? ucfirst($rhOption->{&CFGDEF_SECTION}) : 'CommandLine') .
"),\n";
if ($rhOption->{&CFGDEF_SECURE})
{
$strBuildSource .=
" PARSE_RULE_OPTION_SECURE(true),\n";
}
if ($rhOption->{&CFGDEF_TYPE} eq CFGDEF_TYPE_HASH || $rhOption->{&CFGDEF_TYPE} eq CFGDEF_TYPE_LIST)
{
$strBuildSource .=
" PARSE_RULE_OPTION_MULTI(true),\n";
}
# Build group info
# --------------------------------------------------------------------------------------------------------------------------
if ($rhOption->{&CFGDEF_GROUP})
{
$strBuildSource .=
" PARSE_RULE_OPTION_GROUP_MEMBER(true),\n" .
" PARSE_RULE_OPTION_GROUP_ID(" . buildConfigOptionGroupEnum($rhOption->{&CFGDEF_GROUP}) . "),\n";
}
# Build command role valid lists
#---------------------------------------------------------------------------------------------------------------------------
my $strBuildSourceSub = "";
foreach my $strCommandRole (CFGCMD_ROLE_MAIN, CFGCMD_ROLE_ASYNC, CFGCMD_ROLE_LOCAL, CFGCMD_ROLE_REMOTE)
{
$strBuildSourceSub = "";
foreach my $strCommand (cfgDefineCommandList())
{
if (defined($rhOption->{&CFGDEF_COMMAND}{$strCommand}))
{
if (defined($rhOption->{&CFGDEF_COMMAND}{$strCommand}{&CFGDEF_COMMAND_ROLE}{$strCommandRole}))
{
$strBuildSourceSub .=
" PARSE_RULE_OPTION_COMMAND(" . buildConfigCommandEnum($strCommand) . ")\n";
}
}
}
if ($strBuildSourceSub ne "")
{
$strBuildSource .=
"\n" .
" PARSE_RULE_OPTION_COMMAND_ROLE_" . uc($strCommandRole) . "_VALID_LIST\n" .
" (\n" .
$strBuildSourceSub .
" ),\n";
}
}
# Render optional data and command overrides
# --------------------------------------------------------------------------------------------------------------------------
my $strBuildSourceOptional = renderOptional($rhOption, false);
foreach my $strCommand (cfgDefineCommandList())
{
my $strBuildSourceOptionalCommand;
my $rhCommand = $rhOption->{&CFGDEF_COMMAND}{$strCommand};
$rhCommand->{&CFGDEF_TYPE} = $rhOption->{&CFGDEF_TYPE};
if (defined($rhCommand))
{
$strBuildSourceOptionalCommand = renderOptional($rhCommand, true, $strCommand, $strOption);
if (defined($strBuildSourceOptionalCommand))
{
$strBuildSourceOptional .=
(defined($strBuildSourceOptional) ? "\n" : '') .
" PARSE_RULE_OPTION_OPTIONAL_COMMAND_OVERRIDE\n" .
" (\n" .
" PARSE_RULE_OPTION_OPTIONAL_COMMAND(" . buildConfigCommandEnum($strCommand) . "),\n" .
"\n" .
$strBuildSourceOptionalCommand .
" )\n";
}
}
}
if (defined($strBuildSourceOptional))
{
$strBuildSource .=
"\n" .
" PARSE_RULE_OPTION_OPTIONAL_LIST\n" .
" (\n" .
$strBuildSourceOptional .
" ),\n";
}
$strBuildSource .=
" ),\n";
}
$strBuildSource .=
"};\n";
$rhBuild->{&BLD_FILE}{&BLDLCL_FILE_DEFINE}{&BLD_DATA}{&BLDLCL_DATA_OPTION}{&BLD_SOURCE} = $strBuildSource;
# Build option list for getopt_long()
#-------------------------------------------------------------------------------------------------------------------------------
$strBuildSource =
"static const struct option optionList[] =\n" .
"{";
foreach my $strOption (sort(keys(%{$rhConfigDefine})))
{
my $rhOption = $rhConfigDefine->{$strOption};
my $strOptionEnum = buildConfigOptionEnum($strOption);
my $strOptionArg = ($rhOption->{&CFGDEF_TYPE} ne CFGDEF_TYPE_BOOLEAN ? " .has_arg = required_argument,\n" : '');
my $strOptionPrefix = $rhConfigDefine->{$strOption}{&CFGDEF_PREFIX};
my @stryOptionName = ($strOption);
if (defined($rhOption->{&CFGDEF_DEPRECATE}))
{
foreach my $strOptionNameAlt (sort(keys(%{$rhOption->{&CFGDEF_DEPRECATE}})))
{
push(@stryOptionName, $strOptionNameAlt);
}
}
$strBuildSource .=
"\n" .
" // ${strOption} option" . (@stryOptionName > 1 ? ' and deprecations' : '') . "\n" .
" // " . (qw{-} x 125) . "\n";
for (my $iOptionIdx = 1; $iOptionIdx <= $rhOption->{&CFGDEF_INDEX_TOTAL}; $iOptionIdx++)
{
for (my $iOptionNameIdx = 0; $iOptionNameIdx < @stryOptionName; $iOptionNameIdx++)
{
my $strOptionName = $stryOptionName[$iOptionNameIdx];
my $rhNameAlt = $rhOption->{&CFGDEF_DEPRECATE}{$strOptionName};
# Skip alt name if it is not valid for this option index
if ($iOptionNameIdx > 0 && defined($rhNameAlt->{&CFGDEF_INDEX}) && $rhNameAlt->{&CFGDEF_INDEX} != $iOptionIdx)
{
next;
}
# Generate output name
my $strOptionNameOut = $strOptionName;
my $strOptionConst;
if (defined($strOptionPrefix))
{
if ($iOptionNameIdx == 0)
{
$strOptionNameOut =
"${strOptionPrefix}${iOptionIdx}-" . substr($strOptionName, length($strOptionPrefix) + 1);
}
else
{
$strOptionNameOut =~ s/\?/$iOptionIdx/g;
}
}
# Generate option value used for parsing (offset is added so options don't conflict with getopt_long return values)
my $strOptionFlag = 'PARSE_OPTION_FLAG |';
# Build option constant name if this is the current name for the option
if ($iOptionNameIdx == 0)
{
if (!$rhConfigDefine->{$strOption}{&CFGDEF_GROUP})
{
$strOptionConst = "CFGOPT_" . uc($strOptionNameOut);
$strOptionConst =~ s/\-/_/g;
}
}
# Else use bare string and mark as deprecated
else
{
$strOptionFlag .= ' PARSE_DEPRECATE_FLAG |';
}
my $strOptionVal =
($rhOption->{&CFGDEF_GROUP} ? "(" . ($iOptionIdx - 1) . " << PARSE_KEY_IDX_SHIFT) | " : '') . $strOptionEnum;
# Add option
$strBuildSource .=
" {\n" .
" .name = \"${strOptionNameOut}\",\n" .
$strOptionArg .
" .val = ${strOptionFlag} ${strOptionVal},\n" .
" },\n";
# Add negation when defined
if ($rhOption->{&CFGDEF_NEGATE} &&
!($iOptionNameIdx > 0 && defined($rhNameAlt->{&CFGDEF_NEGATE}) && !$rhNameAlt->{&CFGDEF_NEGATE}))
{
$strBuildSource .=
" {\n" .
" .name = \"no-${strOptionNameOut}\",\n" .
" .val = ${strOptionFlag} PARSE_NEGATE_FLAG | ${strOptionVal},\n" .
" },\n";
}
# Add reset when defined
if ($rhOption->{&CFGDEF_RESET} &&
!($iOptionNameIdx > 0 && defined($rhNameAlt->{&CFGDEF_RESET}) && !$rhNameAlt->{&CFGDEF_RESET}))
{
$strBuildSource .=
" {\n" .
" .name = \"reset-${strOptionNameOut}\",\n" .
" .val = ${strOptionFlag} PARSE_RESET_FLAG | ${strOptionVal},\n" .
" },\n";
}
}
}
}
# The option list needs to be terminated or getopt_long will just keep on reading
$strBuildSource .=
" // Terminate option list\n" .
" {\n" .
" .name = NULL\n" .
" }\n" .
"};\n";
$rhBuild->{&BLD_FILE}{&BLDLCL_FILE_DEFINE}{&BLD_DATA}{&BLDLCL_DATA_OPTION_GETOPT}{&BLD_SOURCE} = $strBuildSource;
# Build option resolve order list. This allows the option validation in C to take place in a single pass.
#
# Always process the stanza option first since confusing error message are produced if it is missing.
#-------------------------------------------------------------------------------------------------------------------------------
my @stryResolveOrder = (buildConfigOptionEnum(CFGOPT_STANZA));
my $rhResolved = {&CFGOPT_STANZA => true};
my $bAllResolved;
do
{
# Assume that we will finish on this loop
$bAllResolved = true;
# Loop through all options
foreach my $strOption (sort(keys(%{$rhConfigDefine})))
{
my $bSkip = false;
# Check the default depend
my $strOptionDepend =
ref($rhConfigDefine->{$strOption}{&CFGDEF_DEPEND}) eq 'HASH' ?
$rhConfigDefine->{$strOption}{&CFGDEF_DEPEND}{&CFGDEF_DEPEND_OPTION} :
$rhConfigDefine->{$strOption}{&CFGDEF_DEPEND};
if (defined($strOptionDepend) && !$rhResolved->{$strOptionDepend})
{
# &log(WARN, "$strOptionDepend is not resolved");
$bSkip = true;
}
# Check the command depends
foreach my $strCommand (sort(keys(%{$rhConfigDefine->{$strOption}{&CFGDEF_COMMAND}})))
{
my $strOptionDepend =
ref($rhConfigDefine->{$strOption}{&CFGDEF_COMMAND}{$strCommand}{&CFGDEF_DEPEND}) eq 'HASH' ?
$rhConfigDefine->{$strOption}{&CFGDEF_COMMAND}{$strCommand}{&CFGDEF_DEPEND}{&CFGDEF_DEPEND_OPTION} :
$rhConfigDefine->{$strOption}{&CFGDEF_COMMAND}{$strCommand}{&CFGDEF_DEPEND};
if (defined($strOptionDepend) && !$rhResolved->{$strOptionDepend})
{
$bSkip = true;
}
}
# If dependency was not found try again on the next loop
if ($bSkip)
{
$bAllResolved = false;
}
# Else add option to resolve order list
elsif (!$rhResolved->{$strOption})
{
push(@stryResolveOrder, buildConfigOptionEnum($strOption));
$rhResolved->{$strOption} = true;
}
}
}
while (!$bAllResolved);
$rhBuild->{&BLD_FILE}{&BLDLCL_FILE_DEFINE}{&BLD_DATA}{&BLDLCL_DATA_OPTION_RESOLVE}{&BLD_SOURCE} =
"static const ConfigOption optionResolveOrder[] =\n" .
"{\n" .
" " . join(",\n ", @stryResolveOrder) . ",\n" .
"};\n";
return $rhBuild;
}
push @EXPORT, qw(buildConfigParse);
1;

View File

@ -216,7 +216,7 @@ SRCS_BUILD_CONFIG = \
OBJS_BUILD_CONFIG = $(patsubst %.c,$(BUILDDIR)/%.o,$(SRCS_BUILD) $(SRCS_BUILD_CONFIG))
build-config: $(OBJS_BUILD_CONFIG) build/config/config.yaml config/config.auto.h
build-config: $(OBJS_BUILD_CONFIG) build/config/config.yaml config/config.auto.h config/config.auto.c config/parse.auto.c
$(CC) -o build-config $(OBJS_BUILD_CONFIG) $(LDFLAGS) $(LIBS) $(LIBS_BUILD)
./build-config $(VPATH)

View File

@ -17,6 +17,10 @@ Block comments
"****************************************************************************************************************************" \
"*******/"
#define COMMENT_SEPARATOR \
" // ---------------------------------------------------------------------------------------------------------------------" \
"--------"
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/

View File

@ -15,6 +15,9 @@ main(int argListSize, const char *argList[])
// Check parameters
CHECK(argListSize <= 2);
// Initialize logging
logInit(logLevelWarn, logLevelError, logLevelOff, false, 0, 1, false);
// If the path was specified
const String *pathRepo;

File diff suppressed because it is too large Load Diff

View File

@ -4,44 +4,131 @@ Parse Configuration Yaml
#ifndef BUILD_CONFIG_PARSE_H
#define BUILD_CONFIG_PARSE_H
#include "common/type/stringList.h"
/***********************************************************************************************************************************
Command role constants
***********************************************************************************************************************************/
#define CMD_ROLE_ASYNC "async"
STRING_DECLARE(CMD_ROLE_ASYNC_STR);
#define CMD_ROLE_LOCAL "local"
STRING_DECLARE(CMD_ROLE_LOCAL_STR);
#define CMD_ROLE_MAIN "main"
STRING_DECLARE(CMD_ROLE_MAIN_STR);
#define CMD_ROLE_REMOTE "remote"
STRING_DECLARE(CMD_ROLE_REMOTE_STR);
/***********************************************************************************************************************************
Command constants
***********************************************************************************************************************************/
#define CMD_HELP "help"
STRING_DECLARE(CMD_HELP_STR);
#define CMD_VERSION "version"
STRING_DECLARE(CMD_VERSION_STR);
/***********************************************************************************************************************************
Option type constants
***********************************************************************************************************************************/
#define OPT_TYPE_BOOLEAN "boolean"
STRING_DECLARE(OPT_TYPE_BOOLEAN_STR);
#define OPT_TYPE_HASH "hash"
STRING_DECLARE(OPT_TYPE_HASH_STR);
#define OPT_TYPE_LIST "list"
STRING_DECLARE(OPT_TYPE_LIST_STR);
#define OPT_TYPE_STRING "string"
STRING_DECLARE(OPT_TYPE_STRING_STR);
#define OPT_TYPE_TIME "time"
STRING_DECLARE(OPT_TYPE_TIME_STR);
/***********************************************************************************************************************************
Option constants
***********************************************************************************************************************************/
#define OPT_STANZA "stanza"
STRING_DECLARE(OPT_STANZA_STR);
/***********************************************************************************************************************************
Section constants
***********************************************************************************************************************************/
#define SECTION_COMMAND_LINE "command-line"
STRING_DECLARE(SECTION_COMMAND_LINE_STR);
#define SECTION_GLOBAL "global"
STRING_DECLARE(SECTION_GLOBAL_STR);
#define SECTION_STANZA "stanza"
STRING_DECLARE(SECTION_STANZA_STR);
/***********************************************************************************************************************************
Types
***********************************************************************************************************************************/
typedef struct BldCfgCommand
{
const String *name; // Name
bool logFile; // Does the command write automatically to a log file?
const String *logLevelDefault; // Default log level
bool lockRequired; // Is a lock required
bool lockRemoteRequired; // Is a remote lock required?
const String *lockType; // Lock type
const String *const name; // Name
const bool logFile; // Does the command write automatically to a log file?
const String *const logLevelDefault; // Default log level
const bool lockRequired; // Is a lock required
const bool lockRemoteRequired; // Is a remote lock required?
const String *const lockType; // Lock type
const bool parameterAllowed; // Are command line parameters allowed?
const StringList *const roleList; // Roles valid for the command
} BldCfgCommand;
typedef struct BldCfgOptionGroup
{
const String *name; // Name
const String *const name; // Name
const unsigned int indexTotal; // Total indexes for option
} BldCfgOptionGroup;
typedef struct BldCfgOption BldCfgOption; // Forward declaration
typedef struct BldCfgOptionDepend
{
const BldCfgOption *const option; // Option dependency is on
const StringList *const valueList; // Allowed value list
} BldCfgOptionDepend;
typedef struct BldCfgOptionDeprecate
{
const String *const name; // Deprecated option name
const unsigned int index; // Option index to deprecate
const bool reset; // Does the deprecated option allow reset
} BldCfgOptionDeprecate;
typedef struct BldCfgOptionCommand
{
const String *name; // Name
const StringList *allowList; // Allowed value list
const String *const name; // Name
const bool required; // Is the option required?
const String *const defaultValue; // Default value, if any
const BldCfgOptionDepend *const depend; // Dependency, if any
const StringList *const allowList; // Allowed value list
const StringList *const roleList; // Roles valid for the command
} BldCfgOptionCommand;
typedef struct BldCfgOption
struct BldCfgOption
{
const String *name; // Name
const String *type; // Option type, e.g. integer
const String *group; // Option group, if any
const StringList *allowList; // Allowed value list
const List *cmdList; // Command override list
} BldCfgOption;
const String *const name; // Name
const String *const type; // Option type, e.g. integer
const String *const section; // Option section, i.e. stanza or global
const bool required; // Is the option required?
const bool negate; // Can the option be negated?
const bool reset; // Can the option be reset?
const String *const defaultValue; // Default value, if any
const bool defaultLiteral; // Should default be interpreted literally, i.e. not a string
const String *const group; // Option group, if any
const bool secure; // Does the option contain a secret?
const BldCfgOptionDepend *const depend; // Dependency, if any
const StringList *const allowList; // Allowed value list
const String *const allowRangeMin; // Allow range min, if any
const String *const allowRangeMax; // Allow range max, if any
const List *const cmdList; // Command override list
const StringList *const cmdRoleList; // Roles valid for the option
const List *const deprecateList; // List of option deprecations
};
typedef struct BldCfg
{
List *commandList; // Command list
List *optGrpList; // Option group list
List *optList; // Option list
const List *const cmdList; // Command list
const List *const optGrpList; // Option group list
const List *const optList; // Option list
const List *const optResolveList; // Option list in resolved dependency order
} BldCfg;
/***********************************************************************************************************************************

View File

@ -73,18 +73,20 @@ bldEnumOpt(const String *const value)
return bldEnum("cfgOpt", value);
}
/**********************************************************************************************************************************/
void
bldCfgRender(const Storage *const storageRepo, const BldCfg bldCfg)
/***********************************************************************************************************************************
Render config.auto.h
***********************************************************************************************************************************/
#define CONFIG_MODULE "config"
#define CONFIG_AUTO_COMMENT "Command and Option Configuration"
static void
bldCfgRenderConfigAutoH(const Storage *const storageRepo, const BldCfg bldCfg)
{
// Build Header
// -----------------------------------------------------------------------------------------------------------------------------
const String *const header = bldHeader("config", "Command and Option Configuration");
String *config = strNewFmt(
"%s"
"#ifndef CONFIG_CONFIG_AUTO_H\n"
"#define CONFIG_CONFIG_AUTO_H\n",
strZ(header));
strZ(bldHeader(CONFIG_MODULE, CONFIG_AUTO_COMMENT)));
// Command constants
// -----------------------------------------------------------------------------------------------------------------------------
@ -95,18 +97,14 @@ bldCfgRender(const Storage *const storageRepo, const BldCfg bldCfg)
"Command constants\n"
COMMENT_BLOCK_END "\n");
unsigned int cmdTotal = 0;
for (unsigned int cmdIdx = 0; cmdIdx < lstSize(bldCfg.commandList); cmdIdx++)
for (unsigned int cmdIdx = 0; cmdIdx < lstSize(bldCfg.cmdList); cmdIdx++)
{
const BldCfgCommand *const cmd = lstGet(bldCfg.commandList, cmdIdx);
const BldCfgCommand *const cmd = lstGet(bldCfg.cmdList, cmdIdx);
strCatFmt(config, "%s\n", strZ(bldDefineRender(bldConst("CFGCMD", cmd->name), strNewFmt("\"%s\"", strZ(cmd->name)))));
cmdTotal++;
}
strCatFmt(config, "\n%s\n", strZ(bldDefineRender(STRDEF("CFG_COMMAND_TOTAL"), strNewFmt("%u", cmdTotal))));
strCatFmt(config, "\n%s\n", strZ(bldDefineRender(STRDEF("CFG_COMMAND_TOTAL"), strNewFmt("%u", lstSize(bldCfg.cmdList)))));
// Option group constants
// -----------------------------------------------------------------------------------------------------------------------------
@ -117,12 +115,7 @@ bldCfgRender(const Storage *const storageRepo, const BldCfg bldCfg)
"Option group constants\n"
COMMENT_BLOCK_END "\n");
unsigned int optGrpTotal = 0;
for (unsigned int optGrpIdx = 0; optGrpIdx < lstSize(bldCfg.optGrpList); optGrpIdx++)
optGrpTotal++;
strCatFmt(config, "%s\n", strZ(bldDefineRender(STRDEF("CFG_OPTION_GROUP_TOTAL"), strNewFmt("%u", optGrpTotal))));
strCatFmt(config, "%s\n", strZ(bldDefineRender(STRDEF("CFG_OPTION_GROUP_TOTAL"), strNewFmt("%u", lstSize(bldCfg.optGrpList)))));
// Option constants
// -----------------------------------------------------------------------------------------------------------------------------
@ -133,19 +126,15 @@ bldCfgRender(const Storage *const storageRepo, const BldCfg bldCfg)
"Option constants\n"
COMMENT_BLOCK_END "\n");
unsigned int optTotal = 0;
for (unsigned int optIdx = 0; optIdx < lstSize(bldCfg.optList); optIdx++)
{
const BldCfgOption *const opt = lstGet(bldCfg.optList, optIdx);
if (opt->group == NULL)
strCatFmt(config, "%s\n", strZ(bldDefineRender(bldConst("CFGOPT", opt->name), strNewFmt("\"%s\"", strZ(opt->name)))));
optTotal++;
}
strCatFmt(config, "\n%s\n", strZ(bldDefineRender(STRDEF("CFG_OPTION_TOTAL"), strNewFmt("%u", optTotal))));
strCatFmt(config, "\n%s\n", strZ(bldDefineRender(STRDEF("CFG_OPTION_TOTAL"), strNewFmt("%u", lstSize(bldCfg.optList)))));
// Option value constants
// -----------------------------------------------------------------------------------------------------------------------------
@ -172,17 +161,14 @@ bldCfgRender(const Storage *const storageRepo, const BldCfg bldCfg)
strLstAddIfMissing(allowList, strLstGet(opt->allowList, allowListIdx));
}
if (opt->cmdList != NULL)
for (unsigned int optCmdListIdx = 0; optCmdListIdx < lstSize(opt->cmdList); optCmdListIdx++)
{
for (unsigned int optCmdListIdx = 0; optCmdListIdx < lstSize(opt->cmdList); optCmdListIdx++)
{
BldCfgOptionCommand *optCmd = lstGet(opt->cmdList, optCmdListIdx);
BldCfgOptionCommand *optCmd = lstGet(opt->cmdList, optCmdListIdx);
if (optCmd->allowList != NULL)
{
for (unsigned int allowListIdx = 0; allowListIdx < strLstSize(optCmd->allowList); allowListIdx++)
strLstAddIfMissing(allowList, strLstGet(optCmd->allowList, allowListIdx));
}
if (optCmd->allowList != NULL)
{
for (unsigned int allowListIdx = 0; allowListIdx < strLstSize(optCmd->allowList); allowListIdx++)
strLstAddIfMissing(allowList, strLstGet(optCmd->allowList, allowListIdx));
}
}
@ -224,9 +210,9 @@ bldCfgRender(const Storage *const storageRepo, const BldCfg bldCfg)
"typedef enum\n"
"{\n");
for (unsigned int cmdIdx = 0; cmdIdx < lstSize(bldCfg.commandList); cmdIdx++)
for (unsigned int cmdIdx = 0; cmdIdx < lstSize(bldCfg.cmdList); cmdIdx++)
{
const BldCfgCommand *const cmd = lstGet(bldCfg.commandList, cmdIdx);
const BldCfgCommand *const cmd = lstGet(bldCfg.cmdList, cmdIdx);
strCatFmt(config, " %s,\n", strZ(bldEnumCmd(cmd->name)));
}
@ -288,22 +274,30 @@ bldCfgRender(const Storage *const storageRepo, const BldCfg bldCfg)
"#endif\n");
bldPut(storageRepo, "src/config/config.auto.h", BUFSTR(config));
}
// Build C
/***********************************************************************************************************************************
Render config.auto.c
***********************************************************************************************************************************/
static void
bldCfgRenderConfigAutoC(const Storage *const storageRepo, const BldCfg bldCfg)
{
String *const config = bldHeader(CONFIG_MODULE, CONFIG_AUTO_COMMENT);
// Command data
// -----------------------------------------------------------------------------------------------------------------------------
config = strNewFmt(
"%s"
strCatZ(
config,
"\n"
COMMENT_BLOCK_BEGIN "\n"
"Command data\n"
COMMENT_BLOCK_END "\n"
"static const ConfigCommandData configCommandData[CFG_COMMAND_TOTAL] = CONFIG_COMMAND_LIST\n"
"(\n",
strZ(header));
"(\n");
for (unsigned int cmdIdx = 0; cmdIdx < lstSize(bldCfg.commandList); cmdIdx++)
for (unsigned int cmdIdx = 0; cmdIdx < lstSize(bldCfg.cmdList); cmdIdx++)
{
const BldCfgCommand *const cmd = lstGet(bldCfg.commandList, cmdIdx);
const BldCfgCommand *const cmd = lstGet(bldCfg.cmdList, cmdIdx);
if (cmdIdx != 0)
strCatZ(config, "\n");
@ -328,5 +322,571 @@ bldCfgRender(const Storage *const storageRepo, const BldCfg bldCfg)
config,
")\n");
// Write to storage
// -----------------------------------------------------------------------------------------------------------------------------
bldPut(storageRepo, "src/config/config.auto.c", BUFSTR(config));
}
/***********************************************************************************************************************************
Render parse.auto.c
***********************************************************************************************************************************/
#define PARSE_AUTO_COMMENT "Config Parse Rules"
static void
bldCfgRenderLf(String *const config, const bool lf)
{
if (lf)
strCatZ(config, "\n");
}
static const String *
bldCfgRenderValue(const String *const type, const String *const value)
{
// Translate boolean values
if (strEq(type, OPT_TYPE_BOOLEAN_STR))
{
if (strEq(value, FALSE_STR))
return ZERO_STR;
CHECK(strEq(value, TRUE_STR));
return strNewZ("1");
}
// Translate time values
else if (strEq(type, OPT_TYPE_TIME_STR))
return strNewFmt("%" PRId64, (int64_t)(cvtZToDouble(strZ(value)) * 1000));
return value;
}
// Helper to render allow list
static bool
bldCfgRenderAllowList(String *const config, const StringList *const allowList, const bool command)
{
if (allowList != NULL)
{
const char *indent = command ? " " : " ";
strCatFmt(
config,
"%sPARSE_RULE_OPTION_OPTIONAL_ALLOW_LIST\n"
"%s(\n",
indent, indent);
for (unsigned int allowIdx = 0; allowIdx < strLstSize(allowList); allowIdx++)
{
strCatFmt(
config,
"%s \"%s\"%s\n",
indent, strZ(strLstGet(allowList, allowIdx)),
allowIdx < strLstSize(allowList) - 1 ? "," : "");
}
strCatFmt(config, "%s),\n", indent);
return true;
}
return false;
}
// Helper to render default
static bool
bldCfgRenderDefault(
String *const config, const String *const type, const String *const defaultValue,
const bool defaultLiteral, const bool command, bool multi)
{
if (defaultValue != NULL)
{
const char *indent = command ? " " : " ";
bldCfgRenderLf(config, multi);
strCatFmt(
config,
"%sPARSE_RULE_OPTION_OPTIONAL_DEFAULT(%s%s%s),\n",
indent, defaultLiteral ? "" : "\"", strZ(bldCfgRenderValue(type, defaultValue)), defaultLiteral ? "" : "\"");
return false;
}
return multi;
}
// Helper to render depend
static bool
bldCfgRenderDepend(String *const config, const BldCfgOptionDepend *const depend, const bool command, const bool multi)
{
if (depend != NULL)
{
const char *indent = command ? " " : " ";
bldCfgRenderLf(config, multi);
if (depend->valueList != NULL)
{
strCatFmt(
config,
"%sPARSE_RULE_OPTION_OPTIONAL_DEPEND_LIST\n"
"%s(\n"
"%s %s,\n",
indent, indent, indent, strZ(bldEnum("cfgOpt", depend->option->name)));
for (unsigned int valueIdx = 0; valueIdx < strLstSize(depend->valueList); valueIdx++)
{
strCatFmt(
config, "%s \"%s\"%s\n", indent,
strZ(bldCfgRenderValue(depend->option->type, strLstGet(depend->valueList, valueIdx))),
valueIdx < strLstSize(depend->valueList) - 1 ? "," : "");
}
strCatFmt(config, "%s),\n", indent);
return true;
}
else
{
strCatFmt(
config,
"%sPARSE_RULE_OPTION_OPTIONAL_DEPEND(%s),\n",
indent, strZ(bldEnum("cfgOpt", depend->option->name)));
return false;
}
}
return multi;
}
static void
bldCfgRenderParseAutoC(const Storage *const storageRepo, const BldCfg bldCfg)
{
String *const config = bldHeader(CONFIG_MODULE, PARSE_AUTO_COMMENT);
// Command parse rules
// -----------------------------------------------------------------------------------------------------------------------------
strCatFmt(
config,
"\n"
COMMENT_BLOCK_BEGIN "\n"
"Command parse data\n"
COMMENT_BLOCK_END "\n"
"static const ParseRuleCommand parseRuleCommand[CFG_COMMAND_TOTAL] =\n"
"{\n");
for (unsigned int cmdIdx = 0; cmdIdx < lstSize(bldCfg.cmdList); cmdIdx++)
{
const BldCfgCommand *const cmd = lstGet(bldCfg.cmdList, cmdIdx);
bldCfgRenderLf(config, cmdIdx != 0);
strCatFmt(
config,
COMMENT_SEPARATOR "\n"
" PARSE_RULE_COMMAND\n"
" (\n"
" PARSE_RULE_COMMAND_NAME(\"%s\"),\n",
strZ(cmd->name));
if (cmd->parameterAllowed)
strCatZ(config, " PARSE_RULE_COMMAND_PARAMETER_ALLOWED(true),\n");
strCatFmt(
config,
"\n"
" PARSE_RULE_COMMAND_ROLE_VALID_LIST\n"
" (\n");
for (unsigned int cmdRoleIdx = 0; cmdRoleIdx < strLstSize(cmd->roleList); cmdRoleIdx++)
{
strCatFmt(
config,
" PARSE_RULE_COMMAND_ROLE(%s)\n",
strZ(bldEnum("cfgCmdRole", strLstGet(cmd->roleList, cmdRoleIdx))));
}
strCatZ(
config,
" ),\n"
" ),\n");
}
strCatZ(
config,
"};\n");
// Option group rules
// -----------------------------------------------------------------------------------------------------------------------------
strCatFmt(
config,
"\n"
COMMENT_BLOCK_BEGIN "\n"
"Option group parse data\n"
COMMENT_BLOCK_END "\n"
"static const ParseRuleOptionGroup parseRuleOptionGroup[CFG_OPTION_GROUP_TOTAL] =\n"
"{\n");
for (unsigned int optGrpIdx = 0; optGrpIdx < lstSize(bldCfg.optGrpList); optGrpIdx++)
{
const BldCfgOptionGroup *const optGrp = lstGet(bldCfg.optGrpList, optGrpIdx);
bldCfgRenderLf(config, optGrpIdx != 0);
strCatFmt(
config,
COMMENT_SEPARATOR "\n"
" PARSE_RULE_OPTION_GROUP\n"
" (\n"
" PARSE_RULE_OPTION_GROUP_NAME(\"%s\"),\n"
" ),\n",
strZ(optGrp->name));
}
strCatZ(
config,
"};\n");
// Option rules
// -----------------------------------------------------------------------------------------------------------------------------
strCatFmt(
config,
"\n"
COMMENT_BLOCK_BEGIN "\n"
"Option parse data\n"
COMMENT_BLOCK_END "\n"
"static const ParseRuleOption parseRuleOption[CFG_OPTION_TOTAL] =\n"
"{\n");
StringList *const cmdRoleAllList = strLstNew();
strLstAdd(cmdRoleAllList, CMD_ROLE_MAIN_STR);
strLstAdd(cmdRoleAllList, CMD_ROLE_ASYNC_STR);
strLstAdd(cmdRoleAllList, CMD_ROLE_LOCAL_STR);
strLstAdd(cmdRoleAllList, CMD_ROLE_REMOTE_STR);
for (unsigned int optIdx = 0; optIdx < lstSize(bldCfg.optList); optIdx++)
{
const BldCfgOption *const opt = lstGet(bldCfg.optList, optIdx);
bldCfgRenderLf(config, optIdx != 0);
strCatFmt(
config,
COMMENT_SEPARATOR "\n"
" PARSE_RULE_OPTION\n"
" (\n"
" PARSE_RULE_OPTION_NAME(\"%s\"),\n"
" PARSE_RULE_OPTION_TYPE(%s),\n"
" PARSE_RULE_OPTION_REQUIRED(%s),\n"
" PARSE_RULE_OPTION_SECTION(%s),\n",
strZ(opt->name), strZ(bldEnum("cfgOptType", opt->type)), cvtBoolToConstZ(opt->required),
strZ(bldEnum("cfgSection", opt->section)));
if (opt->secure)
strCatZ(config, " PARSE_RULE_OPTION_SECURE(true),\n");
if (strEq(opt->type, OPT_TYPE_HASH_STR) || strEq(opt->type, OPT_TYPE_LIST_STR))
strCatZ(config, " PARSE_RULE_OPTION_MULTI(true),\n");
if (opt->group != NULL)
{
strCatFmt(
config,
" PARSE_RULE_OPTION_GROUP_MEMBER(true),\n"
" PARSE_RULE_OPTION_GROUP_ID(%s),\n",
strZ(bldEnum("cfgOptGrp", opt->group)));
}
// Build command role valid lists
for (unsigned int cmdRoleAllIdx = 0; cmdRoleAllIdx < strLstSize(cmdRoleAllList); cmdRoleAllIdx++)
{
String *const configRole = strNew();
const String *const cmdRole = strLstGet(cmdRoleAllList, cmdRoleAllIdx);
for (unsigned int optCmdIdx = 0; optCmdIdx < lstSize(opt->cmdList); optCmdIdx++)
{
BldCfgOptionCommand *const optCmd = lstGet(opt->cmdList, optCmdIdx);
if (strLstExists(optCmd->roleList, cmdRole))
{
strCatFmt(
configRole,
" PARSE_RULE_OPTION_COMMAND(%s)\n", strZ(bldEnum("cfgCmd", optCmd->name)));
}
}
if (!strEmpty(configRole))
{
strCatFmt(
config,
"\n"
" PARSE_RULE_OPTION_COMMAND_ROLE_%s_VALID_LIST\n"
" (\n"
"%s"
" ),\n",
strZ(strUpper(strDup(cmdRole))), strZ(configRole));
}
}
// Build optional data
String *const configOptional = strNew();
if (opt->allowRangeMin != NULL)
{
CHECK(opt->allowRangeMax != NULL);
const String *allowRangeMin = opt->allowRangeMin;
const String *allowRangeMax = opt->allowRangeMax;
if (strEq(opt->type, OPT_TYPE_TIME_STR))
{
allowRangeMin = strNewFmt("%" PRId64, (int64_t)(cvtZToDouble(strZ(allowRangeMin)) * 1000));
allowRangeMax = strNewFmt("%" PRId64, (int64_t)(cvtZToDouble(strZ(allowRangeMax)) * 1000));
}
strCatFmt(
configOptional,
" PARSE_RULE_OPTION_OPTIONAL_ALLOW_RANGE(%s, %s),\n",
strZ(allowRangeMin), strZ(allowRangeMax));
}
bool multi = bldCfgRenderAllowList(configOptional, opt->allowList, false);
multi = bldCfgRenderDepend(configOptional, opt->depend, false, multi);
multi = bldCfgRenderDefault(configOptional, opt->type, opt->defaultValue, opt->defaultLiteral, false, multi);
// Build optional data for commands
for (unsigned int optCmdIdx = 0; optCmdIdx < lstSize(opt->cmdList); optCmdIdx++)
{
BldCfgOptionCommand *const optCmd = lstGet(opt->cmdList, optCmdIdx);
String *const configCommand = strNew();
bool multi = bldCfgRenderAllowList(configCommand, optCmd->allowList, true);
multi = bldCfgRenderDepend(configCommand, optCmd->depend, true, multi);
multi = bldCfgRenderDefault(configCommand, opt->type, optCmd->defaultValue, false, true, multi);
if (optCmd->required != opt->required)
{
bldCfgRenderLf(configCommand, multi);
strCatFmt(
configCommand,
" PARSE_RULE_OPTION_OPTIONAL_REQUIRED(%s),\n",
cvtBoolToConstZ(optCmd->required));
}
if (!strEmpty(configCommand))
{
bldCfgRenderLf(configOptional, !strEmpty(configOptional));
strCatFmt(
configOptional,
" PARSE_RULE_OPTION_OPTIONAL_COMMAND_OVERRIDE\n"
" (\n"
" PARSE_RULE_OPTION_OPTIONAL_COMMAND(%s),\n"
"\n"
"%s"
" )\n",
strZ(bldEnum("cfgCmd", optCmd->name)), strZ(configCommand));
}
}
// Add optional data
if (!strEmpty(configOptional))
{
strCatFmt(
config,
"\n"
" PARSE_RULE_OPTION_OPTIONAL_LIST\n"
" (\n"
"%s"
" ),\n",
strZ(configOptional));
}
strCatZ(config, " ),\n");
}
strCatZ(
config,
"};\n");
// Option data for getopt_long()
// -----------------------------------------------------------------------------------------------------------------------------
strCatFmt(
config,
"\n"
COMMENT_BLOCK_BEGIN "\n"
"Option data for getopt_long()\n"
COMMENT_BLOCK_END "\n"
"static const struct option optionList[] =\n"
"{\n");
for (unsigned int optIdx = 0; optIdx < lstSize(bldCfg.optList); optIdx++)
{
const BldCfgOption *const opt = lstGet(bldCfg.optList, optIdx);
// Determine if the option is indexed
unsigned int indexTotal = 1;
const BldCfgOptionGroup *optGrp = NULL;
if (opt->group != NULL)
{
optGrp = lstFind(bldCfg.optGrpList, &opt->group);
CHECK(optGrp != NULL);
indexTotal = optGrp->indexTotal;
}
bldCfgRenderLf(config, optIdx != 0);
strCatFmt(
config,
" // %s option%s\n"
COMMENT_SEPARATOR "\n",
strZ(opt->name), opt->deprecateList != NULL ? " and deprecations" : "");
for (unsigned int index = 0; index < indexTotal; index++)
{
const String *optName = opt->name;
const String *optShift = EMPTY_STR;
// Generate indexed name
if (optGrp != NULL)
{
optName = strNewFmt("%s%u%s", strZ(optGrp->name), index + 1, strZ(strSub(optName, strSize(optGrp->name))));
optShift = strNewFmt(" | (%u << PARSE_KEY_IDX_SHIFT)", index);
}
strCatFmt(
config,
" {\n"
" .name = \"%s\",\n"
"%s"
" .val = PARSE_OPTION_FLAG%s | %s,\n"
" },\n",
strZ(optName),
strEq(opt->type, OPT_TYPE_BOOLEAN_STR) ? "" : " .has_arg = required_argument,\n", strZ(optShift),
strZ(bldEnum("cfgOpt", opt->name)));
if (opt->negate)
{
strCatFmt(
config,
" {\n"
" .name = \"no-%s\",\n"
" .val = PARSE_OPTION_FLAG | PARSE_NEGATE_FLAG%s | %s,\n"
" },\n",
strZ(optName), strZ(optShift), strZ(bldEnum("cfgOpt", opt->name)));
}
if (opt->reset)
{
strCatFmt(
config,
" {\n"
" .name = \"reset-%s\",\n"
" .val = PARSE_OPTION_FLAG | PARSE_RESET_FLAG%s | %s,\n"
" },\n",
strZ(optName), strZ(optShift), strZ(bldEnum("cfgOpt", opt->name)));
}
if (opt->deprecateList != 0)
{
for (unsigned int deprecateIdx = 0; deprecateIdx < lstSize(opt->deprecateList); deprecateIdx++)
{
const BldCfgOptionDeprecate *const deprecate = lstGet(opt->deprecateList, deprecateIdx);
const String *deprecateName = deprecate->name;
// Skip the deprecation if it does not apply to this index
if (deprecate->index > 0 && deprecate->index != index + 1)
continue;
// Generate name if deprecation applies to all indexes
int deprecateIndexPos = strChr(deprecateName, '?');
if (deprecateIndexPos != -1)
{
CHECK(optGrp != NULL);
deprecateName = strNewFmt(
"%s%u%s", strZ(strSubN(deprecateName, 0, (size_t)deprecateIndexPos)), index + 1,
strZ(strSub(deprecateName, (size_t)deprecateIndexPos + 1)));
}
strCatFmt(
config,
" {\n"
" .name = \"%s\",\n"
"%s"
" .val = PARSE_OPTION_FLAG | PARSE_DEPRECATE_FLAG%s | %s,\n"
" },\n",
strZ(deprecateName),
strEq(opt->type, OPT_TYPE_BOOLEAN_STR) ? "" : " .has_arg = required_argument,\n", strZ(optShift),
strZ(bldEnum("cfgOpt", opt->name)));
if (opt->negate)
{
strCatFmt(
config,
" {\n"
" .name = \"no-%s\",\n"
" .val = PARSE_OPTION_FLAG | PARSE_DEPRECATE_FLAG | PARSE_NEGATE_FLAG%s | %s,\n"
" },\n",
strZ(deprecateName), strZ(optShift), strZ(bldEnum("cfgOpt", opt->name)));
}
if (opt->reset && deprecate->reset)
{
strCatFmt(
config,
" {\n"
" .name = \"reset-%s\",\n"
" .val = PARSE_OPTION_FLAG | PARSE_DEPRECATE_FLAG | PARSE_RESET_FLAG%s | %s,\n"
" },\n",
strZ(deprecateName), strZ(optShift), strZ(bldEnum("cfgOpt", opt->name)));
}
}
}
}
}
strCatZ(
config,
" // Terminate option list\n"
" {\n"
" .name = NULL\n"
" }\n"
"};\n");
// Order for option parse resolution
// -----------------------------------------------------------------------------------------------------------------------------
strCatFmt(
config,
"\n"
COMMENT_BLOCK_BEGIN "\n"
"Order for option parse resolution\n"
COMMENT_BLOCK_END "\n"
"static const ConfigOption optionResolveOrder[] =\n"
"{\n");
// Render resolve order
for (unsigned int optResolveIdx = 0; optResolveIdx < lstSize(bldCfg.optResolveList); optResolveIdx++)
{
strCatFmt(
config, " %s,\n", strZ(bldEnum("cfgOpt", (*(BldCfgOption **)lstGet(bldCfg.optResolveList, optResolveIdx))->name)));
}
strCatZ(config, "};\n");
// Write to storage
// -----------------------------------------------------------------------------------------------------------------------------
bldPut(storageRepo, "src/config/parse.auto.c", BUFSTR(config));
}
/**********************************************************************************************************************************/
void
bldCfgRender(const Storage *const storageRepo, const BldCfg bldCfg)
{
bldCfgRenderConfigAutoH(storageRepo, bldCfg);
bldCfgRenderConfigAutoC(storageRepo, bldCfg);
bldCfgRenderParseAutoC(storageRepo, bldCfg);
}

View File

@ -1,7 +1,7 @@
/***********************************************************************************************************************************
Config Parse Rules
Automatically generated by Build.pm -- do not modify directly.
Automatically generated by 'make build-config' -- do not modify directly.
***********************************************************************************************************************************/
/***********************************************************************************************************************************

View File

@ -11,18 +11,10 @@ build/lib/pgBackRestBuild/Build/Common.pm:
class: build
type: perl
build/lib/pgBackRestBuild/Config/Build.pm:
class: build
type: perl
build/lib/pgBackRestBuild/Config/BuildHelp.pm:
class: build
type: perl
build/lib/pgBackRestBuild/Config/BuildParse.pm:
class: build
type: perl
build/lib/pgBackRestBuild/Config/Data.pm:
class: build
type: perl

File diff suppressed because it is too large Load Diff

View File

@ -37,7 +37,6 @@ use pgBackRestDoc::ProjectInfo;
use pgBackRestBuild::Build;
use pgBackRestBuild::Build::Common;
use pgBackRestBuild::Config::BuildHelp;
use pgBackRestBuild::Config::BuildParse;
use pgBackRestBuild::Error::Build;
use pgBackRestBuild::Error::Data;
@ -532,12 +531,6 @@ eval
&BLD_PATH => 'command/help',
},
'configParse' =>
{
&BLD_DATA => buildConfigParse(),
&BLD_PATH => 'config',
},
'error' =>
{
&BLD_DATA => buildError(),