View of xos/usr/lib/libc/strtol.c


XOS | Parent Directory | View | Download

/* Copyright (C) 2008  Emmanuel Varoquaux
 
   This file is part of XOS.
 
   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.
 
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
 
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
#include <stdlib.h>
 
#include "ctype.h"
 
#include <string.h>
#include <limits.h>
#include <errno.h>
 
#include "misc.h"
 
static const char digits_lc[] = "0123456789abcdefghijklmnopqrstuvwxyz";
static const char digits_uc[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
 
long __attribute__ ((weak, visibility ("default"))) strtol(const char *str, char **endptr, int base)
{
  int negative;
  long val;
  char *p;
  int i;
 
  if (base != 0 && (base < 2 || base > 36)) {
    errno = EINVAL;
    return 0;
  }
 
  while (__isspace(*str))
    str++;
 
  if (*str == '+') {
    negative = 0;
    str++;
  }
  else if (*str == '-') {
    negative = 1;
    str++;
  }
  else
    negative = 0;
  if (base == 0) {
    if (!strncmp(str, "0x", 2) || !strncmp(str, "0X", 2)) {
      base = 16;
      str += 2;
    }
    else if (*str == '0') {
      base = 8;
      str++;
    }
    else
      base = 10;
  }
  else if (base == 16)
    if (!strncmp(str, "0x", 2) || !strncmp(str, "0X", 2))
      str += 2;
  val = 0;
  while (*str) {
    if ((p = strchr(digits_lc, *str)))
      i = p - digits_lc;
    else if ((p = strchr(digits_uc, *str)))
      i = p - digits_uc;
    else
      break;
    if (i >= base)
      break;
    if (!negative) {
      if (val > (LONG_MAX - i) / base) {
        if (endptr)
          *endptr = strchr(str, '\0');
        errno = ERANGE;
        return LONG_MAX;
      }
      val = val * base + i;
    }
    else {
      if (val < (LONG_MIN + i) / base) {
        if (endptr)
          *endptr = strchr(str, '\0');
        errno = ERANGE;
        return LONG_MIN;
      }
      val = val * base - i;
    }
    str++;
  }
 
  if (endptr)
    *endptr = const_cast(char *, str);
  return val;
}
 
unsigned long __attribute__ ((weak, visibility ("default"))) strtoul(const char *str, char **endptr, int base)
{
  int negative;
  unsigned long val;
  char *p;
  int i;
 
  if (base != 0 && (base < 2 || base > 36)) {
    errno = EINVAL;
    return 0;
  }
 
  while (__isspace(*str))
    str++;
 
  if (*str == '+') {
    negative = 0;
    str++;
  }
  else if (*str == '-') {
    negative = 1;
    str++;
  }
  else
    negative = 0;
  if (base == 0) {
    if (!strncmp(str, "0x", 2) || !strncmp(str, "0X", 2)) {
      base = 16;
      str += 2;
    }
    else if (*str == '0') {
      base = 8;
      str++;
    }
    else
      base = 10;
  }
  else if (base == 16)
    if (!strncmp(str, "0x", 2) || !strncmp(str, "0X", 2))
      str += 2;
  val = 0;
  while (*str) {
    if ((p = strchr(digits_lc, *str)))
      i = p - digits_lc;
    else if ((p = strchr(digits_uc, *str)))
      i = p - digits_uc;
    else
      break;
    if (i >= base)
      break;
    if (val > (ULONG_MAX - i) / base) {
      if (endptr)
        *endptr = strchr(str, '\0');
      errno = ERANGE;
      return ULONG_MAX;
    }
    val = val * base + i;
    str++;
  }
 
  if (endptr)
    *endptr = const_cast(char *, str);
  return !negative ? val : -val;
}