diff options
Diffstat (limited to 'newlib/libc/stdio/ssputs_r.c')
-rw-r--r-- | newlib/libc/stdio/ssputs_r.c | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/newlib/libc/stdio/ssputs_r.c b/newlib/libc/stdio/ssputs_r.c new file mode 100644 index 0000000..abd18ef --- /dev/null +++ b/newlib/libc/stdio/ssputs_r.c @@ -0,0 +1,69 @@ +#include <newlib.h> + +#include <reent.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +int +__ssputs_r (struct _reent *ptr, + FILE *fp, + const char *buf, + size_t len) +{ + register int w; + + w = fp->_w; + if (len >= w && fp->_flags & (__SMBF | __SOPT)) { + /* must be asprintf family */ + unsigned char *str; + int curpos = (fp->_p - fp->_bf._base); + /* Choose a geometric growth factor to avoid + * quadratic realloc behavior, but use a rate less + * than (1+sqrt(5))/2 to accomodate malloc + * overhead. asprintf EXPECTS us to overallocate, so + * that it can add a trailing \0 without + * reallocating. The new allocation should thus be + * max(prev_size*1.5, curpos+len+1). */ + int newsize = fp->_bf._size * 3 / 2; + if (newsize < curpos + len + 1) + newsize = curpos + len + 1; + if (fp->_flags & __SOPT) + { + /* asnprintf leaves original buffer alone. */ + str = (unsigned char *)_malloc_r (ptr, newsize); + if (!str) + goto err; + memcpy (str, fp->_bf._base, curpos); + fp->_flags = (fp->_flags & ~__SOPT) | __SMBF; + } + else + { + str = (unsigned char *)_realloc_r (ptr, fp->_bf._base, + newsize); + if (!str) { + /* Free unneeded buffer. */ + _free_r (ptr, fp->_bf._base); + goto err; + } + } + fp->_bf._base = str; + fp->_p = str + curpos; + fp->_bf._size = newsize; + w = len; + fp->_w = newsize - curpos; + } + if (len < w) + w = len; + memmove ((void *) fp->_p, (void *) buf, (size_t) (w)); + fp->_w -= w; + fp->_p += w; + + return 0; + +err: + _REENT_ERRNO(ptr) = ENOMEM; + fp->_flags |= __SERR; + return EOF; +} |