跳转至

base/utils/linux/proc_parser.cpp

Modern C++17 utilities for parsing Linux /proc and /sys files. More...

Namespaces

Name
cf

Detailed Description

Modern C++17 utilities for parsing Linux /proc and /sys files.

Author: Charliechen114514 (chengh1922@mails.jlu.edu.cn)

Version: 0.1

Date: 2026-02-22

Copyright: Copyright © 2026

Source code

#include "base/linux/proc_parser.h"

#include <cstdio>

namespace cf {

namespace {

// Compile-time ARM implementer to vendor mapping table
struct ArmImplementer {
    uint32_t code;
    const char* name;
};

constexpr ArmImplementer arm_implementers[] = {
    {0x41, "ARM"}, {0x42, "Broadcom"}, {0x43, "Cavium"},  {0x44, "DEC"},     {0x4E, "NVIDIA"},
    {0x50, "APM"}, {0x51, "Qualcomm"}, {0x53, "Samsung"}, {0x56, "Marvell"}, {0x69, "Intel"}};

constexpr size_t num_implementers = sizeof(arm_implementers) / sizeof(arm_implementers[0]);

} // anonymous namespace

std::string_view trim_whitespace(std::string_view sv) noexcept {
    return ltrim_whitespace(rtrim_whitespace(sv));
}

std::string_view ltrim_whitespace(std::string_view sv) noexcept {
    const size_t start = sv.find_first_not_of(" \t\r\n");
    if (start == std::string_view::npos) {
        return {};
    }
    return sv.substr(start);
}

std::string_view rtrim_whitespace(std::string_view sv) noexcept {
    const size_t end = sv.find_last_not_of(" \t\r\n");
    if (end == std::string_view::npos) {
        return {};
    }
    return sv.substr(0, end + 1);
}

std::string_view parse_cpuinfo_field(std::string_view line, std::string_view field) noexcept {
    // Find colon separator
    const size_t colon_pos = line.find(':');
    if (colon_pos == std::string_view::npos) {
        return {};
    }

    // Get key and value as views (no copies!)
    const std::string_view key = line.substr(0, colon_pos);
    const std::string_view value = line.substr(colon_pos + 1);

    // Trim key
    const std::string_view trimmed_key = ltrim_whitespace(key);

    // Check if key matches requested field
    if (trimmed_key != field) {
        return {};
    }

    // Trim and return value
    return ltrim_whitespace(value);
}

std::optional<uint32_t> parse_cache_size(std::string_view size_str) noexcept {
    if (size_str.empty()) {
        return std::nullopt;
    }

    // Parse number manually to avoid std::stoul exceptions
    uint32_t size = 0;
    size_t pos = 0;

    for (; pos < size_str.size(); ++pos) {
        const char c = size_str[pos];
        if (c >= '0' && c <= '9') {
            // Check for overflow
            if (size > (UINT32_MAX - 9) / 10) {
                return std::nullopt;
            }
            size = size * 10 + static_cast<uint32_t>(c - '0');
        } else {
            break; // Reached unit specifier
        }
    }

    if (pos == 0) {
        return std::nullopt; // No digits found
    }

    // Parse unit
    if (pos < size_str.size()) {
        const char unit = size_str[pos];
        if (unit == 'K' || unit == 'k') {
            // Already in KB
        } else if (unit == 'M' || unit == 'm') {
            if (size > UINT32_MAX / 1024) {
                return std::nullopt; // Overflow
            }
            size *= 1024;
        } else if (unit == 'G' || unit == 'g') {
            if (size > UINT32_MAX / (1024 * 1024)) {
                return std::nullopt; // Overflow
            }
            size *= 1024 * 1024;
        }
    }

    return size;
}

std::optional<uint32_t> parse_uint32(std::string_view str) noexcept {
    if (str.empty()) {
        return std::nullopt;
    }

    uint32_t value = 0;
    for (char c : str) {
        if (c >= '0' && c <= '9') {
            // Check for overflow
            if (value > (UINT32_MAX - 9) / 10) {
                return std::nullopt;
            }
            value = value * 10 + static_cast<uint32_t>(c - '0');
        } else {
            return std::nullopt; // Invalid character
        }
    }

    return value;
}

std::optional<uint32_t> parse_hex_uint32(std::string_view str) noexcept {
    if (str.empty()) {
        return std::nullopt;
    }

    // Skip "0x" or "0X" prefix if present
    if (str.size() >= 2 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
        str = str.substr(2);
    }

    if (str.empty()) {
        return std::nullopt;
    }

    uint32_t value = 0;
    for (char c : str) {
        value <<= 4;
        if (c >= '0' && c <= '9') {
            value |= static_cast<uint32_t>(c - '0');
        } else if (c >= 'a' && c <= 'f') {
            value |= static_cast<uint32_t>(c - 'a' + 10);
        } else if (c >= 'A' && c <= 'F') {
            value |= static_cast<uint32_t>(c - 'A' + 10);
        } else {
            return std::nullopt; // Invalid hex digit
        }
    }

    return value;
}

std::optional<uint32_t> read_uint32_file(const char* path) noexcept {
    FILE* file = fopen(path, "r");
    if (!file) {
        return std::nullopt;
    }

    uint32_t value = 0;
    if (fscanf(file, "%u", &value) != 1) {
        fclose(file);
        return std::nullopt;
    }

    fclose(file);
    return value;
}

std::string_view arm_implementer_to_vendor(uint32_t impl_val) noexcept {
    for (size_t i = 0; i < num_implementers; ++i) {
        if (arm_implementers[i].code == impl_val) {
            return arm_implementers[i].name;
        }
    }
    return "Unknown";
}

} // namespace cf

Updated on 2026-03-09 at 10:14:01 +0000