Exemplo n.º 1
0
/* Compare two MAC addresses, ignoring differences in case,
 * as well as leading zeros.
 */
int
virMacAddrCompare(const char *p, const char *q)
{
    unsigned char c, d;
    do {
        while (*p == '0' && c_isxdigit(p[1]))
            ++p;
        while (*q == '0' && c_isxdigit(q[1]))
            ++q;
        c = c_tolower(*p);
        d = c_tolower(*q);

        if (c == 0 || d == 0)
            break;

        ++p;
        ++q;
    } while (c == d);

    if (UCHAR_MAX <= INT_MAX)
        return c - d;

    /* On machines where 'char' and 'int' are types of the same size, the
       difference of two 'unsigned char' values - including the sign bit -
       doesn't fit in an 'int'.  */
    return c > d ? 1 : c < d ? -1 : 0;
}
Exemplo n.º 2
0
static void
strdecode(char *to, char *from)
{
	for (; *from != '\0'; ++to, ++from) {
		if (from[0] == '%' && c_isxdigit(from[1]) && c_isxdigit(from[2])) {
			*to = hexit(from[1]) * 16 + hexit(from[2]);
			from += 2;
		} else
			*to = *from;
	}
	*to = '\0';
}
Exemplo n.º 3
0
/**
 * virUUIDParse:
 * @uuidstr: zero terminated string representation of the UUID
 * @uuid: array of VIR_UUID_BUFLEN bytes to store the raw UUID
 *
 * Parses the external string representation, allowing spaces and '-'
 * character in the sequence, and storing the result as a raw UUID
 *
 * Returns 0 in case of success and -1 in case of error.
 */
int
virUUIDParse(const char *uuidstr, unsigned char *uuid)
{
    const char *cur;
    size_t i;

    /*
     * do a liberal scan allowing '-' and ' ' anywhere between character
     * pairs, and surrounding whitespace, as long as there are exactly
     * 32 hexadecimal digits the end.
     */
    cur = uuidstr;
    while (c_isspace(*cur))
        cur++;

    for (i = 0; i < VIR_UUID_BUFLEN;) {
        uuid[i] = 0;
        if (*cur == 0)
            goto error;
        if ((*cur == '-') || (*cur == ' ')) {
            cur++;
            continue;
        }
        if (!c_isxdigit(*cur))
            goto error;
        uuid[i] = virHexToBin(*cur);
        uuid[i] *= 16;
        cur++;
        if (*cur == 0)
            goto error;
        if (!c_isxdigit(*cur))
            goto error;
        uuid[i] += virHexToBin(*cur);
        i++;
        cur++;
    }

    while (*cur) {
        if (!c_isspace(*cur))
            goto error;
        cur++;
    }

    return 0;

 error:
    return -1;
}
Exemplo n.º 4
0
/**
 * virMacAddrParse:
 * @str: string representation of MAC address, e.g., "0:1E:FC:E:3a:CB"
 * @addr: 6-byte MAC address
 *
 * Parse a MAC address
 *
 * Return 0 upon success, or -1 in case of error.
 */
