Browse Source

revamp automatic enumeration of power-of-two enumerators

i found a neat trick to do it with the C pre-processor after all.
this makes the enum definitions themselves arguably somewhat less
legible, but on the upside the build system becomes simpler, and IDEs
can build/update their code models without having to (re-)build the
project first.

somewhat as a side effect, this gives bit enums proper names, so we
don't need to refer to them by cryptic prefixes anymore.

amends 6a78e2c5f.
master
Oswald Buddenhagen 1 year ago
parent
commit
ee832951e2
  1. 1
      src/.gitignore
  2. 26
      src/Makefile.am
  3. 70
      src/bit_enum_gen.pl
  4. 131
      src/common.h
  5. 2
      src/config.c
  6. 83
      src/driver.h
  7. 2
      src/drv_imap.c
  8. 2
      src/drv_proxy.c
  9. 37
      src/sync.c
  10. 57
      src/sync.h
  11. 43
      src/sync_p.h
  12. 2
      src/sync_state.c

1
src/.gitignore vendored

@ -1,4 +1,3 @@
/*_enum.h
/drv_proxy.inc
/mbsync
/mdconvert

26
src/Makefile.am

@ -20,28 +20,6 @@ drv_proxy.$(OBJEXT): drv_proxy.inc
drv_proxy.inc: $(srcdir)/driver.h $(srcdir)/drv_proxy.c $(srcdir)/drv_proxy_gen.pl
perl $(srcdir)/drv_proxy_gen.pl $(srcdir)/driver.h $(srcdir)/drv_proxy.c drv_proxy.inc
ENUM_GEN = $(srcdir)/bit_enum_gen.pl
$(mbsync_OBJECTS): common_enum.h
common_enum.h: common.h $(ENUM_GEN)
perl $(ENUM_GEN) < $< > $@
$(mbsync_OBJECTS): driver_enum.h
driver_enum.h: driver.h $(ENUM_GEN)
perl $(ENUM_GEN) < $< > $@
$(mbsync_OBJECTS): sync_enum.h
sync_enum.h: sync.h $(ENUM_GEN)
perl $(ENUM_GEN) < $< > $@
sync.$(OBJEXT): sync_c_enum.h
sync_c_enum.h: sync.c $(ENUM_GEN)
perl $(ENUM_GEN) < $< > $@
sync.$(OBJEXT) sync_state.$(OBJEXT): sync_p_enum.h
sync_p_enum.h: sync_p.h $(ENUM_GEN)
perl $(ENUM_GEN) < $< > $@
mdconvert_SOURCES = mdconvert.c
mdconvert_LDADD = $(DB_LIBS)
if with_mdconvert
@ -69,6 +47,6 @@ EXTRA_PROGRAMS = tst_timers
exampledir = $(docdir)/examples
example_DATA = mbsyncrc.sample
EXTRA_DIST = bit_enum_gen.pl drv_proxy_gen.pl run-tests.pl $(example_DATA) $(man_MANS)
EXTRA_DIST = drv_proxy_gen.pl run-tests.pl $(example_DATA) $(man_MANS)
CLEANFILES = *_enum.h drv_proxy.inc
CLEANFILES = drv_proxy.inc

70
src/bit_enum_gen.pl

@ -1,70 +0,0 @@
#!/usr/bin/perl
#
# SPDX-FileCopyrightText: 2022 Oswald Buddenhagen <ossi@users.sf.net>
# SPDX-License-Identifier: GPL-2.0-or-later
#
# mbsync - mailbox synchronizer
#
use strict;
use warnings;
my $in_enum = 0;
my $conts;
while (<>) {
s,\s*(?://.*)?$,,;
if ($in_enum) {
if (/^\)$/) {
$conts =~ s/\s//g;
$conts =~ s/,$//;
my @vals = split(/,/, $conts);
my ($pfx, $pfx1);
for my $e (@vals) {
if (!defined($pfx)) {
$pfx1 = $pfx = ($e =~ /^([A-Z]+_)/) ? $1 : "";
} elsif (length($pfx)) {
$pfx = "" if ((($e =~ /^([A-Z]+_)/) ? $1 : "") ne $pfx);
}
}
my $bit = 1;
my $bitn = 0;
my (@names, @nameos);
my $nameo = 0;
for my $e (@vals) {
my $bits = ($e =~ s/\((\d+)\)$//) ? $1 : 1;
my $n = substr($e, length($pfx));
if ($bits != 1) {
die("Unsupported field size $bits\n") if ($bits != 2);
print "#define $e(b) ($bit << (b))\n";
push @names, "F-".$n, "N-".$n;
my $nl = length($n) + 3;
push @nameos, $nameo, $nameo + $nl;
$nameo += $nl * 2;
} else {
print "#define $e $bit\n";
push @names, $n;
push @nameos, $nameo;
$nameo += length($n) + 1;
}
$bit <<= $bits;
$bitn += $bits;
}
if (length($pfx)) {
print "#define ${pfx}_NUM_BITS $bitn\n";
}
if (length($pfx1)) {
print "#define ${pfx1}_STRINGS \"".join("\\0", @names)."\"\n";
print "#define ${pfx1}_OFFSETS ".join(", ", @nameos)."\n";
}
print "\n";
$in_enum = 0;
} else {
$conts .= $_;
}
} else {
if (/^BIT_ENUM\($/) {
$conts = "";
$in_enum = 1;
}
}
}

131
src/common.h

@ -21,8 +21,6 @@
#include <string.h>
#include <time.h>
#include "common_enum.h"
typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned int uint;
@ -43,10 +41,55 @@ typedef unsigned long ulong;
#define shifted_bit(in, from, to) \
((int)(((uint)(in) / (from > to ? from / to : 1) * (to > from ? to / from : 1)) & to))
#define BIT_ENUM(...)
#define BIT_ENUM_VAL(name) \
name, \
name##_dummy = 2 * name - 1,
#define DEFINE_BIT_ENUM(list) \
enum list { \
list##_dummy, \
list(BIT_ENUM_VAL) \
};
#define PFX_BIT_ENUM_VAL(pfx, name) \
pfx##_##name, \
pfx##_##name##_dummy = 2 * pfx##_##name - 1,
#define PFX_BIT_ENUM_NUM(pfx, name) \
pfx##_##name##_bit,
#define DEFINE_PFX_BIT_ENUM(list) \
enum list { \
list##_dummy, \
list(PFX_BIT_ENUM_VAL) \
}; \
enum { \
list(PFX_BIT_ENUM_NUM) \
list##_num_bits \
};
#define BIT_ENUM_STR(pfx, name) \
stringify(name) "\0"
#define BIT_ENUM_STR_OFF(pfx, name) \
name##_str_off, \
name##_str_off_dummy = name##_str_off + sizeof(stringify(name)) - 1,
#define GET_BIT_ENUM_STR_OFF(pfx, name) \
name##_str_off,
#define static_assert_bits(pfx, type, field) \
static_assert( pfx##__NUM_BITS <= sizeof(((type){ 0 }).field) * 8, \
#define PFX_BIT_ENUM_STR(pfx, name) \
stringify(pfx) "_" stringify(name) "\0"
#define PFX_BIT_ENUM_STR_OFF(pfx, name) \
pfx##_##name##_str_off, \
pfx##_##name##_str_end = pfx##_##name##_str_off + sizeof(stringify(pfx) "_" stringify(name)) - 1,
#define GET_PFX_BIT_ENUM_STR_OFF(pfx, name) \
pfx##_##name##_str_off,
#define static_assert_bits(list, type, field) \
static_assert( list##_num_bits <= sizeof(((type){ 0 }).field) * 8, \
stringify(type) "::" stringify(field) " is too small" )
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
@ -100,30 +143,32 @@ enum {
VERBOSE,
};
BIT_ENUM(
DEBUG_MAILDIR,
DEBUG_NET,
DEBUG_NET_ALL,
DEBUG_SYNC,
DEBUG_MAIN,
DEBUG_DRV,
DEBUG_DRV_ALL,
DEBUG_CRASH,
PROGRESS,
DRYRUN,
EXT_EXIT,
ZERODELAY,
KEEPJOURNAL,
FORCEJOURNAL,
FORCEASYNC(2),
FAKEEXPUNGE,
FAKEDUMBSTORE,
)
#define options_enum(fn) \
fn(DEBUG_MAILDIR) \
fn(DEBUG_NET) \
fn(DEBUG_NET_ALL) \
fn(DEBUG_SYNC) \
fn(DEBUG_MAIN) \
fn(DEBUG_DRV) \
fn(DEBUG_DRV_ALL) \
\
fn(DEBUG_CRASH) \
\
fn(PROGRESS) \
\
fn(DRYRUN) \
\
fn(EXT_EXIT) \
\
fn(ZERODELAY) \
fn(KEEPJOURNAL) \
fn(FORCEJOURNAL) \
fn(FORCEASYNC_F) \
fn(FORCEASYNC_N) \
fn(FAKEEXPUNGE) \
fn(FAKEDUMBSTORE)
DEFINE_BIT_ENUM(options_enum)
#define FORCEASYNC(b) (FORCEASYNC_F << (b))
#define DEBUG_ANY (DEBUG_MAILDIR | DEBUG_NET | DEBUG_SYNC | DEBUG_MAIN | DEBUG_DRV)
#define DEBUG_ALL (DEBUG_ANY | DEBUG_CRASH)
@ -209,34 +254,38 @@ time_t timegm( struct tm *tm );
void fmt_bits( uint bits, uint num_bits, const char *bit_str, const int *bit_off, char *buf );
#define BIT_FORMATTER_RET(name, pfx) \
struct name##_str { char str[sizeof(pfx##__STRINGS)]; };
#define BIT_FORMATTER_RET(name, list, fn) \
enum { list(fn##_OFF) name##_str_len }; \
struct name##_str { char str[name##_str_len]; };
#define BIT_FORMATTER_PROTO(name, storage) \
storage struct name##_str ATTR_OPTIMIZE /* force RVO */ \
fmt_##name( uint bits )
#define BIT_FORMATTER_IMPL(name, pfx, storage) \
#define BIT_FORMATTER_IMPL(name, list, fn, storage) \
BIT_FORMATTER_PROTO(name, storage) \
{ \
static const char strings[] = pfx##__STRINGS; \
static const int offsets[] = { pfx##__OFFSETS }; \
static const char strings[] = list(fn); \
static const int offsets[] = { list(GET_##fn##_OFF) }; \
\
struct name##_str buf; \
fmt_bits( bits, as(offsets), strings, offsets, buf.str ); \
return buf; \
}
#define BIT_FORMATTER_FUNCTION(name, pfx) \
BIT_FORMATTER_RET(name, pfx) \
BIT_FORMATTER_IMPL(name, pfx, static)
// Note that this one uses enum labels without prefix ...
#define BIT_FORMATTER_FUNCTION(name, list) \
BIT_FORMATTER_RET(name, list, BIT_ENUM_STR) \
BIT_FORMATTER_IMPL(name, list, BIT_ENUM_STR, static)
#define DECL_BIT_FORMATTER_FUNCTION(name, pfx) \
BIT_FORMATTER_RET(name, pfx) \
// ... while these ones use enum labels with prefix - this
// is not fundamental, but simply because of the use cases.
#define DECL_BIT_FORMATTER_FUNCTION(name, list) \
BIT_FORMATTER_RET(name, list, PFX_BIT_ENUM_STR) \
BIT_FORMATTER_PROTO(name, );
#define DEF_BIT_FORMATTER_FUNCTION(name, pfx) \
BIT_FORMATTER_IMPL(name, pfx, )
#define DEF_BIT_FORMATTER_FUNCTION(name, list) \
BIT_FORMATTER_IMPL(name, list, PFX_BIT_ENUM_STR, )
void *nfmalloc( size_t sz );
void *nfzalloc( size_t sz );

2
src/config.c

@ -22,7 +22,7 @@ char FieldDelimiter = ';';
char FieldDelimiter = ':';
#endif
DEF_BIT_FORMATTER_FUNCTION(ops, OP)
DEF_BIT_FORMATTER_FUNCTION(ops, sync_op_enum)
char *
expand_strdup( const char *s, const conffile_t *cfile )

83
src/driver.h

@ -9,7 +9,6 @@
#define DRIVER_H
#include "config.h"
#include "driver_enum.h"
typedef struct driver driver_t;
@ -36,32 +35,32 @@ extern store_conf_t *stores;
/* For message->flags */
// Keep the MESSAGE_FLAGS in sync (grep that)!
/* The order is according to alphabetical maildir flag sort */
BIT_ENUM(
F_DRAFT, // Draft
F_FLAGGED, // Flagged
F_FORWARDED, // Passed
F_ANSWERED, // Replied
F_SEEN, // Seen
F_DELETED, // Trashed
)
extern const char MsgFlags[F__NUM_BITS];
typedef struct { char str[F__NUM_BITS + 1]; } flag_str_t;
#define msg_flags_enum(fn) \
fn(F, DRAFT) /* Draft */ \
fn(F, FLAGGED) /* Flagged */ \
fn(F, FORWARDED) /* Passed */ \
fn(F, ANSWERED) /* Replied */ \
fn(F, SEEN) /* Seen */ \
fn(F, DELETED) /* Trashed */
DEFINE_PFX_BIT_ENUM(msg_flags_enum)
extern const char MsgFlags[msg_flags_enum_num_bits];
typedef struct { char str[msg_flags_enum_num_bits + 1]; } flag_str_t;
flag_str_t ATTR_OPTIMIZE /* force RVO */ fmt_flags( uchar flags );
flag_str_t ATTR_OPTIMIZE /* force RVO */ fmt_lone_flags( uchar flags );
/* For message->status */
BIT_ENUM(
M_RECENT, // unsyncable flag; maildir_*() depend on this being bit 0
M_DEAD, // expunged
M_EXPUNGE, // for driver_t->close_box()
M_FLAGS, // flags are valid
// The following are only for IMAP FETCH response parsing
M_DATE,
M_SIZE,
M_BODY,
M_HEADER,
)
#define msg_sts_enum(fn) \
fn(M, RECENT) /* unsyncable flag; maildir_*() depend on this being bit 0 */ \
fn(M, DEAD) /* expunged */ \
fn(M, EXPUNGE) /* for driver_t->close_box() */ \
fn(M, FLAGS) /* flags are valid */ \
/* The following are only for IMAP FETCH response parsing */ \
fn(M, DATE) \
fn(M, SIZE) \
fn(M, BODY) \
fn(M, HEADER)
DEFINE_PFX_BIT_ENUM(msg_sts_enum)
#define TUIDL 12
@ -79,29 +78,29 @@ typedef struct message {
MESSAGE(struct message)
} message_t;
static_assert_bits(F, message_t, flags);
static_assert_bits(M, message_t, status);
static_assert_bits(msg_flags_enum, message_t, flags);
static_assert_bits(msg_sts_enum, message_t, status);
// For driver_t->prepare_load_box(), which may amend the passed flags.
// The drivers don't use the first three, but may set them if loading the
// particular range is required to handle some other flag; note that these
// ranges may overlap.
BIT_ENUM(
OPEN_PAIRED, // Paired messages *in* this store.
OPEN_OLD, // Messages that should be already propagated *from* this store.
OPEN_NEW, // Messages (possibly) not yet propagated *from* this store.
OPEN_FIND,
OPEN_FLAGS, // Note that fetch_msg() gets the flags regardless.
OPEN_OLD_SIZE,
OPEN_NEW_SIZE,
OPEN_PAIRED_IDS,
OPEN_APPEND,
OPEN_SETFLAGS,
OPEN_EXPUNGE,
// Expunge only deleted messages we know about. Relies on OPEN_{OLD,NEW,FLAGS}
// being set externally. The driver may unset it if it can't handle it.
OPEN_UID_EXPUNGE,
)
#define open_flags_enum(fn) \
fn(OPEN, PAIRED) /* Paired messages *in* this store. */ \
fn(OPEN, OLD) /* Messages that should be already propagated *from* this store. */ \
fn(OPEN, NEW) /* Messages (possibly) not yet propagated *from* this store. */ \
fn(OPEN, FIND) \
fn(OPEN, FLAGS) /* Note that fetch_msg() gets the flags regardless. */ \
fn(OPEN, OLD_SIZE) \
fn(OPEN, NEW_SIZE) \
fn(OPEN, PAIRED_IDS) \
fn(OPEN, APPEND) \
fn(OPEN, SETFLAGS) \
fn(OPEN, EXPUNGE) \
/* Expunge only deleted messages we know about. Relies on OPEN_{OLD,NEW,FLAGS} */ \
/* being set externally. The driver may unset it if it can't handle it. */ \
fn(OPEN, UID_EXPUNGE)
DEFINE_PFX_BIT_ENUM(open_flags_enum)
#define UIDVAL_BAD ((uint)-1)
@ -122,7 +121,7 @@ typedef struct {
uchar flags;
} msg_data_t;
static_assert_bits(F, msg_data_t, flags);
static_assert_bits(msg_flags_enum, msg_data_t, flags);
#define DRV_OK 0
/* Message went missing, or mailbox is full, etc. */

2
src/drv_imap.c

@ -3110,7 +3110,7 @@ imap_load_box( store_t *gctx, uint minuid, uint maxuid, uint finduid, uint pairu
if (i != j)
bl += sprintf( buf + bl, ":%u", excs.data[i] );
}
imap_submit_load( ctx, buf, shifted_bit( ctx->opts, OPEN_PAIRED_IDS, WantMsgids ), sts );
imap_submit_load( ctx, buf, shifted_bit( ctx->opts, (int)OPEN_PAIRED_IDS, WantMsgids ), sts );
}
if (maxuid == UINT_MAX)
maxuid = ctx->uidnext - 1;

2
src/drv_proxy.c

@ -8,7 +8,7 @@
#include "driver.h"
BIT_FORMATTER_FUNCTION(opts, OPEN)
BIT_FORMATTER_FUNCTION(opts, open_flags_enum)
typedef struct gen_cmd gen_cmd_t;

37
src/sync.c

@ -6,7 +6,6 @@
*/
#include "sync_p.h"
#include "sync_c_enum.h"
channel_conf_t global_conf;
channel_conf_t *channels;
@ -45,24 +44,24 @@ static int check_cancel( sync_vars_t *svars );
cleanup: close(F) & close(N)
*/
BIT_ENUM(
ST_PRESENT,
ST_CONFIRMED,
ST_SELECTED,
ST_FIND_OLD,
ST_LOADED,
ST_SENT_FLAGS,
ST_SENDING_NEW,
ST_SENT_NEW,
ST_FIND_NEW,
ST_FOUND_NEW,
ST_SENT_TRASH,
ST_TRASH_BAD,
ST_CLOSING,
ST_CLOSED,
ST_SENT_CANCEL,
ST_CANCELED,
)
#define sync_sts_enum(fn) \
fn(ST, PRESENT) \
fn(ST, CONFIRMED) \
fn(ST, SELECTED) \
fn(ST, FIND_OLD) \
fn(ST, LOADED) \
fn(ST, SENT_FLAGS) \
fn(ST, SENDING_NEW) \
fn(ST, SENT_NEW) \
fn(ST, FIND_NEW) \
fn(ST, FOUND_NEW) \
fn(ST, SENT_TRASH) \
fn(ST, TRASH_BAD) \
fn(ST, CLOSING) \
fn(ST, CLOSED) \
fn(ST, SENT_CANCEL) \
fn(ST, CANCELED)
DEFINE_PFX_BIT_ENUM(sync_sts_enum)
static uchar
sanitize_flags( uchar tflags, sync_vars_t *svars, int t )

57
src/sync.h

@ -9,44 +9,43 @@
#define SYNC_H
#include "driver.h"
#include "sync_enum.h"
#define F 0 // far side
#define N 1 // near side
BIT_ENUM(
OP_NEW,
OP_OLD,
OP_UPGRADE,
OP_GONE,
OP_FLAGS,
OP_EXPUNGE,
OP_EXPUNGE_SOLO,
OP_CREATE,
OP_REMOVE,
XOP_PUSH,
XOP_PULL,
XOP_HAVE_TYPE, // Aka mode; have at least one of dir and type (see below)
// The following must all have the same bit shift from the corresponding OP_* flags.
XOP_HAVE_EXPUNGE,
XOP_HAVE_EXPUNGE_SOLO,
XOP_HAVE_CREATE,
XOP_HAVE_REMOVE,
// ... until here.
XOP_TYPE_NOOP,
// ... and here again from scratch.
XOP_EXPUNGE_NOOP,
XOP_EXPUNGE_SOLO_NOOP,
XOP_CREATE_NOOP,
XOP_REMOVE_NOOP,
)
#define sync_op_enum(fn) \
fn(OP, NEW) \
fn(OP, OLD) \
fn(OP, UPGRADE) \
fn(OP, GONE) \
fn(OP, FLAGS) \
fn(OP, EXPUNGE) \
fn(OP, EXPUNGE_SOLO) \
fn(OP, CREATE) \
fn(OP, REMOVE) \
\
fn(XOP, PUSH) \
fn(XOP, PULL) \
fn(XOP, HAVE_TYPE) /* Aka mode; have at least one of dir and type (see below) */ \
/* The following must all have the same bit shift from the corresponding OP_* flags. */ \
fn(XOP, HAVE_EXPUNGE) \
fn(XOP, HAVE_EXPUNGE_SOLO) \
fn(XOP, HAVE_CREATE) \
fn(XOP, HAVE_REMOVE) \
/* ... until here. */ \
fn(XOP, TYPE_NOOP) \
/* ... and here again from scratch. */ \
fn(XOP, EXPUNGE_NOOP) \
fn(XOP, EXPUNGE_SOLO_NOOP) \
fn(XOP, CREATE_NOOP) \
fn(XOP, REMOVE_NOOP)
DEFINE_PFX_BIT_ENUM(sync_op_enum)
#define OP_DFLT_TYPE (OP_NEW | OP_UPGRADE | OP_GONE | OP_FLAGS)
#define OP_MASK_TYPE (OP_DFLT_TYPE | OP_OLD) // Asserted in the target side ops
#define XOP_MASK_DIR (XOP_PUSH | XOP_PULL)
DECL_BIT_FORMATTER_FUNCTION(ops, OP)
DECL_BIT_FORMATTER_FUNCTION(ops, sync_op_enum)
typedef struct channel_conf {
struct channel_conf *next;

43
src/sync_p.h

@ -7,23 +7,28 @@
#define DEBUG_FLAG DEBUG_SYNC
#include "sync.h"
#include "sync_p_enum.h"
BIT_ENUM(
S_DEAD, // ephemeral: the entry was killed and should be ignored
S_EXPIRE, // the entry is being expired (expire-side message removal scheduled)
S_EXPIRED, // the entry is expired (expire-side message removal confirmed)
S_NEXPIRE, // temporary: new expiration state
S_PENDING, // the entry is new and awaits propagation (possibly a retry)
S_DUMMY(2), // f/n message is only a placeholder
S_SKIPPED, // pre-1.4 legacy: the entry was not propagated (message is too big)
S_GONE(2), // ephemeral: f/n message has been expunged
S_DEL(2), // ephemeral: f/n message would be subject to non-selective expunge
S_DELETE, // ephemeral: flags propagation is a deletion
S_UPGRADE, // ephemeral: upgrading placeholder, do not apply MaxSize
S_PURGE, // ephemeral: placeholder is being nuked
S_PURGED, // ephemeral: placeholder was nuked
)
#define srec_sts_enum(fn) \
fn(S, DEAD) /* ephemeral: the entry was killed and should be ignored */ \
fn(S, EXPIRE) /* the entry is being expired (expire-side message removal scheduled) */ \
fn(S, EXPIRED) /* the entry is expired (expire-side message removal confirmed) */ \
fn(S, NEXPIRE) /* temporary: new expiration state */ \
fn(S, PENDING) /* the entry is new and awaits propagation (possibly a retry) */ \
fn(S, DUMMY_F) /* f/n message is only a placeholder */ \
fn(S, DUMMY_N) \
fn(S, SKIPPED) /* pre-1.4 legacy: the entry was not propagated (message is too big) */ \
fn(S, GONE_F) /* ephemeral: f/n message has been expunged */ \
fn(S, GONE_N) \
fn(S, DEL_F) /* ephemeral: f/n message would be subject to non-selective expunge */ \
fn(S, DEL_N) \
fn(S, DELETE) /* ephemeral: flags propagation is a deletion */ \
fn(S, UPGRADE) /* ephemeral: upgrading placeholder, do not apply MaxSize */ \
fn(S, PURGE) /* ephemeral: placeholder is being nuked */ \
fn(S, PURGED) /* ephemeral: placeholder was nuked */
DEFINE_PFX_BIT_ENUM(srec_sts_enum)
#define S_DUMMY(b) (S_DUMMY_F << (b))
#define S_GONE(b) (S_GONE_F << (b))
#define S_DEL(b) (S_DEL_F << (b))
// This is the persistent status of the sync record, with regard to the journal.
#define S_LOGGED (S_EXPIRE | S_EXPIRED | S_PENDING | S_DUMMY(F) | S_DUMMY(N) | S_SKIPPED)
@ -38,8 +43,8 @@ typedef struct sync_rec {
char tuid[TUIDL];
} sync_rec_t;
static_assert_bits(F, sync_rec_t, flags);
static_assert_bits(S, sync_rec_t, status);
static_assert_bits(msg_flags_enum, sync_rec_t, flags);
static_assert_bits(srec_sts_enum, sync_rec_t, status);
typedef struct {
int t[2];

2
src/sync_state.c

@ -17,7 +17,7 @@
const char *str_fn[] = { "far side", "near side" }, *str_hl[] = { "push", "pull" };
BIT_FORMATTER_FUNCTION(sts, S)
BIT_FORMATTER_FUNCTION(sts, srec_sts_enum)
static char *
clean_strdup( const char *s )

Loading…
Cancel
Save