aboutsummaryrefslogtreecommitdiff
path: root/newlib/libc/stdio/ssputs_r.c
diff options
context:
space:
mode:
Diffstat (limited to 'newlib/libc/stdio/ssputs_r.c')
-rw-r--r--newlib/libc/stdio/ssputs_r.c69
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;
+}