int
virMacAddrParse(const char* str, unsigned char *addr)
{
    int i;

    errno = 0;
    for (i = 0; i < VIR_MAC_BUFLEN; i++) {
        char *end_ptr;
        unsigned long result;

        /* This is solely to avoid accepting the leading
         * space or "+" that strtoul would otherwise accept.
         */
        if (!c_isxdigit(*str))
            break;

        result = strtoul(str, &end_ptr, 16); /* exempt from syntax-check */

        if ((end_ptr - str) < 1 || 2 < (end_ptr - str) ||
            (errno != 0) ||
            (0xFF < result))
            break;

        addr[i] = (unsigned char) result;

        if ((i == 5) && (*end_ptr == '\0'))
            return 0;
        if (*end_ptr != ':')
            break;

        str = end_ptr + 1;
    }

    return -1;
}
Exemplo n.º 5
0
static unsigned long
virHostCPUCountThreadSiblings(const char *dir, unsigned int cpu)
{
    unsigned long ret = 0;
    char *path;
    char *str = NULL;
    size_t i;

    if (virAsprintf(&path, "%s/cpu%u/topology/thread_siblings",
                    dir, cpu) < 0)
        return 0;

    if (!virFileExists(path)) {
        /* If file doesn't exist, then pretend our only
         * sibling is ourself */
        ret = 1;
        goto cleanup;
    }

    if (virFileReadAll(path, SYSFS_THREAD_SIBLINGS_LIST_LENGTH_MAX, &str) < 0)
        goto cleanup;

    for (i = 0; str[i] != '\0'; i++) {
        if (c_isxdigit(str[i]))
            ret += count_one_bits(virHexToBin(str[i]));
    }

 cleanup:
    VIR_FREE(str);
    VIR_FREE(path);
    return ret;
}
Exemplo n.º 6
0
Arquivo: host.c Projeto: AOSC-Dev/wget
bool
is_valid_ipv6_address (const char *str, const char *end)
{
  /* Use lower-case for these to avoid clash with system headers.  */
  enum {
    ns_inaddrsz  = 4,
    ns_in6addrsz = 16,
    ns_int16sz   = 2
  };

  const char *curtok;
  int tp;
  const char *colonp;
  bool saw_xdigit;
  unsigned int val;

  tp = 0;
  colonp = NULL;

  if (str == end)
    return false;

  /* Leading :: requires some special handling. */
  if (*str == ':')
    {
      ++str;
      if (str == end || *str != ':')
        return false;
    }

  curtok = str;
  saw_xdigit = false;
  val = 0;

  while (str < end)
    {
      int ch = *str++;

      /* if ch is a number, add it to val. */
      if (c_isxdigit (ch))
        {
          val <<= 4;
          val |= XDIGIT_TO_NUM (ch);
          if (val > 0xffff)
            return false;
          saw_xdigit = true;
          continue;
        }

      /* if ch is a colon ... */
      if (ch == ':')
        {
          curtok = str;
          if (!saw_xdigit)
            {
              if (colonp != NULL)
                return false;
              colonp = str + tp;
              continue;
            }
          else if (str == end)
            return false;
          if (tp > ns_in6addrsz - ns_int16sz)
            return false;
          tp += ns_int16sz;
          saw_xdigit = false;
          val = 0;
          continue;
        }

      /* if ch is a dot ... */
      if (ch == '.' && (tp <= ns_in6addrsz - ns_inaddrsz)
          && is_valid_ipv4_address (curtok, end) == 1)
        {
          tp += ns_inaddrsz;
          saw_xdigit = false;
          break;
        }

      return false;
    }

  if (saw_xdigit)
    {
      if (tp > ns_in6addrsz - ns_int16sz)
        return false;
      tp += ns_int16sz;
    }

  if (colonp != NULL)
    {
      if (tp == ns_in6addrsz)
        return false;
      tp = ns_in6addrsz;
    }

  if (tp != ns_in6addrsz)
    return false;

  return true;
}
Exemplo n.º 7
0
static void
test_all (void)
{
  int c;

  for (c = -0x80; c < 0x100; c++)
    {
      ASSERT (c_isascii (c) == (c >= 0 && c < 0x80));

      switch (c)
        {
        case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
        case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
        case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
        case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
        case 'Y': case 'Z':
        case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
        case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
        case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
        case 's': case 't': case 'u': case 'v': case 'w': case 'x':
        case 'y': case 'z':
        case '0': case '1': case '2': case '3': case '4': case '5':
        case '6': case '7': case '8': case '9':
          ASSERT (c_isalnum (c) == 1);
          break;
        default:
          ASSERT (c_isalnum (c) == 0);
          break;
        }

      switch (c)
        {
        case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
        case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
        case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
        case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
        case 'Y': case 'Z':
        case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
        case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
        case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
        case 's': case 't': case 'u': case 'v': case 'w': case 'x':
        case 'y': case 'z':
          ASSERT (c_isalpha (c) == 1);
          break;
        default:
          ASSERT (c_isalpha (c) == 0);
          break;
        }

      switch (c)
        {
        case '\t': case ' ':
          ASSERT (c_isblank (c) == 1);
          break;
        default:
          ASSERT (c_isblank (c) == 0);
          break;
        }

      ASSERT (c_iscntrl (c) == ((c >= 0 && c < 0x20) || c == 0x7f));

      switch (c)
        {
        case '0': case '1': case '2': case '3': case '4': case '5':
        case '6': case '7': case '8': case '9':
          ASSERT (c_isdigit (c) == 1);
          break;
        default:
          ASSERT (c_isdigit (c) == 0);
          break;
        }

      switch (c)
        {
        case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
        case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
        case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
        case 's': case 't': case 'u': case 'v': case 'w': case 'x':
        case 'y': case 'z':
          ASSERT (c_islower (c) == 1);
          break;
        default:
          ASSERT (c_islower (c) == 0);
          break;
        }

      ASSERT (c_isgraph (c) == ((c >= 0x20 && c < 0x7f) && c != ' '));

      ASSERT (c_isprint (c) == (c >= 0x20 && c < 0x7f));

      ASSERT (c_ispunct (c) == (c_isgraph (c) && !c_isalnum (c)));

      switch (c)
        {
        case ' ': case '\t': case '\n': case '\v': case '\f': case '\r':
          ASSERT (c_isspace (c) == 1);
          break;
        default:
          ASSERT (c_isspace (c) == 0);
          break;
        }

      switch (c)
        {
        case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
        case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
        case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
        case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
        case 'Y': case 'Z':
          ASSERT (c_isupper (c) == 1);
          break;
        default:
          ASSERT (c_isupper (c) == 0);
          break;
        }

      switch (c)
        {
        case '0': case '1': case '2': case '3': case '4': case '5':
        case '6': case '7': case '8': case '9':
        case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
        case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
          ASSERT (c_isxdigit (c) == 1);
          break;
        default:
          ASSERT (c_isxdigit (c) == 0);
          break;
        }

      switch (c)
        {
        case 'A':
          ASSERT (c_tolower (c) == 'a');
          ASSERT (c_toupper (c) == c);
          break;
        case 'B':
          ASSERT (c_tolower (c) == 'b');
          ASSERT (c_toupper (c) == c);
          break;
        case 'C':
          ASSERT (c_tolower (c) == 'c');
          ASSERT (c_toupper (c) == c);
          break;
        case 'D':
          ASSERT (c_tolower (c) == 'd');
          ASSERT (c_toupper (c) == c);
          break;
        case 'E':
          ASSERT (c_tolower (c) == 'e');
          ASSERT (c_toupper (c) == c);
          break;
        case 'F':
          ASSERT (c_tolower (c) == 'f');
          ASSERT (c_toupper (c) == c);
          break;
        case 'G':
          ASSERT (c_tolower (c) == 'g');
          ASSERT (c_toupper (c) == c);
          break;
        case 'H':
          ASSERT (c_tolower (c) == 'h');
          ASSERT (c_toupper (c) == c);
          break;
        case 'I':
          ASSERT (c_tolower (c) == 'i');
          ASSERT (c_toupper (c) == c);
          break;
        case 'J':
          ASSERT (c_tolower (c) == 'j');
          ASSERT (c_toupper (c) == c);
          break;
        case 'K':
          ASSERT (c_tolower (c) == 'k');
          ASSERT (c_toupper (c) == c);
          break;
        case 'L':
          ASSERT (c_tolower (c) == 'l');
          ASSERT (c_toupper (c) == c);
          break;
        case 'M':
          ASSERT (c_tolower (c) == 'm');
          ASSERT (c_toupper (c) == c);
          break;
        case 'N':
          ASSERT (c_tolower (c) == 'n');
          ASSERT (c_toupper (c) == c);
          break;
        case 'O':
          ASSERT (c_tolower (c) == 'o');
          ASSERT (c_toupper (c) == c);
          break;
        case 'P':
          ASSERT (c_tolower (c) == 'p');
          ASSERT (c_toupper (c) == c);
          break;
        case 'Q':
          ASSERT (c_tolower (c) == 'q');
          ASSERT (c_toupper (c) == c);
          break;
        case 'R':
          ASSERT (c_tolower (c) == 'r');
          ASSERT (c_toupper (c) == c);
          break;
        case 'S':
          ASSERT (c_tolower (c) == 's');
          ASSERT (c_toupper (c) == c);
          break;
        case 'T':
          ASSERT (c_tolower (c) == 't');
          ASSERT (c_toupper (c) == c);
          break;
        case 'U':
          ASSERT (c_tolower (c) == 'u');
          ASSERT (c_toupper (c) == c);
          break;
        case 'V':
          ASSERT (c_tolower (c) == 'v');
          ASSERT (c_toupper (c) == c);
          break;
        case 'W':
          ASSERT (c_tolower (c) == 'w');
          ASSERT (c_toupper (c) == c);
          break;
        case 'X':
          ASSERT (c_tolower (c) == 'x');
          ASSERT (c_toupper (c) == c);
          break;
        case 'Y':
          ASSERT (c_tolower (c) == 'y');
          ASSERT (c_toupper (c) == c);
          break;
        case 'Z':
          ASSERT (c_tolower (c) == 'z');
          ASSERT (c_toupper (c) == c);
          break;
        case 'a':
          ASSERT (c_tolower (c) == c);
          ASSERT (c_toupper (c) == 'A');
          break;
        case 'b':
          ASSERT (c_tolower (c) == c);
          ASSERT (c_toupper (c) == 'B');
          break;
        case 'c':
          ASSERT (c_tolower (c) == c);
          ASSERT (c_toupper (c) == 'C');
          break;
        case 'd':
          ASSERT (c_tolower (c) == c);
          ASSERT (c_toupper (c) == 'D');
          break;
        case 'e':
          ASSERT (c_tolower (c) == c);
          ASSERT (c_toupper (c) == 'E');
          break;
        case 'f':
          ASSERT (c_tolower (c) == c);
          ASSERT (c_toupper (c) == 'F');
          break;
        case 'g':
          ASSERT (c_tolower (c) == c);
          ASSERT (c_toupper (c) == 'G');
          break;
        case 'h':
          ASSERT (c_tolower (c) == c);
          ASSERT (c_toupper (c) == 'H');
          break;
        case 'i':
          ASSERT (c_tolower (c) == c);
          ASSERT (c_toupper (c) == 'I');
          break;
        case 'j':
          ASSERT (c_tolower (c) == c);
          ASSERT (c_toupper (c) == 'J');
          break;
        case 'k':
          ASSERT (c_tolower (c) == c);
          ASSERT (c_toupper (c) == 'K');
          break;
        case 'l':
          ASSERT (c_tolower (c) == c);
          ASSERT (c_toupper (c) == 'L');
          break;
        case 'm':
          ASSERT (c_tolower (c) == c);
          ASSERT (c_toupper (c) == 'M');
          break;
        case 'n':
          ASSERT (c_tolower (c) == c);
          ASSERT (c_toupper (c) == 'N');
          break;
        case 'o':
          ASSERT (c_tolower (c) == c);
          ASSERT (c_toupper (c) == 'O');
          break;
        case 'p':
          ASSERT (c_tolower (c) == c);
          ASSERT (c_toupper (c) == 'P');
          break;
        case 'q':
          ASSERT (c_tolower (c) == c);
          ASSERT (c_toupper (c) == 'Q');
          break;
        case 'r':
          ASSERT (c_tolower (c) == c);
          ASSERT (c_toupper (c) == 'R');
          break;
        case 's':
          ASSERT (c_tolower (c) == c);
          ASSERT (c_toupper (c) == 'S');
          break;
        case 't':
          ASSERT (c_tolower (c) == c);
          ASSERT (c_toupper (c) == 'T');
          break;
        case 'u':
          ASSERT (c_tolower (c) == c);
          ASSERT (c_toupper (c) == 'U');
          break;
        case 'v':
          ASSERT (c_tolower (c) == c);
          ASSERT (c_toupper (c) == 'V');
          break;
        case 'w':
          ASSERT (c_tolower (c) == c);
          ASSERT (c_toupper (c) == 'W');
          break;
        case 'x':
          ASSERT (c_tolower (c) == c);
          ASSERT (c_toupper (c) == 'X');
          break;
        case 'y':
          ASSERT (c_tolower (c) == c);
          ASSERT (c_toupper (c) == 'Y');
          break;
        case 'z':
          ASSERT (c_tolower (c) == c);
          ASSERT (c_toupper (c) == 'Z');
          break;
        default:
          ASSERT (c_tolower (c) == c);
          ASSERT (c_toupper (c) == c);
          break;
        }
    }
}
Exemplo n.º 8
0
/* Convert NPTR to a double.  If ENDPTR is not NULL, a pointer to the
   character after the last one used in the number is put in *ENDPTR.  */
