Logo Search packages:      
Sourcecode: ksh version File versions  Download package

strtoi.h

/***********************************************************************
*                                                                      *
*               This software is part of the ast package               *
*          Copyright (c) 1985-2008 AT&T Intellectual Property          *
*                      and is licensed under the                       *
*                  Common Public License, Version 1.0                  *
*                    by AT&T Intellectual Property                     *
*                                                                      *
*                A copy of the License is available at                 *
*            http://www.opensource.org/licenses/cpl1.0.txt             *
*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
*                                                                      *
*              Information and Software Systems Research               *
*                            AT&T Research                             *
*                           Florham Park NJ                            *
*                                                                      *
*                 Glenn Fowler <gsf@research.att.com>                  *
*                  David Korn <dgk@research.att.com>                   *
*                   Phong Vo <kpv@research.att.com>                    *
*                                                                      *
***********************************************************************/
/*
 * AT&T Research
 * Glenn Fowler
 * Phong Vo
 *
 * common header and implementation for
 *
 *    strtol            strtoul           strton
 *    strtoll           strtoull    strtonll
 *    strntol           strntoul    strnton
 *    strntoll    strntoull   strntonll
 *
 * define these macros to instantiate an implementation:
 *
 *    S2I_function      the function name
 *    S2I_number  the signed number type
 *    S2I_unumber the unsigned number type
 *    S2I_unsigned      1 for unsigned, 0 for signed
 *    S2I_multiplier    1 for optional multiplier suffix, 0 otherwise
 *    S2I_size    the second argument is the input string size
 *
 * convert string to number
 * errno=ERANGE on overflow (LONG_MAX) or underflow (LONG_MIN)
 * if non-null e will point to first unrecognized char in s
 * if basep!=0 it points to the default base on input and
 * will point to the explicit base on return
 * a default base of 0 will determine the base from the input
 * a default base of 1 will determine the base from the input using bb#*
 * a base prefix in the string overrides *b
 * *b will not be set if the string has no base prefix
 * if m>1 and no multipler was specified then the result is multiplied by m
 * if m<0 then multipliers are not consumed
 * if a base arg or prefix is specified then multiplier is not consumed
 *
 * integer numbers are of the form:
 *
 *    [sign][base][number[qualifier]][multiplier]
 *
 *    base:       nnn#        base nnn
 *                0[xX]       hex
 *                0           octal
 *                [1-9]       decimal
 *
 *    number:           [0-9a-zA-Z]*
 *
 *    qualifier:  [lL]
 *                [uU]
 *                [uU][lL] 
 *                [lL][uU]
 *                [lL][lL][uU]
 *                [uU][lL][lL]
 *
 *    multiplier: .           pseudo-float if m>1
 *                [bB]        block (512)
 *                [cC]        char (1)
 *                [gG]        giga (1024*1024*1024)
 *                [kK]        kilo (1024)
 *                [mM]        mega (1024*1024)
 */

#include <ast.h>
#include <ctype.h>

#include "sfhdr.h"

#if !__STD_C && !defined(const)
#define const
#endif

#ifndef ERANGE
#define ERANGE          EINVAL
#endif

#define QL        01
#define QU        02

#define S2I_umax  (~((S2I_unumber)0))

#if S2I_unsigned
#define S2I_type  S2I_unumber
#define S2I_min         0
#define S2I_max         S2I_umax
#else
#define S2I_type  S2I_number
#define S2I_min         (-S2I_max-1)
#define S2I_max         (S2I_umax>>1)
#endif

#if S2I_size
#define S2I_valid(s)    ((s)<(z))
#else
#define S2I_valid(s)    1
#endif

#define ADDOVER(n,c,s)  ((S2I_umax-(n))<((S2I_unumber)((c)+(s))))
#define MPYOVER(n,c)    (((S2I_unumber)(n))>(S2I_umax/(c)))

