[tz] [PROPOSED 4/5] Avoid C macros when this is easy

Paul Eggert eggert at cs.ucla.edu
Tue Jul 12 16:14:06 UTC 2022


Some compiler debugging formats do not represent C macros,
making it more of a pain to debug at the source-code level.
The macros in question mostly predate C89 when macros were
more portable than enums, but it’s safe to use enums now.
* asctime.c (ASCTIME_FMT, ASCTIME_FMT_B, STD_ASCTIME_BUF_SIZE):
* date.c (INCR):
* localtime.c (lclptr, gmtptr) [!ALL_STATE]:
* private.h (SECSPERMIN, MINSPERHOUR, HOURSPERDAY)
(DAYSPERWEEK, DAYSPERNYEAR, DAYSPERLYEAR, SECSPERHOUR)
(MONSPERYEAR, YEARSPERREPEAT, TM_SUNDAY, TM_MONDAY, TM_TUESDAY)
(TM_WEDNESDAY, TM_THURSDAY, TM_FRIDAY, TM_SATURDAY, TM_JANUARY)
(TM_FEBRUARY, TM_MARCH, TM_APRIL, TM_MAY, TM_JUNE, TM_JULY)
(TM_AUGUST, TM_SEPTEMBER, TM_OCTOBER, TM_NOVEMBER, TM_DECEMBER)
(TM_YEAR_BASE, TM_WDAY_BASE, EPOCH_YEAR, EPOCH_WDAY):
* strftime.c (Locale, DIVISOR):
* zdump.c (DIVISOR):
* zic.c (DC_DOM, DC_DOWGEQ, DC_DOWLEQ, LC_RULE, LC_ZONE)
(LC_LINK, LC_LEAP, LC_EXPIRES, ZF_NAME, ZF_STDOFF, ZF_RULE)
(ZF_FORMAT, ZF_TILYEAR, ZF_TILMONTH, ZF_TILDAY, ZF_TILTIME)
(ZONE_MINFIELDS, ZONE_MAXFIELDS, ZFC_STDOFF, ZFC_RULE)
(ZFC_FORMAT, ZFC_TILYEAR, ZFC_TILMONTH, ZFC_TILDAY, ZFC_TILTIME)
(ZONEC_MINFIELDS, ZONEC_MAXFIELDS, RF_NAME, RF_LOYEAR)
(RF_HIYEAR, RF_COMMAND, RF_MONTH, RF_DAY, RF_TOD, RF_SAVE)
(RF_ABBRVAR, RULE_FIELDS, LF_TARGET, LF_LINKNAME, LINK_FIELDS)
(LP_YEAR, LP_MONTH, LP_DAY, LP_TIME, LP_CORR, LP_ROLL)
(LEAP_FIELDS, EXPIRES_FIELDS, MAX_FIELDS, YR_MINIMUM)
(YR_MAXIMUM, YR_ONLY, TIME_T_BITS_IN_FILE):
Replace macros with ordinary identifiers when this is easy.
* asctime.c (MAX_ASCTIME_BUF_SIZE):
* localtime.c (OPEN_MODE):
Remove these macros.  All uses removed.
* localtime.c (O_BINARY): Define to 0 if not defined.
---
 asctime.c   |  26 +++++-----
 date.c      |   3 +-
 localtime.c |  15 +++---
 private.h   |  78 ++++++++++++++++--------------
 strftime.c  |   6 +--
 zdump.c     |   2 +-
 zic.c       | 135 ++++++++++++++++++++++++++++++----------------------
 7 files changed, 143 insertions(+), 122 deletions(-)

diff --git a/asctime.c b/asctime.c
index 68fbb80..fd3b038 100644
--- a/asctime.c
+++ b/asctime.c
@@ -35,10 +35,10 @@
 ** but many implementations pad anyway; most likely the standards are buggy.
 */
 #ifdef __GNUC__