double
strtod (const char *nptr, char **endptr)
{
  bool negative = false;

  /* The number so far.  */
  double num;

  const char *s = nptr;
  const char *end;
  char *endbuf;
  int saved_errno;

  /* Eat whitespace.  */
  while (locale_isspace (*s))
    ++s;

  /* Get the sign.  */
  negative = *s == '-';
  if (*s == '-' || *s == '+')
    ++s;

  saved_errno = errno;
  num = underlying_strtod (s, &endbuf);
  end = endbuf;

  if (c_isdigit (s[*s == '.']))
    {
      /* If a hex float was converted incorrectly, do it ourselves.
         If the string starts with "0x" but does not contain digits,
         consume the "0" ourselves.  If a hex float is followed by a
         'p' but no exponent, then adjust the end pointer.  */
      if (*s == '0' && c_tolower (s[1]) == 'x')
        {
          if (! c_isxdigit (s[2 + (s[2] == '.')]))
            end = s + 1;
          else if (end <= s + 2)
            {
              num = parse_number (s + 2, 16, 2, 4, 'p', &endbuf);
              end = endbuf;
            }
          else
            {
              const char *p = s + 2;
              while (p < end && c_tolower (*p) != 'p')
                p++;
              if (p < end && ! c_isdigit (p[1 + (p[1] == '-' || p[1] == '+')]))
                end = p;
            }
        }
      else
        {
          /* If "1e 1" was misparsed as 10.0 instead of 1.0, re-do the
             underlying strtod on a copy of the original string
             truncated to avoid the bug.  */
          const char *e = s + 1;
          while (e < end && c_tolower (*e) != 'e')
            e++;
          if (e < end && ! c_isdigit (e[1 + (e[1] == '-' || e[1] == '+')]))
            {
              char *dup = strdup (s);
              errno = saved_errno;
              if (!dup)
                {
                  /* Not really our day, is it.  Rounding errors are
                     better than outright failure.  */
                  num = parse_number (s, 10, 10, 1, 'e', &endbuf);
                }
              else
                {
                  dup[e - s] = '\0';
                  num = underlying_strtod (dup, &endbuf);
                  saved_errno = errno;
                  free (dup);
                  errno = saved_errno;
                }
              end = e;
            }
        }

      s = end;
    }

  /* Check for infinities and NaNs.  */
  else if (c_tolower (*s) == 'i'
           && c_tolower (s[1]) == 'n'
           && c_tolower (s[2]) == 'f')
    {
      s += 3;
      if (c_tolower (*s) == 'i'
          && c_tolower (s[1]) == 'n'
          && c_tolower (s[2]) == 'i'
          && c_tolower (s[3]) == 't'
          && c_tolower (s[4]) == 'y')
        s += 5;
      num = HUGE_VAL;
      errno = saved_errno;
    }
  else if (c_tolower (*s) == 'n'
           && c_tolower (s[1]) == 'a'
           && c_tolower (s[2]) == 'n')
    {
      s += 3;
      if (*s == '(')
        {
          const char *p = s + 1;
          while (c_isalnum (*p))
            p++;
          if (*p == ')')
            s = p + 1;
        }

      /* If the underlying implementation misparsed the NaN, assume
         its result is incorrect, and return a NaN.  Normally it's
         better to use the underlying implementation's result, since a
         nice implementation populates the bits of the NaN according
         to interpreting n-char-sequence as a hexadecimal number.  */
      if (s != end)
        num = NAN;
      errno = saved_errno;
    }
  else
    {
      /* No conversion could be performed.  */
      errno = EINVAL;
      s = nptr;
    }

  if (endptr != NULL)
    *endptr = (char *) s;
  /* Special case -0.0, since at least ICC miscompiles negation.  We
     can't use copysign(), as that drags in -lm on some platforms.  */
  if (!num && negative)
    return minus_zero;
  return negative ? -num : num;
}
Exemplo n.º 9
0
/* Parse a number at NPTR; this is a bit like strtol (NPTR, ENDPTR)
   except there are no leading spaces or signs or "0x", and ENDPTR is
   nonnull.  The number uses a base BASE (either 10 or 16) fraction, a
   radix RADIX (either 10 or 2) exponent, and exponent character
   EXPCHAR.  To convert from a number of digits to a radix exponent,
   multiply by RADIX_MULTIPLIER (either 1 or 4).  */