static const S2I_unumber      mm[] =
{
      0,
      S2I_umax /  1,
      S2I_umax /  2,
      S2I_umax /  3,
      S2I_umax /  4,
      S2I_umax /  5,
      S2I_umax /  6,
      S2I_umax /  7,
      S2I_umax /  8,
      S2I_umax /  9,
      S2I_umax / 10,
      S2I_umax / 11,
      S2I_umax / 12,
      S2I_umax / 13,
      S2I_umax / 14,
      S2I_umax / 15,
      S2I_umax / 16,
      S2I_umax / 17,
      S2I_umax / 18,
      S2I_umax / 19,
      S2I_umax / 20,
      S2I_umax / 21,
      S2I_umax / 22,
      S2I_umax / 23,
      S2I_umax / 24,
      S2I_umax / 25,
      S2I_umax / 26,
      S2I_umax / 27,
      S2I_umax / 28,
      S2I_umax / 29,
      S2I_umax / 30,
      S2I_umax / 31,
      S2I_umax / 32,
      S2I_umax / 33,
      S2I_umax / 34,
      S2I_umax / 35,
      S2I_umax / 36,
      S2I_umax / 37,
      S2I_umax / 38,
      S2I_umax / 39,
      S2I_umax / 40,
      S2I_umax / 41,
      S2I_umax / 42,
      S2I_umax / 43,
      S2I_umax / 44,
      S2I_umax / 45,
      S2I_umax / 46,
      S2I_umax / 47,
      S2I_umax / 48,
      S2I_umax / 49,
      S2I_umax / 50,
      S2I_umax / 51,
      S2I_umax / 52,
      S2I_umax / 53,
      S2I_umax / 54,
      S2I_umax / 55,
      S2I_umax / 56,
      S2I_umax / 57,
      S2I_umax / 58,
      S2I_umax / 59,
      S2I_umax / 60,
      S2I_umax / 61,
      S2I_umax / 62,
      S2I_umax / 63,
      S2I_umax / 64,
};

