Skip to content
Permalink
Browse files

Refactor Ini interface to expose String values instead of Variant.

Variants were being used to expose String and StringList types but this can be done more simply with an additional method.

Using only strings also allows for a more efficient implementation down the road.
  • Loading branch information...
dwsteele committed Apr 22, 2019
1 parent cc39bdd commit fdf19e5ab68c64f6c063c265bd3ddc5b39b56620
Showing with 141 additions and 70 deletions.
  1. +4 −0 doc/xml/release.xml
  2. +1 −1 src/Makefile
  3. +61 −23 src/common/ini.c
  4. +26 −6 src/common/ini.h
  5. +26 −22 src/config/parse.c
  6. +5 −5 src/info/info.c
  7. +1 −1 src/info/infoBackup.c
  8. +2 −2 src/info/infoPg.c
  9. +15 −10 test/src/module/common/iniTest.c
@@ -33,6 +33,10 @@
<p>Add <code>unsigned int</code> <code>Variant</code> type and update code to use it.</p>
</release-item>

<release-item>
<p>Refactor <code>Ini</code> interface to expose <code>String</code> values instead of <code>Variant</code>.</p>
</release-item>

<release-item>
<p>Refactor <code>main()</code> as a <code>switch()</code> statement.</p>
</release-item>
@@ -284,7 +284,7 @@ common/exit.o: common/exit.c command/command.h common/assert.h common/debug.h co
common/fork.o: common/fork.c common/assert.h common/debug.h common/error.auto.h common/error.h common/log.h common/logLevel.h common/stackTrace.h common/type/convert.h
$(CC) $(CFLAGS) -c common/fork.c -o common/fork.o

common/ini.o: common/ini.c common/assert.h common/debug.h common/error.auto.h common/error.h common/ini.h common/logLevel.h common/memContext.h common/stackTrace.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/variant.h common/type/variantList.h
common/ini.o: common/ini.c common/assert.h common/debug.h common/error.auto.h common/error.h common/ini.h common/io/filter/filter.h common/io/filter/group.h common/io/write.h common/logLevel.h common/memContext.h common/stackTrace.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/variant.h common/type/variantList.h
$(CC) $(CFLAGS) -c common/ini.c -o common/ini.o

common/io/bufferRead.o: common/io/bufferRead.c common/assert.h common/debug.h common/error.auto.h common/error.h common/io/bufferRead.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/read.intern.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/variant.h common/type/variantList.h
@@ -46,12 +46,13 @@ iniNew(void)
Internal function to get an ini value
***********************************************************************************************************************************/
static const Variant *
iniGetInternal(const Ini *this, const String *section, const String *key)
iniGetInternal(const Ini *this, const String *section, const String *key, bool required)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(INI, this);
FUNCTION_TEST_PARAM(STRING, section);
FUNCTION_TEST_PARAM(STRING, key);
FUNCTION_TEST_PARAM(BOOL, required);
FUNCTION_TEST_END();

ASSERT(this != NULL);
@@ -67,13 +68,17 @@ iniGetInternal(const Ini *this, const String *section, const String *key)
if (sectionKv != NULL)
result = kvGet(sectionKv, VARSTR(key));

// If value is null and required then error
if (result == NULL && required)
THROW_FMT(FormatError, "section '%s', key '%s' does not exist", strPtr(section), strPtr(key));

FUNCTION_TEST_RETURN(result);
}

/***********************************************************************************************************************************
Get an ini value -- error if it does not exist
***********************************************************************************************************************************/
const Variant *
const String *
iniGet(const Ini *this, const String *section, const String *key)
{
FUNCTION_TEST_BEGIN();
@@ -87,40 +92,76 @@ iniGet(const Ini *this, const String *section, const String *key)
ASSERT(key != NULL);

// Get the value
const Variant *result = iniGetInternal(this, section, key);

// If value is null replace it with default
if (result == NULL)
THROW_FMT(FormatError, "section '%s', key '%s' does not exist", strPtr(section), strPtr(key));
const Variant *result = iniGetInternal(this, section, key, true);

FUNCTION_TEST_RETURN(result);
FUNCTION_TEST_RETURN(varStr(result));
}

