From 7b567164fff524b8d9ddbe09a8ffa78f66c6f8b5 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 4 Nov 2016 21:48:58 +0100 Subject: [PATCH] abstract growable arrays somewhat ... and sneak in a C99 requirement on the way. just because. --- configure.ac | 4 +-- src/common.h | 31 +++++++++++++++++- src/driver.h | 2 +- src/drv_imap.c | 18 +++++----- src/drv_maildir.c | 83 ++++++++++++++++++++++------------------------- src/sync.c | 27 +++++++-------- src/util.c | 4 +-- 7 files changed, 93 insertions(+), 76 deletions(-) diff --git a/configure.ac b/configure.ac index b103f71..2eab91a 100644 --- a/configure.ac +++ b/configure.ac @@ -4,9 +4,9 @@ AM_INIT_AUTOMAKE AM_MAINTAINER_MODE -AC_PROG_CC +AC_PROG_CC_C99 if test "$GCC" = yes; then - CFLAGS="$CFLAGS -pipe -W -Wall -Wshadow -Wstrict-prototypes -ansi -pedantic -Wno-overlength-strings" + CFLAGS="$CFLAGS -pipe -W -Wall -Wshadow -Wstrict-prototypes -std=c99 -pedantic -Wno-overlength-strings" fi CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE" diff --git a/src/common.h b/src/common.h index 18390f3..a2f80de 100644 --- a/src/common.h +++ b/src/common.h @@ -43,10 +43,12 @@ typedef unsigned int uint; # define ATTR_UNUSED __attribute__((unused)) # define ATTR_NORETURN __attribute__((noreturn)) # define ATTR_PRINTFLIKE(fmt,var) __attribute__((format(printf,fmt,var))) +# define ATTR_PACKED(ref) __attribute__((packed,aligned(sizeof(ref)))) #else # define ATTR_UNUSED # define ATTR_NORETURN # define ATTR_PRINTFLIKE(fmt,var) +# define ATTR_PACKED(ref) #endif #ifdef __GNUC__ @@ -137,7 +139,34 @@ char *expand_strdup( const char *s ); int map_name( const char *arg, char **result, int reserve, const char *in, const char *out ); -void sort_ints( int *arr, int len ); +#define DEFINE_ARRAY_TYPE(T) \ + typedef struct T##_array { \ + T *data; \ + int size; \ + } ATTR_PACKED(T *) T##_array_t; \ + typedef struct T##_array_alloc { \ + T##_array_t array; \ + int alloc; \ + } ATTR_PACKED(T *) T##_array_alloc_t; \ + static INLINE T *T##_array_append( T##_array_alloc_t *arr ) \ + { \ + if (arr->array.size == arr->alloc) { \ + arr->alloc = arr->alloc * 2 + 100; \ + arr->array.data = nfrealloc( arr->array.data, arr->alloc * sizeof(T) ); \ + } \ + return &arr->array.data[arr->array.size++]; \ + } + +#define ARRAY_INIT(arr) \ + do { (arr)->array.data = 0; (arr)->array.size = (arr)->alloc = 0; } while (0) + +#define ARRAY_SQUEEZE(arr) \ + do { \ + (arr)->data = nfrealloc( (arr)->data, (arr)->size * sizeof((arr)->data[0]) ); \ + } while (0) + +DEFINE_ARRAY_TYPE(int) +void sort_int_array( int_array_t array ); void arc4_init( void ); uchar arc4_getbyte( void ); diff --git a/src/driver.h b/src/driver.h index 1abf671..42000e8 100644 --- a/src/driver.h +++ b/src/driver.h @@ -207,7 +207,7 @@ struct driver { * and those named in the excs array (smaller than minuid). * The driver takes ownership of the excs array. Messages below newuid do not need * to have the TUID populated even if OPEN_FIND is set. */ - void (*load_box)( store_t *ctx, int minuid, int maxuid, int newuid, int *excs, int nexcs, + void (*load_box)( store_t *ctx, int minuid, int maxuid, int newuid, int_array_t excs, void (*cb)( int sts, void *aux ), void *aux ); /* Fetch the contents and flags of the given message from the current mailbox. */ diff --git a/src/drv_imap.c b/src/drv_imap.c index 4911f18..e2ae985 100644 --- a/src/drv_imap.c +++ b/src/drv_imap.c @@ -2292,7 +2292,7 @@ imap_prepare_load_box( store_t *gctx, int opts ) static void imap_submit_load( imap_store_t *, const char *, int, struct imap_cmd_refcounted_state * ); static void -imap_load_box( store_t *gctx, int minuid, int maxuid, int newuid, int *excs, int nexcs, +imap_load_box( store_t *gctx, int minuid, int maxuid, int newuid, int_array_t excs, void (*cb)( int sts, void *aux ), void *aux ) { imap_store_t *ctx = (imap_store_t *)gctx; @@ -2300,21 +2300,21 @@ imap_load_box( store_t *gctx, int minuid, int maxuid, int newuid, int *excs, int char buf[1000]; if (!ctx->gen.count) { - free( excs ); + free( excs.data ); cb( DRV_OK, aux ); } else { struct imap_cmd_refcounted_state *sts = imap_refcounted_new_state( cb, aux ); - sort_ints( excs, nexcs ); - for (i = 0; i < nexcs; ) { - for (bl = 0; i < nexcs && bl < 960; i++) { + sort_int_array( excs ); + for (i = 0; i < excs.size; ) { + for (bl = 0; i < excs.size && bl < 960; i++) { if (bl) buf[bl++] = ','; - bl += sprintf( buf + bl, "%d", excs[i] ); + bl += sprintf( buf + bl, "%d", excs.data[i] ); j = i; - for (; i + 1 < nexcs && excs[i + 1] == excs[i] + 1; i++) {} + for (; i + 1 < excs.size && excs.data[i + 1] == excs.data[i] + 1; i++) {} if (i != j) - bl += sprintf( buf + bl, ":%d", excs[i] ); + bl += sprintf( buf + bl, ":%d", excs.data[i] ); } imap_submit_load( ctx, buf, 0, sts ); } @@ -2333,7 +2333,7 @@ imap_load_box( store_t *gctx, int minuid, int maxuid, int newuid, int *excs, int imap_submit_load( ctx, buf, (ctx->gen.opts & OPEN_FIND), sts ); } done: - free( excs ); + free( excs.data ); imap_refcounted_done( sts ); } } diff --git a/src/drv_maildir.c b/src/drv_maildir.c index f97ac82..6e99d22 100644 --- a/src/drv_maildir.c +++ b/src/drv_maildir.c @@ -70,7 +70,8 @@ typedef struct maildir_message { typedef struct maildir_store { store_t gen; int uvfd, uvok, nuid, is_inbox, fresh[3]; - int minuid, maxuid, newuid, nexcs, *excs; + int minuid, maxuid, newuid; + int_array_t excs; char *trash; #ifdef USE_DB DB *db; @@ -262,7 +263,7 @@ maildir_cleanup( store_t *gctx ) free( ctx->usedb ); #endif /* USE_DB */ free( gctx->path ); - free( ctx->excs ); + free( ctx->excs.data ); if (ctx->uvfd >= 0) close( ctx->uvfd ); conf_wakeup( &ctx->lcktmr, -1 ); @@ -446,20 +447,17 @@ typedef struct { char tuid[TUIDL]; } msg_t; -typedef struct { - msg_t *ents; - int nents, nalloc; -} msglist_t; +DEFINE_ARRAY_TYPE(msg_t) static void -maildir_free_scan( msglist_t *msglist ) +maildir_free_scan( msg_t_array_alloc_t *msglist ) { int i; - if (msglist->ents) { - for (i = 0; i < msglist->nents; i++) - free( msglist->ents[i].base ); - free( msglist->ents ); + if (msglist->array.data) { + for (i = 0; i < msglist->array.size; i++) + free( msglist->array.data[i].base ); + free( msglist->array.data ); } } @@ -821,7 +819,7 @@ maildir_compare( const void *l, const void *r ) } static int -maildir_scan( maildir_store_t *ctx, msglist_t *msglist ) +maildir_scan( maildir_store_t *ctx, msg_t_array_alloc_t *msglist ) { maildir_store_conf_t *conf = (maildir_store_conf_t *)ctx->gen.conf; DIR *d; @@ -839,8 +837,7 @@ maildir_scan( maildir_store_t *ctx, msglist_t *msglist ) char buf[_POSIX_PATH_MAX], nbuf[_POSIX_PATH_MAX]; again: - msglist->ents = 0; - msglist->nents = msglist->nalloc = 0; + ARRAY_INIT( msglist ); ctx->gen.count = ctx->gen.recent = 0; if (ctx->uvok || ctx->maxuid == INT_MAX) { #ifdef USE_DB @@ -926,17 +923,13 @@ maildir_scan( maildir_store_t *ctx, msglist_t *msglist ) } if (uid <= ctx->maxuid) { if (uid < ctx->minuid) { - for (j = 0; j < ctx->nexcs; j++) - if (ctx->excs[j] == uid) + for (j = 0; j < ctx->excs.size; j++) + if (ctx->excs.data[j] == uid) goto oke; continue; oke: ; } - if (msglist->nalloc == msglist->nents) { - msglist->nalloc = msglist->nalloc * 2 + 100; - msglist->ents = nfrealloc( msglist->ents, msglist->nalloc * sizeof(msg_t) ); - } - entry = &msglist->ents[msglist->nents++]; + entry = msg_t_array_append( msglist ); entry->base = nfstrdup( e->d_name ); entry->uid = uid; entry->recent = i; @@ -992,9 +985,9 @@ maildir_scan( maildir_store_t *ctx, msglist_t *msglist ) tdb->close( tdb, 0 ); } #endif /* USE_DB */ - qsort( msglist->ents, msglist->nents, sizeof(msg_t), maildir_compare ); - for (uid = i = 0; i < msglist->nents; i++) { - entry = &msglist->ents[i]; + qsort( msglist->array.data, msglist->array.size, sizeof(msg_t), maildir_compare ); + for (uid = i = 0; i < msglist->array.size; i++) { + entry = &msglist->array.data[i]; if (entry->uid != INT_MAX) { if (uid == entry->uid) { #if 1 @@ -1134,7 +1127,7 @@ maildir_select_box( store_t *gctx, const char *name ) maildir_cleanup( gctx ); gctx->msgs = 0; - ctx->excs = 0; + ctx->excs.data = 0; ctx->uvfd = -1; #ifdef USE_DB ctx->db = 0; @@ -1215,9 +1208,9 @@ static int maildir_confirm_box_empty( store_t *gctx ) { maildir_store_t *ctx = (maildir_store_t *)gctx; - msglist_t msglist; + msg_t_array_alloc_t msglist; - ctx->nexcs = ctx->minuid = ctx->maxuid = ctx->newuid = 0; + ctx->excs.size = ctx->minuid = ctx->maxuid = ctx->newuid = 0; if (maildir_scan( ctx, &msglist ) != DRV_OK) return DRV_BOX_BAD; @@ -1289,27 +1282,27 @@ maildir_prepare_load_box( store_t *gctx, int opts ) } static void -maildir_load_box( store_t *gctx, int minuid, int maxuid, int newuid, int *excs, int nexcs, +maildir_load_box( store_t *gctx, int minuid, int maxuid, int newuid, int_array_t excs, void (*cb)( int sts, void *aux ), void *aux ) { maildir_store_t *ctx = (maildir_store_t *)gctx; message_t **msgapp; - msglist_t msglist; + msg_t_array_alloc_t msglist; int i; ctx->minuid = minuid; ctx->maxuid = maxuid; ctx->newuid = newuid; - ctx->excs = nfrealloc( excs, nexcs * sizeof(int) ); - ctx->nexcs = nexcs; + ARRAY_SQUEEZE( &excs ); + ctx->excs = excs; if (maildir_scan( ctx, &msglist ) != DRV_OK) { cb( DRV_BOX_BAD, aux ); return; } msgapp = &ctx->gen.msgs; - for (i = 0; i < msglist.nents; i++) - maildir_app_msg( ctx, &msgapp, msglist.ents + i ); + for (i = 0; i < msglist.array.size; i++) + maildir_app_msg( ctx, &msgapp, msglist.array.data + i ); maildir_free_scan( &msglist ); cb( DRV_OK, aux ); @@ -1320,37 +1313,37 @@ maildir_rescan( maildir_store_t *ctx ) { message_t **msgapp; maildir_message_t *msg; - msglist_t msglist; + msg_t_array_alloc_t msglist; int i; ctx->fresh[0] = ctx->fresh[1] = 0; if (maildir_scan( ctx, &msglist ) != DRV_OK) return DRV_BOX_BAD; for (msgapp = &ctx->gen.msgs, i = 0; - (msg = (maildir_message_t *)*msgapp) || i < msglist.nents; ) + (msg = (maildir_message_t *)*msgapp) || i < msglist.array.size; ) { if (!msg) { #if 0 - debug( "adding new message %d\n", msglist.ents[i].uid ); - maildir_app_msg( ctx, &msgapp, msglist.ents + i ); + debug( "adding new message %d\n", msglist.array.data[i].uid ); + maildir_app_msg( ctx, &msgapp, msglist.array.data + i ); #else - debug( "ignoring new message %d\n", msglist.ents[i].uid ); + debug( "ignoring new message %d\n", msglist.array.data[i].uid ); #endif i++; - } else if (i >= msglist.nents) { + } else if (i >= msglist.array.size) { debug( "purging deleted message %d\n", msg->gen.uid ); msg->gen.status = M_DEAD; msgapp = &msg->gen.next; - } else if (msglist.ents[i].uid < msg->gen.uid) { + } else if (msglist.array.data[i].uid < msg->gen.uid) { /* this should not happen, actually */ #if 0 - debug( "adding new message %d\n", msglist.ents[i].uid ); - maildir_app_msg( ctx, &msgapp, msglist.ents + i ); + debug( "adding new message %d\n", msglist.array.data[i].uid ); + maildir_app_msg( ctx, &msgapp, msglist.array.data + i ); #else - debug( "ignoring new message %d\n", msglist.ents[i].uid ); + debug( "ignoring new message %d\n", msglist.array.data[i].uid ); #endif i++; - } else if (msglist.ents[i].uid > msg->gen.uid) { + } else if (msglist.array.data[i].uid > msg->gen.uid) { debug( "purging deleted message %d\n", msg->gen.uid ); msg->gen.status = M_DEAD; msgapp = &msg->gen.next; @@ -1358,7 +1351,7 @@ maildir_rescan( maildir_store_t *ctx ) debug( "updating message %d\n", msg->gen.uid ); msg->gen.status &= ~(M_FLAGS|M_RECENT); free( msg->base ); - maildir_init_msg( ctx, msg, msglist.ents + i ); + maildir_init_msg( ctx, msg, msglist.array.data + i ); i++, msgapp = &msg->gen.next; } } diff --git a/src/sync.c b/src/sync.c index 5ec377c..a6ebea8 100644 --- a/src/sync.c +++ b/src/sync.c @@ -938,7 +938,7 @@ static void box_deleted( int sts, void *aux ); static void box_created( int sts, void *aux ); static void box_opened( int sts, void *aux ); static void box_opened2( sync_vars_t *svars, int t ); -static void load_box( sync_vars_t *svars, int t, int minwuid, int *mexcs, int nmexcs ); +static void load_box( sync_vars_t *svars, int t, int minwuid, int_array_t mexcs ); void sync_boxes( store_t *ctx[], const char *names[], int present[], channel_conf_t *chan, @@ -1138,8 +1138,8 @@ box_opened2( sync_vars_t *svars, int t ) store_t *ctx[2]; channel_conf_t *chan; sync_rec_t *srec; - int opts[2], fails; - int *mexcs, nmexcs, rmexcs, minwuid; + int_array_alloc_t mexcs; + int opts[2], fails, minwuid; svars->state[t] |= ST_SELECTED; if (!(svars->state[1-t] & ST_SELECTED)) @@ -1224,8 +1224,7 @@ box_opened2( sync_vars_t *svars, int t ) svars->drv[M]->prepare_load_box( ctx[M], opts[M] ); svars->drv[S]->prepare_load_box( ctx[S], opts[S] ); - mexcs = 0; - nmexcs = rmexcs = 0; + ARRAY_INIT( &mexcs ); if (svars->ctx[M]->opts & OPEN_OLD) { if (chan->max_messages) { /* When messages have been expired on the slave, the master fetch is split into @@ -1263,16 +1262,12 @@ box_opened2( sync_vars_t *svars, int t ) if (srec->uid[M] > 0 && srec->uid[S] > 0 && minwuid > srec->uid[M] && (!(svars->ctx[M]->opts & OPEN_NEW) || svars->maxuid[M] >= srec->uid[M])) { /* The pair is alive, but outside the bulk range. */ - if (nmexcs == rmexcs) { - rmexcs = rmexcs * 2 + 100; - mexcs = nfrealloc( mexcs, rmexcs * sizeof(int) ); - } - mexcs[nmexcs++] = srec->uid[M]; + *int_array_append( &mexcs ) = srec->uid[M]; } } debugn( " exception list is:" ); - for (t = 0; t < nmexcs; t++) - debugn( " %d", mexcs[t] ); + for (t = 0; t < mexcs.array.size; t++) + debugn( " %d", mexcs.array.data[t] ); debug( "\n" ); } else { minwuid = 1; @@ -1281,16 +1276,16 @@ box_opened2( sync_vars_t *svars, int t ) minwuid = INT_MAX; } sync_ref( svars ); - load_box( svars, M, minwuid, mexcs, nmexcs ); + load_box( svars, M, minwuid, mexcs.array ); if (!check_cancel( svars )) - load_box( svars, S, (ctx[S]->opts & OPEN_OLD) ? 1 : INT_MAX, 0, 0 ); + load_box( svars, S, (ctx[S]->opts & OPEN_OLD) ? 1 : INT_MAX, (int_array_t){ 0, 0 } ); sync_deref( svars ); } static void box_loaded( int sts, void *aux ); static void -load_box( sync_vars_t *svars, int t, int minwuid, int *mexcs, int nmexcs ) +load_box( sync_vars_t *svars, int t, int minwuid, int_array_t mexcs ) { sync_rec_t *srec; int maxwuid; @@ -1308,7 +1303,7 @@ load_box( sync_vars_t *svars, int t, int minwuid, int *mexcs, int nmexcs ) maxwuid = 0; info( "Loading %s...\n", str_ms[t] ); debug( maxwuid == INT_MAX ? "loading %s [%d,inf]\n" : "loading %s [%d,%d]\n", str_ms[t], minwuid, maxwuid ); - svars->drv[t]->load_box( svars->ctx[t], minwuid, maxwuid, svars->newuid[t], mexcs, nmexcs, box_loaded, AUX ); + svars->drv[t]->load_box( svars->ctx[t], minwuid, maxwuid, svars->newuid[t], mexcs, box_loaded, AUX ); } typedef struct { diff --git a/src/util.c b/src/util.c index e5a6632..726054f 100644 --- a/src/util.c +++ b/src/util.c @@ -540,9 +540,9 @@ compare_ints( const void *l, const void *r ) } void -sort_ints( int *arr, int len ) +sort_int_array( int_array_t array ) { - qsort( arr, len, sizeof(int), compare_ints ); + qsort( array.data, array.size, sizeof(int), compare_ints ); }