-# define ASCTIME_FMT "%s %s%3d %2.2d:%2.2d:%2.2d %-4s\n"
-#else /* !defined __GNUC__ */
-# define ASCTIME_FMT "%s %s%3d %02.2d:%02.2d:%02.2d %-4s\n"
-#endif /* !defined __GNUC__ */
+static char const ASCTIME_FMT[] = "%s %s%3d %2.2d:%2.2d:%2.2d %-4s\n";
+#else
+static char const ASCTIME_FMT[] = "%s %s%3d %02.2d:%02.2d:%02.2d %-4s\n";
+#endif
 /*
 ** For years that are more than four digits we put extra spaces before the year
 ** so that code trying to overwrite the newline won't end up overwriting
@@ -46,12 +46,12 @@
 ** that no output is better than wrong output).
 */
 #ifdef __GNUC__
-# define ASCTIME_FMT_B "%s %s%3d %2.2d:%2.2d:%2.2d     %s\n"
-#else /* !defined __GNUC__ */
-# define ASCTIME_FMT_B "%s %s%3d %02.2d:%02.2d:%02.2d     %s\n"
-#endif /* !defined __GNUC__ */
+static char const ASCTIME_FMT_B[] = "%s %s%3d %2.2d:%2.2d:%2.2d     %s\n";
+#else
+static char const ASCTIME_FMT_B[] = "%s %s%3d %02.2d:%02.2d:%02.2d     %s\n";
+#endif
 
-#define STD_ASCTIME_BUF_SIZE	26
+enum { STD_ASCTIME_BUF_SIZE = 26 };
 /*
 ** Big enough for something such as
 ** ??? ???-2147483648 -2147483648:-2147483648:-2147483648     -2147483648\n
@@ -59,12 +59,10 @@
 ** seven explicit spaces, two explicit colons, a newline,
 ** and a trailing NUL byte).
 ** The values above are for systems where an int is 32 bits and are provided
-** as an example; the define below calculates the maximum for the system at
+** as an example; the size expression below is a bound for the system at
 ** hand.
 */
-#define MAX_ASCTIME_BUF_SIZE	(2*3+5*INT_STRLEN_MAXIMUM(int)+7+2+1+1)
-
-static char	buf_asctime[MAX_ASCTIME_BUF_SIZE];
+static char buf_asctime[2*3 + 5*INT_STRLEN_MAXIMUM(int) + 7 + 2 + 1 + 1];
 
 char *
 asctime_r(register const struct tm *timeptr, char *buf)
@@ -79,7 +77,7 @@ asctime_r(register const struct tm *timeptr, char *buf)
 	register const char *	wn;
 	register const char *	mn;
 	char			year[INT_STRLEN_MAXIMUM(int) + 2];
-	char			result[MAX_ASCTIME_BUF_SIZE];
+	char result[sizeof buf_asctime];
 
 	if (timeptr == NULL) {
 		errno = EINVAL;
diff --git a/date.c b/date.c
index 5c511ba..56e6c87 100644
--- a/date.c
+++ b/date.c
@@ -180,8 +180,6 @@ display(char const *format, time_t now)
 	}
 }
 
