/* =====================================
 * Generated by Mod-c 0.22.1
 * MODULE utils
 * ===================================== */

#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <limits.h>
#include <float.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <stdarg.h>
#include <errno.h>

#define nil NULL
typedef int8_t int8;
typedef int16_t	int16;
typedef int32_t int32;
typedef int64_t	int64;
typedef uint8_t	uint8;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
typedef char* pchar;
typedef char* string;
typedef intptr_t integer;
typedef uintptr_t cardinal;
typedef double_t real;

#include "utils.h"

/**
 * Mod-c
 * By M. Scott Reynolds
 * Date 20 February 2026
 *
 * utils.c - Portable helper functions and safe arithmetic utilities.
 */
#include "limits.h"
#include <string.h>
#include <ctype.h>
/**
 * Portable replacement for strnlen (not in C89/C95, but very useful).
 * Returns the length of the string or maxlen if no null terminator found.
 */
size_t utils_strnlen(const char* s, size_t maxlen)
{
    size_t results = 0;
    if (s != nil)
    {
        const char* z = memchr(s, '\0', maxlen);
        if (z != nil)
        {
            results = (size_t)(z - s);
        }
        else
        {
            results = maxlen;
        }
    }
    /* return value captured before defers */
    size_t __ret_l40 = results;
    return __ret_l40;
}

/**
 * Portable replacement for strndup.
 * Allocates and returns a new null-terminated copy of the first n chars of s.
 * Returns NULL on allocation failure (caller must check).
 */
pchar utils_strndup(const char* s, size_t n)
{
    pchar new_str = nil;
    if (s != nil)
    {
        const size_t len = utils_strnlen(s, n);
        new_str = malloc(len + 1);
        if (new_str != nil)
        {
            memcpy(new_str, s, len);
            new_str[len] = '\0';
        }
    }
    /* return value captured before defers */
    pchar __ret_l61 = new_str;
    return __ret_l61;
}

/**
 * Integer power using exponentiation by squaring (positive exponents only) 
 * Checks for overflow before each multiplication.
 * Exits program on detected overflow.
 *
 * @param base  Base value (may be negative)
 * @param exp   Non-negative exponent
 * @return      base^exp if representable in long long
 */
long_long utils_power(long_long base, uint exp)
{
    long_long result = 1;
    long_long b = base;
    while (exp > 0)
    {
        {
            if (exp & (uint)1)
            {
                if (b != 0 && result > LLONG_MAX / b)
                {
                    fprintf(stderr, "ERROR: utils_power: multiplication overflow\n");
                    exit(1);
                }
                result *= b;
            }
            if (exp > (uint)1)
            {
                if (b != 0 && b > LLONG_MAX / b)
                {
                    fprintf(stderr, "ERROR: utils_power: squaring overflow\n");
                    exit(1);
                }
                b *= b;
            }
            exp >>= 1;
        }
    }
    /* return value captured before defers */
    long_long __ret_l99 = result;
    return __ret_l99;
}

/**
 * @brief   Safely multiplies two signed long long integers.
 * @details Checks for overflow before performing the multiplication.
 *          Uses the standard method of testing against LLONG_MAX / LLONG_MIN
 *          to detect cases where the result would exceed the representable range.
 *
 * @param   a        First operand
 * @param   b        Second operand
 * @return  The product a * b if it can be represented in long long.
 *          Exits the program with an error message on overflow.
 *
 * @note    Assumes two's complement (guaranteed in C11 for signed integers).
 *          Corectly handles the edge case LLONG_MIN * -1.
 */
long_long utils_safe_multiply(long_long a, long_long b)
{
    if (a == 0 || b == 0)
    {
        /* return value captured before defers */
        long_long __ret_l121 = 0;
        return __ret_l121;
    }
    if (a == LLONG_MIN && b == -(long_long)1)
    {
        fprintf(stderr, "ERROR: utils_safe_multiply: overflow - LLONG_MIN * -1 is not representable\n");
        exit(1);
    }
    if (b > 0)
    {
        if (a > 0)
        {
            if (a > LLONG_MAX / b)
            {
                fprintf(stderr, "ERROR: utils_safe_multiply: overflow (positive * positive)\n");
                exit(1);
            }
        }
        else
        {
            if (a < LLONG_MIN / b)
            {
                fprintf(stderr, "ERROR: utils_safe_multiply: overflow (negative * positive)\n");
                exit(1);
            }
        }
    }
    else
    {
        if (a > 0)
        {
            if (a > LLONG_MIN / b)
            {
                fprintf(stderr, "ERROR: utils_safe_multiply: overflow (positive * negative)\n");
                exit(1);
            }
        }
        else
        {
            if (a < LLONG_MAX / b)
            {
                fprintf(stderr, "ERROR: utils_safe_multiply: overflow (negative * negative)\n");
                exit(1);
            }
        }
    }
    /* return value captured before defers */
    long_long __ret_l163 = a * b;
    return __ret_l163;
}

/**
 * Parse integer literal that may contain:
 *  - _ digit separators (ignored)
 *  - 0x / 0X   hexadecimal
 *  - 0o / 0O   octal
 *  - 0b / 0B   binary
 * Exits on overflow or invalid characters.
 */
long_long utils_parse_integer_literal(const char* s, size_t len)
{
    int base = 10;
    size_t i = 0;
    long_long result = 0;
    if (s == NULL || len == 0)
    {
        /* return value captured before defers */
        long_long __ret_l182 = 0;
        return __ret_l182;
    }
    while (len > 0 && isspace((uchar)*s))
    {
        {
            s++;
            len++;
        }
    }
    if (len >= 2 && s[0] == '0')
    {
        const char p = s[1];
        if (p == 'x' || p == 'X')
        {
            base = 16;
            i = 2;
        }
        else if (p == 'o' || p == 'O')
        {
            base = 8;
            i = 2;
        }
        else if (p == 'b' || p == 'B')
        {
            base = 2;
            i = 2;
        }
    }
    while (i < len)
    {
        {
            int digit = {0};
            const char c = s[i];
            if (c != '_')
            {
                if (isdigit((uchar)c))
                {
                    digit = c - '0';
                }
                else if (base == 16 && c >= 'a' && c <= 'f')
                {
                    digit = 10 + (c - 'a');
                }
                else if (base == 16 && c >= 'A' && c <= 'F')
                {
                    digit = 10 + (c - 'A');
                }
                else
                {
                    fprintf(stderr, "ERROR: utils_parse_integer_literal: invalid digit '%c' in bases %d\n", c, base);
                    exit(1);
                }
                if (digit >= base)
                {
                    fprintf(stderr, "ERROR: utils_parse_integer_literal: digit '%c' out of range for base %d\n", c, base);
                    exit(1);
                }
                if (result > (LLONG_MAX - digit) / base)
                {
                    fprintf(stderr, "ERROR: utils_parse_integer_literal: integer overflow\n");
                    exit(1);
                }
                result = result * base + digit;
            }
            i++;
        }
    }
    /* return value captured before defers */
    long_long __ret_l234 = result;
    return __ret_l234;
}


void utils(void)
{
}