static double
parse_number (const char *nptr,
              int base, int radix, int radix_multiplier, char expchar,
              char **endptr)
{
  const char *s = nptr;
  bool got_dot = false;
  long int exponent = 0;
  double num = 0;

  for (;; ++s)
    {
      int digit;
      if (c_isdigit (*s))
        digit = *s - '0';
      else if (base == 16 && c_isxdigit (*s))
        digit = c_tolower (*s) - ('a' - 10);
      else if (! got_dot && *s == '.')
        {
          /* Record that we have found the decimal point.  */
          got_dot = true;
          continue;
        }
      else
        /* Any other character terminates the number.  */
        break;

      /* Make sure that multiplication by base will not overflow.  */
      if (num <= DBL_MAX / base)
        num = num * base + digit;
      else
        {
          /* The value of the digit doesn't matter, since we have already
             gotten as many digits as can be represented in a 'double'.
             This doesn't necessarily mean the result will overflow.
             The exponent may reduce it to within range.

             We just need to record that there was another
             digit so that we can multiply by 10 later.  */
          exponent += radix_multiplier;
        }

      /* Keep track of the number of digits after the decimal point.
         If we just divided by base here, we might lose precision.  */
      if (got_dot)
        exponent -= radix_multiplier;
    }

  if (c_tolower (*s) == expchar && ! locale_isspace (s[1]))
    {
      /* Add any given exponent to the implicit one.  */
      int save = errno;
      char *end;
      long int value = strtol (s + 1, &end, 10);
      errno = save;

      if (s + 1 != end)
        {
          /* Skip past the exponent, and add in the implicit exponent,
             resulting in an extreme value on overflow.  */
          s = end;
          exponent =
            (exponent < 0
             ? (value < LONG_MIN - exponent ? LONG_MIN : exponent + value)
             : (LONG_MAX - exponent < value ? LONG_MAX : exponent + value));
        }
    }

  *endptr = (char *) s;
  return scale_radix_exp (num, radix, exponent);
}
Exemplo n.º 10
0
Arquivo: strtod.c Projeto: 4solo/cs35
/* Convert NPTR to a double.  If ENDPTR is not NULL, a pointer to the
   character after the last one used in the number is put in *ENDPTR.  */