-#define INCR	1024
-
 static void
 timeout(FILE *fp, char const *format, struct tm const *tmp)
 {
@@ -189,6 +187,7 @@ timeout(FILE *fp, char const *format, struct tm const *tmp)
 	size_t	result;
 	size_t	size;
 	struct tm tm;
+	int INCR = 1024;
 
 	if (!tmp) {
 		fprintf(stderr, _("date: error: time out of range\n"));
diff --git a/localtime.c b/localtime.c
index 6380146..7de9d9d 100644
--- a/localtime.c
+++ b/localtime.c
@@ -42,15 +42,12 @@ static void unlock(void) { }
 #endif /* !defined TZ_ABBR_ERR_CHAR */
 
 /*
-** SunOS 4.1.1 headers lack O_BINARY.
+** Support non-POSIX platforms that distinguish between text and binary files.
 */
 
-#ifdef O_BINARY
-# define OPEN_MODE (O_RDONLY | O_BINARY)
-#endif /* defined O_BINARY */
 #ifndef O_BINARY
-# define OPEN_MODE O_RDONLY
-#endif /* !defined O_BINARY */
+# define O_BINARY 0
+#endif
 
 #ifndef WILDABBR
 /*
@@ -171,8 +168,8 @@ static struct state *	gmtptr;
 #ifndef ALL_STATE
 static struct state	lclmem;
 static struct state	gmtmem;
-# define lclptr (&lclmem)
-# define gmtptr (&gmtmem)
+static struct state *const lclptr = &lclmem;
+static struct state *const gmtptr = &gmtmem;
 #endif /* State Farm */
 
 #ifndef TZ_STRLEN_MAX
@@ -451,7 +448,7 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
 	}
 	if (doaccess && access(name, R_OK) != 0)
 	  return errno;
-	fid = open(name, OPEN_MODE);
+	fid = open(name, O_RDONLY | O_BINARY);
 	if (fid < 0)
 	  return errno;
 
diff --git a/private.h b/private.h
index ff98608..9b9389f 100644
--- a/private.h
+++ b/private.h
@@ -742,47 +742,55 @@ char *ctime_r(time_t const *, char *);
 
 /* Handy macros that are independent of tzfile implementation.  */
 
-#define SECSPERMIN	60
-#define MINSPERHOUR	60
-#define HOURSPERDAY	24
-#define DAYSPERWEEK	7
-#define DAYSPERNYEAR	365
-#define DAYSPERLYEAR	366
-#define SECSPERHOUR	(SECSPERMIN * MINSPERHOUR)
+enum {
+  SECSPERMIN = 60,
+  MINSPERHOUR = 60,
+  SECSPERHOUR = SECSPERMIN * MINSPERHOUR,
+  HOURSPERDAY = 24,
+  DAYSPERWEEK = 7,
+  DAYSPERNYEAR = 365,
+  DAYSPERLYEAR = DAYSPERNYEAR + 1,
+  MONSPERYEAR = 12,
+  YEARSPERREPEAT = 400	/* years before a Gregorian repeat */
+};
+
 #define SECSPERDAY	((int_fast32_t) SECSPERHOUR * HOURSPERDAY)
-#define MONSPERYEAR	12
 
-#define YEARSPERREPEAT		400	/* years before a Gregorian repeat */
 #define DAYSPERREPEAT		((int_fast32_t) 400 * 365 + 100 - 4 + 1)
 #define SECSPERREPEAT		((int_fast64_t) DAYSPERREPEAT * SECSPERDAY)
 #define AVGSECSPERYEAR		(SECSPERREPEAT / YEARSPERREPEAT)
 
-#define TM_SUNDAY	0
-#define TM_MONDAY	1
-#define TM_TUESDAY	2
-#define TM_WEDNESDAY	3
-#define TM_THURSDAY	4
-#define TM_FRIDAY	5
-#define TM_SATURDAY	6
-
-#define TM_JANUARY	0
-#define TM_FEBRUARY	1
-#define TM_MARCH	2
-#define TM_APRIL	3
-#define TM_MAY		4
-#define TM_JUNE		5
-#define TM_JULY		6
-#define TM_AUGUST	7
-#define TM_SEPTEMBER	8
-#define TM_OCTOBER	9
-#define TM_NOVEMBER	10
-#define TM_DECEMBER	11
-
-#define TM_YEAR_BASE	1900
-#define TM_WDAY_BASE	TM_MONDAY
-
-#define EPOCH_YEAR	1970
-#define EPOCH_WDAY	TM_THURSDAY
+enum {
+  TM_SUNDAY,
+  TM_MONDAY,
+  TM_TUESDAY,
+  TM_WEDNESDAY,
+  TM_THURSDAY,
+  TM_FRIDAY,
+  TM_SATURDAY
+};
+
+enum {
+  TM_JANUARY,
+  TM_FEBRUARY,
+  TM_MARCH,
+  TM_APRIL,
+  TM_MAY,
+  TM_JUNE,
+  TM_JULY,
+  TM_AUGUST,
+  TM_SEPTEMBER,
+  TM_OCTOBER,
+  TM_NOVEMBER,
+  TM_DECEMBER
+};
+
+enum {
+  TM_YEAR_BASE = 1900,
+  TM_WDAY_BASE = TM_MONDAY,
+  EPOCH_YEAR = 1970,
+  EPOCH_WDAY = TM_THURSDAY
+};
 
 #define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
 
diff --git a/strftime.c b/strftime.c
index 7425a64..deba2b5 100644
--- a/strftime.c
+++ b/strftime.c
@@ -56,8 +56,6 @@ struct lc_time_T {
 	const char *	date_fmt;
 };
 
-#define Locale	(&C_time_locale)
-
 static const struct lc_time_T	C_time_locale = {
 	{
 		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
@@ -164,6 +162,8 @@ static char *
 _fmt(const char *format, const struct tm *t, char *pt,
      const char *ptlim, enum warn *warnp)
 {
+	struct lc_time_T const *Locale = &C_time_locale;
+
 	for ( ; *format; ++format) {
 		if (*format == '%') {
 label:
@@ -626,7 +626,7 @@ _yconv(int a, int b, bool convert_top, bool convert_yy,
 	register int	lead;
 	register int	trail;
 
-#define DIVISOR	100
+	int DIVISOR = 100;
 	trail = a % DIVISOR + b % DIVISOR;
 	lead = a / DIVISOR + b / DIVISOR + trail / DIVISOR;
 	trail %= DIVISOR;
diff --git a/zdump.c b/zdump.c
index b153812..a63a343 100644
--- a/zdump.c
+++ b/zdump.c
@@ -1193,6 +1193,7 @@ dumptime(register const struct tm *timeptr)
 	};
 	register int		lead;
 	register int		trail;
+	int DIVISOR = 10;
 
 	/*
 	** The packaged localtime_rz and gmtime_r never put out-of-range
@@ -1208,7 +1209,6 @@ dumptime(register const struct tm *timeptr)
 		 ? mon_name[timeptr->tm_mon] : "???"),
 		timeptr->tm_mday, timeptr->tm_hour,
 		timeptr->tm_min, timeptr->tm_sec);
-#define DIVISOR	10
 	trail = timeptr->tm_year % DIVISOR + TM_YEAR_BASE % DIVISOR;
 	lead = timeptr->tm_year / DIVISOR + TM_YEAR_BASE / DIVISOR +
 		trail / DIVISOR;
diff --git a/zic.c b/zic.c
index 7742422..a29f679 100644
--- a/zic.c
+++ b/zic.c
@@ -96,12 +96,13 @@ struct rule {
 };
 
 /*
-**	r_dycode		r_dayofmonth	r_wday
+** r_dycode	r_dayofmonth	r_wday
 */
-
-#define DC_DOM		0	/* 1..31 */	/* unused */
-#define DC_DOWGEQ	1	/* 1..31 */	/* 0..6 (Sun..Sat) */
-#define DC_DOWLEQ	2	/* 1..31 */	/* 0..6 (Sun..Sat) */
+enum {
+  DC_DOM,	/* 1..31 */	/* unused */
+  DC_DOWGEQ,	/* 1..31 */	/* 0..6 (Sun..Sat) */
+  DC_DOWLEQ	/* 1..31 */	/* 0..6 (Sun..Sat) */
+};
 
 struct zone {
 	const char *	z_filename;
@@ -213,89 +214,107 @@ static int		unspecifiedtype;
 ** Line codes.
 */
 
-#define LC_RULE		0
-#define LC_ZONE		1
-#define LC_LINK		2
-#define LC_LEAP		3
-#define LC_EXPIRES	4
+enum {
+  LC_RULE,
+  LC_ZONE,
+  LC_LINK,
+  LC_LEAP,
+  LC_EXPIRES
+};
 
 /*
 ** Which fields are which on a Zone line.
 */
 
-#define ZF_NAME		1
-#define ZF_STDOFF	2
-#define ZF_RULE		3
-#define ZF_FORMAT	4
-#define ZF_TILYEAR	5
-#define ZF_TILMONTH	6
-#define ZF_TILDAY	7
-#define ZF_TILTIME	8
-#define ZONE_MINFIELDS	5
-#define ZONE_MAXFIELDS	9
+enum {
+  ZF_NAME = 1,
+  ZF_STDOFF,
+  ZF_RULE,
+  ZF_FORMAT,
+  ZF_TILYEAR,
+  ZF_TILMONTH,
+  ZF_TILDAY,
+  ZF_TILTIME,
+  ZONE_MAXFIELDS,
+  ZONE_MINFIELDS = ZF_TILYEAR
+};
 
 /*
 ** Which fields are which on a Zone continuation line.
 */
 
-#define ZFC_STDOFF	0
-#define ZFC_RULE	1
-#define ZFC_FORMAT	2
-#define ZFC_TILYEAR	3
-#define ZFC_TILMONTH	4
-#define ZFC_TILDAY	5
-#define ZFC_TILTIME	6
-#define ZONEC_MINFIELDS	3
-#define ZONEC_MAXFIELDS	7
+enum {
+  ZFC_STDOFF,
+  ZFC_RULE,
+  ZFC_FORMAT,
+  ZFC_TILYEAR,
+  ZFC_TILMONTH,
+  ZFC_TILDAY,
+  ZFC_TILTIME,
+  ZONEC_MAXFIELDS,
+  ZONEC_MINFIELDS = ZFC_TILYEAR
+};
 
 /*
 ** Which files are which on a Rule line.
 */
 
-#define RF_NAME		1
-#define RF_LOYEAR	2
-#define RF_HIYEAR	3
-#define RF_COMMAND	4
-#define RF_MONTH	5
-#define RF_DAY		6
-#define RF_TOD		7
-#define RF_SAVE		8
-#define RF_ABBRVAR	9
-#define RULE_FIELDS	10
+enum {
+  RF_NAME = 1,
+  RF_LOYEAR,
+  RF_HIYEAR,
+  RF_COMMAND,
+  RF_MONTH,
+  RF_DAY,
+  RF_TOD,
+  RF_SAVE,
+  RF_ABBRVAR,
+  RULE_FIELDS
+};
 
 /*
 ** Which fields are which on a Link line.
 */
 
-#define LF_TARGET	1
-#define LF_LINKNAME	2
-#define LINK_FIELDS	3
+enum {
+  LF_TARGET = 1,
+  LF_LINKNAME,
+  LINK_FIELDS
+};
 
 /*
 ** Which fields are which on a Leap line.
 */
 
-#define LP_YEAR		1
-#define LP_MONTH	2
-#define LP_DAY		3
-#define LP_TIME		4
-#define LP_CORR		5
-#define LP_ROLL		6
-#define LEAP_FIELDS	7
-
-/* Expires lines are like Leap lines, except without CORR and ROLL fields.  */
-#define EXPIRES_FIELDS	5
+enum {
+  LP_YEAR = 1,
+  LP_MONTH,
+  LP_DAY,
+  LP_TIME,
+  LP_CORR,
+  LP_ROLL,
+  LEAP_FIELDS,
+
+  /* Expires lines are like Leap lines, except without CORR and ROLL fields.  */
+  EXPIRES_FIELDS = LP_TIME + 1
+};
 
-/* The maximum number of fields on any of the above lines.  */
-#define MAX_FIELDS RULE_FIELDS
+/* The maximum number of fields on any of the above lines.
+   (The "+"s pacify gcc -Wenum-compare.)  */
+enum {
+  MAX_FIELDS = max(max(+RULE_FIELDS, +LINK_FIELDS),
+		   max(+LEAP_FIELDS, +EXPIRES_FIELDS))
+};
 
 /*
 ** Year synonyms.
 */
 
-#define YR_MINIMUM	0
-#define YR_MAXIMUM	1
-#define YR_ONLY		2
+enum {
+  YR_MINIMUM,
+  YR_MAXIMUM,
+  YR_ONLY
+};
 
 static struct rule *	rules;
 static ptrdiff_t	nrules;	/* number of rules */
@@ -671,7 +690,7 @@ check_for_signal(void)
   }
 }
 
-#define TIME_T_BITS_IN_FILE 64
+enum { TIME_T_BITS_IN_FILE = 64 };
 
 /* The minimum and maximum values representable in a TZif file.  */
 static zic_t const min_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE);
-- 
2.34.1



More information about the tz mailing list