LCOV - code coverage report
Current view: top level - Python - mystrtoul.c (source / functions) Hit Total Coverage
Test: CPython lcov report Lines: 50 104 48.1 %
Date: 2017-04-19 Functions: 2 2 100.0 %

          Line data    Source code
       1             : 
       2             : #include "Python.h"
       3             : 
       4             : #if defined(__sgi) && defined(WITH_THREAD) && !defined(_SGI_MP_SOURCE)
       5             : #define _SGI_MP_SOURCE
       6             : #endif
       7             : 
       8             : /* strtol and strtoul, renamed to avoid conflicts */
       9             : 
      10             : 
      11             : #include <ctype.h>
      12             : #ifdef HAVE_ERRNO_H
      13             : #include <errno.h>
      14             : #endif
      15             : 
      16             : /* Static overflow check values for bases 2 through 36.
      17             :  * smallmax[base] is the largest unsigned long i such that
      18             :  * i * base doesn't overflow unsigned long.
      19             :  */
      20             : static unsigned long smallmax[] = {
      21             :     0, /* bases 0 and 1 are invalid */
      22             :     0,
      23             :     ULONG_MAX / 2,
      24             :     ULONG_MAX / 3,
      25             :     ULONG_MAX / 4,
      26             :     ULONG_MAX / 5,
      27             :     ULONG_MAX / 6,
      28             :     ULONG_MAX / 7,
      29             :     ULONG_MAX / 8,
      30             :     ULONG_MAX / 9,
      31             :     ULONG_MAX / 10,
      32             :     ULONG_MAX / 11,
      33             :     ULONG_MAX / 12,
      34             :     ULONG_MAX / 13,
      35             :     ULONG_MAX / 14,
      36             :     ULONG_MAX / 15,
      37             :     ULONG_MAX / 16,
      38             :     ULONG_MAX / 17,
      39             :     ULONG_MAX / 18,
      40             :     ULONG_MAX / 19,
      41             :     ULONG_MAX / 20,
      42             :     ULONG_MAX / 21,
      43             :     ULONG_MAX / 22,
      44             :     ULONG_MAX / 23,
      45             :     ULONG_MAX / 24,
      46             :     ULONG_MAX / 25,
      47             :     ULONG_MAX / 26,
      48             :     ULONG_MAX / 27,
      49             :     ULONG_MAX / 28,
      50             :     ULONG_MAX / 29,
      51             :     ULONG_MAX / 30,
      52             :     ULONG_MAX / 31,
      53             :     ULONG_MAX / 32,
      54             :     ULONG_MAX / 33,
      55             :     ULONG_MAX / 34,
      56             :     ULONG_MAX / 35,
      57             :     ULONG_MAX / 36,
      58             : };
      59             : 
      60             : /* maximum digits that can't ever overflow for bases 2 through 36,
      61             :  * calculated by [int(math.floor(math.log(2**32, i))) for i in range(2, 37)].
      62             :  * Note that this is pessimistic if sizeof(long) > 4.
      63             :  */
      64             : #if SIZEOF_LONG == 4
      65             : static int digitlimit[] = {
      66             :     0,  0, 32, 20, 16, 13, 12, 11, 10, 10,  /*  0 -  9 */
      67             :     9,  9,  8,  8,  8,  8,  8,  7,  7,  7,  /* 10 - 19 */
      68             :     7,  7,  7,  7,  6,  6,  6,  6,  6,  6,  /* 20 - 29 */
      69             :     6,  6,  6,  6,  6,  6,  6};             /* 30 - 36 */
      70             : #elif SIZEOF_LONG == 8
      71             : /* [int(math.floor(math.log(2**64, i))) for i in range(2, 37)] */
      72             : static int digitlimit[] = {
      73             :          0,   0, 64, 40, 32, 27, 24, 22, 21, 20,  /*  0 -  9 */
      74             :     19,  18, 17, 17, 16, 16, 16, 15, 15, 15,  /* 10 - 19 */
      75             :     14,  14, 14, 14, 13, 13, 13, 13, 13, 13,  /* 20 - 29 */
      76             :     13,  12, 12, 12, 12, 12, 12};             /* 30 - 36 */
      77             : #else
      78             : #error "Need table for SIZEOF_LONG"
      79             : #endif
      80             : 
      81             : /*
      82             : **      strtoul
      83             : **              This is a general purpose routine for converting
      84             : **              an ascii string to an integer in an arbitrary base.
      85             : **              Leading white space is ignored.  If 'base' is zero
      86             : **              it looks for a leading 0, 0b, 0B, 0o, 0O, 0x or 0X
      87             : **              to tell which base.  If these are absent it defaults
      88             : **              to 10. Base must be 0 or between 2 and 36 (inclusive).
      89             : **              If 'ptr' is non-NULL it will contain a pointer to
      90             : **              the end of the scan.
      91             : **              Errors due to bad pointers will probably result in
      92             : **              exceptions - we don't check for them.
      93             : */
      94             : unsigned long
      95        3834 : PyOS_strtoul(register char *str, char **ptr, int base)
      96             : {
      97        3834 :     register unsigned long result = 0; /* return value of the function */
      98             :     register int c;             /* current input character */
      99             :     register int ovlimit;       /* required digits to overflow */
     100             : 
     101             :     /* skip leading white space */
     102        7668 :     while (*str && isspace(Py_CHARMASK(*str)))
     103           0 :         ++str;
     104             : 
     105             :     /* check for leading 0 or 0x for auto-base or base 16 */
     106        3834 :     switch (base) {
     107             :     case 0:             /* look for leading 0, 0b, 0o or 0x */
     108         759 :         if (*str == '0') {
     109         268 :             ++str;
     110         268 :             if (*str == 'x' || *str == 'X') {
     111             :                 /* there must be at least one digit after 0x */
     112           3 :                 if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 16) {
     113           0 :                     if (ptr)
     114           0 :                         *ptr = str;
     115           0 :                     return 0;
     116             :                 }
     117           3 :                 ++str;
     118           3 :                 base = 16;
     119         265 :             } else if (*str == 'o' || *str == 'O') {
     120             :                 /* there must be at least one digit after 0o */
     121           0 :                 if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 8) {
     122           0 :                     if (ptr)
     123           0 :                         *ptr = str;
     124           0 :                     return 0;
     125             :                 }
     126           0 :                 ++str;
     127           0 :                 base = 8;
     128         265 :             } else if (*str == 'b' || *str == 'B') {
     129             :                 /* there must be at least one digit after 0b */
     130           0 :                 if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 2) {
     131           0 :                     if (ptr)
     132           0 :                         *ptr = str;
     133           0 :                     return 0;
     134             :                 }
     135           0 :                 ++str;
     136           0 :                 base = 2;
     137             :             } else {
     138         265 :                 base = 8;
     139             :             }
     140             :         }
     141             :         else
     142         491 :             base = 10;
     143         759 :         break;
     144             : 
     145             :     case 2:     /* skip leading 0b or 0B */
     146        1584 :         if (*str == '0') {
     147        1485 :             ++str;
     148        1485 :             if (*str == 'b' || *str == 'B') {
     149             :                 /* there must be at least one digit after 0b */
     150           0 :                 if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 2) {
     151           0 :                     if (ptr)
     152           0 :                         *ptr = str;
     153           0 :                     return 0;
     154             :                 }
     155           0 :                 ++str;
     156             :             }
     157             :         }
     158        1584 :         break;
     159             : 
     160             :     case 8:     /* skip leading 0o or 0O */
     161          18 :         if (*str == '0') {
     162          18 :             ++str;
     163          18 :             if (*str == 'o' || *str == 'O') {
     164             :                 /* there must be at least one digit after 0o */
     165           0 :                 if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 8) {
     166           0 :                     if (ptr)
     167           0 :                         *ptr = str;
     168           0 :                     return 0;
     169             :                 }
     170           0 :                 ++str;
     171             :             }
     172             :         }
     173          18 :         break;
     174             : 
     175             :     case 16:            /* skip leading 0x or 0X */
     176        1470 :         if (*str == '0') {
     177          72 :             ++str;
     178          72 :             if (*str == 'x' || *str == 'X') {
     179             :                 /* there must be at least one digit after 0x */
     180           0 :                 if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 16) {
     181           0 :                     if (ptr)
     182           0 :                         *ptr = str;
     183           0 :                     return 0;
     184             :                 }
     185           0 :                 ++str;
     186             :             }
     187             :         }
     188        1470 :         break;
     189             :     }
     190             : 
     191             :     /* catch silly bases */
     192        3834 :     if (base < 2 || base > 36) {
     193           0 :         if (ptr)
     194           0 :             *ptr = str;
     195           0 :         return 0;
     196             :     }
     197             : 
     198             :     /* skip leading zeroes */
     199       45951 :     while (*str == '0')
     200       38283 :         ++str;
     201             : 
     202             :     /* base is guaranteed to be in [2, 36] at this point */
     203        3834 :     ovlimit = digitlimit[base];
     204             : 
     205             :     /* do the conversion until non-digit character encountered */
     206       22009 :     while ((c = _PyLong_DigitValue[Py_CHARMASK(*str)]) < base) {
     207       14341 :         if (ovlimit > 0) /* no overflow check required */
     208       14341 :             result = result * base + c;
     209             :         else { /* requires overflow check */
     210             :             register unsigned long temp_result;
     211             : 
     212           0 :             if (ovlimit < 0) /* guaranteed overflow */
     213           0 :                 goto overflowed;
     214             : 
     215             :             /* there could be an overflow */
     216             :             /* check overflow just from shifting */
     217           0 :             if (result > smallmax[base])
     218           0 :                 goto overflowed;
     219             : 
     220           0 :             result *= base;
     221             : 
     222             :             /* check overflow from the digit's value */
     223           0 :             temp_result = result + c;
     224           0 :             if (temp_result < result)
     225           0 :                 goto overflowed;
     226             : 
     227           0 :             result = temp_result;
     228             :         }
     229             : 
     230       14341 :         ++str;
     231       14341 :         --ovlimit;
     232             :     }
     233             : 
     234             :     /* set pointer to point to the last character scanned */
     235        3834 :     if (ptr)
     236        3834 :         *ptr = str;
     237             : 
     238        3834 :     return result;
     239             : 
     240             : overflowed:
     241           0 :     if (ptr) {
     242             :         /* spool through remaining digit characters */
     243           0 :         while (_PyLong_DigitValue[Py_CHARMASK(*str)] < base)
     244           0 :             ++str;
     245           0 :         *ptr = str;
     246             :     }
     247           0 :     errno = ERANGE;
     248           0 :     return (unsigned long)-1;
     249             : }
     250             : 
     251             : /* Checking for overflow in PyOS_strtol is a PITA; see comments
     252             :  * about PY_ABS_LONG_MIN in longobject.c.
     253             :  */
     254             : #define PY_ABS_LONG_MIN         (0-(unsigned long)LONG_MIN)
     255             : 
     256             : long
     257        3834 : PyOS_strtol(char *str, char **ptr, int base)
     258             : {
     259             :     long result;
     260             :     unsigned long uresult;
     261             :     char sign;
     262             : 
     263        7668 :     while (*str && isspace(Py_CHARMASK(*str)))
     264           0 :         str++;
     265             : 
     266        3834 :     sign = *str;
     267        3834 :     if (sign == '+' || sign == '-')
     268          87 :         str++;
     269             : 
     270        3834 :     uresult = PyOS_strtoul(str, ptr, base);
     271             : 
     272        3834 :     if (uresult <= (unsigned long)LONG_MAX) {
     273        3834 :         result = (long)uresult;
     274        3834 :         if (sign == '-')
     275          87 :             result = -result;
     276             :     }
     277           0 :     else if (sign == '-' && uresult == PY_ABS_LONG_MIN) {
     278           0 :         result = LONG_MIN;
     279             :     }
     280             :     else {
     281           0 :         errno = ERANGE;
     282           0 :         result = LONG_MAX;
     283             :     }
     284        3834 :     return result;
     285             : }

Generated by: LCOV version 1.10