double
strtod (const char *nptr, char **endptr)
{
  const unsigned char *s;
  bool negative = false;

  /* The number so far.  */
  double num;

  bool got_dot;			/* Found a decimal point.  */
  bool got_digit;		/* Seen any digits.  */
  bool hex = false;		/* Look for hex float exponent.  */

  /* The exponent of the number.  */
  long int exponent;

  if (nptr == NULL)
    {
      errno = EINVAL;
      goto noconv;
    }

  /* Use unsigned char for the ctype routines.  */
  s = (unsigned char *) nptr;

  /* Eat whitespace.  */
  while (isspace (*s))
    ++s;

  /* Get the sign.  */
  negative = *s == '-';
  if (*s == '-' || *s == '+')
    ++s;

  num = 0.0;
  got_dot = false;
  got_digit = false;
  exponent = 0;

  /* Check for hex float.  */
  if (*s == '0' && c_tolower (s[1]) == 'x'
      && (c_isxdigit (s[2]) || ('.' == s[2] && c_isxdigit (s[3]))))
    {
      hex = true;
      s += 2;
      for (;; ++s)
	{
	  if (c_isxdigit (*s))
	    {
	      got_digit = true;

	      /* Make sure that multiplication by 16 will not overflow.  */
	      if (num > DBL_MAX / 16)
		/* The value of the digit doesn't matter, since we have already
		   gotten as many digits as can be represented in a `double'.
		   This doesn't necessarily mean the result will overflow.
		   The exponent may reduce it to within range.

		   We just need to record that there was another
		   digit so that we can multiply by 16 later.  */
		++exponent;
	      else
		num = ((num * 16.0)
		       + (c_tolower (*s) - (c_isdigit (*s) ? '0' : 'a' - 10)));

	      /* Keep track of the number of digits after the decimal point.
		 If we just divided by 16 here, we would lose precision.  */
	      if (got_dot)
		--exponent;
	    }
	  else if (!got_dot && *s == '.')
	    /* Record that we have found the decimal point.  */
	    got_dot = true;
	  else
	    /* Any other character terminates the number.  */
	    break;
	}
    }

  /* Not a hex float.  */
  else
    {
      for (;; ++s)
	{
	  if (c_isdigit (*s))
	    {
	      got_digit = true;

	      /* Make sure that multiplication by 10 will not overflow.  */
	      if (num > DBL_MAX * 0.1)
		/* The value of the digit doesn't matter, since we have already
		   gotten as many digits as can be represented in a `double'.
		   This doesn't necessarily mean the result will overflow.
		   The exponent may reduce it to within range.

		   We just need to record that there was another
		   digit so that we can multiply by 10 later.  */
		++exponent;
	      else
		num = (num * 10.0) + (*s - '0');

	      /* Keep track of the number of digits after the decimal point.
		 If we just divided by 10 here, we would lose precision.  */
	      if (got_dot)
		--exponent;
	    }
	  else if (!got_dot && *s == '.')
	    /* Record that we have found the decimal point.  */
	    got_dot = true;
	  else
	    /* Any other character terminates the number.  */
	    break;
	}
    }

  if (!got_digit)
    {
      /* Check for infinities and NaNs.  */
      if (c_tolower (*s) == 'i'
	  && c_tolower (s[1]) == 'n'
	  && c_tolower (s[2]) == 'f')
	{
	  s += 3;
	  num = HUGE_VAL;
	  if (c_tolower (*s) == 'i'
	      && c_tolower (s[1]) == 'n'
	      && c_tolower (s[2]) == 'i'
	      && c_tolower (s[3]) == 't'
	      && c_tolower (s[4]) == 'y')
	    s += 5;
	  goto valid;
	}
#ifdef NAN
      else if (c_tolower (*s) == 'n'
	       && c_tolower (s[1]) == 'a'
	       && c_tolower (s[2]) == 'n')
	{
	  s += 3;
	  num = NAN;
	  /* Since nan(<n-char-sequence>) is implementation-defined,
	     we define it by ignoring <n-char-sequence>.  A nicer
	     implementation would populate the bits of the NaN
	     according to interpreting n-char-sequence as a
	     hexadecimal number, but the result is still a NaN.  */
	  if (*s == '(')
	    {
	      const unsigned char *p = s + 1;
	      while (c_isalnum (*p))
		p++;
	      if (*p == ')')
		s = p + 1;
	    }
	  goto valid;
	}
#endif
      goto noconv;
    }

  if (c_tolower (*s) == (hex ? 'p' : 'e') && !isspace (s[1]))
    {
      /* Get the exponent specified after the `e' or `E'.  */
      int save = errno;
      char *end;
      long int value;

      errno = 0;
      ++s;
      value = strtol ((char *) s, &end, 10);
      if (errno == ERANGE && num)
	{
	  /* The exponent overflowed a `long int'.  It is probably a safe
	     assumption that an exponent that cannot be represented by
	     a `long int' exceeds the limits of a `double'.  */
	  if (endptr != NULL)
	    *endptr = end;
	  if (value < 0)
	    goto underflow;
	  else
	    goto overflow;
	}
      else if (end == (char *) s)
	/* There was no exponent.  Reset END to point to
	   the 'e' or 'E', so *ENDPTR will be set there.  */
	end = (char *) s - 1;
      errno = save;
      s = (unsigned char *) end;
      exponent += value;
    }

  if (num == 0.0)
    goto valid;

  if (hex)
    {
      /* ldexp takes care of range errors.  */
      num = ldexp (num, exponent);
      goto valid;
    }

  /* Multiply NUM by 10 to the EXPONENT power,
     checking for overflow and underflow.  */

  if (exponent < 0)
    {
      if (num < DBL_MIN * pow (10.0, (double) -exponent))
	goto underflow;
    }
  else if (exponent > 0)
    {
      if (num > DBL_MAX * pow (10.0, (double) -exponent))
	goto overflow;
    }

  num *= pow (10.0, (double) exponent);

 valid:
  if (endptr != NULL)
    *endptr = (char *) s;
  return negative ? -num : num;

 overflow:
  /* Return an overflow error.  */
  if (endptr != NULL)
    *endptr = (char *) s;
  errno = ERANGE;
  return negative ? -HUGE_VAL : HUGE_VAL;

 underflow:
  /* Return an underflow error.  */
  if (endptr != NULL)
    *endptr = (char *) s;
  errno = ERANGE;
  return negative ? -0.0 : 0.0;

 noconv:
  /* There was no number.  */
  if (endptr != NULL)
    *endptr = (char *) nptr;
  errno = EINVAL;
  return 0.0;
}
Exemplo n.º 11
0
/* Return true if a format is a valid choiceFormatPattern.
   Extracts argument type information into spec.  */
