diff options
Diffstat (limited to 'src/output.c')
-rw-r--r-- | src/output.c | 90 |
1 files changed, 60 insertions, 30 deletions
diff --git a/src/output.c b/src/output.c index f62e7ea..4d3b4c2 100644 --- a/src/output.c +++ b/src/output.c @@ -99,9 +99,6 @@ struct output *out1 = &output; struct output *out2 = &errout; -#ifndef USE_GLIBC_STDIO -static void __outstr(const char *, size_t, struct output *); -#endif static int xvsnprintf(char *, size_t, const char *, va_list); @@ -134,16 +131,20 @@ RESET { #endif -#ifndef USE_GLIBC_STDIO -static void -__outstr(const char *p, size_t len, struct output *dest) +void +outmem(const char *p, size_t len, struct output *dest) { +#ifdef USE_GLIBC_STDIO + INTOFF; + fwrite(p, 1, len, dest->stream); + INTON; +#else size_t bufsize; size_t offset; size_t nleft; nleft = dest->end - dest->nextc; - if (nleft >= len) { + if (likely(nleft >= len)) { buffered: dest->nextc = mempcpy(dest->nextc, p, len); return; @@ -153,10 +154,13 @@ buffered: if (!bufsize) { ; } else if (dest->buf == NULL) { +#ifdef notyet if (dest->fd == MEM_OUT && len > bufsize) { bufsize = len; } +#endif offset = 0; +#ifdef notyet goto alloc; } else if (dest->fd == MEM_OUT) { offset = bufsize; @@ -168,6 +172,7 @@ buffered: if (bufsize < offset) goto err; alloc: +#endif INTOFF; dest->buf = ckrealloc(dest->buf, bufsize); dest->bufsize = bufsize; @@ -183,11 +188,13 @@ alloc: goto buffered; if ((xwrite(dest->fd, p, len))) { +#ifdef notyet err: +#endif dest->flags |= OUTPUT_ERR; } -} #endif +} void @@ -201,7 +208,7 @@ outstr(const char *p, struct output *file) size_t len; len = strlen(p); - __outstr(p, len, file); + outmem(p, len, file); #endif } @@ -213,7 +220,7 @@ void outcslow(int c, struct output *dest) { char buf = c; - __outstr(&buf, 1, dest); + outmem(&buf, 1, dest); } #endif @@ -283,35 +290,58 @@ fmtstr(char *outbuf, size_t length, const char *fmt, ...) } +static int xvasprintf(char **sp, size_t size, const char *f, va_list ap) +{ + char *s; + int len; + va_list ap2; + + va_copy(ap2, ap); + len = xvsnprintf(*sp, size, f, ap2); + va_end(ap2); + if (len < 0) + sh_error("xvsnprintf failed"); + if (len < size) + return len; + + s = stalloc((len >= stackblocksize() ? len : stackblocksize()) + 1); + *sp = s; + len = xvsnprintf(s, len + 1, f, ap); + return len; +} + + +int xasprintf(char **sp, const char *f, ...) +{ + va_list ap; + int ret; + + va_start(ap, f); + ret = xvasprintf(sp, 0, f, ap); + va_end(ap); + return ret; +} + + #ifndef USE_GLIBC_STDIO void doformat(struct output *dest, const char *f, va_list ap) { struct stackmark smark; char *s; - int len, ret; - size_t size; - va_list ap2; + int len; + int olen; - va_copy(ap2, ap); - size = dest->end - dest->nextc; - len = xvsnprintf(dest->nextc, size, f, ap2); - va_end(ap2); - if (len < 0) { - dest->flags |= OUTPUT_ERR; - return; - } - if (len < size) { + setstackmark(&smark); + s = dest->nextc; + olen = dest->end - dest->nextc; + len = xvasprintf(&s, olen, f, ap); + if (likely(olen > len)) { dest->nextc += len; - return; + goto out; } - setstackmark(&smark); - s = stalloc((len >= stackblocksize() ? len : stackblocksize()) + 1); - ret = xvsnprintf(s, len + 1, f, ap); - if (ret == len) - __outstr(s, len, dest); - else - dest->flags |= OUTPUT_ERR; + outmem(s, len, dest); +out: popstackmark(&smark); } #endif |