move imap_vprintf() to util.c and rename it to xvasprintf()
it's currently used only by IMAP, but it's logically low-level.
This commit is contained in:
parent
859b7dd7f2
commit
1a89f8a178
|
@ -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 ATTR_PRINTFLIKE(1, 2) sys_error( const char *, ... );
|
||||||
void flushn( void );
|
void flushn( void );
|
||||||
|
|
||||||
|
char *xvasprintf( const char *fmt, va_list ap );
|
||||||
|
|
||||||
#if !defined(_POSIX_SYNCHRONIZED_IO) || _POSIX_SYNCHRONIZED_IO <= 0
|
#if !defined(_POSIX_SYNCHRONIZED_IO) || _POSIX_SYNCHRONIZED_IO <= 0
|
||||||
# define fdatasync fsync
|
# define fdatasync fsync
|
||||||
#endif
|
#endif
|
||||||
|
|
104
src/drv_imap.c
104
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
|
static void
|
||||||
imap_exec( imap_store_t *ctx, imap_cmd_t *cmdp,
|
imap_exec( imap_store_t *ctx, imap_cmd_t *cmdp,
|
||||||
void (*done)( imap_store_t *ctx, imap_cmd_t *cmd, int response ),
|
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 = new_imap_cmd( sizeof(*cmdp) );
|
||||||
cmdp->param.done = done;
|
cmdp->param.done = done;
|
||||||
va_start( ap, fmt );
|
va_start( ap, fmt );
|
||||||
cmdp->cmd = imap_vprintf( fmt, ap );
|
cmdp->cmd = xvasprintf( fmt, ap );
|
||||||
va_end( ap );
|
va_end( ap );
|
||||||
submit_imap_cmd( ctx, cmdp );
|
submit_imap_cmd( ctx, cmdp );
|
||||||
}
|
}
|
||||||
|
|
106
src/util.c
106
src/util.c
|
@ -184,6 +184,112 @@ sys_error( const char *msg, ... )
|
||||||
va_end( va );
|
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
|
void
|
||||||
vFprintf( FILE *f, const char *msg, va_list va )
|
vFprintf( FILE *f, const char *msg, va_list va )
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue
Block a user