int __vfprintf(FILE *fp, const char *fmt0, __va_list ap) { char *fmt; /* format string */ int ch; /* character from fmt */ int n, n2; /* handy integers (short term usage) */ char *cp; /* handy char pointer (short term usage) */ struct __siov *iovp; /* for PRINT macro */ int flags; /* flags as above */ int ret; /* return value accumulator */ int width; /* width from format (%8d), or 0 */ int prec; /* precision from format; <0 for N/A */ char sign; /* sign prefix (' ', '+', '-', or \0) */ wchar_t wc; mbstate_t ps; #ifdef FLOATING_POINT /* * We can decompose the printed representation of floating * point numbers into several parts, some of which may be empty: * * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ * A B ---C--- D E F * * A: 'sign' holds this value if present; '\0' otherwise * B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal * C: cp points to the string MMMNNN. Leading and trailing * zeros are not in the string and must be added. * D: expchar holds this character; '\0' if no exponent, e.g. %f * F: at least two digits for decimal, at least one digit for hex */ char *decimal_point = NULL; int signflag; /* true if float is negative */ union { /* floating point arguments %[aAeEfFgG] */ double dbl; long double ldbl; } fparg; int expt; /* integer value of exponent */ char expchar; /* exponent character: [eEpP\0] */ char *dtoaend; /* pointer to end of converted digits */ int expsize; /* character count for expstr */ int lead; /* sig figs before decimal or group sep */ int ndig; /* actual number of digits returned by dtoa */ char expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */ char *dtoaresult = NULL; #endif uintmax_t _umax; /* integer arguments %[diouxX] */ enum { OCT, DEC, HEX } base; /* base for %[diouxX] conversion */ int dprec; /* a copy of prec if %[diouxX], 0 otherwise */ int realsz; /* field size expanded by dprec */ int size; /* size of converted field or string */ const char *xdigs; /* digits for %[xX] conversion */ #define NIOV 8 struct __suio uio; /* output information: summary */ struct __siov iov[NIOV];/* ... and individual io vectors */ char buf[BUF]; /* buffer with space for digits of uintmax_t */ char ox[2]; /* space for 0x; ox[1] is either x, X, or \0 */ union arg *argtable; /* args, built due to positional arg */ union arg statargtable[STATIC_ARG_TBL_SIZE]; size_t argtablesiz; int nextarg; /* 1-based argument index */ va_list orgap; /* original argument pointer */ #ifdef PRINTF_WIDE_CHAR char *convbuf; /* buffer for wide to multi-byte conversion */ #endif /* * Choose PADSIZE to trade efficiency vs. size. If larger printf * fields occur frequently, increase PADSIZE and make the initialisers * below longer. */ #define PADSIZE 16 /* pad chunk size */ static char blanks[PADSIZE] = {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; static char zeroes[PADSIZE] = {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; static const char xdigs_lower[16] = "0123456789abcdef"; static const char xdigs_upper[16] = "0123456789ABCDEF"; /* * BEWARE, these `goto error' on error, and PAD uses `n'. */ #define PRINT(ptr, len) do { \ iovp->iov_base = (ptr); \ iovp->iov_len = (len); \ uio.uio_resid += (len); \ iovp++; \ if (++uio.uio_iovcnt >= NIOV) { \ if (__sprint(fp, &uio)) \ goto error; \ iovp = iov; \ } \ } while (0) #define PAD(howmany, with) do { \ if ((n = (howmany)) > 0) { \ while (n > PADSIZE) { \ PRINT(with, PADSIZE); \ n -= PADSIZE; \ } \ PRINT(with, n); \ } \ } while (0) #define PRINTANDPAD(p, ep, len, with) do { \ n2 = (ep) - (p); \ if (n2 > (len)) \ n2 = (len); \ if (n2 > 0) \ PRINT((p), n2); \ PAD((len) - (n2 > 0 ? n2 : 0), (with)); \ } while(0) #define FLUSH() do { \ if (uio.uio_resid && __sprint(fp, &uio)) \ goto error; \ uio.uio_iovcnt = 0; \ iovp = iov; \ } while (0) /* * To extend shorts properly, we need both signed and unsigned * argument extraction methods. */ #define SARG() \ ((intmax_t)(flags&MAXINT ? GETARG(intmax_t) : \ flags&LLONGINT ? GETARG(long long) : \ flags&LONGINT ? GETARG(long) : \ flags&PTRINT ? GETARG(ptrdiff_t) : \ flags&SIZEINT ? GETARG(ssize_t) : \ flags&SHORTINT ? (short)GETARG(int) : \ flags&CHARINT ? (__signed char)GETARG(int) : \ GETARG(int))) #define UARG() \ ((uintmax_t)(flags&MAXINT ? GETARG(uintmax_t) : \ flags&LLONGINT ? GETARG(unsigned long long) : \ flags&LONGINT ? GETARG(unsigned long) : \ flags&PTRINT ? (uintptr_t)GETARG(ptrdiff_t) : /* XXX */ \ flags&SIZEINT ? GETARG(size_t) : \ flags&SHORTINT ? (unsigned short)GETARG(int) : \ flags&CHARINT ? (unsigned char)GETARG(int) : \ GETARG(unsigned int))) /* * Append a digit to a value and check for overflow. */ #define APPEND_DIGIT(val, dig) do { \ if ((val) > INT_MAX / 10) \ goto overflow; \ (val) *= 10; \ if ((val) > INT_MAX - to_digit((dig))) \ goto overflow; \ (val) += to_digit((dig)); \ } while (0) /* * Get * arguments, including the form *nn$. Preserve the nextarg * that the argument can be gotten once the type is determined. */ #define GETASTER(val) \ n2 = 0; \ cp = fmt; \ while (is_digit(*cp)) { \ APPEND_DIGIT(n2, *cp); \ cp++; \ } \ if (*cp == '$') { \ int hold = nextarg; \ if (argtable == NULL) { \ argtable = statargtable; \ __find_arguments(fmt0, orgap, &argtable, &argtablesiz); \ } \ nextarg = n2; \ val = GETARG(int); \ nextarg = hold; \ fmt = ++cp; \ } else { \ val = GETARG(int); \ } /* * Get the argument indexed by nextarg. If the argument table is * built, use it to get the argument. If its not, get the next * argument (and arguments must be gotten sequentially). */ #define GETARG(type) \ ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \ (nextarg++, va_arg(ap, type))) _SET_ORIENTATION(fp, -1); /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */ if (cantwrite(fp)) { errno = EBADF; return (EOF); } /* optimise fprintf(stderr) (and other unbuffered Unix files) */ if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && fp->_file >= 0) return (__sbprintf(fp, fmt0, ap)); fmt = (char *)fmt0; argtable = NULL; nextarg = 1; va_copy(orgap, ap); uio.uio_iov = iovp = iov; uio.uio_resid = 0; uio.uio_iovcnt = 0; ret = 0; #ifdef PRINTF_WIDE_CHAR convbuf = NULL; #endif memset(&ps, 0, sizeof(ps)); /* * Scan the format for conversions (`%' character). */ for (;;) { cp = fmt; while ((n = mbrtowc(&wc, fmt, MB_CUR_MAX, &ps)) > 0) { fmt += n; if (wc == '%') { fmt--; break; } } if (fmt != cp) { ptrdiff_t m = fmt - cp; if (m < 0 || m > INT_MAX - ret) goto overflow; PRINT(cp, m); ret += m; } if (n <= 0) goto done; fmt++; /* skip over '%' */ flags = 0; dprec = 0; width = 0; prec = -1; sign = '\0'; ox[1] = '\0'; rflag: ch = *fmt++; reswitch: switch (ch) { case ' ': /* * ``If the space and + flags both appear, the space * flag will be ignored.'' * -- ANSI X3J11 */ if (!sign) sign = ' '; goto rflag; case '#': flags |= ALT; goto rflag; case '\'': /* grouping not implemented */ goto rflag; case '*': /* * ``A negative field width argument is taken as a * - flag followed by a positive field width.'' * -- ANSI X3J11 * They don't exclude field widths read from args. */ GETASTER(width); if (width >= 0) goto rflag; if (width == INT_MIN) goto overflow; width = -width; /* FALLTHROUGH */ case '-': flags |= LADJUST; goto rflag; case '+': sign = '+'; goto rflag; case '.': if ((ch = *fmt++) == '*') { GETASTER(n); prec = n < 0 ? -1 : n; goto rflag; } n = 0; while (is_digit(ch)) { APPEND_DIGIT(n, ch); ch = *fmt++; } if (ch == '$') { nextarg = n; if (argtable == NULL) { argtable = statargtable; __find_arguments(fmt0, orgap, &argtable, &argtablesiz); } goto rflag; } prec = n; goto reswitch; case '0': /* * ``Note that 0 is taken as a flag, not as the * beginning of a field width.'' * -- ANSI X3J11 */ flags |= ZEROPAD; goto rflag; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': n = 0; do { APPEND_DIGIT(n, ch); ch = *fmt++; } while (is_digit(ch)); if (ch == '$') { nextarg = n; if (argtable == NULL) { argtable = statargtable; __find_arguments(fmt0, orgap, &argtable, &argtablesiz); } goto rflag; } width = n; goto reswitch; #ifdef FLOATING_POINT case 'L': flags |= LONGDBL; goto rflag; #endif case 'h': if (*fmt == 'h') { fmt++; flags |= CHARINT; } else { flags |= SHORTINT; } goto rflag; case 'j': flags |= MAXINT; goto rflag; case 'l': if (*fmt == 'l') { fmt++; flags |= LLONGINT; } else { flags |= LONGINT; } goto rflag; case 'q': flags |= LLONGINT; goto rflag; case 't': flags |= PTRINT; goto rflag; case 'z': flags |= SIZEINT; goto rflag; case 'c': #ifdef PRINTF_WIDE_CHAR if (flags & LONGINT) { mbstate_t mbs; size_t mbseqlen; memset(&mbs, 0, sizeof(mbs)); mbseqlen = wcrtomb(buf, (wchar_t)GETARG(wint_t), &mbs); if (mbseqlen == (size_t)-1) { fp->_flags |= __SERR; errno = EILSEQ; goto error; } cp = buf; size = (int)mbseqlen; } else { #endif *(cp = buf) = GETARG(int); size = 1; #ifdef PRINTF_WIDE_CHAR } #endif sign = '\0'; break; case 'D': flags |= LONGINT; /*FALLTHROUGH*/ case 'd': case 'i': _umax = SARG(); if ((intmax_t)_umax < 0) { _umax = -_umax; sign = '-'; } base = DEC; goto number; #ifdef FLOATING_POINT case 'a': case 'A': if (ch == 'a') { ox[1] = 'x'; xdigs = xdigs_lower; expchar = 'p'; } else { ox[1] = 'X'; xdigs = xdigs_upper; expchar = 'P'; } if (prec >= 0) prec++; if (dtoaresult) __freedtoa(dtoaresult); if (flags & LONGDBL) { fparg.ldbl = GETARG(long double); dtoaresult = cp = __hldtoa(fparg.ldbl, xdigs, prec, &expt, &signflag, &dtoaend); if (dtoaresult == NULL) { errno = ENOMEM; goto error; } } else { fparg.dbl = GETARG(double); dtoaresult = cp = __hdtoa(fparg.dbl, xdigs, prec, &expt, &signflag, &dtoaend); if (dtoaresult == NULL) { errno = ENOMEM; goto error; } } if (prec < 0) prec = dtoaend - cp; if (expt == INT_MAX) ox[1] = '\0'; goto fp_common; case 'e': case 'E': expchar = ch; if (prec < 0) /* account for digit before decpt */ prec = DEFPREC + 1; else prec++; goto fp_begin; case 'f': case 'F': expchar = '\0'; goto fp_begin; case 'g': case 'G': expchar = ch - ('g' - 'e'); if (prec == 0) prec = 1; fp_begin: if (prec < 0) prec = DEFPREC; if (dtoaresult) __freedtoa(dtoaresult); if (flags & LONGDBL) { fparg.ldbl = GETARG(long double); dtoaresult = cp = __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec, &expt, &signflag, &dtoaend); if (dtoaresult == NULL) { errno = ENOMEM; goto error; } } else {
/* * Non-MT-safe version */ int __vfprintf(FILE *fp, locale_t locale, const char *fmt0, __va_list ap) { char *fmt; /* format string */ int ch; /* character from fmt */ int n, n2; /* handy integers (short term usage) */ char *cp; /* handy char pointer (short term usage) */ int flags; /* flags as above */ int ret; /* return value accumulator */ int width; /* width from format (%8d), or 0 */ int prec; /* precision from format; <0 for N/A */ char sign; /* sign prefix (' ', '+', '-', or \0) */ struct grouping_state gs; /* thousands' grouping info */ #ifdef FLOATING_POINT /* * We can decompose the printed representation of floating * point numbers into several parts, some of which may be empty: * * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ * A B ---C--- D E F * * A: 'sign' holds this value if present; '\0' otherwise * B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal * C: cp points to the string MMMNNN. Leading and trailing * zeros are not in the string and must be added. * D: expchar holds this character; '\0' if no exponent, e.g. %f * F: at least two digits for decimal, at least one digit for hex */ char *decimal_point = NULL; /* locale specific decimal point */ int decpt_len; /* length of decimal_point */ int signflag; /* true if float is negative */ union { /* floating point arguments %[aAeEfFgG] */ double dbl; long double ldbl; } fparg; int expt; /* integer value of exponent */ char expchar; /* exponent character: [eEpP\0] */ char *dtoaend; /* pointer to end of converted digits */ int expsize; /* character count for expstr */ int ndig; /* actual number of digits returned by dtoa */ char expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */ char *dtoaresult = NULL; /* buffer allocated by dtoa */ #endif u_long ulval; /* integer arguments %[diouxX] */ uintmax_t ujval; /* %j, %ll, %q, %t, %z integers */ int base; /* base for [diouxX] conversion */ int dprec; /* a copy of prec if [diouxX], 0 otherwise */ int realsz; /* field size expanded by dprec, sign, etc */ int size; /* size of converted field or string */ const char *xdigs; /* digits for %[xX] conversion */ struct io_state io; /* I/O buffering state */ char buf[BUF]; /* buffer with space for digits of uintmax_t */ char ox[2]; /* space for 0x; ox[1] is either x, X, or \0 */ union arg *argtable; /* args, built due to positional arg */ union arg statargtable [STATIC_ARG_TBL_SIZE]; int nextarg; /* 1-based argument index */ va_list orgap; /* original argument pointer */ char *convbuf; /* wide to multibyte conversion result */ static const char xdigs_lower[16] = "0123456789abcdef"; static const char xdigs_upper[16] = "0123456789ABCDEF"; /* BEWARE, these `goto error' on error. */ #define PRINT(ptr, len) { \ if (io_print(&io, (ptr), (len), locale)) \ goto error; \ } #define PAD(howmany, with) { \ if (io_pad(&io, (howmany), (with), locale)) \ goto error; \ } #define PRINTANDPAD(p, ep, len, with) { \ if (io_printandpad(&io, (p), (ep), (len), (with), locale)) \ goto error; \ } #define FLUSH() { \ if (io_flush(&io, locale)) \ goto error; \ } /* * Get the argument indexed by nextarg. If the argument table is * built, use it to get the argument. If its not, get the next * argument (and arguments must be gotten sequentially). */ #define GETARG(type) \ ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \ (nextarg++, va_arg(ap, type))) /* * To extend shorts properly, we need both signed and unsigned * argument extraction methods. */ #define SARG() \ (flags&LONGINT ? GETARG(long) : \ flags&SHORTINT ? (long)(short)GETARG(int) : \ flags&CHARINT ? (long)(signed char)GETARG(int) : \ (long)GETARG(int)) #define UARG() \ (flags&LONGINT ? GETARG(u_long) : \ flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \ flags&CHARINT ? (u_long)(u_char)GETARG(int) : \ (u_long)GETARG(u_int)) #define INTMAX_SIZE (INTMAXT|SIZET|PTRDIFFT|LLONGINT) #define SJARG() \ (flags&INTMAXT ? GETARG(intmax_t) : \ flags&SIZET ? (intmax_t)GETARG(ssize_t) : \ flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \ (intmax_t)GETARG(long long)) #define UJARG() \ (flags&INTMAXT ? GETARG(uintmax_t) : \ flags&SIZET ? (uintmax_t)GETARG(size_t) : \ flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \ (uintmax_t)GETARG(unsigned long long)) /* * Append a digit to a value and check for overflow. */ #define APPEND_DIGIT(val, dig) do { \ if ((val) > INT_MAX / 10) \ goto overflow; \ (val) *= 10; \ if ((val) > INT_MAX - to_digit((dig))) \ goto overflow; \ (val) += to_digit((dig)); \ } while (0) /* * Get * arguments, including the form *nn$. Preserve the nextarg * that the argument can be gotten once the type is determined. */ #define GETASTER(val) \ n2 = 0; \ cp = fmt; \ while (is_digit(*cp)) { \ APPEND_DIGIT(n2, *cp); \ cp++; \ } \ if (*cp == '$') { \ int hold = nextarg; \ if (argtable == NULL) { \ argtable = statargtable; \ if (__find_arguments (fmt0, orgap, &argtable)) { \ ret = EOF; \ goto error; \ } \ } \ nextarg = n2; \ val = GETARG(int); \ nextarg = hold; \ fmt = ++cp; \ } else { \ val = GETARG(int); \ } _SET_ORIENTATION(fp, -1); /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */ if (cantwrite(fp)) { errno = EBADF; return (EOF); } fmt = (char *)fmt0; argtable = NULL; nextarg = 1; va_copy(orgap, ap); io_init(&io, fp); ret = 0; #ifdef FLOATING_POINT decimal_point = localeconv_l(locale)->decimal_point; /* The overwhelmingly common case is decpt_len == 1. */ decpt_len = (decimal_point[1] == '\0' ? 1 : strlen(decimal_point)); #endif #ifdef PRINTF_WIDE_CHAR convbuf = NULL; #endif /* * Scan the format for conversions (`%' character). */ for (;;) { for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) /* void */; if (fmt != cp) { ptrdiff_t m = fmt - cp; if (m < 0 || m > INT_MAX - ret) goto overflow; PRINT(cp, m); ret += m; } if (ch == '\0') goto done; fmt++; /* skip over '%' */ flags = 0; dprec = 0; width = 0; prec = -1; gs.grouping = NULL; sign = '\0'; ox[1] = '\0'; rflag: ch = *fmt++; reswitch: switch (ch) { case ' ': /* * ``If the space and + flags both appear, the space * flag will be ignored.'' * -- ANSI X3J11 */ if (!sign) sign = ' '; goto rflag; case '#': flags |= ALT; goto rflag; case '*': /* * ``A negative field width argument is taken as a * - flag followed by a positive field width.'' * -- ANSI X3J11 * They don't exclude field widths read from args. */ GETASTER(width); if (width >= 0) goto rflag; if (width == INT_MIN) goto overflow; width = -width; /* FALLTHROUGH */ case '-': flags |= LADJUST; goto rflag; case '+': sign = '+'; goto rflag; case '\'': flags |= GROUPING; goto rflag; case '.': if ((ch = *fmt++) == '*') { GETASTER(n); prec = n < 0 ? -1 : n; goto rflag; } n = 0; while (is_digit(ch)) { APPEND_DIGIT(n, ch); ch = *fmt++; } if (ch == '$') { nextarg = n; if (argtable == NULL) { argtable = statargtable; if (__find_arguments (fmt0, orgap, &argtable)) { ret = EOF; goto error; } } goto rflag; } prec = n; goto reswitch; case '0': /* * ``Note that 0 is taken as a flag, not as the * beginning of a field width.'' * -- ANSI X3J11 */ flags |= ZEROPAD; goto rflag; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': n = 0; do { APPEND_DIGIT(n, ch); ch = *fmt++; } while (is_digit(ch)); if (ch == '$') { nextarg = n; if (argtable == NULL) { argtable = statargtable; if (__find_arguments (fmt0, orgap, &argtable)) { ret = EOF; goto error; } } goto rflag; } width = n; goto reswitch; #ifdef FLOATING_POINT case 'L': flags |= LONGDBL; goto rflag; #endif case 'h': if (flags & SHORTINT) { flags &= ~SHORTINT; flags |= CHARINT; } else { flags |= SHORTINT; } goto rflag; case 'j': flags |= INTMAXT; goto rflag; case 'l': if (flags & LONGINT) { flags &= ~LONGINT; flags |= LLONGINT; } else { flags |= LONGINT; } goto rflag; case 'q': flags |= LLONGINT; /* not necessarily */ goto rflag; case 't': flags |= PTRDIFFT; goto rflag; case 'z': flags |= SIZET; goto rflag; case 'C': flags |= LONGINT; /*FALLTHROUGH*/ case 'c': #ifdef PRINTF_WIDE_CHAR if (flags & LONGINT) { mbstate_t mbs; size_t mbseqlen; memset(&mbs, 0, sizeof(mbs)); mbseqlen = wcrtomb(buf, (wchar_t)GETARG(wint_t), &mbs); if (mbseqlen == (size_t)-1) { fp->_flags |= __SERR; errno = EILSEQ; goto error; } cp = buf; size = (int)mbseqlen; } else { #endif *(cp = buf) = GETARG(int); size = 1; #ifdef PRINTF_WIDE_CHAR } #endif sign = '\0'; break; case 'D': flags |= LONGINT; /*FALLTHROUGH*/ case 'd': case 'i': if (flags & INTMAX_SIZE) { ujval = SJARG(); if ((intmax_t)ujval < 0) { ujval = -ujval; sign = '-'; } } else { ulval = SARG(); if ((long)ulval < 0) { ulval = -ulval; sign = '-'; } } base = 10; goto number; #ifdef FLOATING_POINT case 'a': case 'A': if (ch == 'a') { ox[1] = 'x'; xdigs = xdigs_lower; expchar = 'p'; } else { ox[1] = 'X'; xdigs = xdigs_upper; expchar = 'P'; } if (prec >= 0) prec++; if (dtoaresult != NULL) __freedtoa(dtoaresult); if (flags & LONGDBL) { fparg.ldbl = GETARG(long double); dtoaresult = cp = __hldtoa(fparg.ldbl, xdigs, prec, &expt, &signflag, &dtoaend); if (dtoaresult == NULL) { errno = ENOMEM; goto error; } } else { fparg.dbl = GETARG(double); dtoaresult = cp = __hdtoa(fparg.dbl, xdigs, prec, &expt, &signflag, &dtoaend); if (dtoaresult == NULL) { errno = ENOMEM; goto error; } } if (prec < 0) prec = dtoaend - cp; if (expt == INT_MAX) ox[1] = '\0'; goto fp_common; case 'e': case 'E': expchar = ch; if (prec < 0) /* account for digit before decpt */ prec = DEFPREC + 1; else prec++; goto fp_begin; case 'f': case 'F': expchar = '\0'; goto fp_begin; case 'g': case 'G': expchar = ch - ('g' - 'e'); if (prec == 0) prec = 1; fp_begin: if (prec < 0) prec = DEFPREC; if (dtoaresult != NULL) __freedtoa(dtoaresult); if (flags & LONGDBL) { fparg.ldbl = GETARG(long double); dtoaresult = cp = __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec, &expt, &signflag, &dtoaend); if (dtoaresult == NULL) { errno = ENOMEM; goto error; } } else {