static bool
choice_format_parse (const char *format, struct spec *spec,
                     char **invalid_reason)
{
  /* Pattern syntax:
       pattern   := | choice | choice '|' pattern
       choice    := number separator messageformat
       separator := '<' | '#' | '\u2264'
     Single-quote starts a quoted section, to be terminated at the next
     single-quote or string end.  Double single-quote gives a single
     single-quote.
   */
  bool quoting = false;

  HANDLE_QUOTE;
  if (*format == '\0')
    return true;
  for (;;)
    {
      /* Don't bother looking too precisely into the syntax of the number.
         It can contain various Unicode characters.  */
      bool number_nonempty;
      char *msgformat;
      char *mp;
      bool msgformat_valid;

      /* Parse number.  */
      number_nonempty = false;
      while (*format != '\0'
             && !(!quoting && (*format == '<' || *format == '#'
                               || strncmp (format, "\\u2264", 6) == 0
                               || *format == '|')))
        {
          if (format[0] == '\\')
            {
              if (format[1] == 'u'
                  && c_isxdigit (format[2])
                  && c_isxdigit (format[3])
                  && c_isxdigit (format[4])
                  && c_isxdigit (format[5]))
                format += 6;
              else
                format += 2;
            }
          else
            format += 1;
          number_nonempty = true;
          HANDLE_QUOTE;
        }

      /* Short clause at end of pattern is valid and is ignored!  */
      if (*format == '\0')
        break;

      if (!number_nonempty)
        {
          *invalid_reason =
            xasprintf (_("In the directive number %u, a choice contains no number."), spec->directives);
          return false;
        }

      if (*format == '<' || *format == '#')
        format += 1;
      else if (strncmp (format, "\\u2264", 6) == 0)
        format += 6;
      else
        {
          *invalid_reason =
            xasprintf (_("In the directive number %u, a choice contains a number that is not followed by '<', '#' or '%s'."), spec->directives, "\\u2264");
          return false;
        }
      HANDLE_QUOTE;

      msgformat = (char *) xmalloca (strlen (format) + 1);
      mp = msgformat;

      while (*format != '\0' && !(!quoting && *format == '|'))
        {
          *mp++ = *format++;
          HANDLE_QUOTE;
        }
      *mp = '\0';

      msgformat_valid =
        message_format_parse (msgformat, NULL, spec, invalid_reason);

      freea (msgformat);

      if (!msgformat_valid)
        return false;

      if (*format == '\0')
        break;

      format++;
      HANDLE_QUOTE;
    }

  return true;
}
Exemplo n.º 12
0
/* Return true if a format is a valid numberFormatPattern.  */
static bool
number_format_parse (const char *format)
{
  /* Pattern Syntax:
       pattern     := pos_pattern{';' neg_pattern}
       pos_pattern := {prefix}number{suffix}
       neg_pattern := {prefix}number{suffix}
       number      := integer{'.' fraction}{exponent}
       prefix      := '\u0000'..'\uFFFD' - special_characters
       suffix      := '\u0000'..'\uFFFD' - special_characters
       integer     := min_int | '#' | '#' integer | '#' ',' integer
       min_int     := '0' | '0' min_int | '0' ',' min_int
       fraction    := '0'* '#'*
       exponent    := 'E' '0' '0'*
     Notation:
       X*       0 or more instances of X
       { X }    0 or 1 instances of X
       X | Y    either X or Y
       X..Y     any character from X up to Y, inclusive
       S - T    characters in S, except those in T
     Single-quote starts a quoted section, to be terminated at the next
     single-quote or string end.  Double single-quote gives a single
     single-quote.
   */
  bool quoting = false;
  bool seen_semicolon = false;

  HANDLE_QUOTE;
  for (;;)
    {
      /* Parse prefix.  */
      while (*format != '\0'
             && !(!quoting && (*format == '0' || *format == '#')))
        {
          if (format[0] == '\\')
            {
              if (format[1] == 'u'
                  && c_isxdigit (format[2])
                  && c_isxdigit (format[3])
                  && c_isxdigit (format[4])
                  && c_isxdigit (format[5]))
                format += 6;
              else
                format += 2;
            }
          else
            format += 1;
          HANDLE_QUOTE;
        }

      /* Parse integer.  */
      if (!(!quoting && (*format == '0' || *format == '#')))
        return false;
      while (!quoting && *format == '#')
        {
          format++;
          HANDLE_QUOTE;
          if (!quoting && *format == ',')
            {
              format++;
              HANDLE_QUOTE;
            }
        }
      while (!quoting && *format == '0')
        {
          format++;
          HANDLE_QUOTE;
          if (!quoting && *format == ',')
            {
              format++;
              HANDLE_QUOTE;
            }
        }

      /* Parse fraction.  */
      if (!quoting && *format == '.')
        {
          format++;
          HANDLE_QUOTE;
          while (!quoting && *format == '0')
            {
              format++;
              HANDLE_QUOTE;
            }
          while (!quoting && *format == '#')
            {
              format++;
              HANDLE_QUOTE;
            }
        }

      /* Parse exponent.  */
      if (!quoting && *format == 'E')
        {
          const char *format_save = format;
          format++;
          HANDLE_QUOTE;
          if (!quoting && *format == '0')
            {
              do
                {
                  format++;
                  HANDLE_QUOTE;
                }
              while (!quoting && *format == '0');
            }
          else
            {
              /* Back up.  */
              format = format_save;
              quoting = false;
            }
        }

      /* Parse suffix.  */
      while (*format != '\0'
             && (seen_semicolon || !(!quoting && *format == ';')))
        {
          if (format[0] == '\\')
            {
              if (format[1] == 'u'
                  && c_isxdigit (format[2])
                  && c_isxdigit (format[3])
                  && c_isxdigit (format[4])
                  && c_isxdigit (format[5]))
                format += 6;
              else
                format += 2;
            }
          else
            format += 1;
          HANDLE_QUOTE;
        }

      if (seen_semicolon || !(!quoting && *format == ';'))
        break;
    }

  return (*format == '\0');
}