From 6a78e2c5f61fdc1ec18a87f05f800d22ca59dfa6 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 31 May 2022 14:05:28 +0200 Subject: [PATCH] automate enumeration of power-of-two #defines this is a lot more legible, and makes it possible to insert values in the middle without churn. i didn't find a way to do this with the pre-processor, so we now have another code generator. we now use the $< make variable, which requires gmake on netbsd < 9.0, and possibly other systems with an ancient make. --- src/.gitignore | 1 + src/Makefile.am | 26 +++++++++++++++++++-- src/bit_enum_gen.pl | 55 ++++++++++++++++++++++++++++++++++++++++++++ src/common.h | 33 ++++++++++++++++---------- src/driver.h | 56 +++++++++++++++++++++++++-------------------- src/drv_maildir.c | 2 +- src/sync.c | 36 +++++++++++++++-------------- src/sync.h | 37 +++++++++++++++++------------- src/sync_p.h | 27 +++++++++++++--------- src/sync_state.c | 2 +- 10 files changed, 190 insertions(+), 85 deletions(-) create mode 100755 src/bit_enum_gen.pl diff --git a/src/.gitignore b/src/.gitignore index 116456f..15e76db 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,3 +1,4 @@ +/*_enum.h /drv_proxy.inc /mbsync /mdconvert diff --git a/src/Makefile.am b/src/Makefile.am index e06005d..1df4cca 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -19,6 +19,28 @@ 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 @@ -36,6 +58,6 @@ EXTRA_PROGRAMS = tst_timers exampledir = $(docdir)/examples example_DATA = mbsyncrc.sample -EXTRA_DIST = drv_proxy_gen.pl run-tests.pl $(example_DATA) $(man_MANS) +EXTRA_DIST = bit_enum_gen.pl drv_proxy_gen.pl run-tests.pl $(example_DATA) $(man_MANS) -CLEANFILES = drv_proxy.inc +CLEANFILES = *_enum.h drv_proxy.inc diff --git a/src/bit_enum_gen.pl b/src/bit_enum_gen.pl new file mode 100755 index 0000000..9bf0e6a --- /dev/null +++ b/src/bit_enum_gen.pl @@ -0,0 +1,55 @@ +#!/usr/bin/perl +# +# SPDX-FileCopyrightText: 2022 Oswald Buddenhagen +# 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; + for my $e (@vals) { + if (!defined($pfx)) { + $pfx = ($e =~ /^([A-Z]+_)/) ? $1 : ""; + } elsif (length($pfx)) { + $pfx = "" if ((($e =~ /^([A-Z]+_)/) ? $1 : "") ne $pfx); + } + } + my $bit = 1; + my $bitn = 0; + for my $e (@vals) { + my $bits = ($e =~ s/\((\d+)\)$//) ? $1 : 1; + if ($bits != 1) { + print "#define $e(b) ($bit << (b))\n"; + } else { + print "#define $e $bit\n"; + } + $bit <<= $bits; + $bitn += $bits; + } + if (length($pfx)) { + print "#define ${pfx}_NUM_BITS $bitn\n"; + } + print "\n"; + $in_enum = 0; + } else { + $conts .= $_; + } + } else { + if (/^BIT_ENUM\($/) { + $conts = ""; + $in_enum = 1; + } + } +} diff --git a/src/common.h b/src/common.h index 9ec6b36..112b735 100644 --- a/src/common.h +++ b/src/common.h @@ -21,6 +21,8 @@ #include #include +#include "common_enum.h" + typedef unsigned char uchar; typedef unsigned short ushort; typedef unsigned int uint; @@ -41,6 +43,8 @@ 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(...) + #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4) # define ATTR_UNUSED __attribute__((unused)) # define ATTR_NORETURN __attribute__((noreturn)) @@ -90,18 +94,23 @@ enum { VERBOSE, }; -#define DEBUG_CRASH 0x01 -#define DEBUG_MAILDIR 0x02 -#define DEBUG_NET 0x04 -#define DEBUG_NET_ALL 0x08 -#define DEBUG_SYNC 0x10 -#define DEBUG_MAIN 0x20 -#define DEBUG_DRV 0x40 -#define DEBUG_DRV_ALL 0x80 -#define PROGRESS 0x400 -#define KEEPJOURNAL 0x1000 -#define ZERODELAY 0x2000 -#define FORCEASYNC 0x4000 +BIT_ENUM( + DEBUG_MAILDIR, + DEBUG_NET, + DEBUG_NET_ALL, + DEBUG_SYNC, + DEBUG_MAIN, + DEBUG_DRV, + DEBUG_DRV_ALL, + + DEBUG_CRASH, + + PROGRESS, + + ZERODELAY, + KEEPJOURNAL, + FORCEASYNC, +) #define DEBUG_ANY (DEBUG_MAILDIR | DEBUG_NET | DEBUG_SYNC | DEBUG_MAIN | DEBUG_DRV) #define DEBUG_ALL (DEBUG_ANY | DEBUG_CRASH) diff --git a/src/driver.h b/src/driver.h index edb9404..1f9749f 100644 --- a/src/driver.h +++ b/src/driver.h @@ -9,6 +9,7 @@ #define DRIVER_H #include "config.h" +#include "driver_enum.h" typedef struct driver driver_t; @@ -33,26 +34,29 @@ typedef struct store_conf { /* For message->flags */ // Keep the MESSAGE_FLAGS in sync (grep that)! /* The order is according to alphabetical maildir flag sort */ -#define F_DRAFT (1<<0) /* Draft */ -#define F_FLAGGED (1<<1) /* Flagged */ -#define F_FORWARDED (1<<2) /* Passed */ -#define F_ANSWERED (1<<3) /* Replied */ -#define F_SEEN (1<<4) /* Seen */ -#define F_DELETED (1<<5) /* Trashed */ -#define NUM_FLAGS 6 +BIT_ENUM( + F_DRAFT, // Draft + F_FLAGGED, // Flagged + F_FORWARDED, // Passed + F_ANSWERED, // Replied + F_SEEN, // Seen + F_DELETED, // Trashed +) -extern const char MsgFlags[NUM_FLAGS]; +extern const char MsgFlags[F__NUM_BITS]; void make_flags( uchar flags, char *buf ); /* For message->status */ -#define M_RECENT (1<<0) /* unsyncable flag; maildir_* depend on this being 1<<0 */ -#define M_DEAD (1<<1) /* expunged */ -#define M_FLAGS (1<<2) /* flags fetched */ -// The following are only for IMAP FETCH response parsing -#define M_DATE (1<<3) -#define M_SIZE (1<<4) -#define M_BODY (1<<5) -#define M_HEADER (1<<6) +BIT_ENUM( + M_RECENT, // unsyncable flag; maildir_*() depend on this being bit 0 + M_DEAD, // expunged + M_FLAGS, // flags are valid + // The following are only for IMAP FETCH response parsing + M_DATE, + M_SIZE, + M_BODY, + M_HEADER, +) #define TUIDL 12 @@ -74,15 +78,17 @@ typedef struct message { // The drivers don't use the first two, but may set them if loading the // particular range is required to handle some other flag; note that these // ranges may overlap. -#define OPEN_OLD (1<<0) // Paired messages *in* this store. -#define OPEN_NEW (1<<1) // Messages (possibly) not yet propagated *from* this store. -#define OPEN_FLAGS (1<<2) // Note that fetch_msg() gets the flags regardless. -#define OPEN_NEW_SIZE (1<<4) -#define OPEN_EXPUNGE (1<<5) -#define OPEN_SETFLAGS (1<<6) -#define OPEN_APPEND (1<<7) -#define OPEN_FIND (1<<8) -#define OPEN_OLD_IDS (1<<9) +BIT_ENUM( + OPEN_OLD, // Paired messages *in* 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_NEW_SIZE, + OPEN_OLD_IDS, + OPEN_APPEND, + OPEN_SETFLAGS, + OPEN_EXPUNGE, +) #define UIDVAL_BAD ((uint)-1) diff --git a/src/drv_maildir.c b/src/drv_maildir.c index c1de4dc..fbef3a8 100644 --- a/src/drv_maildir.c +++ b/src/drv_maildir.c @@ -1565,7 +1565,7 @@ maildir_store_msg( store_t *gctx, msg_data_t *data, int to_trash, const char *box; int ret, fd, bl; uint uid; - char buf[_POSIX_PATH_MAX], nbuf[_POSIX_PATH_MAX], fbuf[NUM_FLAGS + 3], base[128]; + char buf[_POSIX_PATH_MAX], nbuf[_POSIX_PATH_MAX], fbuf[as(MsgFlags) + 3], base[128]; bl = nfsnprintf( base, sizeof(base), "%lld.%d_%d.%s", (long long)time( NULL ), Pid, ++MaildirCount, Hostname ); if (!to_trash) { diff --git a/src/sync.c b/src/sync.c index 50bf56d..99b852a 100644 --- a/src/sync.c +++ b/src/sync.c @@ -6,6 +6,7 @@ */ #include "sync_p.h" +#include "sync_c_enum.h" channel_conf_t global_conf; channel_conf_t *channels; @@ -43,23 +44,24 @@ static int check_cancel( sync_vars_t *svars ); cleanup: close(F) & close(N) */ -#define ST_LOADED (1<<0) -#define ST_FIND_OLD (1<<1) -#define ST_SENT_NEW (1<<2) -#define ST_FIND_NEW (1<<3) -#define ST_FOUND_NEW (1<<4) -#define ST_SENT_FLAGS (1<<5) -#define ST_SENT_TRASH (1<<6) -#define ST_CLOSED (1<<7) -#define ST_SENT_CANCEL (1<<8) -#define ST_CANCELED (1<<9) -#define ST_SELECTED (1<<10) -#define ST_DID_EXPUNGE (1<<11) -#define ST_CLOSING (1<<12) -#define ST_CONFIRMED (1<<13) -#define ST_PRESENT (1<<14) -#define ST_SENDING_NEW (1<<15) - +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_CLOSING, + ST_CLOSED, + ST_DID_EXPUNGE, + ST_SENT_CANCEL, + ST_CANCELED, +) static uchar sanitize_flags( uchar tflags, sync_vars_t *svars, int t ) diff --git a/src/sync.h b/src/sync.h index d091609..af31ad3 100644 --- a/src/sync.h +++ b/src/sync.h @@ -9,26 +9,31 @@ #define SYNC_H #include "driver.h" +#include "sync_enum.h" #define F 0 // far side #define N 1 // near side -#define OP_NEW (1<<0) -#define OP_RENEW (1<<1) -#define OP_DELETE (1<<2) -#define OP_FLAGS (1<<3) -#define OP_MASK_TYPE (OP_NEW|OP_RENEW|OP_DELETE|OP_FLAGS) /* asserted in the target ops */ -#define OP_EXPUNGE (1<<4) -#define OP_CREATE (1<<5) -#define OP_REMOVE (1<<6) -#define XOP_PUSH (1<<8) -#define XOP_PULL (1<<9) -#define XOP_MASK_DIR (XOP_PUSH|XOP_PULL) -#define XOP_HAVE_TYPE (1<<10) // Aka mode; at least one of dir and type -// The following must all have the same bit shift from the corresponding OP_* flags. -#define XOP_HAVE_EXPUNGE (1<<11) -#define XOP_HAVE_CREATE (1<<12) -#define XOP_HAVE_REMOVE (1<<13) +BIT_ENUM( + OP_NEW, + OP_RENEW, + OP_DELETE, + OP_FLAGS, + OP_EXPUNGE, + 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_CREATE, + XOP_HAVE_REMOVE, +) + +#define OP_MASK_TYPE (OP_NEW | OP_RENEW | OP_DELETE | OP_FLAGS) // Asserted in the target side ops +#define XOP_MASK_DIR (XOP_PUSH | XOP_PULL) typedef struct channel_conf { struct channel_conf *next; diff --git a/src/sync_p.h b/src/sync_p.h index 07eefcb..e623475 100644 --- a/src/sync_p.h +++ b/src/sync_p.h @@ -7,23 +7,28 @@ #define DEBUG_FLAG DEBUG_SYNC #include "sync.h" +#include "sync_p_enum.h" // This is the (mostly) persistent status of the sync record. // Most of these bits are actually mutually exclusive. It is a // bitfield to allow for easy testing for multiple states. -#define S_EXPIRE (1<<0) // the entry is being expired (near side message removal scheduled) -#define S_EXPIRED (1<<1) // the entry is expired (near side message removal confirmed) -#define S_PENDING (1<<2) // the entry is new and awaits propagation (possibly a retry) -#define S_DUMMY(fn) (1<<(3+(fn))) // f/n message is only a placeholder -#define S_SKIPPED (1<<5) // pre-1.4 legacy: the entry was not propagated (message is too big) -#define S_DEAD (1<<7) // ephemeral: the entry was killed and should be ignored +BIT_ENUM( + S_DEAD, // ephemeral: the entry was killed and should be ignored + S_EXPIRE, // the entry is being expired (near side message removal scheduled) + S_EXPIRED, // the entry is expired (near side message removal confirmed) + 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) +) // Ephemeral working set. -#define W_NEXPIRE (1<<0) // temporary: new expiration state -#define W_DELETE (1<<1) // ephemeral: flags propagation is a deletion -#define W_DEL(fn) (1<<(2+(fn))) // ephemeral: f/n message would be subject to expunge -#define W_UPGRADE (1<<4) // ephemeral: upgrading placeholder, do not apply MaxSize -#define W_PURGE (1<<5) // ephemeral: placeholder is being nuked +BIT_ENUM( + W_NEXPIRE, // temporary: new expiration state + W_DELETE, // ephemeral: flags propagation is a deletion + W_DEL(2), // ephemeral: f/n message would be subject to expunge + W_UPGRADE, // ephemeral: upgrading placeholder, do not apply MaxSize + W_PURGE, // ephemeral: placeholder is being nuked +) typedef struct sync_rec { struct sync_rec *next; diff --git a/src/sync_state.c b/src/sync_state.c index 0b0cfd6..d9917ec 100644 --- a/src/sync_state.c +++ b/src/sync_state.c @@ -13,7 +13,7 @@ #include #include -#define JOURNAL_VERSION "4" +#define JOURNAL_VERSION "5" const char *str_fn[] = { "far side", "near side" }, *str_hl[] = { "push", "pull" };