/***********************************************************************************************************************************
Get an ini value -- if it does not exist then return specified default
***********************************************************************************************************************************/
const Variant *
iniGetDefault(const Ini *this, const String *section, const String *key, const Variant *defaultValue)
const String *
iniGetDefault(const Ini *this, const String *section, const String *key, const String *defaultValue)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(INI, this);
FUNCTION_TEST_PARAM(STRING, section);
FUNCTION_TEST_PARAM(STRING, key);
FUNCTION_TEST_PARAM(VARIANT, defaultValue);
FUNCTION_TEST_PARAM(STRING, defaultValue);
FUNCTION_TEST_END();

ASSERT(this != NULL);
ASSERT(section != NULL);
ASSERT(key != NULL);

// Get the value
const Variant *result = iniGetInternal(this, section, key);
const Variant *result = iniGetInternal(this, section, key, false);

// If value is null replace it with default
if (result == NULL)
result = defaultValue;
FUNCTION_TEST_RETURN(result == NULL ? defaultValue : varStr(result));
}

FUNCTION_TEST_RETURN(result);
/***********************************************************************************************************************************
Internal function to get an ini value list
***********************************************************************************************************************************/
StringList *
iniGetList(const Ini *this, const String *section, const String *key)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(INI, this);
FUNCTION_TEST_PARAM(STRING, section);
FUNCTION_TEST_PARAM(STRING, key);
FUNCTION_TEST_END();

ASSERT(this != NULL);
ASSERT(section != NULL);
ASSERT(key != NULL);

// Get the value
const Variant *result = iniGetInternal(this, section, key, false);

FUNCTION_TEST_RETURN(result == NULL ? false : strLstNewVarLst(varVarLst(result)));
}

/***********************************************************************************************************************************
Internal function to get an ini value list
***********************************************************************************************************************************/
bool
iniSectionKeyIsList(const Ini *this, const String *section, const String *key)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(INI, this);
FUNCTION_TEST_PARAM(STRING, section);
FUNCTION_TEST_PARAM(STRING, key);
FUNCTION_TEST_END();

ASSERT(this != NULL);
ASSERT(section != NULL);
ASSERT(key != NULL);

// Get the value
const Variant *result = iniGetInternal(this, section, key, true);

FUNCTION_TEST_RETURN(varType(result) == varTypeVariantList);
}

/***********************************************************************************************************************************
@@ -249,11 +290,8 @@ iniParse(Ini *this, const String *content)
if (strSize(key) == 0)
THROW_FMT(FormatError, "key is zero-length at line %u: %s", lineIdx++, linePtr);

// Extract the value
const Variant *value = VARSTR(strTrim(strNew(lineEqual + 1)));

// Store the section/key/value
iniSet(this, section, key, value);
iniSet(this, section, key, strTrim(strNew(lineEqual + 1)));
}
}
}
@@ -270,13 +308,13 @@ iniParse(Ini *this, const String *content)
Set an ini value
***********************************************************************************************************************************/
void
iniSet(Ini *this, const String *section, const String *key, const Variant *value)
iniSet(Ini *this, const String *section, const String *key, const String *value)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(INI, this);
FUNCTION_TEST_PARAM(STRING, section);
FUNCTION_TEST_PARAM(STRING, key);
FUNCTION_TEST_PARAM(VARIANT, value);
FUNCTION_TEST_PARAM(STRING, value);
FUNCTION_TEST_END();

ASSERT(this != NULL);
@@ -292,7 +330,7 @@ iniSet(Ini *this, const String *section, const String *key, const Variant *value
if (sectionKv == NULL)
sectionKv = kvPutKv(this->store, sectionKey);

kvAdd(sectionKv, VARSTR(key), value);
kvAdd(sectionKv, VARSTR(key), VARSTR(value));
}
MEM_CONTEXT_TEMP_END();

@@ -9,22 +9,42 @@ Ini object
***********************************************************************************************************************************/
typedef struct Ini Ini;

#include "common/io/write.h"
#include "common/type/variant.h"

/***********************************************************************************************************************************
Functions
Constructor
***********************************************************************************************************************************/
Ini *iniNew(void);
const Variant *iniGet(const Ini *this, const String *section, const String *key);
const Variant *iniGetDefault(const Ini *this, const String *section, const String *key, const Variant *defaultValue);

/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
void iniParse(Ini *this, const String *content);
void iniSet(Ini *this, const String *section, const String *key, const String *value);

