+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) { \
+ .neg_prefix = AFFIX ("-"), \
+ .prefix = AFFIX (PREFIX), \
+ .suffix = AFFIX (SUFFIX), \
+ .neg_suffix = AFFIX (""), \
+ .decimal = DECIMAL, \
+ .grouping = GROUPING, \
+ }
+#define ANS(DECIMAL, GROUPING) { \
+ [FMT_F] = NS( "", "", DECIMAL, 0), \
+ [FMT_E] = NS( "", "", DECIMAL, 0), \
+ [FMT_COMMA] = NS( "", "", DECIMAL, GROUPING), \
+ [FMT_DOT] = NS( "", "", GROUPING, DECIMAL), \
+ [FMT_DOLLAR] = NS("$", "", DECIMAL, GROUPING), \
+ [FMT_PCT] = NS( "", "%", DECIMAL, 0), \
+ }
+
+ static const struct fmt_number_style period_styles[6] = ANS ('.', ',');
+ static const struct fmt_number_style comma_styles[6] = ANS (',', '.');
+ static const struct fmt_number_style default_style = NS ("", "", '.', 0);
+
+ switch (type)
+ {
+ case FMT_F:
+ case FMT_COMMA:
+ case FMT_DOT:
+ case FMT_DOLLAR:
+ case FMT_PCT:
+ case FMT_E:
+ return (settings->decimal == '.'
+ ? &period_styles[type]
+ : &comma_styles[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)