in src/utils/configuration.cpp [59:233]
bool configuration::load(const char *file_name, const char *arguments)
{
_file_name = std::string(file_name);
auto s = rocksdb::ReadFileToString(
dsn::utils::PegasusEnv(dsn::utils::FileDataType::kNonSensitive), _file_name, &_file_data);
if (!s.ok()) {
fmt::print(stderr, "ERROR: read file '{}' failed, err = {}\n", _file_name, s.ToString());
return false;
}
if (_file_data.empty()) {
fmt::print(stderr, "ERROR: file '{}' is empty\n", _file_name);
return false;
}
// replace data with arguments
if (arguments != nullptr) {
std::string str_arguments(arguments);
std::replace(str_arguments.begin(), str_arguments.end(), ',', ';');
std::list<std::string> argkvs;
utils::split_args(str_arguments.c_str(), argkvs, ';');
for (auto &kv : argkvs) {
std::list<std::string> vs;
utils::split_args(kv.c_str(), vs, '=');
if (vs.size() != 2) {
printf(
"ERROR: invalid configuration argument: '%s' in '%s'\n", kv.c_str(), arguments);
return false;
}
std::string key = std::string("%") + *vs.begin() + std::string("%");
std::string value = *vs.rbegin();
_file_data = utils::replace_string(_file_data, key, value);
}
}
//
// parse mapped file and build conf map
//
std::map<std::string, conf *> *pSection = nullptr;
char *p, *pLine = (char *)"", *pNextLine, *pEnd, *pSectionName = nullptr, *pEqual;
int lineno = 0;
// ATTENTION: arguments replace_string() may cause _file_data changed,
// so set `p' and `pEnd' carefully.
p = (char *)_file_data.c_str();
pEnd = p + _file_data.size();
while (p < pEnd) {
//
// get line
//
lineno++;
while (*p == ' ' || *p == '\t' || *p == '\r')
p++;
pLine = p;
int shift = 0;
while (*p != '\n' && p < pEnd) {
if (*p == '#' || *p == ';') {
if (p != pLine && *(p - 1) == '^') {
shift++;
} else {
*p = '\0';
}
}
if (shift > 0) {
*(p - shift) = *p;
}
p++;
}
*(p - shift) = '\0';
pNextLine = ++p;
//
// parse line
//
p = pLine;
if (*p == '\0')
goto Next; // skip comment line or empty line
pEqual = strchr(p, '=');
if (nullptr == pEqual && *p != '[') {
goto ConfReg;
}
if (nullptr != pEqual && *p == '[')
goto err;
//
// conf
//
if (pEqual) {
ConfReg:
if (pSection == nullptr) {
printf("ERROR: configuration section not defined\n");
goto err;
}
if (pEqual)
*pEqual = '\0';
char *pKey = utils::trim_string(p);
char *pValue = pEqual ? utils::trim_string(++pEqual) : nullptr;
if (*pKey == '\0')
goto err;
if (pSection->find((const char *)pKey) != pSection->end()) {
auto it = pSection->find((const char *)pKey);
printf("WARNING: skip redefinition of option [%s] %s (line %u), already defined as "
"[%s] %s (line %u)\n",
pSectionName,
pKey,
lineno,
it->second->section.c_str(),
it->second->key.c_str(),
it->second->line);
} else {
conf *cf = new conf;
cf->section = (const char *)pSectionName;
cf->key = pKey;
cf->line = lineno;
cf->present = true;
if (pValue) {
// if argument is not provided
if (strlen(pValue) > 2 && *pValue == '%' && pValue[strlen(pValue) - 1] == '%')
cf->value = "";
else
cf->value = pValue;
} else {
cf->value = "";
}
pSection->insert(std::make_pair(std::string(pKey), cf));
}
}
//
// section
//
else {
char *pRight = strchr(p, ']');
if (nullptr == pRight)
goto err;
*pRight = '\0';
p++;
pSectionName = utils::trim_string(p);
if (*pSectionName == '\0')
goto err;
bool old = set_warning(false);
if (has_section((const char *)pSectionName)) {
printf("ERROR: configuration section '[%s]' is redefined\n", pSectionName);
set_warning(old);
goto err;
}
set_warning(old);
std::map<std::string, conf *> sm;
auto it = _configs.insert(config_map::value_type(std::string(pSectionName), sm));
assert(it.second);
pSection = &it.first->second;
}
//
// iterate nextline
//
Next:
p = pNextLine;
}
return true;
err:
printf("ERROR: unexpected configuration in %s(line %d): %s\n", file_name, lineno, pLine);
return false;
}