/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "KernelConfigParser.h"

#include <regex>

#define KEY "(CONFIG[\\w_]+)"
#define COMMENT "(?:#.*)"

namespace android {
namespace vintf {

KernelConfigParser::KernelConfigParser(bool processComments, bool relaxedFormat)
    : mProcessComments(processComments), mRelaxedFormat(relaxedFormat) {}

status_t KernelConfigParser::finish() {
    return process("\n", 1 /* sizeof "\n" */);
}

std::stringbuf* KernelConfigParser::error() const {
    return mError.rdbuf();
}

std::map<std::string, std::string>& KernelConfigParser::configs() {
    return mConfigs;
}

const std::map<std::string, std::string>& KernelConfigParser::configs() const {
    return mConfigs;
}

// trim spaces between value and #, value and end of line
std::string trimTrailingSpaces(const std::string& s) {
    auto r = s.rbegin();
    for (; r != s.rend() && std::isspace(*r); ++r)
        ;
    return std::string{s.begin(), r.base()};
}

status_t KernelConfigParser::processRemaining() {
    if (mRemaining.empty()) {
        return OK;
    }

    static const std::regex sKeyValuePattern("^\\s*" KEY "\\s*=\\s*([^#]+)" COMMENT "?$");
    static const std::regex sNotSetPattern("^\\s*#\\s*" KEY " is not set\\s*$");
    static const std::regex sCommentPattern("^\\s*" COMMENT "$");

    std::smatch match;

    if (mRelaxedFormat) {
        // Allow free format like "   CONFIG_FOO  = bar    #trailing comments"
        if (std::regex_match(mRemaining, match, sKeyValuePattern)) {
            if (mConfigs.emplace(match[1], trimTrailingSpaces(match[2])).second) {
                return OK;
            }
            mError << "Duplicated key in configs: " << match[1] << "\n";
            return UNKNOWN_ERROR;
        }
    } else {
        // No spaces. Strictly like "CONFIG_FOO=bar"
        size_t equalPos = mRemaining.find('=');
        if (equalPos != std::string::npos) {
            std::string key = mRemaining.substr(0, equalPos);
            std::string value = mRemaining.substr(equalPos + 1);
            if (mConfigs.emplace(std::move(key), std::move(value)).second) {
                return OK;
            }
            mError << "Duplicated key in configs: " << mRemaining.substr(0, equalPos) << "\n";
            return UNKNOWN_ERROR;
        }
    }

    if (mProcessComments && std::regex_match(mRemaining, match, sNotSetPattern)) {
        if (mConfigs.emplace(match[1], "n").second) {
            return OK;
        }
        mError << "Key " << match[1] << " is set but commented as not set"
               << "\n";
        return UNKNOWN_ERROR;
    }

    if (mRelaxedFormat) {
        // Allow free format like "   #comments here"
        if (std::regex_match(mRemaining, match, sCommentPattern)) {
            return OK;
        }
    } else {
        // No leading spaces before the comment
        if (mRemaining.at(0) == '#') {
            return OK;
        }
    }

    mError << "Unrecognized line in configs: " << mRemaining << "\n";
    return UNKNOWN_ERROR;
}

status_t KernelConfigParser::process(const char* buf, size_t len) {
    const char* begin = buf;
    const char* end = buf;
    const char* stop = buf + len;
    status_t err = OK;
    while (end < stop) {
        if (*end == '\n') {
            mRemaining.insert(mRemaining.size(), begin, end - begin);
            status_t newErr = processRemaining();
            if (newErr != OK && err == OK) {
                err = newErr;
                // but continue to get more
            }
            mRemaining.clear();
            begin = end + 1;
        }
        end++;
    }
    mRemaining.insert(mRemaining.size(), begin, end - begin);
    return err;
}

status_t KernelConfigParser::processAndFinish(const char* buf, size_t len) {
    status_t err = process(buf, len);
    if (err != OK) {
        return err;
    }
    return finish();
}

status_t KernelConfigParser::processAndFinish(const std::string& content) {
    return processAndFinish(content.c_str(), content.size());
}

}  // namespace vintf
}  // namespace android
