int vasprintf (char **resultp, const char *format, va_list args) { size_t length; char *result = vasnprintf (NULL, &length, format, args); if (result == NULL) return -1; if (length > INT_MAX) { free (result); errno = EOVERFLOW; return -1; } *resultp = result; /* Return the number of resulting bytes, excluding the trailing NUL. */ return length; }
/* Print formatted output to the stream FP. Return string length of formatted string. On error, return a negative value. */ int fprintf (FILE *fp, const char *format, ...) { char buf[2000]; char *output; size_t len; size_t lenbuf = sizeof (buf); va_list args; va_start (args, format); output = vasnprintf (buf, &lenbuf, format, args); len = lenbuf; va_end (args); if (!output) { fseterr (fp); return -1; } if (fwrite (output, 1, len, fp) < len) { if (output != buf) { int saved_errno = errno; free (output); errno = saved_errno; } return -1; } if (output != buf) free (output); if (len > INT_MAX) { errno = EOVERFLOW; fseterr (fp); return -1; } return len; }
/* Print formatted output to string STR. Return string length of formatted string. On error, return a negative value. */ int sprintf (char *str, const char *format, ...) { char *output; size_t len; size_t lenbuf; va_list args; /* vasnprintf fails with EOVERFLOW when the buffer size argument is larger than INT_MAX (if that fits into a 'size_t' at all). Also note that glibc's iconv fails with E2BIG when we pass a length that is so large that str + lenbuf wraps around, i.e. (uintptr_t) (str + lenbuf) < (uintptr_t) str. Therefore set lenbuf = min (SIZE_MAX, INT_MAX, - (uintptr_t) str - 1). */ lenbuf = (SIZE_MAX < INT_MAX ? SIZE_MAX : INT_MAX); if (lenbuf > ~ (uintptr_t) str) lenbuf = ~ (uintptr_t) str; va_start (args, format); output = vasnprintf (str, &lenbuf, format, args); len = lenbuf; va_end (args); if (!output) return -1; if (output != str) { /* len is near SIZE_MAX. */ free (output); errno = EOVERFLOW; return -1; } if (len > INT_MAX) { errno = EOVERFLOW; return -1; } return len; }
/* Print formatted output to string STR. Similar to vsprintf, but additional length SIZE limit how much is written into STR. Returns string length of formatted string (which may be larger than SIZE). STR may be NULL, in which case nothing will be written. On error, return a negative value. */ int vsnprintf (char *str, size_t size, const char *format, va_list args) { char *output; size_t len; len = size; output = vasnprintf (str, &len, format, args); if (!output) return -1; if (str != NULL) if (len > size - 1) /* equivalent to: (size > 0 && len >= size) */ str[size - 1] = '\0'; if (output != str) free (output); return len; }
/* Grow an obstack with formatted output. Return the number of bytes added to OBS. No trailing nul byte is added, and the object should be closed with obstack_finish before use. Upon memory allocation error, call obstack_alloc_failed_handler. Upon other error, return -1. */ int obstack_vprintf (struct obstack *obs, const char *format, va_list args) { /* If we are close to the end of the current obstack chunk, use a stack-allocated buffer and copy, to reduce the likelihood of a small-size malloc. Otherwise, print directly into the obstack. */ enum { CUTOFF = 1024 }; char buf[CUTOFF]; char *base = obstack_next_free (obs); size_t len = obstack_room (obs); char *str; if (len < CUTOFF) { base = buf; len = CUTOFF; } str = vasnprintf (base, &len, format, args); if (!str) { if (errno == ENOMEM) obstack_alloc_failed_handler (); return -1; } if (str == base && str != buf) /* The output was already computed in place, but we need to account for its size. */ obstack_blank_fast (obs, len); else { /* The output exceeded available obstack space or we used buf; copy the resulting string. */ obstack_grow (obs, str, len); if (str != buf) free (str); } return len; }
int rpl_vfprintf( FILE *fp, char *format, va_list args ) { int eax; char buf[2000]; char *output; size_t len; size_t lenbuf = 2000; output = vasnprintf( buf, &lenbuf, format, args ); len = lenbuf; if ( output == 0 ) { fseterr( fp ); return -1; } else { if ( fwrite( output, 1, len, fp ) < len ) { if ( output != buf[0] ) { int saved_errno = *(int*)(__errno_location( )); free( output ); *(int*)(__errno_location( )) = saved_errno; } return -1; } else { if ( (int)len < 0 ) { *(int*)(__errno_location( )) = 75; fseterr( fp ); return -1; } else return (int)len; } } }
int dprintf (int fd, const char *format, ...) { char buf[2000]; char *output; size_t len; size_t lenbuf = sizeof (buf); va_list args; va_start (args, format); output = vasnprintf (buf, &lenbuf, format, args); len = lenbuf; va_end (args); if (!output) return -1; if (full_write (fd, output, len) < len) { if (output != buf) { int saved_errno = errno; free (output); errno = saved_errno; } return -1; } if (output != buf) free (output); if (len > INT_MAX) { errno = EOVERFLOW; return -1; } return len; }
/* Print formatted output to string STR. Similar to sprintf, but additional length SIZE limit how much is written into STR. Returns string length of formatted string (which may be larger than SIZE). STR may be NULL, in which case nothing will be written. On error, return a negative value. */ int snprintf (char *str, size_t size, const char *format, ...) { char *output; size_t len; size_t lenbuf = size; va_list args; va_start (args, format); output = vasnprintf (str, &lenbuf, format, args); len = lenbuf; va_end (args); if (!output) return -1; if (output != str) { if (size) { size_t pruned_len = (len < size ? len : size - 1); memcpy (str, output, pruned_len); str[pruned_len] = '\0'; } free (output); } if (INT_MAX < len) { errno = EOVERFLOW; return -1; } return len; }