Index: ossp-pkg/sa/TODO RCS File: /v/ossp/cvs/ossp-pkg/sa/TODO,v rcsdiff -q -kk '-r1.20' '-r1.21' -u '/v/ossp/cvs/ossp-pkg/sa/TODO,v' 2>/dev/null --- TODO 2001/10/10 07:57:29 1.20 +++ TODO 2001/10/10 09:05:18 1.21 @@ -2,11 +2,6 @@ TODO ---- -o Perhaps move 1024-buffer of writef into sa_t and make adjustable or - even better: provide a sa_mvsnprintf() variant which directly does the - sa_write calls and this way the whole buffering is the SA_BUFFER_WRITE. - This would be exactly what the user would expect. - o Provide a full test suite for the whole API. - inet://0.0.0.0:0 -> inet://0.0.0.0:514 Index: ossp-pkg/sa/sa.c RCS File: /v/ossp/cvs/ossp-pkg/sa/sa.c,v rcsdiff -q -kk '-r1.26' '-r1.27' -u '/v/ossp/cvs/ossp-pkg/sa/sa.c,v' 2>/dev/null --- sa.c 2001/10/10 07:42:26 1.26 +++ sa.c 2001/10/10 09:05:18 1.27 @@ -248,62 +248,117 @@ #endif } -/* minimal vsnprintf(3) variant which supports %{c,s,d} only */ -static int sa_mvsnprintf(char *buffer, size_t bufsize, const char *format, va_list ap) +/* minimal output-independent vprintf(3) variant which supports %{c,s,d,%} only */ +static int sa_mvxprintf(int (*output)(void *ctx, const char *buffer, size_t bufsize), void *ctx, const char *format, va_list ap) { - char *bufptr; - char *bufend; /* sufficient integer buffer: x log_10(2) + safety */ char ibuf[((sizeof(int)*8)/3)+10]; char *cp; char c; int d; int n; + int bytes; - bufptr = buffer; - bufend = buffer + bufsize - 1; - while ((c = *format++) != '\0' && bufptr < bufend) { - if (c == '%') { - c = *format++; - if (c == '%') - /* implement "%%" */ - *bufptr++ = c; - else if (c == 'c') - /* implement "%c" */ - *bufptr++ = (char)va_arg(ap, int); + if (format == NULL || ap == NULL) + return -1; + bytes = 0; + while (*format != '\0') { + if (*format == '%') { + c = *(format+1); + if (c == '%') { + /* expand "%%" */ + cp = &c; + n = sizeof(char); + } + else if (c == 'c') { + /* expand "%c" */ + c = (char)va_arg(ap, int); + cp = &c; + n = sizeof(char); + } else if (c == 's') { - /* implement "%s" */ + /* expand "%s" */ if ((cp = (char *)va_arg(ap, char *)) == NULL) cp = "(null)"; n = strlen(cp); - if ((bufptr + n) > bufend) - n = bufend - bufptr; - memcpy(bufptr, cp, n); - bufptr += n; } else if (c == 'd') { - /* implement "%d" */ + /* expand "%d" */ d = (int)va_arg(ap, int); #ifdef HAVE_SNPRINTF snprintf(ibuf, sizeof(ibuf), "%d", d); /* explicitly secure */ #else sprintf(ibuf, "%d", d); /* implicitly secure */ #endif - n = strlen(ibuf); - memcpy(bufptr, ibuf, n); - bufptr += n; + cp = ibuf; + n = strlen(cp); } else { - *bufptr++ = '%'; - if (bufptr < bufend) - *bufptr++ = c; + /* any other "%X" */ + cp = (char *)format; + n = 2; } + format += 2; } - else - *bufptr++ = c; + else { + /* plain text */ + cp = (char *)format; + if ((format = strchr(cp, '%')) == NULL) + format = strchr(cp, '\0'); + n = format - cp; + } + /* perform output operation */ + if (output != NULL) + if ((n = output(ctx, cp, n)) == -1) + break; + bytes += n; } - *bufptr = '\0'; - return (bufptr - buffer); + return bytes; +} + +/* output callback function context for sa_mvsnprintf() */ +typedef struct { + char *bufptr; + size_t buflen; +} sa_mvsnprintf_cb_t; + +/* output callback function for sa_mvsnprintf() */ +static int sa_mvsnprintf_cb(void *_ctx, const char *buffer, size_t bufsize) +{ + sa_mvsnprintf_cb_t *ctx = (sa_mvsnprintf_cb_t *)_ctx; + + if (bufsize > ctx->buflen) + return -1; + memcpy(ctx->bufptr, buffer, bufsize); + ctx->bufptr += bufsize; + ctx->buflen -= bufsize; + return bufsize; +} + +/* minimal vsnprintf(3) variant which supports %{c,s,d} only */ +static int sa_mvsnprintf(char *buffer, size_t bufsize, const char *format, va_list ap) +{ + int n; + sa_mvsnprintf_cb_t ctx; + + if (format == NULL || ap == NULL) + return -1; + if (buffer != NULL && bufsize == 0) + return -1; + if (buffer == NULL) + /* just determine output length */ + n = sa_mvxprintf(NULL, NULL, format, ap); + else { + /* perform real output */ + ctx.bufptr = buffer; + ctx.buflen = bufsize - 1; + n = sa_mvxprintf(sa_mvsnprintf_cb, &ctx, format, ap); + } + if (n != -1 && ctx.buflen == 0) + n = -1; + if (n != -1) + *(ctx.bufptr) = '\0'; + return n; } /* minimal snprintf(3) variant which supports %{c,s,d} only */ @@ -312,10 +367,6 @@ int chars; va_list ap; - /* argument sanity check(s) */ - if (buffer == NULL || bufsize == 0 || format == NULL) - return 0; - /* pass through to va_list based variant */ va_start(ap, format); chars = sa_mvsnprintf(buffer, bufsize, format, ap); @@ -1675,13 +1726,29 @@ return rv; } +/* output callback function context for sa_writef() */ +typedef struct { + sa_t *sa; + sa_rc_t rv; +} sa_writef_cb_t; + +/* output callback function for sa_writef() */ +static int sa_writef_cb(void *_ctx, const char *buffer, size_t bufsize) +{ + size_t n; + sa_writef_cb_t *ctx = (sa_writef_cb_t *)_ctx; + + if ((ctx->rv = sa_write(ctx->sa, buffer, bufsize, &n)) != SA_OK) + n = -1; + return n; +} + /* write formatted string to socket (convinience function) */ sa_rc_t sa_writef(sa_t *sa, const char *cpFmt, ...) { va_list ap; size_t n; - char caBuf[1024]; - sa_rc_t rv; + sa_writef_cb_t ctx; /* argument sanity check(s) */ if (sa == NULL || cpFmt == NULL) @@ -1697,13 +1764,12 @@ /* format string into temporary buffer */ va_start(ap, cpFmt); - n = sa_mvsnprintf(caBuf, sizeof(caBuf), cpFmt, ap); + ctx.sa = sa; + ctx.rv = SA_OK; + n = sa_mvxprintf(sa_writef_cb, &ctx, cpFmt, ap); va_end(ap); - /* write result buffer to socket */ - rv = sa_write(sa, caBuf, n, &n); - - return rv; + return ctx.rv; } /* flush write/outgoing I/O buffer */