bool configuration::load()

in src/utils/configuration.cpp [66:256]


bool configuration::load(const char *file_name, const char *arguments)
{
    _file_name = std::string(file_name);

    FILE *fd = ::fopen(file_name, "rb");
    if (fd == nullptr) {
        std::string cdir;
        dsn::utils::filesystem::get_current_directory(cdir);
        printf("ERROR: cannot open file %s in %s, err = %s\n",
               file_name,
               cdir.c_str(),
               strerror(errno));
        return false;
    }
    ::fseek(fd, 0, SEEK_END);
    int len = ftell(fd);
    if (len == -1 || len == 0) {
        printf("ERROR: cannot get length of %s, err = %s\n", file_name, strerror(errno));
        ::fclose(fd);
        return false;
    }

    _file_data.resize(len + 1);
    ::fseek(fd, 0, SEEK_SET);
    auto sz = ::fread((char *)_file_data.c_str(), len, 1, fd);
    ::fclose(fd);
    if (sz != 1) {
        printf("ERROR: cannot read correct data of %s, err = %s\n", file_name, strerror(errno));
        return false;
    }
    _file_data[len] = '\n';

    // 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;
}