/***********************************************************************************************************************************
Getters
***********************************************************************************************************************************/
const String *iniGet(const Ini *this, const String *section, const String *key);
const String *iniGetDefault(const Ini *this, const String *section, const String *key, const String *defaultValue);
StringList *iniGetList(const Ini *this, const String *section, const String *key);
bool iniSectionKeyIsList(const Ini *this, const String *section, const String *key);
StringList *iniSectionKeyList(const Ini *this, const String *section);
StringList *iniSectionList(const Ini *this);
void iniParse(Ini *this, const String *content);
void iniSet(Ini *this, const String *section, const String *key, const Variant *value);
void iniFree(Ini *this);
String *iniFileName(const Ini *this);
bool iniFileExists(const Ini *this);

/***********************************************************************************************************************************
Constructor
***********************************************************************************************************************************/
void iniFree(Ini *this);

/***********************************************************************************************************************************
Destructor
***********************************************************************************************************************************/
void iniFree(Ini *this);

/***********************************************************************************************************************************
Macros for function logging
***********************************************************************************************************************************/
@@ -759,39 +759,43 @@ configParse(unsigned int argListSize, const char *argList[], bool resetLogLevel)
if (parseOptionList[optionId].found)
continue;

// Get the option value
const Variant *value = iniGetDefault(config, section, key, NULL);

if (varType(value) == varTypeString && strSize(varStr(value)) == 0)
{
THROW_FMT(
OptionInvalidValueError, "section '%s', key '%s' must have a value", strPtr(section), strPtr(key));
}

parseOptionList[optionId].found = true;
parseOptionList[optionId].source = cfgSourceConfig;

