--- 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: <available-bits> 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 */
|