Edit

kc3-lang/libxkbcommon/src/utils-numbers.h

Branch :

  • Show log

    Commit

  • Author : Pierre Le Marre
    Date : 2025-04-06 19:38:53
    Hash : 102f4ba1
    Message : Fix integer conversion warnings

  • src/utils-numbers.h
  • /*
     * Copyright © 2025 Pierre Le Marre <dev@wismill.eu>
     * SPDX-License-Identifier: MIT
     */
    #pragma once
    
    #include "config.h"
    
    #include <stdbool.h>
    #include <stdint.h>
    
    #include "utils.h"
    
    /*
     * Define various parsers to avoid the use of strto* -- it’s slower and accepts
     * a bunch of stuff we don’t want to allow, like signs, spaces, even locale stuff.
     *
     * But the real feature is that it does not require a NULL-terminated string, so
     * it works safely *also* on any buffer, assuming the correct corresponding size
     * is provided. For NULL-terminated strings, just pass `SIZE_MAX` as the length:
     * the parsers will *always* stop on a NULL character.
     */
    
    #define MAKE_PARSE_DEC_TO(type, max)                         \
    static inline int                                            \
    parse_dec_to_##type(const char *s, size_t len, type (*out))  \
    {                                                            \
        type result = 0;                                         \
        size_t i;                                                \
        for (i = 0;                                              \
             i < len && (unsigned char)(s[i] - '0') < 10U &&     \
             result <= (max) / 10 &&                             \
             result * 10 <= (max) - (unsigned char) (s[i] - '0');\
             i++) {                                              \
            result = result * 10 + (s[i] - '0');                 \
        }                                                        \
        *out = result;                                           \
        /* Check if there is more to parse */                    \
        /* We can safely convert the length to int on success */ \
        return (i >= len || (unsigned char)(s[i] - '0') >= 10U)  \
               ? (int) i                                         \
               : -1;                                             \
    }
    
    /**
     * Parse a `uint32_t` in decimal format.
     *
     * @returns -1 on error (overflow) or the count of characters parsed.
     */
    MAKE_PARSE_DEC_TO(uint32_t, UINT32_MAX)
    
    /**
     * Parse a `uint64_t` in decimal format.
     *
     * @returns -1 on error (overflow) or the count of characters parsed.
     */
    MAKE_PARSE_DEC_TO(uint64_t, UINT64_MAX)
    
    #undef MAKE_PARSE_DEC_TO
    
    static const unsigned char digits__[] = {
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0,    1,    2,    3,    4,    5,    6,    7,    8,    9,    0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 10,   11,   12,   13,   14,   15,   0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 10,   11,   12,   13,   14,   15,   0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff
    };
    
    #define MAKE_PARSE_HEX_TO(type, max)                           \
    static inline int                                              \
    parse_hex_to_##type(const char *s, size_t len, type (*out))    \
    {                                                              \
        type result = 0;                                           \
        size_t i = 0;                                              \
        for (; i < len && digits__[(unsigned char) s[i]] < 16u &&  \
             result <= (max) >> 4;                                 \
             i++) {                                                \
            result = result * 16 + digits__[(unsigned char) s[i]]; \
        }                                                          \
        *out = result;                                             \
        /* Check if there is more to parse */                      \
        /* We can safely convert the length to int on success */   \
        return (i >= len || !is_xdigit(s[i])) ? (int) i : -1;      \
    }
    
    /**
     * Parse a `uint32_t` in hexdecimal format.
     *
     * @returns -1 on error (overflow) or the count of characters parsed.
     */
    MAKE_PARSE_HEX_TO(uint32_t, UINT32_MAX)
    
    /**
     * Parse a `uint64_t` in hexdecimal format.
     *
     * @returns -1 on error (overflow) or the count of characters parsed.
     */
    MAKE_PARSE_HEX_TO(uint64_t, UINT64_MAX)
    
    #undef MAKE_PARSE_HEX_TO