if (varType(value) == varTypeVariantList)
// Process list
if (iniSectionKeyIsList(config, section, key))
{
// Error if the option cannot be specified multiple times
if (!cfgDefOptionMulti(optionDefId))
THROW_FMT(OptionInvalidError, "option '%s' cannot be set multiple times", cfgOptionName(optionId));

parseOptionList[optionId].valueList = strLstNewVarLst(varVarLst(value));
parseOptionList[optionId].valueList = iniGetList(config, section, key);
}
// Convert boolean
else if (cfgDefOptionType(optionDefId) == cfgDefOptTypeBoolean)
{
if (strcasecmp(strPtr(varStr(value)), "n") == 0)
parseOptionList[optionId].negate = true;
else if (strcasecmp(strPtr(varStr(value)), "y") != 0)
THROW_FMT(OptionInvalidValueError, "boolean option '%s' must be 'y' or 'n'", strPtr(key));
}
// Else add the string value
else
{
parseOptionList[optionId].valueList = strLstNew();
strLstAdd(parseOptionList[optionId].valueList, varStr(value));
// Get the option value
const String *value = iniGet(config, section, key);

if (strSize(value) == 0)
{
THROW_FMT(
OptionInvalidValueError, "section '%s', key '%s' must have a value", strPtr(section),
strPtr(key));
}

if (cfgDefOptionType(optionDefId) == cfgDefOptTypeBoolean)
{
if (strEqZ(value, "n"))
parseOptionList[optionId].negate = true;
else if (!strEqZ(value, "y"))
THROW_FMT(OptionInvalidValueError, "boolean option '%s' must be 'y' or 'n'", strPtr(key));
}
// Else add the string value
else
{
parseOptionList[optionId].valueList = strLstNew();
strLstAdd(parseOptionList[optionId].valueList, value);
}
}
}
}
@@ -89,7 +89,7 @@ infoHash(const Ini *ini)
cryptoHashProcessC(result, (const unsigned char *)"\"", 1);
cryptoHashProcessStr(result, key);
cryptoHashProcessC(result, (const unsigned char *)"\":", 2);
cryptoHashProcessStr(result, varStr(iniGet(ini, section, strLstGet(keyList, keyIdx))));
cryptoHashProcessStr(result, iniGet(ini, section, strLstGet(keyList, keyIdx)));
if ((keyListSize > 1) && (keyIdx < keyListSize - 1))
cryptoHashProcessC(result, (const unsigned char *)",", 1);
}
@@ -159,7 +159,7 @@ infoLoad(Info *this, const Storage *storage, bool copyFile, CipherType cipherTyp
iniParse(this->ini, strNewBuf(buffer));

// Make sure the ini is valid by testing the checksum
const String *infoChecksum = varStr(iniGet(this->ini, INFO_SECTION_BACKREST_STR, INFO_KEY_CHECKSUM_STR));
const String *infoChecksum = iniGet(this->ini, INFO_SECTION_BACKREST_STR, INFO_KEY_CHECKSUM_STR);

CryptoHash *hash = infoHash(this->ini);

@@ -178,11 +178,11 @@ infoLoad(Info *this, const Storage *storage, bool copyFile, CipherType cipherTyp
}

// Make sure that the format is current, otherwise error
if (varIntForce(iniGet(this->ini, INFO_SECTION_BACKREST_STR, INFO_KEY_FORMAT_STR)) != REPOSITORY_FORMAT)
if (varIntForce(VARSTR(iniGet(this->ini, INFO_SECTION_BACKREST_STR, INFO_KEY_FORMAT_STR))) != REPOSITORY_FORMAT)
{
THROW_FMT(
FormatError, "invalid format in '%s', expected %d but found %d", strPtr(fileName), REPOSITORY_FORMAT,
varIntForce(iniGet(this->ini, INFO_SECTION_BACKREST_STR, INFO_KEY_FORMAT_STR)));
varIntForce(VARSTR(iniGet(this->ini, INFO_SECTION_BACKREST_STR, INFO_KEY_FORMAT_STR))));
}
}
MEM_CONTEXT_TEMP_END();
@@ -255,7 +255,7 @@ infoNew(const Storage *storage, const String *fileName, CipherType cipherType, c
TRY_END();

// Load the cipher passphrase if it exists
const String *cipherPass = varStr(iniGetDefault(this->ini, INFO_SECTION_CIPHER_STR, INFO_KEY_CIPHER_PASS_STR, NULL));
const String *cipherPass = iniGetDefault(this->ini, INFO_SECTION_CIPHER_STR, INFO_KEY_CIPHER_PASS_STR, NULL);

if (cipherPass != NULL)
this->cipherPass = strSubN(cipherPass, 1, strSize(cipherPass) - 2);
@@ -100,7 +100,7 @@ infoBackupNew(const Storage *storage, const String *fileName, bool ignoreMissing
for (unsigned int backupLabelIdx = 0; backupLabelIdx < strLstSize(backupLabelList); backupLabelIdx++)
{
const String *backupLabelKey = strLstGet(backupLabelList, backupLabelIdx);
const KeyValue *backupKv = varKv(jsonToVar(varStr(iniGet(infoIni, backupCurrentSection, backupLabelKey))));
const KeyValue *backupKv = varKv(jsonToVar(iniGet(infoIni, backupCurrentSection, backupLabelKey)));

InfoBackupData infoBackupData =
{
@@ -83,7 +83,7 @@ infoPgNew(const Storage *storage, const String *fileName, InfoPgType type, Ciphe
const StringList *pgHistoryKey = iniSectionKeyList(infoPgIni, INFO_SECTION_DB_HISTORY_STR);

// Get the current history id
unsigned int pgId = (unsigned int)varUInt64Force(iniGet(infoPgIni, INFO_SECTION_DB_STR, varStr(INFO_KEY_DB_ID_VAR)));
unsigned int pgId = varUIntForce(VARSTR(iniGet(infoPgIni, INFO_SECTION_DB_STR, varStr(INFO_KEY_DB_ID_VAR))));

// History must include at least one item or the file is corrupt
ASSERT(strLstSize(pgHistoryKey) > 0);
@@ -95,7 +95,7 @@ infoPgNew(const Storage *storage, const String *fileName, InfoPgType type, Ciphe
{
// Load JSON data into a KeyValue
const KeyValue *pgDataKv = varKv(
jsonToVar(varStr(iniGet(infoPgIni, INFO_SECTION_DB_HISTORY_STR, strLstGet(pgHistoryKey, pgHistoryIdx)))));
jsonToVar(iniGet(infoPgIni, INFO_SECTION_DB_HISTORY_STR, strLstGet(pgHistoryKey, pgHistoryIdx))));

// Get db values that are common to all info files
InfoPgData infoPgData =
Oops, something went wrong.

0 comments on commit fdf19e5

Please sign in to comment.
You can’t perform that action at this time.