dgaudet 98/03/29 01:35:44
Modified: src/ap ap_snprintf.c
src/include ap.h
src/main alloc.c buff.c
Log:
Revamp the apapi_vformatter interface to reduce copies. In this interface
the callers hand apapi_vformatter pointers into their own private buffers,
and are called back for flushing when appropriate. This is more efficient
and seems somewhat more clean.
Revision Changes Path
1.16 +23 -44 apache-1.3/src/ap/ap_snprintf.c
Index: ap_snprintf.c
===================================================================
RCS file: /export/home/cvs/apache-1.3/src/ap/ap_snprintf.c,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -r1.15 -r1.16
--- ap_snprintf.c 1998/03/28 21:58:38 1.15
+++ ap_snprintf.c 1998/03/29 09:35:40 1.16
@@ -266,10 +266,11 @@
#define INS_CHAR(c, sp, bep, cc) \
{ \
if (sp == bep) { \
- if (write_func(write_data, staging_buf, \
- sizeof(staging_buf)) != 0) \
+ vbuff->curpos = sp; \
+ if (flush_func(vbuff)) \
return -1; \
- sp = staging_buf; \
+ sp = vbuff->curpos; \
+ bep = vbuff->endpos; \
} \
*sp++ = (c); \
cc++; \
@@ -503,9 +504,8 @@
/*
* Do format conversion placing the output in buffer
*/
-API_EXPORT(int) apapi_vformatter(
- int (*write_func)(void *, const char *, size_t),
- void *write_data, const char *fmt, va_list ap)
+API_EXPORT(int) apapi_vformatter(int (*flush_func)(apapi_vformatter_buff *),
+ apapi_vformatter_buff *vbuff, const char *fmt, va_list ap)
{
register char *sp;
register char *bep;
@@ -531,8 +531,6 @@
char num_buf[NUM_BUF_SIZE];
char char_buf[2]; /* for printing %% and %<unknown> */
- char staging_buf[MAX_STRING_LEN];
-
/*
* Flag variables
*/
@@ -544,8 +542,8 @@
boolean_e adjust_width;
bool_int is_negative;
- sp = staging_buf;
- bep = sp + sizeof(staging_buf);
+ sp = vbuff->curpos;
+ bep = vbuff->endpos;
while (*fmt) {
if (*fmt != '%') {
@@ -875,33 +873,14 @@
}
fmt++;
}
- if (sp > staging_buf) {
- if (write_func(write_data, staging_buf, sp - staging_buf) != 0) {
- return -1;
- }
- }
+ vbuff->curpos = sp;
return cc;
}
-struct snprintf_write_data {
- char *strp;
- char *end_buf;
-};
-
-static int snprintf_write(void *vdata, const char *inp, size_t len)
+static int snprintf_flush(apapi_vformatter_buff *vbuff)
{
- struct snprintf_write_data *wd;
- size_t amt;
-
- wd = vdata;
- amt = wd->end_buf - wd->strp;
- if (len > amt) {
- len = amt;
- }
- memcpy(wd->strp, inp, len);
- wd->strp += len;
- return 0;
+ return -1;
}
@@ -909,19 +888,19 @@
{
int cc;
va_list ap;
- struct snprintf_write_data wd;
+ apapi_vformatter_buff vbuff;
if (len == 0)
return 0;
/* save one byte for nul terminator */
- wd.strp = buf;
- wd.end_buf = buf + len - 1;
+ vbuff.curpos = buf;
+ vbuff.endpos = buf + len - 1;
va_start(ap, format);
- cc = apapi_vformatter(snprintf_write, &wd, format, ap);
- *wd.strp = '\0';
+ cc = apapi_vformatter(snprintf_flush, &vbuff, format, ap);
va_end(ap);
- return (cc);
+ *vbuff.curpos = '\0';
+ return (cc == -1) ? len : cc;
}
@@ -929,15 +908,15 @@
va_list ap)
{
int cc;
- struct snprintf_write_data wd;
+ apapi_vformatter_buff vbuff;
if (len == 0)
return 0;
/* save one byte for nul terminator */
- wd.strp = buf;
- wd.end_buf = buf + len - 1;
- cc = apapi_vformatter(snprintf_write, &wd, format, ap);
- *wd.strp = '\0';
- return (cc);
+ vbuff.curpos = buf;
+ vbuff.endpos = buf + len - 1;
+ cc = apapi_vformatter(snprintf_flush, &vbuff, format, ap);
+ *vbuff.curpos = '\0';
+ return (cc == -1) ? len : cc;
}
1.9 +41 -11 apache-1.3/src/include/ap.h
Index: ap.h
===================================================================
RCS file: /export/home/cvs/apache-1.3/src/include/ap.h,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- ap.h 1998/03/28 11:58:17 1.8
+++ ap.h 1998/03/29 09:35:41 1.9
@@ -80,21 +80,51 @@
/* apapi_vformatter() is a generic printf-style formatting routine
* with some extensions.
*
- * The write_func() is called when there is data available to be
- * output. write_func() should return 0 when it wishes apapi_vformatter
- * to continue, and non-zero otherwise. apapi_vformatter will stop
- * immediately and return -1 when a non-zero return from
- * write_func().
+ * The apapi_vformatter_buff has two elements curpos and endpos.
+ * curpos is where apapi_vformatter will write the next byte of output.
+ * It proceeds writing output to curpos, and updating curpos, until
+ * either the end of output is reached, or curpos == endpos (i.e. the
+ * buffer is full).
*
- * If write_func() always returns 0 then apapi_vformatter will return
- * the number of characters written.
+ * If the end of output is reached, apapi_vformatter returns the
+ * number of bytes written.
+ *
+ * When the buffer is full, the flush_func is called. The flush_func
+ * can return -1 to indicate that no further output should be attempted,
+ * and apapi_vformatter will return immediately with -1. Otherwise
+ * the flush_func should flush the buffer in whatever manner is
+ * appropriate, re-initialize curpos and endpos, and return 0.
+ *
+ * Note that flush_func is only invoked as a result of attempting to
+ * write another byte at curpos when curpos == endpos. So for
+ * example, it's possible when the output exactly matches the buffer
+ * space available that curpos == endpos will be true when
+ * apapi_vformatter returns.
*/
-API_EXPORT(int) apapi_vformatter(
- int (*write_func)(void *write_data, const char *outp, size_t len),
- void *write_data, const char *fmt, va_list ap);
+typedef struct {
+ char *curpos;
+ char *endpos;
+} apapi_vformatter_buff;
-/* These are snprintf implementations based on apapi_vformatter(). */
+API_EXPORT(int) apapi_vformatter(int (*flush_func)(apapi_vformatter_buff *),
+ apapi_vformatter_buff *, const char *fmt, va_list ap);
+
+/* These are snprintf implementations based on apapi_vformatter().
+ *
+ * Note that various standards and implementations disagree on the return
+ * value of snprintf, and side-effects due to %n in the formatting string.
+ * ap_snprintf behaves as follows:
+ *
+ * Process the format string until the entire string is exhausted, or
+ * the buffer fills. If the buffer fills then stop processing immediately
+ * (so no further %n arguments are processed), and return the buffer
+ * length. In all cases the buffer is NUL terminated.
+ *
+ * In no event does ap_snprintf return a negative number. It's not possible
+ * to distinguish between an output which was truncated, and an output which
+ * exactly filled the buffer.
+ */
API_EXPORT(int) ap_snprintf(char *buf, size_t len, const char *format,...)
__attribute__((format(printf,3,4)));
API_EXPORT(int) ap_vsnprintf(char *buf, size_t len, const char *format,
1.82 +31 -40 apache-1.3/src/main/alloc.c
Index: alloc.c
===================================================================
RCS file: /export/home/cvs/apache-1.3/src/main/alloc.c,v
retrieving revision 1.81
retrieving revision 1.82
diff -u -r1.81 -r1.82
--- alloc.c 1998/03/28 21:35:41 1.81
+++ alloc.c 1998/03/29 09:35:42 1.82
@@ -779,68 +779,52 @@
*/
struct psprintf_data {
- pool *p;
+ apapi_vformatter_buff vbuff;
#ifdef ALLOC_USE_MALLOC
char *base;
- size_t len;
#else
union block_hdr *blok;
- char *strp;
int got_a_new_block;
#endif
};
-static int psprintf_write(void *vdata, const char *inp, size_t len)
+static int psprintf_flush(apapi_vformatter_buff *vbuff)
{
+ struct psprintf_data *ps = (struct psprintf_data *)vbuff;
#ifdef ALLOC_USE_MALLOC
- struct psprintf_data *ps;
int size;
char *ptr;
- ps = vdata;
-
- size = ps->len + len + 1;
- ptr = realloc(ps->base, size);
+ size = ps->vbuff.curpos - ps->base;
+ ptr = realloc(ps->base, 2*size);
if (ptr == NULL) {
fputs("Ouch! Out of memory!\n", stderr);
exit(1);
}
ps->base = ptr;
- memcpy(ptr + ps->len, inp, len);
- ps->len += len;
+ ps->vbuff.curpos = ptr + size;
+ ps->vbuff.endpos = ptr + 2*size - 1;
return 0;
#else
- struct psprintf_data *ps;
union block_hdr *blok;
union block_hdr *nblok;
size_t cur_len;
char *strp;
- ps = vdata;
-
- /* does it fit in the current block? */
blok = ps->blok;
- strp = ps->strp;
- if (strp + len + 1 < blok->h.endp) {
- memcpy(strp, inp, len);
- ps->strp = strp + len;
- return 0;
- }
-
+ strp = ps->vbuff.curpos;
cur_len = strp - blok->h.first_avail;
/* must try another blok */
block_alarms();
(void) acquire_mutex(alloc_mutex);
- nblok = new_block((cur_len + len)*2);
+ nblok = new_block(2 * cur_len);
(void) release_mutex(alloc_mutex);
unblock_alarms();
- strp = nblok->h.first_avail;
- memcpy(strp, blok->h.first_avail, cur_len);
- strp += cur_len;
- memcpy(strp, inp, len);
- strp += len;
- ps->strp = strp;
+ memcpy(nblok->h.first_avail, strp, cur_len);
+ strp = nblok->h.first_avail + cur_len;
+ ps->vbuff.curpos = strp;
+ ps->vbuff.endpos = nblok->h.endp - 1;
/* did we allocate the current blok? if so free it up */
if (ps->got_a_new_block) {
@@ -865,16 +849,23 @@
void *ptr;
block_alarms();
- ps.p = p;
- ps.base = NULL;
- ps.len = CLICK_SZ; /* need room at beginning for allocation_list */
- apapi_vformatter(psprintf_write, &ps, fmt, ap);
+ ps.base = malloc(512);
+ if (ps.base == NULL) {
+ fputs("Ouch! Out of memory!\n", stderr);
+ exit(1);
+ }
+ /* need room at beginning for allocation_list */
+ ps.vbuff.curpos = ps.base + CLICK_SZ;
+ ps.vbuff.endpos = ps.base + 511;
+ apapi_vformatter(psprintf_flush, &ps.vbuff, fmt, ap);
+ *ps.vbuff.curpos++ = '\0';
ptr = ps.base;
+ /* shrink */
+ ptr = realloc(ptr, ps.vbuff.curpos - ptr);
if (ptr == NULL) {
- unblock_alarms();
- return pstrdup(p, "");
+ fputs("Ouch! Out of memory!\n", stderr);
+ exit(1);
}
- *((char *)ptr + ps.len) = '\0'; /* room was saved for this */
*(void **)ptr = p->allocation_list;
p->allocation_list = ptr;
unblock_alarms();
@@ -884,14 +875,14 @@
char *strp;
int size;
- ps.p = p;
ps.blok = p->last;
- ps.strp = ps.blok->h.first_avail;
+ ps.vbuff.curpos = ps.blok->h.first_avail;
+ ps.vbuff.endpos = ps.blok->h.endp - 1;
ps.got_a_new_block = 0;
- apapi_vformatter(psprintf_write, &ps, fmt, ap);
+ apapi_vformatter(psprintf_flush, &ps.vbuff, fmt, ap);
- strp = ps.strp;
+ strp = ps.vbuff.curpos;
*strp++ = '\0';
size = strp - ps.blok->h.first_avail;
1.68 +35 -5 apache-1.3/src/main/buff.c
Index: buff.c
===================================================================
RCS file: /export/home/cvs/apache-1.3/src/main/buff.c,v
retrieving revision 1.67
retrieving revision 1.68
diff -u -r1.67 -r1.68
--- buff.c 1998/03/28 11:58:22 1.67
+++ buff.c 1998/03/29 09:35:43 1.68
@@ -1445,11 +1445,24 @@
fb->error_data = data;
}
-static int bprintf_write(void *vdata, const char *inp, size_t len)
+struct bprintf_data {
+ apapi_vformatter_buff vbuff;
+ BUFF *fb;
+};
+
+static int bprintf_flush(apapi_vformatter_buff *vbuff)
{
- if (bwrite(vdata, inp, len) != len) {
- return -1;
+ struct bprintf_data *b = (struct bprintf_data *)vbuff;
+ BUFF *fb = b->fb;
+
+ fb->outcnt += b->vbuff.curpos - (char *)&fb->outbase[fb->outcnt];
+ if (fb->outcnt == fb->bufsiz) {
+ if (bflush(fb)) {
+ return -1;
+ }
}
+ vbuff->curpos = &fb->outbase[fb->outcnt];
+ vbuff->endpos = &fb->outbase[fb->bufsiz];
return 0;
}
@@ -1457,14 +1470,31 @@
{
va_list ap;
int res;
+ struct bprintf_data b;
+ b.vbuff.curpos = &fb->outbase[fb->outcnt];
+ b.vbuff.endpos = &fb->outbase[fb->bufsiz];
+ b.fb = fb;
va_start(ap, fmt);
- res = apapi_vformatter(bprintf_write, fb, fmt, ap);
+ res = apapi_vformatter(bprintf_flush, &b.vbuff, fmt, ap);
va_end(ap);
+ if (res != -1) {
+ fb->outcnt += b.vbuff.curpos - (char *)&fb->outbase[fb->outcnt];
+ }
return res;
}
API_EXPORT(int) vbprintf(BUFF *fb, const char *fmt, va_list ap)
{
- return apapi_vformatter(bprintf_write, fb, fmt, ap);
+ struct bprintf_data b;
+ int res;
+
+ b.vbuff.curpos = &fb->outbase[fb->outcnt];
+ b.vbuff.endpos = &fb->outbase[fb->bufsiz];
+ b.fb = fb;
+ res = apapi_vformatter(bprintf_flush, &b.vbuff, fmt, ap);
+ if (res != -1) {
+ fb->outcnt += b.vbuff.curpos - (char *)&fb->outbase[fb->outcnt];
+ }
+ return res;
}