#if defined(__EXPORT__)
#define extern          __EXPORT__
#endif
extern S2I_type
#undef      extern
#if S2I_size
#if S2I_multiplier
#if __STD_C
S2I_function(const char* a, size_t size, char** e, char* basep, int m)
#else
S2I_function(a, size, e, basep, m) const char* a; size_t size; char** e; char* basep; int m;
#endif
#else
#if __STD_C
S2I_function(const char* a, size_t size, char** e, int base)
#else
S2I_function(a, size, e, base) const char* a; size_t size; char** e; int base;
#endif
#endif
#else
#if S2I_multiplier
#if __STD_C
S2I_function(const char* a, char** e, char* basep, int m)
#else
S2I_function(a, e, basep, m) const char* a; char** e; char* basep; int m;
#endif
#else
#if __STD_C
S2I_function(const char* a, char** e, int base)
#else
S2I_function(a, e, base) const char* a; char** e; int base;
#endif
#endif
#endif
{
      register unsigned char* s = (unsigned char*)a;
#if S2I_size
      register unsigned char* z = s + size;
#endif
      register S2I_unumber    n;
      register S2I_unumber    x;
      register int            c;
      register int            shift;
      register unsigned char* p;
      register unsigned char* cv;
      unsigned char*          b;
      unsigned char*          k;
      S2I_unumber       v;
#if S2I_multiplier
      register int            base;
#endif
      int               negative;
      int               overflow = 0;
      int               decimal = 0;
      int               thousand = 0;
#if !S2I_unsigned
      int               qualifier = 0;
#endif

#if S2I_multiplier
      base = basep ? *((unsigned char*)basep) : 0;
#else
      if (base > 36 && base <= SF_RADIX)
      {
            static int  conformance = -1;

            if (conformance < 0)
                  conformance = !strcmp(astconf("CONFORMANCE", NiL, NiL), "standard");
            if (conformance)
                  base = 1;
      }
#endif
      if (base && (base < 2 || base > SF_RADIX))
      {
            errno = EINVAL;
            return 0;
      }
      while (S2I_valid(s) && isspace(*s))
            s++;
      if ((negative = S2I_valid(s) && (*s == '-')) || S2I_valid(s) && *s == '+')
            k = ++s;
      else
            k = 0;
      p = s;
      if (!base)
      {
            if (S2I_valid(p) && (c = *p++) >= '0' && c <= '9')
            {
                  n = c - '0';
                  if (S2I_valid(p) && (c = *p) >= '0' && c <= '9')
                  {
                        n = (n << 3) + (n << 1) + c - '0';
                        p++;
                  }
                  if (S2I_valid(p) && *p == '#')
                  {
                        if (n >= 2 && n <= 64)
                        {
                              k = s = p + 1;
                              base = n;
                        }
                  }
                  else if (base)
                        base = 0;
                  else if (S2I_valid(s) && *s == '0' && S2I_valid(s + 1))
                  {
                        if ((c = *(s + 1)) == 'x' || c == 'X')
                        {
                              k = s += 2;
                              base = 16;
                        }
                        else if (c >= '0' && c <= '7')
                        {
                              s++;
                              base = 8;
                        }
                  }
            }
            if (!base)
                  base = 10;
            else if (base < 2 || base > SF_RADIX)
            {
                  errno = EINVAL;
                  return 0;
            }
#if S2I_multiplier
            else
            {
                  if (basep)
                        *basep = base;
                  m = -1;
            }
#endif
      }
#if S2I_multiplier
      else
            m = -1;
#endif

      /*
       * this part transcribed from sfvscanf()
       */

      SFSETLOCALE(&decimal, &thousand);
      x = mm[base];
      n = 0;
      if (base == 10)
      {
            b = s;
            p = 0;
            for (;;)
            {
                  if (S2I_valid(s) && (c = *s++) >= '0' && c <= '9')
                  {
                        if (n > x)
                              overflow = 1;
                        else
                        {
                              n = (n << 3) + (n << 1);
                              c -= '0';
                              if (ADDOVER(n, c, negative))
                                    overflow = 1;
                              n += c;
                        }
                  }
                  else if (p && (s - p) != (3 + S2I_valid(s)))
                  {
                        s = p;
                        n = v;
                        c = 0;
                        break;
                  }
                  else if (c != thousand || !S2I_valid(s))
                        break;
                  else if (!p && (s - b) > 4)
                  {
                        if (e)
                              *e = (char*)s - 1;
                        if (overflow)
                        {
                              errno = ERANGE;
#if S2I_unsigned
                              n = S2I_max;
#else
                              n = negative ? S2I_min : S2I_max;
#endif
                        }
                        return n;
                  }
                  else
                  {
                        p = s;
                        v = n;
                  }
            }
      }
      else
      {
            SFCVINIT();
            cv = base <= 36 ? _Sfcv36 : _Sfcv64;
            if ((base & ~(base - 1)) == base)
            {     
#if !S2I_unsigned
                  qualifier |= QU;
#endif
                  if (base < 8)
                        shift = base <  4 ? 1 : 2;
                  else if (base < 32)
                        shift = base < 16 ? 3 : 4;
                  else
                        shift = base < 64 ? 5 : 6;
                  while (S2I_valid(s) && (c = cv[*s++]) < base)
                  {
                        if (n > x)
                              overflow = 1;
                        else
                        {
                              n <<= shift;
                              if (ADDOVER(n, c, negative))
                                    overflow = 1;
                              n += c;
                        }
                  }
            }
            else
                  while (S2I_valid(s) && (c = cv[*s++]) < base)
                  {
                        if (n > x)
                              overflow = 1;
                        else
                        {
                              n *= base;
                              if (ADDOVER(n, c, negative))
                                    overflow = 1;
                              n += c;
                        }
                  }
            c = *(s - 1);
      }

      /*
       * optional qualifier suffix
       */

      if (S2I_valid(s) && s > (unsigned char*)(a + 1))
      {
            base = 0;
            for (;;)
            {
                  if (!(base & QL) && (c == 'l' || c == 'L'))
                  {
                        base |= QL;
                        if (!S2I_valid(s))
                              break;
                        c = *s++;
                        if (c == 'l' || c == 'L')
                        {
                              if (!S2I_valid(s))
                                    break;
                              c = *s++;
                        }
                  }
                  else if (!(base & QU) && (c == 'u' || c == 'U'))
                  {
                        base |= QU;
#if !S2I_unsigned
                        qualifier |= QU;
#endif
                        if (!S2I_valid(s))
                              break;
                        c = *s++;
                  }
                  else
                        break;
            }
      }
      if (S2I_valid(s))
      {
#if S2I_multiplier
            /*
             * optional multiplier suffix
             */

            if (m < 0 || s == (unsigned char*)(a + 1))
                  s--;
            else
            {
                  switch (c)
                  {
                  case 'b':
                  case 'B':
                        shift = 9;
                        break;
                  case 'k':
                  case 'K':
                        shift = 10;
                        break;
                  case 'm':
                  case 'M':
                        shift = 20;
                        break;
                  case 'g':
                  case 'G':
                        shift = 30;
                        break;
                  case 't':
                  case 'T':
                        shift = 40;
                        break;
                  case 'p':
                  case 'P':
                        shift = 50;
                        break;
                  case 'e':
                  case 'E':
                        shift = 60;
                        break;
                  default:
                        if (m <= 1)
                              v = 0;
                        else if (c == decimal && S2I_valid(s))
                        {
                              if (MPYOVER(n, m))
                                    overflow = 1;
                              n *= m;
                              v = 0;
                              while (S2I_valid(s) && (c = *s++) >= '0' && c <= '9')
                                    v += (m /= 10) * (c - '0');
                              if (ADDOVER(n, v, negative))
                                    overflow = 1;
                              n += v;
                              v = 0;
                        }
                        else
                              v = m;
                        s--;
                        shift = 0;
                        break;
                  }
                  if (shift)
                  {
                        if (S2I_valid(s))
                              switch (*s)
                              {
                              case 'b':
                              case 'B':
                              case 'i':
                              case 'I':
                                    s++;
                                    break;
                              }
#if S2I_unsigned
                        if (shift >= (sizeof(S2I_type) * CHAR_BIT))
#else
                        if (shift >= (sizeof(S2I_type) * CHAR_BIT - 1))
#endif
                        {
                              v = 0;
                              overflow = 1;
                        }
                        else
                              v = ((S2I_unumber)1) << shift;
                  }
                  if (v)
                  {
                        if (MPYOVER(n, v))
                              overflow = 1;
                        n *= v;
                  }
            }
#else
            s--;
#endif
      }
      if (s == k)
      {
            s--;
#if S2I_multiplier
            if (basep)
                  *basep = 10;
#endif
      }
#if !S2I_unsigned
      else if (!(qualifier & QU))
      {
            if (negative)
            {
                  if (!n)
                  {
                        b = k;
                        do
                        {
                              if (b >= s)
                              {
                                    negative = 0;
                                    break;
                              }
                        } while (*b++ == '0');
                  }
                  if (negative && (n - 1) > S2I_max)
                        overflow = 1;
            }
            else if (n > S2I_max)
                  overflow = 1;
      }
#endif
      if (e)
            *e = (char*)s;
      if (overflow)
      {
#if !S2I_unsigned
            if (negative)
            {
                  if (x << 1)
                        errno = ERANGE;
                  return (S2I_type)S2I_min;
            }
#endif
            errno = ERANGE;
            return (S2I_type)S2I_max;
      }
      return negative ? -n : n;
}

Generated by  Doxygen 1.6.0   Back to index