"Options",
};
- _cleanup_(table_unref_many) Table *verb_tables[ELEMENTSOF(verb_groups) + 1] = {};
- _cleanup_(table_unref_many) Table *option_tables[ELEMENTSOF(option_groups) + 1] = {};
+ Table *verb_tables[ELEMENTSOF(verb_groups)] = {};
+ CLEANUP_ELEMENTS(verb_tables, table_unref_array_clear);
+ Table *option_tables[ELEMENTSOF(option_groups)] = {};
+ CLEANUP_ELEMENTS(option_tables, table_unref_array_clear);
for (size_t i = 0; i < ELEMENTSOF(verb_groups); i++) {
r = verbs_get_help_table_group(verb_groups[i], &verb_tables[i]);
"TPM2 Enrollment",
};
- _cleanup_(table_unref_many) Table *tables[ELEMENTSOF(groups) + 1] = {};
+ Table *tables[ELEMENTSOF(groups)] = {};
+ CLEANUP_ELEMENTS(tables, table_unref_array_clear);
for (size_t i = 0; i < ELEMENTSOF(groups); i++) {
r = option_parser_get_help_table_group(groups[i], &tables[i]);
free(array); \
}
+/* Like DEFINE_POINTER_ARRAY_FREE_FUNC() but does not deallocate the array itself, useful for
+ * arrays with automatic storage duration (e.g. on the stack). */
+#define DEFINE_POINTER_ARRAY_CLEAR_FUNC(type, helper) \
+ void helper ## _array_clear(type *array, size_t n) { \
+ assert(array || n == 0); \
+ FOREACH_ARRAY(item, array, n) \
+ *item = helper(*item); \
+ }
+
/* Clean up an array of objects of known size by dropping all the items in it.
* Then free the array itself. */
#define DEFINE_ARRAY_FREE_FUNC(name, type, helper) \
_f; \
}), \
}
+
+/* An automatic _cleanup_-like logic for fixed-size arrays where the bound is known via
+ * ELEMENTSOF(). Unlike CLEANUP_ARRAY() this neither frees the storage nor zeroes it: it just
+ * invokes func() across the elements when leaving scope. */
+typedef struct ElementsCleanup {
+ void *array;
+ size_t n;
+ free_array_func_t pfunc;
+} ElementsCleanup;
+
+static inline void elements_cleanup(const ElementsCleanup *c) {
+ assert(c);
+
+ if (c->n == 0)
+ return;
+
+ assert(c->array);
+ assert(c->pfunc);
+ c->pfunc(c->array, c->n);
+}
+
+#define CLEANUP_ELEMENTS(_array, _func) \
+ _cleanup_(elements_cleanup) _unused_ const ElementsCleanup CONCATENATE(_cleanup_elements_, UNIQ) = { \
+ .array = (_array), \
+ .n = ELEMENTSOF(_array), \
+ .pfunc = (free_array_func_t) ({ \
+ void (*_f)(typeof((_array)[0]) *a, size_t b) = _func; \
+ _f; \
+ }), \
+ }
return 0;
}
-static void device_unref_many(sd_device **devices, size_t n) {
- assert(devices || n == 0);
-
- for (size_t i = 0; i < n; i++)
- sd_device_unref(devices[i]);
-}
+static DEFINE_POINTER_ARRAY_CLEAR_FUNC(sd_device*, sd_device_unref);
static void device_enumerator_unref_devices(sd_device_enumerator *enumerator) {
assert(enumerator);
hashmap_clear(enumerator->devices_by_syspath);
- device_unref_many(enumerator->devices, enumerator->n_devices);
+ sd_device_unref_array_clear(enumerator->devices, enumerator->n_devices);
enumerator->devices = mfree(enumerator->devices);
enumerator->n_devices = 0;
}
typesafe_qsort(devices + n_sorted, n - n_sorted, device_compare);
- device_unref_many(enumerator->devices, enumerator->n_devices);
+ sd_device_unref_array_clear(enumerator->devices, enumerator->n_devices);
enumerator->n_devices = n;
free_and_replace(enumerator->devices, devices);
return 0;
failed:
- device_unref_many(devices, n);
+ sd_device_unref_array_clear(devices, n);
free(devices);
return r;
}
"Other",
};
- _cleanup_(table_unref_many) Table* tables[ELEMENTSOF(groups) + 1] = {};
+ Table* tables[ELEMENTSOF(groups)] = {};
+ CLEANUP_ELEMENTS(tables, table_unref_array_clear);
for (size_t i = 0; i < ELEMENTSOF(groups); i++) {
r = option_parser_get_help_table_group(groups[i], &tables[i]);
"El Torito boot catalog",
};
- _cleanup_(table_unref_many) Table *option_tables[ELEMENTSOF(option_groups) + 1] = {};
+ Table *option_tables[ELEMENTSOF(option_groups)] = {};
+ CLEANUP_ELEMENTS(option_tables, table_unref_array_clear);
for (size_t i = 0; i < ELEMENTSOF(option_groups); i++) {
r = option_parser_get_help_table_group(option_groups[i], &option_tables[i]);
"Timer options",
};
- _cleanup_(table_unref_many) Table *tables[ELEMENTSOF(groups) + 1] = {};
+ Table *tables[ELEMENTSOF(groups)] = {};
+ CLEANUP_ELEMENTS(tables, table_unref_array_clear);
for (size_t i = 0; i < ELEMENTSOF(groups); i++) {
r = option_parser_get_help_table_full("systemd-run", groups[i], &tables[i]);
return cached;
}
-static DEFINE_ARRAY_DONE_FUNC(sd_netlink_message*, sd_netlink_message_unref);
+static DEFINE_POINTER_ARRAY_CLEAR_FUNC(sd_netlink_message*, sd_netlink_message_unref);
static int nfnl_open_expr_container(sd_netlink_message *m, const char *name) {
int r;
}
static int fw_nftables_init_family(sd_netlink *nfnl, int family) {
- _cleanup_(sd_netlink_message_unref_many) sd_netlink_message *messages[10] = {};
+ sd_netlink_message *messages[10] = {};
+ CLEANUP_ELEMENTS(messages, sd_netlink_message_unref_array_clear);
size_t msgcnt = 0, ip_type_size;
uint32_t set_id = 0;
int ip_type, r;
uint16_t remote_port,
const union in_addr_union *previous_remote) {
- _cleanup_(sd_netlink_message_unref_many) sd_netlink_message *messages[3] = {};
+ sd_netlink_message *messages[3] = {};
+ CLEANUP_ELEMENTS(messages, sd_netlink_message_unref_array_clear);
uint32_t data[5], key[2], dlen;
size_t msgcnt = 0;
int r;
Table* table_unref(Table *t);
DEFINE_TRIVIAL_CLEANUP_FUNC(Table*, table_unref);
-static inline DEFINE_ARRAY_DONE_FUNC(Table*, table_unref);
+static inline DEFINE_POINTER_ARRAY_CLEAR_FUNC(Table*, table_unref);
int table_add_cell_full(Table *t, TableCell **ret_cell, TableDataType dt, const void *data, size_t minimum_width, size_t maximum_width, unsigned weight, unsigned align_percent, unsigned ellipsize_percent);
static inline int table_add_cell(Table *t, TableCell **ret_cell, TableDataType dt, const void *data) {
"Credentials",
};
- _cleanup_(table_unref_many) Table* tables[ELEMENTSOF(groups) + 1] = {};
+ Table* tables[ELEMENTSOF(groups)] = {};
+ CLEANUP_ELEMENTS(tables, table_unref_array_clear);
for (size_t i = 0; i < ELEMENTSOF(groups); i++) {
r = option_parser_get_help_table_group(groups[i], &tables[i]);