2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License, Version 1.0 only
2N/A * (the "License"). You may not use this file except in compliance
2N/A * with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A#pragma ident "%Z%%M% %I% %E% SMI"
2N/A
2N/A/*
2N/A * This file contains the common part of the functions string_to_decimal,
2N/A * func_to_decimal, and file_to_decimal. Much of this code has been dupli-
2N/A * cated in wstring_to_decimal (see wstod.c) with some simplifications and
2N/A * appropriate modifications for wide characters. DO NOT fix a bug here
2N/A * without fixing the same bug in wstring_to_decimal, if it applies.
2N/A *
2N/A * The code below makes the following assumptions.
2N/A *
2N/A * 1. The first six parameters to the function are declared with the
2N/A * following names and types:
2N/A *
2N/A * char **ppc;
2N/A * int nmax;
2N/A * int fortran_conventions;
2N/A * decimal_record *pd;
2N/A * enum decimal_string_form *pform;
2N/A * char **pechar;
2N/A *
2N/A * 2. Before this file is #included, the following variables have been
2N/A * defined and initialized as shown:
2N/A *
2N/A * char *cp;
2N/A * char *good = *ppc - 1;
2N/A * int current;
2N/A * int nread;
2N/A *
2N/A * If the first character can be read successfully, then current is set
2N/A * to the value of the first character, cp is set to *ppc, (char)current
2N/A * is stored at *cp, and nread = 1. If the first character cannot be
2N/A * read successfully, then current = EOF and nread = 0.
2N/A *
2N/A * 3. The macro NEXT is defined to expand to code that implements
2N/A * the following logic:
2N/A *
2N/A * if (nread < nmax) {
2N/A * current = <next character>;
2N/A * if (current != EOF) {
2N/A * *++cp = (char)current;
2N/A * nread++;
2N/A * }
2N/A * } else
2N/A * current = EOF;
2N/A *
2N/A * Note that nread always reflects the number of characters successfully
2N/A * read, the buffer pointed to by *ppc gets filled only with characters
2N/A * that have been successfully read, and cp always points to the location
2N/A * in the buffer that was filled by the last character successfully read.
2N/A * current == EOF if and only if we can't read any more, either because
2N/A * we've reached the end of the input file or the buffer is full (i.e.,
2N/A * we've read nmax characters).
2N/A *
2N/A * 4. After this file is #included, the following variables may be used
2N/A * and will have the specified values:
2N/A *
2N/A * *ppc, *pd, *pform, and *pechar will be set as documented in the
2N/A * manual page;
2N/A * nmax and fortran_conventions will be unchanged;
2N/A * nread will be the number of characters actually read;
2N/A * cp will point to the last character actually read, provided at least
2N/A * one character was read successfully (in which case cp >= *ppc).
2N/A */
2N/A
2N/A#define UCASE(c) ((('a' <= c) && (c <= 'z'))? c - 32 : c)
2N/A
2N/A#define NZDIGIT(c) (('1' <= c && c <= '9') || ((int)form < 0 && \
2N/A (('a' <= c && c <= 'f') || ('A' <= c && c <= 'F'))))
2N/A
2N/A{
2N/A static const char *infstring = "INFINITY";
2N/A static const char *nanstring = "NAN";
2N/A
2N/A int sigfound, spacefound = 0;
2N/A int ids = 0;
2N/A int i, agree;
2N/A int nzbp = 0; /* number of zeros before point */
2N/A int nzap = 0; /* number of zeros after point */
2N/A char decpt;
2N/A int nfast, nfastlimit;
2N/A char *pfast;
2N/A int e, esign;
2N/A int expshift = 0;
2N/A enum decimal_string_form form;
2N/A
2N/A /*
2N/A * This routine assumes that the radix point is a single
2N/A * ASCII character, so that following this assignment, the
2N/A * condition (current == decpt) will correctly detect it.
2N/A */
2N/A if (fortran_conventions > 0)
2N/A decpt = '.';
2N/A else
2N/A decpt = *(localeconv()->decimal_point);
2N/A
2N/A /* input is invalid until we find something */
2N/A pd->fpclass = fp_signaling;
2N/A pd->sign = 0;
2N/A pd->exponent = 0;
2N/A pd->ds[0] = '\0';
2N/A pd->more = 0;
2N/A pd->ndigits = 0;
2N/A *pform = form = invalid_form;
2N/A *pechar = NULL;
2N/A
2N/A /* skip white space */
2N/A while (isspace(current)) {
2N/A spacefound = 1;
2N/A NEXT;
2N/A }
2N/A
2N/A if (fortran_conventions >= 2 && spacefound) {
2N/A /*
2N/A * We found at least one white space character. For
2N/A * Fortran formatted input, accept this; if we don't
2N/A * find anything else, we'll interpret it as a valid zero.
2N/A */
2N/A pd->fpclass = fp_zero;
2N/A form = whitespace_form;
2N/A sigfound = 0; /* 0 = only zeros found so far */
2N/A if (current == EOF) {
2N/A good = cp;
2N/A goto done;
2N/A } else {
2N/A good = cp - 1;
2N/A }
2N/A } else {
2N/A sigfound = -1; /* -1 = no digits found yet */
2N/A }
2N/A
2N/A /* look for optional leading sign */
2N/A if (current == '+') {
2N/A NEXT;
2N/A } else if (current == '-') {
2N/A pd->sign = 1;
2N/A NEXT;
2N/A }
2N/A
2N/A /*
2N/A * Admissible first non-white-space, non-sign characters are
2N/A * 0-9, i, I, n, N, or the radix point.
2N/A */
2N/A if ('1' <= current && current <= '9') {
2N/A good = cp;
2N/A pd->fpclass = fp_normal;
2N/A form = fixed_int_form;
2N/A sigfound = 1; /* 1 = significant digits found */
2N/A pd->ds[ids++] = (char)current;
2N/A NEXT;
2N/A } else {
2N/A switch (current) {
2N/A case ' ':
2N/A if (fortran_conventions < 2)
2N/A goto done;
2N/A /*
2N/A * When fortran_conventions >= 2, treat leading
2N/A * blanks the same as leading zeroes.
2N/A */
2N/A /*FALLTHRU*/
2N/A
2N/A case '0':
2N/A /*
2N/A * Accept the leading zero and set pd->fpclass
2N/A * accordingly, but don't set sigfound until we
2N/A * determine that this isn't a "fake" hex string
2N/A * (i.e., 0x.p...).
2N/A */
2N/A good = cp;
2N/A pd->fpclass = fp_zero;
2N/A if (fortran_conventions < 0) {
2N/A /* look for a hex fp string */
2N/A NEXT;
2N/A if (current == 'X' || current == 'x') {
2N/A /* assume hex fp form */
2N/A form = (enum decimal_string_form)-1;
2N/A expshift = 2;
2N/A NEXT;
2N/A /*
2N/A * Only a digit or radix point can
2N/A * follow "0x".
2N/A */
2N/A if (NZDIGIT(current)) {
2N/A pd->fpclass = fp_normal;
2N/A good = cp;
2N/A sigfound = 1;
2N/A pd->ds[ids++] = (char)current;
2N/A NEXT;
2N/A break;
2N/A } else if (current == decpt) {
2N/A NEXT;
2N/A goto afterpoint;
2N/A } else if (current != '0') {
2N/A /* not hex fp after all */
2N/A form = fixed_int_form;
2N/A expshift = 0;
2N/A goto done;
2N/A }
2N/A } else {
2N/A form = fixed_int_form;
2N/A }
2N/A } else {
2N/A form = fixed_int_form;
2N/A }
2N/A
2N/A /* skip all leading zeros */
2N/A while (current == '0' || (current == ' ' &&
2N/A fortran_conventions >= 2)) {
2N/A NEXT;
2N/A }
2N/A sigfound = 0; /* 0 = only zeros found so far */
2N/A if (current == EOF) {
2N/A good = cp;
2N/A goto done;
2N/A } else {
2N/A good = cp - 1;
2N/A }
2N/A break;
2N/A
2N/A case 'i':
2N/A case 'I':
2N/A /* look for inf or infinity */
2N/A NEXT;
2N/A agree = 1;
2N/A while (agree <= 7 &&
2N/A UCASE(current) == infstring[agree]) {
2N/A NEXT;
2N/A agree++;
2N/A }
2N/A if (agree < 3)
2N/A goto done;
2N/A /* found valid infinity */
2N/A pd->fpclass = fp_infinity;
2N/A sigfound = 1;
2N/A __inf_read = 1;
2N/A if (agree < 8) {
2N/A good = (current == EOF)? cp + 3 - agree :
2N/A cp + 2 - agree;
2N/A form = inf_form;
2N/A } else {
2N/A good = (current == EOF)? cp : cp - 1;
2N/A form = infinity_form;
2N/A }
2N/A /*
2N/A * Accept trailing blanks if no extra characters
2N/A * intervene.
2N/A */
2N/A if (fortran_conventions >= 2 && (agree == 3 ||
2N/A agree == 8)) {
2N/A while (current == ' ') {
2N/A NEXT;
2N/A }
2N/A good = (current == EOF)? cp : cp - 1;
2N/A }
2N/A goto done;
2N/A
2N/A case 'n':
2N/A case 'N':
2N/A /* look for nan or nan(string) */
2N/A NEXT;
2N/A agree = 1;
2N/A while (agree <= 2 &&
2N/A UCASE(current) == nanstring[agree]) {
2N/A NEXT;
2N/A agree++;
2N/A }
2N/A if (agree < 3)
2N/A goto done;
2N/A /* found valid NaN */
2N/A good = (current == EOF)? cp : cp - 1;
2N/A pd->fpclass = fp_quiet;
2N/A form = nan_form;
2N/A sigfound = 1;
2N/A __nan_read = 1;
2N/A if (current == '(') {
2N/A /* accept parenthesized string */
2N/A NEXT;
2N/A if (fortran_conventions < 0) {
2N/A while ((isalnum(current) ||
2N/A current == '_') &&
2N/A ids < DECIMAL_STRING_LENGTH - 1) {
2N/A pd->ds[ids++] = (char)current;
2N/A NEXT;
2N/A }
2N/A while (isalnum(current) ||
2N/A current == '_') {
2N/A pd->more = 1;
2N/A NEXT;
2N/A }
2N/A } else {
2N/A while (current > 0 && current != ')' &&
2N/A ids < DECIMAL_STRING_LENGTH - 1) {
2N/A pd->ds[ids++] = (char)current;
2N/A NEXT;
2N/A }
2N/A while (current > 0 && current != ')') {
2N/A pd->more = 1;
2N/A NEXT;
2N/A }
2N/A }
2N/A if (current != ')')
2N/A goto done;
2N/A good = cp;
2N/A form = nanstring_form;
2N/A /* prepare for loop below */
2N/A if (fortran_conventions >= 2) {
2N/A NEXT;
2N/A }
2N/A }
2N/A /* accept trailing blanks */
2N/A if (fortran_conventions >= 2) {
2N/A while (current == ' ') {
2N/A NEXT;
2N/A }
2N/A good = (current == EOF)? cp : cp - 1;
2N/A }
2N/A goto done;
2N/A
2N/A default:
2N/A if (current == decpt) {
2N/A /*
2N/A * Don't accept the radix point just yet;
2N/A * we need to see at least one digit.
2N/A */
2N/A NEXT;
2N/A goto afterpoint;
2N/A }
2N/A goto done;
2N/A }
2N/A }
2N/A
2N/Anextnumber:
2N/A /*
2N/A * Admissible characters after the first digit are a valid digit,
2N/A * an exponent delimiter (E or e for any decimal form; +, -, D, d,
2N/A * Q, or q when fortran_conventions >= 2; P or p for hex form),
2N/A * or the radix point. (Note that we can't get here unless we've
2N/A * already found a digit.)
2N/A */
2N/A if (NZDIGIT(current)) {
2N/A /*
2N/A * Found another nonzero digit. If there's enough room
2N/A * in pd->ds, store any intervening zeros we've found so far
2N/A * and then store this digit. Otherwise, stop storing
2N/A * digits in pd->ds and set pd->more.
2N/A */
2N/A if (ids + nzbp + 2 < DECIMAL_STRING_LENGTH) {
2N/A for (i = 0; i < nzbp; i++)
2N/A pd->ds[ids++] = '0';
2N/A pd->ds[ids++] = (char)current;
2N/A } else {
2N/A pd->exponent += (nzbp + 1) << expshift;
2N/A pd->more = 1;
2N/A if (ids < DECIMAL_STRING_LENGTH) {
2N/A pd->ds[ids] = '\0';
2N/A pd->ndigits = ids;
2N/A /* don't store any more digits */
2N/A ids = DECIMAL_STRING_LENGTH;
2N/A }
2N/A }
2N/A pd->fpclass = fp_normal;
2N/A sigfound = 1;
2N/A nzbp = 0;
2N/A NEXT;
2N/A
2N/A /*
2N/A * Use an optimized loop to grab a consecutive sequence
2N/A * of nonzero digits quickly.
2N/A */
2N/A nfastlimit = DECIMAL_STRING_LENGTH - 3 - ids;
2N/A for (nfast = 0, pfast = &(pd->ds[ids]);
2N/A nfast < nfastlimit && NZDIGIT(current);
2N/A nfast++) {
2N/A *pfast++ = (char)current;
2N/A NEXT;
2N/A }
2N/A ids += nfast;
2N/A if (current == '0')
2N/A goto nextnumberzero; /* common case */
2N/A /* advance good to the last accepted digit */
2N/A good = (current == EOF)? cp : cp - 1;
2N/A goto nextnumber;
2N/A } else {
2N/A switch (current) {
2N/A case ' ':
2N/A if (fortran_conventions < 2)
2N/A goto done;
2N/A if (fortran_conventions == 2) {
2N/A while (current == ' ') {
2N/A NEXT;
2N/A }
2N/A good = (current == EOF)? cp : cp - 1;
2N/A goto nextnumber;
2N/A }
2N/A /*
2N/A * When fortran_conventions > 2, treat internal
2N/A * blanks the same as zeroes.
2N/A */
2N/A /*FALLTHRU*/
2N/A
2N/A case '0':
2N/Anextnumberzero:
2N/A /*
2N/A * Count zeros before the radix point. Later we
2N/A * will either put these zeros into pd->ds or add
2N/A * nzbp to pd->exponent to account for them.
2N/A */
2N/A while (current == '0' || (current == ' ' &&
2N/A fortran_conventions > 2)) {
2N/A nzbp++;
2N/A NEXT;
2N/A }
2N/A good = (current == EOF)? cp : cp - 1;
2N/A goto nextnumber;
2N/A
2N/A case '+':
2N/A case '-':
2N/A case 'D':
2N/A case 'd':
2N/A case 'Q':
2N/A case 'q':
2N/A /*
2N/A * Only accept these as the start of the exponent
2N/A * field if fortran_conventions is positive.
2N/A */
2N/A if (fortran_conventions <= 0)
2N/A goto done;
2N/A /*FALLTHRU*/
2N/A
2N/A case 'E':
2N/A case 'e':
2N/A if ((int)form < 0)
2N/A goto done;
2N/A goto exponent;
2N/A
2N/A case 'P':
2N/A case 'p':
2N/A if ((int)form > 0)
2N/A goto done;
2N/A goto exponent;
2N/A
2N/A default:
2N/A if (current == decpt) {
2N/A /* accept the radix point */
2N/A good = cp;
2N/A if (form == fixed_int_form)
2N/A form = fixed_intdot_form;
2N/A NEXT;
2N/A goto afterpoint;
2N/A }
2N/A goto done;
2N/A }
2N/A }
2N/A
2N/Aafterpoint:
2N/A /*
2N/A * Admissible characters after the radix point are a valid digit
2N/A * or an exponent delimiter. (Note that it is possible to get
2N/A * here even though we haven't found any digits yet.)
2N/A */
2N/A if (NZDIGIT(current)) {
2N/A /* found a digit after the point; revise form */
2N/A if (form == invalid_form || form == whitespace_form)
2N/A form = fixed_dotfrac_form;
2N/A else if (form == fixed_intdot_form)
2N/A form = fixed_intdotfrac_form;
2N/A good = cp;
2N/A if (sigfound < 1) {
2N/A /* no significant digits found until now */
2N/A pd->fpclass = fp_normal;
2N/A sigfound = 1;
2N/A pd->ds[ids++] = (char)current;
2N/A pd->exponent = (-(nzap + 1)) << expshift;
2N/A } else {
2N/A /* significant digits have been found */
2N/A if (ids + nzbp + nzap + 2 < DECIMAL_STRING_LENGTH) {
2N/A for (i = 0; i < nzbp + nzap; i++)
2N/A pd->ds[ids++] = '0';
2N/A pd->ds[ids++] = (char)current;
2N/A pd->exponent -= (nzap + 1) << expshift;
2N/A } else {
2N/A pd->exponent += nzbp << expshift;
2N/A pd->more = 1;
2N/A if (ids < DECIMAL_STRING_LENGTH) {
2N/A pd->ds[ids] = '\0';
2N/A pd->ndigits = ids;
2N/A /* don't store any more digits */
2N/A ids = DECIMAL_STRING_LENGTH;
2N/A }
2N/A }
2N/A }
2N/A nzbp = 0;
2N/A nzap = 0;
2N/A NEXT;
2N/A
2N/A /*
2N/A * Use an optimized loop to grab a consecutive sequence
2N/A * of nonzero digits quickly.
2N/A */
2N/A nfastlimit = DECIMAL_STRING_LENGTH - 3 - ids;
2N/A for (nfast = 0, pfast = &(pd->ds[ids]);
2N/A nfast < nfastlimit && NZDIGIT(current);
2N/A nfast++) {
2N/A *pfast++ = (char)current;
2N/A NEXT;
2N/A }
2N/A ids += nfast;
2N/A pd->exponent -= nfast << expshift;
2N/A if (current == '0')
2N/A goto zeroafterpoint;
2N/A /* advance good to the last accepted digit */
2N/A good = (current == EOF)? cp : cp - 1;
2N/A goto afterpoint;
2N/A } else {
2N/A switch (current) {
2N/A case ' ':
2N/A if (fortran_conventions < 2)
2N/A goto done;
2N/A if (fortran_conventions == 2) {
2N/A /*
2N/A * Treat a radix point followed by blanks
2N/A * but no digits as zero so we'll pass FCVS.
2N/A */
2N/A if (sigfound == -1) {
2N/A pd->fpclass = fp_zero;
2N/A sigfound = 0;
2N/A }
2N/A while (current == ' ') {
2N/A NEXT;
2N/A }
2N/A good = (current == EOF)? cp : cp - 1;
2N/A goto afterpoint;
2N/A }
2N/A /*
2N/A * when fortran_conventions > 2, treat internal
2N/A * blanks the same as zeroes
2N/A */
2N/A /*FALLTHRU*/
2N/A
2N/A case '0':
2N/A /* found a digit after the point; revise form */
2N/A if (form == invalid_form || form == whitespace_form)
2N/A form = fixed_dotfrac_form;
2N/A else if (form == fixed_intdot_form)
2N/A form = fixed_intdotfrac_form;
2N/A if (sigfound == -1) {
2N/A pd->fpclass = fp_zero;
2N/A sigfound = 0;
2N/A }
2N/Azeroafterpoint:
2N/A /*
2N/A * Count zeros after the radix point. If we find
2N/A * any more nonzero digits later, we will put these
2N/A * zeros into pd->ds and decrease pd->exponent by
2N/A * nzap.
2N/A */
2N/A while (current == '0' || (current == ' ' &&
2N/A fortran_conventions > 2)) {
2N/A nzap++;
2N/A NEXT;
2N/A }
2N/A if (current == EOF) {
2N/A good = cp;
2N/A goto done;
2N/A } else {
2N/A good = cp - 1;
2N/A }
2N/A goto afterpoint;
2N/A
2N/A case '+':
2N/A case '-':
2N/A case 'D':
2N/A case 'd':
2N/A case 'Q':
2N/A case 'q':
2N/A /*
2N/A * Only accept these as the start of the exponent
2N/A * field if fortran_conventions is positive.
2N/A */
2N/A if (fortran_conventions <= 0)
2N/A goto done;
2N/A /*FALLTHRU*/
2N/A
2N/A case 'E':
2N/A case 'e':
2N/A /* don't accept exponent without preceding digits */
2N/A if (sigfound == -1 || (int)form < 0)
2N/A goto done;
2N/A break;
2N/A
2N/A case 'P':
2N/A case 'p':
2N/A /* don't accept exponent without preceding digits */
2N/A if (sigfound == -1 || (int)form > 0)
2N/A goto done;
2N/A break;
2N/A
2N/A default:
2N/A goto done;
2N/A }
2N/A }
2N/A
2N/Aexponent:
2N/A /*
2N/A * Set *pechar to point to the character that looks like the
2N/A * beginning of the exponent field, then attempt to parse it.
2N/A */
2N/A *pechar = cp;
2N/A if (current != '+' && current != '-') {
2N/A /* skip the exponent character and following blanks */
2N/A NEXT;
2N/A if (fortran_conventions >= 2 && current == ' ') {
2N/A while (current == ' ') {
2N/A NEXT;
2N/A }
2N/A if (fortran_conventions > 2)
2N/A good = (current == EOF)? cp : cp - 1;
2N/A }
2N/A }
2N/A
2N/A e = 0;
2N/A esign = 0;
2N/A
2N/A /* look for optional exponent sign */
2N/A if (current == '+') {
2N/A NEXT;
2N/A } else if (current == '-') {
2N/A esign = 1;
2N/A NEXT;
2N/A }
2N/A
2N/A /*
2N/A * Accumulate explicit exponent. Note that if we don't find at
2N/A * least one digit, good won't be updated and e will remain 0.
2N/A * Also, we keep e from getting too large so we don't overflow
2N/A * the range of int (but notice that the threshold is large
2N/A * enough that any larger e would cause the result to underflow
2N/A * or overflow anyway).
2N/A */
2N/A while (('0' <= current && current <= '9') || current == ' ') {
2N/A if (current == ' ') {
2N/A if (fortran_conventions < 2)
2N/A break;
2N/A if (fortran_conventions == 2) {
2N/A NEXT;
2N/A continue;
2N/A }
2N/A current = '0';
2N/A }
2N/A good = cp;
2N/A if (e <= 1000000)
2N/A e = 10 * e + current - '0';
2N/A NEXT;
2N/A if (fortran_conventions == 2 && current == ' ') {
2N/A /* accept trailing blanks */
2N/A while (current == ' ') {
2N/A NEXT;
2N/A }
2N/A good = (current == EOF)? cp : cp - 1;
2N/A }
2N/A }
2N/A if (esign == 1)
2N/A pd->exponent -= e;
2N/A else
2N/A pd->exponent += e;
2N/A
2N/A /*
2N/A * If we successfully parsed an exponent field, update form
2N/A * accordingly. If we didn't, don't set *pechar.
2N/A */
2N/A if (good >= *pechar) {
2N/A switch (form) {
2N/A case whitespace_form:
2N/A case fixed_int_form:
2N/A form = floating_int_form;
2N/A break;
2N/A
2N/A case fixed_intdot_form:
2N/A form = floating_intdot_form;
2N/A break;
2N/A
2N/A case fixed_dotfrac_form:
2N/A form = floating_dotfrac_form;
2N/A break;
2N/A
2N/A case fixed_intdotfrac_form:
2N/A form = floating_intdotfrac_form;
2N/A break;
2N/A }
2N/A } else {
2N/A *pechar = NULL;
2N/A }
2N/A
2N/Adone:
2N/A /*
2N/A * If we found any zeros before the radix point that were not
2N/A * accounted for earlier, adjust the exponent. (This is only
2N/A * relevant when pd->fpclass == fp_normal, but it's harmless
2N/A * in all other cases.)
2N/A */
2N/A pd->exponent += nzbp << expshift;
2N/A
2N/A /* terminate pd->ds if we haven't already */
2N/A if (ids < DECIMAL_STRING_LENGTH) {
2N/A pd->ds[ids] = '\0';
2N/A pd->ndigits = ids;
2N/A }
2N/A
2N/A /*
2N/A * If we accepted any characters, advance *ppc to point to the
2N/A * first character we didn't accept; otherwise, pass back a
2N/A * signaling nan.
2N/A */
2N/A if (good >= *ppc) {
2N/A *ppc = good + 1;
2N/A } else {
2N/A pd->fpclass = fp_signaling;
2N/A pd->sign = 0;
2N/A form = invalid_form;
2N/A }
2N/A
2N/A *pform = form;
2N/A}