"Fossies" - the Fresh Open Source Software Archive

Member "file-5.35/src/vasprintf.c" (1 Oct 2018, 19680 Bytes) of package /linux/misc/file-5.35.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "vasprintf.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 5.34_vs_5.35.

    1 /*
    2  * Copyright (c) Ian F. Darwin 1986-1995.
    3  * Software written by Ian F. Darwin and others;
    4  * maintained 1995-present by Christos Zoulas and others.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice immediately at the beginning of the file, without modification,
   11  *    this list of conditions, and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 /*###########################################################################
   29   #                                                                           #
   30   #                                vasprintf                                  #
   31   #                                                                           #
   32   #               Copyright (c) 2002-2005 David TAILLANDIER                   #
   33   #                                                                           #
   34   ###########################################################################*/
   35 
   36 /*
   37 
   38 This software is distributed under the "modified BSD licence".
   39 
   40 This software is also released with GNU license (GPL) in another file (same
   41 source-code, only license differ).
   42 
   43 
   44 
   45 Redistribution and use in source and binary forms, with or without
   46 modification, are permitted provided that the following conditions are met:
   47 
   48 Redistributions of source code must retain the above copyright notice, this
   49 list of conditions and the following disclaimer. Redistributions in binary
   50 form must reproduce the above copyright notice, this list of conditions and
   51 the following disclaimer in the documentation and/or other materials
   52 provided with the distribution. The name of the author may not be used to
   53 endorse or promote products derived from this software without specific
   54 prior written permission.
   55 
   56 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
   57 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
   58 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
   59 EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   60 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   61 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   62 OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   63 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   64 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   65 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   66 
   67 ====================
   68 
   69 Hacked from xnprintf version of 26th February 2005 to provide only
   70 vasprintf by Reuben Thomas <rrt@sc3d.org>.
   71 
   72 ====================
   73 
   74 
   75 'printf' function family use the following format string:
   76 
   77 %[flag][width][.prec][modifier]type
   78 
   79 %% is the escape sequence to print a '%'
   80 %  followed by an unknown format will print the characters without
   81 trying to do any interpretation
   82 
   83 flag:   none   +     -     #     (blank)
   84 width:  n    0n    *
   85 prec:   none   .0    .n     .*
   86 modifier:    F N L h l ll z t    ('F' and 'N' are ms-dos/16-bit specific)
   87 type:  d i o u x X f e g E G c s p n
   88 
   89 
   90 The function needs to allocate memory to store the full text before to
   91 actually writing it.  i.e if you want to fnprintf() 1000 characters, the
   92 functions will allocate 1000 bytes.
   93 This behaviour can be modified: you have to customise the code to flush the
   94 internal buffer (writing to screen or file) when it reach a given size. Then
   95 the buffer can have a shorter length. But what? If you really need to write
   96 HUGE string, don't use printf!
   97 During the process, some other memory is allocated (1024 bytes minimum)
   98 to handle the output of partial sprintf() calls. If you have only 10000 bytes
   99 free in memory, you *may* not be able to nprintf() a 8000 bytes-long text.
  100 
  101 note: if a buffer overflow occurs, exit() is called. This situation should
  102 never appear ... but if you want to be *really* sure, you have to modify the
  103 code to handle those situations (only one place to modify).
  104 A buffer overflow can only occur if your sprintf() do strange things or when
  105 you use strange formats.
  106 
  107 */
  108 #include "file.h"
  109 
  110 #ifndef lint
  111 FILE_RCSID("@(#)$File: vasprintf.c,v 1.16 2018/10/01 18:45:39 christos Exp $")
  112 #endif  /* lint */
  113 
  114 #include <assert.h>
  115 #include <string.h>
  116 #include <stdlib.h>
  117 #include <stdarg.h>
  118 #include <ctype.h>
  119 #include <limits.h>
  120 #include <stddef.h>
  121 
  122 #define ALLOC_CHUNK 2048
  123 #define ALLOC_SECURITY_MARGIN 1024   /* big value because some platforms have very big 'G' exponent */
  124 #if ALLOC_CHUNK < ALLOC_SECURITY_MARGIN
  125 #    error  !!! ALLOC_CHUNK < ALLOC_SECURITY_MARGIN !!!
  126 #endif
  127 /* note: to have some interest, ALLOC_CHUNK should be much greater than ALLOC_SECURITY_MARGIN */
  128 
  129 /*
  130  *  To save a lot of push/pop, every variable are stored into this
  131  *  structure, which is passed among nearly every sub-functions.
  132  */
  133 typedef struct {
  134   const char * src_string;        /* current position into intput string */
  135   char *       buffer_base;       /* output buffer */
  136   char *       dest_string;       /* current position into output string */
  137   size_t       buffer_len;        /* length of output buffer */
  138   size_t       real_len;          /* real current length of output text */
  139   size_t       pseudo_len;        /* total length of output text if it were not limited in size */
  140   size_t       maxlen;
  141   va_list      vargs;             /* pointer to current position into vargs */
  142   char *       sprintf_string;
  143   FILE *       fprintf_file;
  144 } xprintf_struct;
  145 
  146 /*
  147  *  Realloc buffer if needed
  148  *  Return value:  0 = ok
  149  *               EOF = not enought memory
  150  */
  151 static int realloc_buff(xprintf_struct *s, size_t len)
  152 {
  153   char * ptr;
  154 
  155   if (len + ALLOC_SECURITY_MARGIN + s->real_len > s->buffer_len) {
  156     len += s->real_len + ALLOC_CHUNK;
  157     ptr = (char *)realloc((void *)(s->buffer_base), len);
  158     if (ptr == NULL) {
  159       s->buffer_base = NULL;
  160       return EOF;
  161     }
  162 
  163     s->dest_string = ptr + (size_t)(s->dest_string - s->buffer_base);
  164     s->buffer_base = ptr;
  165     s->buffer_len = len;
  166 
  167     (s->buffer_base)[s->buffer_len - 1] = 1; /* overflow marker */
  168   }
  169 
  170   return 0;
  171 }
  172 
  173 /*
  174  *  Prints 'usual' characters    up to next '%'
  175  *                            or up to end of text
  176  */
  177 static int usual_char(xprintf_struct * s)
  178 {
  179   size_t len;
  180 
  181   len = strcspn(s->src_string, "%");     /* reachs the next '%' or end of input string */
  182   /* note: 'len' is never 0 because the presence of '%' */
  183   /* or end-of-line is checked in the calling function  */
  184 
  185   if (realloc_buff(s,len) == EOF)
  186     return EOF;
  187 
  188   memcpy(s->dest_string, s->src_string, len);
  189   s->src_string += len;
  190   s->dest_string += len;
  191   s->real_len += len;
  192   s->pseudo_len += len;
  193 
  194   return 0;
  195 }
  196 
  197 /*
  198  *  Return value: 0 = ok
  199  *                EOF = error
  200  */
  201 static int print_it(xprintf_struct *s, size_t approx_len,
  202                     const char *format_string, ...)
  203 {
  204   va_list varg;
  205   int vsprintf_len;
  206   size_t len;
  207 
  208   if (realloc_buff(s,approx_len) == EOF)
  209     return EOF;
  210 
  211   va_start(varg, format_string);
  212   vsprintf_len = vsprintf(s->dest_string, format_string, varg);
  213   va_end(varg);
  214 
  215   /* Check for overflow */
  216   assert((s->buffer_base)[s->buffer_len - 1] == 1);
  217 
  218   if (vsprintf_len == EOF) /* must be done *after* overflow-check */
  219     return EOF;
  220 
  221   s->pseudo_len += vsprintf_len;
  222   len = strlen(s->dest_string);
  223   s->real_len += len;
  224   s->dest_string += len;
  225 
  226   return 0;
  227 }
  228 
  229 /*
  230  *  Prints a string (%s)
  231  *  We need special handling because:
  232  *     a: the length of the string is unknown
  233  *     b: when .prec is used, we must not access any extra byte of the
  234  *        string (of course, if the original sprintf() does... what the
  235  *        hell, not my problem)
  236  *
  237  *  Return value: 0 = ok
  238  *                EOF = error
  239  */
  240 static int type_s(xprintf_struct *s, int width, int prec,
  241                   const char *format_string, const char *arg_string)
  242 {
  243   size_t string_len;
  244 
  245   if (arg_string == NULL)
  246     return print_it(s, (size_t)6, "(null)", 0);
  247 
  248   /* hand-made strlen() whitch stops when 'prec' is reached. */
  249   /* if 'prec' is -1 then it is never reached. */
  250   string_len = 0;
  251   while (arg_string[string_len] != 0 && (size_t)prec != string_len)
  252     string_len++;
  253 
  254   if (width != -1 && string_len < (size_t)width)
  255     string_len = (size_t)width;
  256 
  257   return print_it(s, string_len, format_string, arg_string);
  258 }
  259 
  260 /*
  261  *  Read a serie of digits. Stop when non-digit is found.
  262  *  Return value: the value read (between 0 and 32767).
  263  *  Note: no checks are made against overflow. If the string contain a big
  264  *  number, then the return value won't be what we want (but, in this case,
  265  *  the programmer don't know whatr he wants, then no problem).
  266  */
  267 static int getint(const char **string)
  268 {
  269   int i = 0;
  270 
  271   while (isdigit((unsigned char)**string) != 0) {
  272     i = i * 10 + (**string - '0');
  273     (*string)++;
  274   }
  275 
  276   if (i < 0 || i > 32767)
  277     i = 32767; /* if we have i==-10 this is not because the number is */
  278   /* negative; this is because the number is big */
  279   return i;
  280 }
  281 
  282 /*
  283  *  Read a part of the format string. A part is 'usual characters' (ie "blabla")
  284  *  or '%%' escape sequence (to print a single '%') or any combination of
  285  *  format specifier (ie "%i" or "%10.2d").
  286  *  After the current part is managed, the function returns to caller with
  287  *  everything ready to manage the following part.
  288  *  The caller must ensure than the string is not empty, i.e. the first byte
  289  *  is not zero.
  290  *
  291  *  Return value:  0 = ok
  292  *                 EOF = error
  293  */
  294 static int dispatch(xprintf_struct *s)
  295 {
  296   const char *initial_ptr;
  297   char format_string[24]; /* max length may be something like  "% +-#032768.32768Ld" */
  298   char *format_ptr;
  299   int flag_plus, flag_minus, flag_space, flag_sharp, flag_zero;
  300   int width, prec, modifier, approx_width;
  301   char type;
  302   /* most of those variables are here to rewrite the format string */
  303 
  304 #define SRCTXT  (s->src_string)
  305 #define DESTTXT (s->dest_string)
  306 
  307   /* incoherent format string. Characters after the '%' will be printed with the next call */
  308 #define INCOHERENT()         do {SRCTXT=initial_ptr; return 0;} while (0)     /* do/while to avoid */
  309 #define INCOHERENT_TEST()    do {if(*SRCTXT==0)   INCOHERENT();} while (0)    /* a null statement  */
  310 
  311   /* 'normal' text */
  312   if (*SRCTXT != '%')
  313     return usual_char(s);
  314 
  315   /* we then have a '%' */
  316   SRCTXT++;
  317   /* don't check for end-of-string ; this is done later */
  318 
  319   /* '%%' escape sequence */
  320   if (*SRCTXT == '%') {
  321     if (realloc_buff(s, (size_t)1) == EOF) /* because we can have "%%%%%%%%..." */
  322       return EOF;
  323     *DESTTXT = '%';
  324     DESTTXT++;
  325     SRCTXT++;
  326     (s->real_len)++;
  327     (s->pseudo_len)++;
  328     return 0;
  329   }
  330 
  331   /* '%' managing */
  332   initial_ptr = SRCTXT;   /* save current pointer in case of incorrect */
  333   /* 'decoding'. Points just after the '%' so the '%' */
  334   /* won't be printed in any case, as required. */
  335 
  336   /* flag */
  337   flag_plus = flag_minus = flag_space = flag_sharp = flag_zero = 0;
  338 
  339   for (;; SRCTXT++) {
  340     if (*SRCTXT == ' ')
  341       flag_space = 1;
  342     else if (*SRCTXT == '+')
  343       flag_plus = 1;
  344     else if (*SRCTXT == '-')
  345       flag_minus = 1;
  346     else if (*SRCTXT == '#')
  347       flag_sharp = 1;
  348     else if (*SRCTXT == '0')
  349       flag_zero = 1;
  350     else
  351       break;
  352   }
  353 
  354   INCOHERENT_TEST();    /* here is the first test for end of string */
  355 
  356   /* width */
  357   if (*SRCTXT == '*') {         /* width given by next argument */
  358     SRCTXT++;
  359     width = va_arg(s->vargs, int);
  360     if ((size_t)width > 0x3fffU) /* 'size_t' to check against negative values too */
  361       width = 0x3fff;
  362   } else if (isdigit((unsigned char)*SRCTXT)) /* width given as ASCII number */
  363     width = getint(&SRCTXT);
  364   else
  365     width = -1;                 /* no width specified */
  366 
  367   INCOHERENT_TEST();
  368 
  369   /* .prec */
  370   if (*SRCTXT == '.') {
  371     SRCTXT++;
  372     if (*SRCTXT == '*') {       /* .prec given by next argument */
  373       SRCTXT++;
  374       prec = va_arg(s->vargs, int);
  375       if ((size_t)prec >= 0x3fffU) /* 'size_t' to check against negative values too */
  376         prec = 0x3fff;
  377     } else {                    /* .prec given as ASCII number */
  378       if (isdigit((unsigned char)*SRCTXT) == 0)
  379         INCOHERENT();
  380       prec = getint(&SRCTXT);
  381     }
  382     INCOHERENT_TEST();
  383   } else
  384     prec = -1;                  /* no .prec specified */
  385 
  386   /* modifier */
  387   switch (*SRCTXT) {
  388   case 'L':
  389   case 'h':
  390   case 'l':
  391   case 'z':
  392   case 't':
  393     modifier = *SRCTXT;
  394     SRCTXT++;
  395     if (modifier=='l' && *SRCTXT=='l') {
  396       SRCTXT++;
  397       modifier = 'L';  /* 'll' == 'L'      long long == long double */
  398     } /* only for compatibility ; not portable */
  399     INCOHERENT_TEST();
  400     break;
  401   default:
  402     modifier = -1;              /* no modifier specified */
  403     break;
  404   }
  405 
  406   /* type */
  407   type = *SRCTXT;
  408   if (strchr("diouxXfegEGcspn",type) == NULL)
  409     INCOHERENT();               /* unknown type */
  410   SRCTXT++;
  411 
  412   /* rewrite format-string */
  413   format_string[0] = '%';
  414   format_ptr = &(format_string[1]);
  415 
  416   if (flag_plus) {
  417     *format_ptr = '+';
  418     format_ptr++;
  419   }
  420   if (flag_minus) {
  421     *format_ptr = '-';
  422     format_ptr++;
  423   }
  424   if (flag_space) {
  425     *format_ptr = ' ';
  426     format_ptr++;
  427   }
  428   if (flag_sharp) {
  429     *format_ptr = '#';
  430     format_ptr++;
  431   }
  432   if (flag_zero) {
  433     *format_ptr = '0';
  434     format_ptr++;
  435   } /* '0' *must* be the last one */
  436 
  437   if (width != -1) {
  438     sprintf(format_ptr, "%i", width);
  439     format_ptr += strlen(format_ptr);
  440   }
  441 
  442   if (prec != -1) {
  443     *format_ptr = '.';
  444     format_ptr++;
  445     sprintf(format_ptr, "%i", prec);
  446     format_ptr += strlen(format_ptr);
  447   }
  448 
  449   if (modifier != -1) {
  450     if (modifier == 'L' && strchr("diouxX",type) != NULL) {
  451       *format_ptr = 'l';
  452       format_ptr++;
  453       *format_ptr = 'l';
  454       format_ptr++;
  455     } else {
  456       *format_ptr = modifier;
  457       format_ptr++;
  458     }
  459   }
  460 
  461   *format_ptr = type;
  462   format_ptr++;
  463   *format_ptr = 0;
  464 
  465   /* vague approximation of minimal length if width or prec are specified */
  466   approx_width = width + prec;
  467   if (approx_width < 0) /* because width == -1 and/or prec == -1 */
  468     approx_width = 0;
  469 
  470   switch (type) {
  471     /* int */
  472   case 'd':
  473   case 'i':
  474   case 'o':
  475   case 'u':
  476   case 'x':
  477   case 'X':
  478     switch (modifier) {
  479     case -1 :
  480       return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, int));
  481     case 'L':
  482       return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, long long int));
  483     case 'l':
  484       return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, long int));
  485     case 'h':
  486       return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, int));
  487     case 'z':
  488       return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, size_t));
  489     case 't':
  490       return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, ptrdiff_t));
  491       /* 'int' instead of 'short int' because default promotion is 'int' */
  492     default:
  493       INCOHERENT();
  494     }
  495 
  496     /* char */
  497   case 'c':
  498     if (modifier != -1)
  499       INCOHERENT();
  500     return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, int));
  501     /* 'int' instead of 'char' because default promotion is 'int' */
  502 
  503     /* math */
  504   case 'e':
  505   case 'f':
  506   case 'g':
  507   case 'E':
  508   case 'G':
  509     switch (modifier) {
  510     case -1 : /* because of default promotion, no modifier means 'l' */
  511     case 'l':
  512       return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, double));
  513     case 'L':
  514       return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, long double));
  515     default:
  516       INCOHERENT();
  517     }
  518 
  519     /* string */
  520   case 's':
  521     return type_s(s, width, prec, format_string, va_arg(s->vargs, const char*));
  522 
  523     /* pointer */
  524   case 'p':
  525     if (modifier == -1)
  526       return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, void *));
  527     INCOHERENT();
  528 
  529     /* store */
  530   case 'n':
  531     if (modifier == -1) {
  532       int * p;
  533       p = va_arg(s->vargs, int *);
  534       if (p != NULL) {
  535         *p = s->pseudo_len;
  536         return 0;
  537       }
  538       return EOF;
  539     }
  540     INCOHERENT();
  541 
  542   } /* switch */
  543 
  544   INCOHERENT();                 /* unknown type */
  545 
  546 #undef INCOHERENT
  547 #undef INCOHERENT_TEST
  548 #undef SRCTXT
  549 #undef DESTTXT
  550 }
  551 
  552 /*
  553  *  Return value: number of *virtually* written characters
  554  *                EOF = error
  555  */
  556 static int core(xprintf_struct *s)
  557 {
  558   size_t save_len;
  559   char *dummy_base;
  560 
  561   /* basic checks */
  562   if ((int)(s->maxlen) <= 0) /* 'int' to check against some conversion */
  563     return EOF;           /* error for example if value is (int)-10 */
  564   s->maxlen--;      /* because initial maxlen counts final 0 */
  565   /* note: now 'maxlen' _can_ be zero */
  566 
  567   if (s->src_string == NULL)
  568     s->src_string = "(null)";
  569 
  570   /* struct init and memory allocation */
  571   s->buffer_base = NULL;
  572   s->buffer_len = 0;
  573   s->real_len = 0;
  574   s->pseudo_len = 0;
  575   if (realloc_buff(s, (size_t)0) == EOF)
  576     return EOF;
  577   s->dest_string = s->buffer_base;
  578 
  579   /* process source string */
  580   for (;;) {
  581     /* up to end of source string */
  582     if (*(s->src_string) == 0) {
  583       *(s->dest_string) = '\0';    /* final NUL */
  584       break;
  585     }
  586 
  587     if (dispatch(s) == EOF)
  588       goto free_EOF;
  589 
  590     /* up to end of dest string */
  591     if (s->real_len >= s->maxlen) {
  592       (s->buffer_base)[s->maxlen] = '\0'; /* final NUL */
  593       break;
  594     }
  595   }
  596 
  597   /* for (v)asnprintf */
  598   dummy_base = s->buffer_base;
  599 
  600   dummy_base = s->buffer_base + s->real_len;
  601   save_len = s->real_len;
  602 
  603   /* process the remaining of source string to compute 'pseudo_len'. We
  604    * overwrite again and again, starting at 'dummy_base' because we don't
  605    * need the text, only char count. */
  606   while(*(s->src_string) != 0) { /* up to end of source string */
  607     s->real_len = 0;
  608     s->dest_string = dummy_base;
  609     if (dispatch(s) == EOF)
  610       goto free_EOF;
  611   }
  612 
  613   s->buffer_base = (char *)realloc((void *)(s->buffer_base), save_len + 1);
  614   if (s->buffer_base == NULL)
  615     return EOF; /* should rarely happen because we shrink the buffer */
  616   return s->pseudo_len;
  617 
  618  free_EOF:
  619   free(s->buffer_base);
  620   return EOF;
  621 }
  622 
  623 int vasprintf(char **ptr, const char *format_string, va_list vargs)
  624 {
  625   xprintf_struct s;
  626   int retval;
  627 
  628   s.src_string = format_string;
  629 #ifdef va_copy
  630   va_copy (s.vargs, vargs);
  631 #else
  632 # ifdef __va_copy
  633   __va_copy (s.vargs, vargs);
  634 # else
  635 #  ifdef WIN32
  636   s.vargs = vargs;
  637 #  else
  638   memcpy (&s.vargs, &vargs, sizeof (s.va_args));
  639 #  endif /* WIN32 */
  640 # endif /* __va_copy */
  641 #endif /* va_copy */
  642   s.maxlen = (size_t)INT_MAX;
  643 
  644   retval = core(&s);
  645   va_end(s.vargs);
  646   if (retval == EOF) {
  647     *ptr = NULL;
  648     return EOF;
  649   }
  650 
  651   *ptr = s.buffer_base;
  652   return retval;
  653 }