commit 1a89f8a178f528c1acb4ab130f2163665759614c
parent 859b7dd7f2dc5d8396488700e0ab35d207188ed9
Author: Oswald Buddenhagen <ossi@users.sf.net>
Date: Sun, 1 May 2022 19:20:19 +0200
move imap_vprintf() to util.c and rename it to xvasprintf()
it's currently used only by IMAP, but it's logically low-level.
Diffstat:
M | src/common.h | | | 2 | ++ |
M | src/drv_imap.c | | | 104 | +------------------------------------------------------------------------------ |
M | src/util.c | | | 106 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
3 files changed, 109 insertions(+), 103 deletions(-)
diff --git a/src/common.h b/src/common.h
@@ -165,6 +165,8 @@ void ATTR_PRINTFLIKE(1, 0) vsys_error( const char *, va_list va );
void ATTR_PRINTFLIKE(1, 2) sys_error( const char *, ... );
void flushn( void );
+char *xvasprintf( const char *fmt, va_list ap );
+
#if !defined(_POSIX_SYNCHRONIZED_IO) || _POSIX_SYNCHRONIZED_IO <= 0
# define fdatasync fsync
#endif
diff --git a/src/drv_imap.c b/src/drv_imap.c
@@ -487,108 +487,6 @@ submit_imap_cmd( imap_store_t *ctx, imap_cmd_t *cmd )
}
}
-/* Minimal printf() replacement that supports an %\s format sequence to print backslash-escaped
- * string literals. Note that this does not automatically add quotes around the printed string,
- * so it is possible to concatenate multiple segments. */
-static char *
-imap_vprintf( const char *fmt, va_list ap )
-{
- const char *s;
- char *d, *ed;
- char c;
-#define MAX_SEGS 16
-#define add_seg(s, l) \
- do { \
- if (nsegs == MAX_SEGS) \
- oob(); \
- segs[nsegs] = s; \
- segls[nsegs++] = l; \
- totlen += l; \
- } while (0)
- int nsegs = 0;
- uint totlen = 0;
- const char *segs[MAX_SEGS];
- uint segls[MAX_SEGS];
- char buf[1000];
-
- d = buf;
- ed = d + sizeof(buf);
- s = fmt;
- for (;;) {
- c = *fmt;
- if (!c || c == '%') {
- uint l = fmt - s;
- if (l)
- add_seg( s, l );
- if (!c)
- break;
- uint maxlen = UINT_MAX;
- c = *++fmt;
- if (c == '\\') {
- c = *++fmt;
- if (c != 's') {
- fputs( "Fatal: unsupported escaped format specifier. Please report a bug.\n", stderr );
- abort();
- }
- char *bd = d;
- s = va_arg( ap, const char * );
- while ((c = *s++)) {
- if (d + 2 > ed)
- oob();
- if (c == '\\' || c == '"')
- *d++ = '\\';
- *d++ = c;
- }
- l = d - bd;
- if (l)
- add_seg( bd, l );
- } else { /* \\ cannot be combined with anything else. */
- if (c == '.') {
- c = *++fmt;
- if (c != '*') {
- fputs( "Fatal: unsupported string length specification. Please report a bug.\n", stderr );
- abort();
- }
- maxlen = va_arg( ap, uint );
- c = *++fmt;
- }
- if (c == 'c') {
- if (d + 1 > ed)
- oob();
- add_seg( d, 1 );
- *d++ = (char)va_arg( ap , int );
- } else if (c == 's') {
- s = va_arg( ap, const char * );
- l = strnlen( s, maxlen );
- if (l)
- add_seg( s, l );
- } else if (c == 'd') {
- l = nfsnprintf( d, ed - d, "%d", va_arg( ap, int ) );
- add_seg( d, l );
- d += l;
- } else if (c == 'u') {
- l = nfsnprintf( d, ed - d, "%u", va_arg( ap, uint ) );
- add_seg( d, l );
- d += l;
- } else {
- fputs( "Fatal: unsupported format specifier. Please report a bug.\n", stderr );
- abort();
- }
- }
- s = ++fmt;
- } else {
- fmt++;
- }
- }
- char *out = d = nfmalloc( totlen + 1 );
- for (int i = 0; i < nsegs; i++) {
- memcpy( d, segs[i], segls[i] );
- d += segls[i];
- }
- *d = 0;
- return out;
-}
-
static void
imap_exec( imap_store_t *ctx, imap_cmd_t *cmdp,
void (*done)( imap_store_t *ctx, imap_cmd_t *cmd, int response ),
@@ -600,7 +498,7 @@ imap_exec( imap_store_t *ctx, imap_cmd_t *cmdp,
cmdp = new_imap_cmd( sizeof(*cmdp) );
cmdp->param.done = done;
va_start( ap, fmt );
- cmdp->cmd = imap_vprintf( fmt, ap );
+ cmdp->cmd = xvasprintf( fmt, ap );
va_end( ap );
submit_imap_cmd( ctx, cmdp );
}
diff --git a/src/util.c b/src/util.c
@@ -184,6 +184,112 @@ sys_error( const char *msg, ... )
va_end( va );
}
+// Minimal printf() replacement with custom format sequence(s):
+// - %\\s
+// Print backslash-escaped string literals. Note that this does not
+// automatically add quotes around the printed string, so it is
+// possible to concatenate multiple segments.
+
+// TODO: Trade off segments vs. buffer capacity dynamically.
+#define QPRINTF_SEGS 16
+#define QPRINTF_BUFF 1000
+
+char *
+xvasprintf( const char *fmt, va_list ap )
+{
+ int nsegs = 0;
+ uint totlen = 0;
+ const char *segs[QPRINTF_SEGS];
+ uint segls[QPRINTF_SEGS];
+ char buf[QPRINTF_BUFF];
+
+#define ADD_SEG(p, l) \
+ do { \
+ if (nsegs == QPRINTF_SEGS) \
+ oob(); \
+ segs[nsegs] = p; \
+ segls[nsegs++] = l; \
+ totlen += l; \
+ } while (0)
+
+ char *d = buf;
+ char *ed = d + sizeof(buf);
+ const char *s = fmt;
+ for (;;) {
+ char c = *fmt;
+ if (!c || c == '%') {
+ uint l = fmt - s;
+ if (l)
+ ADD_SEG( s, l );
+ if (!c)
+ break;
+ uint maxlen = UINT_MAX;
+ c = *++fmt;
+ if (c == '\\') {
+ c = *++fmt;
+ if (c != 's') {
+ fputs( "Fatal: unsupported escaped format specifier. Please report a bug.\n", stderr );
+ abort();
+ }
+ char *bd = d;
+ s = va_arg( ap, const char * );
+ while ((c = *s++)) {
+ if (d + 2 > ed)
+ oob();
+ if (c == '\\' || c == '"')
+ *d++ = '\\';
+ *d++ = c;
+ }
+ l = d - bd;
+ if (l)
+ ADD_SEG( bd, l );
+ } else { // \\ cannot be combined with anything else.
+ if (c == '.') {
+ c = *++fmt;
+ if (c != '*') {
+ fputs( "Fatal: unsupported string length specification. Please report a bug.\n", stderr );
+ abort();
+ }
+ maxlen = va_arg( ap, uint );
+ c = *++fmt;
+ }
+ if (c == 'c') {
+ if (d + 1 > ed)
+ oob();
+ ADD_SEG( d, 1 );
+ *d++ = (char)va_arg( ap, int );
+ } else if (c == 's') {
+ s = va_arg( ap, const char * );
+ l = strnlen( s, maxlen );
+ if (l)
+ ADD_SEG( s, l );
+ } else if (c == 'd') {
+ l = nfsnprintf( d, ed - d, "%d", va_arg( ap, int ) );
+ ADD_SEG( d, l );
+ d += l;
+ } else if (c == 'u') {
+ l = nfsnprintf( d, ed - d, "%u", va_arg( ap, uint ) );
+ ADD_SEG( d, l );
+ d += l;
+ } else {
+ fputs( "Fatal: unsupported format specifier. Please report a bug.\n", stderr );
+ abort();
+ }
+ }
+ s = ++fmt;
+ } else {
+ fmt++;
+ }
+ }
+ char *out = d = nfmalloc( totlen + 1 );
+ for (int i = 0; i < nsegs; i++) {
+ memcpy( d, segs[i], segls[i] );
+ d += segls[i];
+ }
+ *d = 0;
+ return out;
+}
+
void
vFprintf( FILE *f, const char *msg, va_list va )
{