+fmt_settings_uninit (struct fmt_settings *settings)
+{
+ for (int i = 0; i < FMT_N_CCS; i++)
+ fmt_number_style_destroy (settings->ccs[i]);
+}
+
+struct fmt_settings
+fmt_settings_copy (const struct fmt_settings *old)
+{
+ struct fmt_settings new = *old;
+ for (int i = 0; i < FMT_N_CCS; i++)
+ new.ccs[i] = fmt_number_style_clone (old->ccs[i]);
+ return new;
+}
+
+static size_t
+fmt_type_to_cc_index (enum fmt_type type)
+{
+ switch (type)
+ {
+ case FMT_CCA: return 0;
+ case FMT_CCB: return 1;
+ case FMT_CCC: return 2;
+ case FMT_CCD: return 3;
+ case FMT_CCE: return 4;
+ default: NOT_REACHED ();
+ }
+}
+
+/* Returns the number formatting style associated with the given
+ format TYPE. */
+const struct fmt_number_style *
+fmt_settings_get_style (const struct fmt_settings *settings,
+ enum fmt_type type)
+{
+ verify (FMT_F < 6);
+ verify (FMT_COMMA < 6);
+ verify (FMT_DOT < 6);
+ verify (FMT_DOLLAR < 6);
+ verify (FMT_PCT < 6);
+ verify (FMT_E < 6);
+
+#define OPPOSITE(C) ((C) == ',' ? '.' : ',')
+#define AFFIX(S) { .s = (char *) (S), .width = sizeof (S) - 1 }
+#define NS(PREFIX, SUFFIX, DECIMAL, GROUPING, INCLUDE_LEADING_ZERO) { \
+ .neg_prefix = AFFIX ("-"), \
+ .prefix = AFFIX (PREFIX), \
+ .suffix = AFFIX (SUFFIX), \
+ .neg_suffix = AFFIX (""), \
+ .decimal = DECIMAL, \
+ .grouping = GROUPING, \
+ .include_leading_zero = INCLUDE_LEADING_ZERO \
+ }
+#define ANS(DECIMAL, GROUPING, INCLUDE_LEADING_ZERO) { \
+ [FMT_F] = NS( "", "", DECIMAL, 0, INCLUDE_LEADING_ZERO), \
+ [FMT_E] = NS( "", "", DECIMAL, 0, INCLUDE_LEADING_ZERO), \
+ [FMT_COMMA] = NS( "", "", DECIMAL, GROUPING, INCLUDE_LEADING_ZERO), \
+ [FMT_DOT] = NS( "", "", GROUPING, DECIMAL, INCLUDE_LEADING_ZERO), \
+ [FMT_DOLLAR] = NS("$", "", DECIMAL, GROUPING, false), \
+ [FMT_PCT] = NS( "", "%", DECIMAL, 0, false), \
+ }
+#define ANS2(DECIMAL, GROUPING) { \
+ ANS(DECIMAL, GROUPING, false), \
+ ANS(DECIMAL, GROUPING, true), \
+ }
+
+ /* First index: 0 for ',' decimal point, 1 for '.' decimal point.
+ Second index: 0 for no leading zero, 1 for leading zero.
+ Third index: TYPE.
+ */
+ static const struct fmt_number_style styles[2][2][6] = {
+ ANS2 (',', '.'),
+ ANS2 ('.', ','),
+ };
+
+ static const struct fmt_number_style default_style = NS ("", "", '.', 0, false);
+
+ switch (type)
+ {
+ case FMT_F:
+ case FMT_COMMA:
+ case FMT_DOT:
+ case FMT_DOLLAR:
+ case FMT_PCT:
+ case FMT_E:
+ {
+ int decimal_idx = settings->decimal == '.';
+ int leadzero_idx = settings->include_leading_zero;
+ return &styles[decimal_idx][leadzero_idx][type];
+ }
+
+ case FMT_CCA:
+ case FMT_CCB:
+ case FMT_CCC:
+ case FMT_CCD:
+ case FMT_CCE:
+ {
+ size_t idx = fmt_type_to_cc_index (type);
+ return settings->ccs[idx] ? settings->ccs[idx] : &default_style;
+ }
+
+ default:
+ return &default_style;
+ }
+}
+
+static int
+default_epoch (void)