union {
uint8_t data[0]; /* data is generic array */
bool boolean;
+ int tristate;
usec_t timestamp;
usec_t timespan;
uint64_t size;
case TABLE_PERCENT:
case TABLE_IFINDEX:
case TABLE_SIGNAL:
+ case TABLE_TRISTATE:
return sizeof(int);
case TABLE_IN_ADDR:
uint64_t uint64;
int percent;
int ifindex;
+ int tristate;
bool b;
union in_addr_union address;
sd_id128_t id128;
data = &buffer.b;
break;
+ case TABLE_TRISTATE:
+ buffer.tristate = va_arg(ap, int);
+ data = &buffer.tristate;
+ break;
+
case TABLE_TIMESTAMP:
case TABLE_TIMESTAMP_UTC:
case TABLE_TIMESTAMP_RELATIVE:
return strv_compare(a->strv, b->strv);
case TABLE_BOOLEAN:
+ case TABLE_BOOLEAN_CHECKMARK:
if (!a->boolean && b->boolean)
return -1;
if (a->boolean && !b->boolean)
return 1;
return 0;
+ case TABLE_TRISTATE:
+ /* NB: we do not use CMP() here, since we want to collapse all negative and all
+ * positive into one bucket each. */
+ if ((a->tristate < 0 && b->tristate >= 0) ||
+ (a->tristate == 0 && b->tristate > 0))
+ return -1;
+
+ if ((b->tristate < 0 && a->tristate >= 0) ||
+ (b->tristate == 0 && a->tristate > 0))
+ return 1;
+ return 0;
+
case TABLE_TIMESTAMP:
case TABLE_TIMESTAMP_UTC:
case TABLE_TIMESTAMP_RELATIVE:
case TABLE_BOOLEAN_CHECKMARK:
return glyph(d->boolean ? GLYPH_CHECK_MARK : GLYPH_CROSS_MARK);
+ case TABLE_TRISTATE:
+ if (d->tristate < 0)
+ return table_ersatz_string(t);
+
+ return yes_no(d->tristate);
+
case TABLE_TIMESTAMP:
case TABLE_TIMESTAMP_UTC:
case TABLE_TIMESTAMP_RELATIVE:
case TABLE_BOOLEAN:
return sd_json_variant_new_boolean(ret, d->boolean);
+ case TABLE_TRISTATE:
+ if (d->tristate < 0)
+ return sd_json_variant_new_null(ret);
+
+ return sd_json_variant_new_boolean(ret, d->tristate);
+
case TABLE_TIMESTAMP:
case TABLE_TIMESTAMP_UTC:
case TABLE_TIMESTAMP_RELATIVE:
"5min 5min \n");
}
+TEST(tristate) {
+ _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL, *w = NULL;
+ _cleanup_(table_unrefp) Table *t = NULL;
+ _cleanup_free_ char *formatted = NULL;
+
+ ASSERT_NOT_NULL((t = table_new("name", "flag")));
+
+ ASSERT_OK(table_add_many(t,
+ TABLE_STRING, "neg",
+ TABLE_TRISTATE, -1));
+ ASSERT_OK(table_add_many(t,
+ TABLE_STRING, "zero",
+ TABLE_TRISTATE, 0));
+ ASSERT_OK(table_add_many(t,
+ TABLE_STRING, "pos",
+ TABLE_TRISTATE, 1));
+
+ ASSERT_OK(table_format(t, &formatted));
+ printf("%s\n", formatted);
+ ASSERT_STREQ(formatted,
+ "NAME FLAG\n"
+ "neg \n"
+ "zero no\n"
+ "pos yes\n");
+ formatted = mfree(formatted);
+
+ /* Try a non-default ersatz string. */
+ table_set_ersatz_string(t, TABLE_ERSATZ_DASH);
+ ASSERT_OK(table_format(t, &formatted));
+ printf("%s\n", formatted);
+ ASSERT_STREQ(formatted,
+ "NAME FLAG\n"
+ "neg -\n"
+ "zero no\n"
+ "pos yes\n");
+ formatted = mfree(formatted);
+
+ /* Sorting: -1 < 0 < 1 */
+ ASSERT_OK(table_set_sort(t, (size_t) 1, SIZE_MAX));
+ ASSERT_OK(table_format(t, &formatted));
+ printf("%s\n", formatted);
+ ASSERT_STREQ(formatted,
+ "NAME FLAG\n"
+ "neg -\n"
+ "zero no\n"
+ "pos yes\n");
+ formatted = mfree(formatted);
+
+ /* JSON: -1 → null, 0 → false, positive → true */
+ ASSERT_OK(table_to_json(t, &v));
+
+ ASSERT_OK(sd_json_build(&w,
+ SD_JSON_BUILD_ARRAY(
+ SD_JSON_BUILD_OBJECT(
+ SD_JSON_BUILD_PAIR("name", JSON_BUILD_CONST_STRING("neg")),
+ SD_JSON_BUILD_PAIR("flag", SD_JSON_BUILD_NULL)),
+ SD_JSON_BUILD_OBJECT(
+ SD_JSON_BUILD_PAIR("name", JSON_BUILD_CONST_STRING("zero")),
+ SD_JSON_BUILD_PAIR_BOOLEAN("flag", false)),
+ SD_JSON_BUILD_OBJECT(
+ SD_JSON_BUILD_PAIR("name", JSON_BUILD_CONST_STRING("pos")),
+ SD_JSON_BUILD_PAIR_BOOLEAN("flag", true)))));
+
+ ASSERT_TRUE(sd_json_variant_equal(v, w));
+}
+
TEST(signed_integers) {
_cleanup_(table_unrefp) Table *t = NULL;
_cleanup_free_ char *formatted = NULL;