Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.   This code is based on strtoul.c which has the following copyright.
  3.   It is used to convert a wide string into a signed long long.
  4.  
  5.   long long _wcstoll_r (struct _reent *rptr, const wchar_t *s,
  6.                         wchar_t **ptr, int base);
  7. */
  8.  
  9. /*-
  10.  * Copyright (c) 1990 The Regents of the University of California.
  11.  * All rights reserved.
  12.  *
  13.  * Redistribution and use in source and binary forms, with or without
  14.  * modification, are permitted provided that the following conditions
  15.  * are met:
  16.  * 1. Redistributions of source code must retain the above copyright
  17.  *    notice, this list of conditions and the following disclaimer.
  18.  * 2. Redistributions in binary form must reproduce the above copyright
  19.  *    notice, this list of conditions and the following disclaimer in the
  20.  *    documentation and/or other materials provided with the distribution.
  21.  * 3. All advertising materials mentioning features or use of this software
  22.  *    must display the following acknowledgement:
  23.  *      This product includes software developed by the University of
  24.  *      California, Berkeley and its contributors.
  25.  * 4. Neither the name of the University nor the names of its contributors
  26.  *    may be used to endorse or promote products derived from this software
  27.  *    without specific prior written permission.
  28.  *
  29.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  30.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  31.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  32.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  33.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  34.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  35.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  36.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  37.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  38.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  39.  * SUCH DAMAGE.
  40.  */
  41.  
  42. #ifdef __GNUC__
  43.  
  44. #define _GNU_SOURCE
  45. #include <_ansi.h>
  46. #include <limits.h>
  47. #include <wctype.h>
  48. #include <errno.h>
  49. #include <wchar.h>
  50. #include <reent.h>
  51.  
  52. /*
  53.  * Convert a wide string to a long long integer.
  54.  *
  55.  * Ignores `locale' stuff.  Assumes that the upper and lower case
  56.  * alphabets and digits are each contiguous.
  57.  */
  58. long long
  59. _DEFUN (_wcstoll_r, (rptr, nptr, endptr, base),
  60.         struct _reent *rptr _AND
  61.         _CONST wchar_t *nptr _AND
  62.         wchar_t **endptr _AND
  63.         int base)
  64. {
  65.         register const wchar_t *s = nptr;
  66.         register unsigned long long acc;
  67.         register int c;
  68.         register unsigned long long cutoff;
  69.         register int neg = 0, any, cutlim;
  70.  
  71.         /*
  72.          * Skip white space and pick up leading +/- sign if any.
  73.          * If base is 0, allow 0x for hex and 0 for octal, else
  74.          * assume decimal; if base is already 16, allow 0x.
  75.          */
  76.         do {
  77.                 c = *s++;
  78.         } while (iswspace(c));
  79.         if (c == L'-') {
  80.                 neg = 1;
  81.                 c = *s++;
  82.         } else if (c == L'+')
  83.                 c = *s++;
  84.         if ((base == 0 || base == 16) &&
  85.             c == L'0' && (*s == L'x' || *s == L'X')) {
  86.                 c = s[1];
  87.                 s += 2;
  88.                 base = 16;
  89.         }
  90.         if (base == 0)
  91.                 base = c == L'0' ? 8 : 10;
  92.  
  93.         /*
  94.          * Compute the cutoff value between legal numbers and illegal
  95.          * numbers.  That is the largest legal value, divided by the
  96.          * base.  An input number that is greater than this value, if
  97.          * followed by a legal input character, is too big.  One that
  98.          * is equal to this value may be valid or not; the limit
  99.          * between valid and invalid numbers is then based on the last
  100.          * digit.  For instance, if the range for longs is
  101.          * [-2147483648..2147483647] and the input base is 10,
  102.          * cutoff will be set to 214748364 and cutlim to either
  103.          * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
  104.          * a value > 214748364, or equal but the next digit is > 7 (or 8),
  105.          * the number is too big, and we will return a range error.
  106.          *
  107.          * Set any if any `digits' consumed; make it negative to indicate
  108.          * overflow.
  109.          */
  110.         cutoff = neg ? -(unsigned long long)LONG_LONG_MIN : LONG_LONG_MAX;
  111.         cutlim = cutoff % (unsigned long long)base;
  112.         cutoff /= (unsigned long long)base;
  113.         for (acc = 0, any = 0;; c = *s++) {
  114.                 if (iswdigit(c))
  115.                         c -= L'0';
  116.                 else if (iswalpha(c))
  117.                         c -= iswupper(c) ? L'A' - 10 : L'a' - 10;
  118.                 else
  119.                         break;
  120.                 if (c >= base)
  121.                         break;
  122.                if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
  123.                         any = -1;
  124.                 else {
  125.                         any = 1;
  126.                         acc *= base;
  127.                         acc += c;
  128.                 }
  129.         }
  130.         if (any < 0) {
  131.                 acc = neg ? LONG_LONG_MIN : LONG_LONG_MAX;
  132.                 rptr->_errno = ERANGE;
  133.         } else if (neg)
  134.                 acc = -acc;
  135.         if (endptr != 0)
  136.                 *endptr = (wchar_t *) (any ? s - 1 : nptr);
  137.         return (acc);
  138. }
  139.  
  140. #endif /* __GNUC__ */
  141.