Blame snmplib/strtoull.c

Packit fcad23
/*
Packit fcad23
 * An implementation of strtoull() for compilers that do not have this
Packit fcad23
 * function, e.g. MSVC.
Packit fcad23
 * See also http://www.opengroup.org/onlinepubs/000095399/functions/strtoul.html
Packit fcad23
 * for more information about strtoull().
Packit fcad23
 */
Packit fcad23
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * For MSVC, disable the warning "unary minus operator applied to unsigned
Packit fcad23
 * type, result still unsigned"
Packit fcad23
 */
Packit fcad23
#ifdef _MSC_VER
Packit fcad23
#pragma warning (disable: 4146)
Packit fcad23
#endif
Packit fcad23
Packit fcad23
Packit fcad23
#define __STDC_CONSTANT_MACROS  /* Enable UINT64_C in <stdint.h> */
Packit fcad23
#define __STDC_FORMAT_MACROS    /* Enable PRIu64 in <inttypes.h> */
Packit fcad23
Packit fcad23
#include <net-snmp/net-snmp-config.h>
Packit fcad23
Packit fcad23
#ifndef HAVE_STRTOULL
Packit fcad23
Packit fcad23
#include <errno.h>
Packit fcad23
#include <ctype.h>
Packit fcad23
#include <limits.h>
Packit fcad23
#ifdef HAVE_INTTYPES_H
Packit fcad23
#include <inttypes.h>
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#include <net-snmp/types.h>
Packit fcad23
#include <net-snmp/library/system.h>
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * UINT64_C: C99 macro for the suffix for uint64_t constants. 
Packit fcad23
 */
Packit fcad23
#ifndef UINT64_C
Packit fcad23
#ifdef _MSC_VER
Packit fcad23
#define UINT64_C(c) c##ui64
Packit fcad23
#else
Packit fcad23
#define UINT64_C(c) c##ULL
Packit fcad23
#endif
Packit fcad23
#endif
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * According to the C99 standard, the constant ULLONG_MAX must be defined in
Packit fcad23
 * <limits.h>. Define it here for pre-C99 compilers.
Packit fcad23
 */
Packit fcad23
#ifndef ULLONG_MAX
Packit fcad23
#define ULLONG_MAX UINT64_C(0xffffffffffffffff)
Packit fcad23
#endif
Packit fcad23
Packit fcad23
uint64_t
Packit fcad23
strtoull(const char *nptr, char **endptr, int base)
Packit fcad23
{
Packit fcad23
    uint64_t        result = 0;
Packit fcad23
    const char     *p;
Packit fcad23
    const char     *first_nonspace;
Packit fcad23
    const char     *digits_start;
Packit fcad23
    int             sign = 1;
Packit fcad23
    int             out_of_range = 0;
Packit fcad23
Packit fcad23
    if (base != 0 && (base < 2 || base > 36))
Packit fcad23
        goto invalid_input;
Packit fcad23
Packit fcad23
    p = nptr;
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * Process the initial, possibly empty, sequence of white-space characters.
Packit fcad23
     */
Packit fcad23
    while (isspace((unsigned char) (*p)))
Packit fcad23
        p++;
Packit fcad23
Packit fcad23
    first_nonspace = p;
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * Determine sign.
Packit fcad23
     */
Packit fcad23
    if (*p == '+')
Packit fcad23
        p++;
Packit fcad23
    else if (*p == '-') {
Packit fcad23
        p++;
Packit fcad23
        sign = -1;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (base == 0) {
Packit fcad23
        /*
Packit fcad23
         * Determine base.
Packit fcad23
         */
Packit fcad23
        if (*p == '0') {
Packit fcad23
            if ((p[1] == 'x' || p[1] == 'X')) {
Packit fcad23
                if (isxdigit((unsigned char)(p[2]))) {
Packit fcad23
                    base = 16;
Packit fcad23
                    p += 2;
Packit fcad23
                } else {
Packit fcad23
                    /*
Packit fcad23
                     * Special case: treat the string "0x" without any further
Packit fcad23
                     * hex digits as a decimal number.
Packit fcad23
                     */
Packit fcad23
                    base = 10;
Packit fcad23
                }
Packit fcad23
            } else {
Packit fcad23
                base = 8;
Packit fcad23
                p++;
Packit fcad23
            }
Packit fcad23
        } else {
Packit fcad23
            base = 10;
Packit fcad23
        }
Packit fcad23
    } else if (base == 16) {
Packit fcad23
        /*
Packit fcad23
         * For base 16, skip the optional "0x" / "0X" prefix.
Packit fcad23
         */
Packit fcad23
        if (*p == '0' && (p[1] == 'x' || p[1] == 'X')
Packit fcad23
            && isxdigit((unsigned char)(p[2]))) {
Packit fcad23
            p += 2;
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
Packit fcad23
    digits_start = p;
Packit fcad23
Packit fcad23
    for (; *p; p++) {
Packit fcad23
        int             digit;
Packit fcad23
        digit = ('0' <= *p && *p <= '9') ? *p - '0'
Packit fcad23
            : ('a' <= *p && *p <= 'z') ? (*p - 'a' + 10)
Packit fcad23
            : ('A' <= *p && *p <= 'Z') ? (*p - 'A' + 10) : 36;
Packit fcad23
        if (digit < base) {
Packit fcad23
            if (! out_of_range) {
Packit fcad23
                if (result > ULLONG_MAX / base
Packit fcad23
                    || result * base > ULLONG_MAX - digit) {
Packit fcad23
                    out_of_range = 1;
Packit fcad23
                }
Packit fcad23
                result = result * base + digit;
Packit fcad23
            }
Packit fcad23
        } else
Packit fcad23
            break;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (p > first_nonspace && p == digits_start)
Packit fcad23
        goto invalid_input;
Packit fcad23
Packit fcad23
    if (p == first_nonspace)
Packit fcad23
        p = nptr;
Packit fcad23
Packit fcad23
    if (endptr)
Packit fcad23
        *endptr = (char *) p;
Packit fcad23
Packit fcad23
    if (out_of_range) {
Packit fcad23
        errno = ERANGE;
Packit fcad23
        return ULLONG_MAX;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    return sign > 0 ? result : -result;
Packit fcad23
Packit fcad23
  invalid_input:
Packit fcad23
    errno = EINVAL;
Packit fcad23
    if (endptr)
Packit fcad23
        *endptr = (char *) nptr;
Packit fcad23
    return 0;
Packit fcad23
}
Packit fcad23
Packit fcad23
#endif /* HAVE_STRTOULL */