isync

mailbox synchronization program
git clone https://git.code.sf.net/p/isync/isync
Log | Files | Refs | README | LICENSE

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:
Msrc/common.h | 2++
Msrc/drv_imap.c | 104+------------------------------------------------------------------------------
Msrc/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 ) {