diff --git a/src/basic/macro.h b/src/basic/macro.h index 2425d27819..3de319d880 100644 --- a/src/basic/macro.h +++ b/src/basic/macro.h @@ -297,6 +297,13 @@ static inline int __coverity_check_and_return__(int condition) { p != (typeof(p)) POINTER_MAX; \ p = *(++_l)) +#define _FOREACH_ARRAY(i, array, num, m, s) \ + for (typeof(num) m = (num); m > 0; m = 0) \ + for (typeof(array[0]) *s = (array), *i = s; s && i < s + m; i++) + +#define FOREACH_ARRAY(i, array, num) \ + _FOREACH_ARRAY(i, array, num, UNIQ_T(m, UNIQ), UNIQ_T(s, UNIQ)) + #define DEFINE_TRIVIAL_DESTRUCTOR(name, type, func) \ static inline void name(type *p) { \ func(p); \ diff --git a/src/systemctl/systemctl-list-units.c b/src/systemctl/systemctl-list-units.c index f9f53bd525..9be9510a2c 100644 --- a/src/systemctl/systemctl-list-units.c +++ b/src/systemctl/systemctl-list-units.c @@ -126,7 +126,7 @@ static int output_units_list(const UnitInfo *unit_infos, size_t c) { table_set_ersatz_string(table, TABLE_ERSATZ_DASH); - for (const UnitInfo *u = unit_infos; unit_infos && (size_t) (u - unit_infos) < c; u++) { + FOREACH_ARRAY(u, unit_infos, c) { _cleanup_free_ char *id = NULL; const char *on_underline = "", *on_loaded = "", *on_active = "", *on_circle = ""; bool circle = false, underline = false; @@ -292,7 +292,7 @@ typedef struct SocketInfo { static void socket_info_array_free(SocketInfo *sockets, size_t n_sockets) { assert(sockets || n_sockets == 0); - for (SocketInfo *s = sockets; s < sockets + n_sockets; s++) { + FOREACH_ARRAY(s, sockets, n_sockets) { free(s->type); free(s->path); strv_free(s->triggered); @@ -422,7 +422,7 @@ static int output_sockets_list(const SocketInfo *sockets, size_t n_sockets) { table_set_ersatz_string(table, TABLE_ERSATZ_DASH); - for (const SocketInfo *s = sockets; s < sockets + n_sockets; s++) { + FOREACH_ARRAY(s, sockets, n_sockets) { _cleanup_free_ char *unit = NULL; unit = format_unit_id(s->id, s->machine); @@ -479,7 +479,7 @@ int verb_list_sockets(int argc, char *argv[], void *userdata) { if (n < 0) return n; - for (const UnitInfo *u = unit_infos; u < unit_infos + n; u++) { + FOREACH_ARRAY(u, unit_infos, n) { r = socket_info_add(bus, u, &sockets, &n_sockets); if (r < 0) return r; @@ -571,7 +571,7 @@ typedef struct TimerInfo { static void timer_info_array_free(TimerInfo *timers, size_t n_timers) { assert(timers || n_timers == 0); - for (TimerInfo *t = timers; t < timers + n_timers; t++) + FOREACH_ARRAY(t, timers, n_timers) strv_free(t->triggered); free(timers); @@ -613,7 +613,7 @@ static int output_timers_list(const TimerInfo *timers, size_t n_timers) { (void) table_set_align_percent(table, table_get_cell(table, 0, 1), 100); (void) table_set_align_percent(table, table_get_cell(table, 0, 3), 100); - for (const TimerInfo *t = timers; t < timers + n_timers; t++) { + FOREACH_ARRAY(t, timers, n_timers) { _cleanup_free_ char *unit = NULL; unit = format_unit_id(t->id, t->machine); @@ -749,7 +749,7 @@ int verb_list_timers(int argc, char *argv[], void *userdata) { dual_timestamp_get(&nw); - for (const UnitInfo *u = unit_infos; u < unit_infos + n; u++) { + FOREACH_ARRAY(u, unit_infos, n) { r = add_timer_info(bus, u, &nw, &timers, &n_timers); if (r < 0) return r; @@ -774,7 +774,7 @@ typedef struct AutomountInfo { static void automount_info_array_free(AutomountInfo *automounts, size_t n_automounts) { assert(automounts || n_automounts == 0); - for (AutomountInfo *i = automounts; i < automounts + n_automounts; i++) { + FOREACH_ARRAY(i, automounts, n_automounts) { free(i->what); free(i->where); } @@ -881,7 +881,7 @@ static int output_automounts_list(const AutomountInfo *infos, size_t n_infos) { table_set_ersatz_string(table, TABLE_ERSATZ_DASH); - for (const AutomountInfo *info = infos; info < infos + n_infos; info++) { + FOREACH_ARRAY(info, infos, n_infos) { _cleanup_free_ char *unit = NULL; unit = format_unit_id(info->id, info->machine); @@ -945,7 +945,7 @@ int verb_list_automounts(int argc, char *argv[], void *userdata) { if (n < 0) return n; - for (const UnitInfo *u = unit_infos; u < unit_infos + n; u++) { + FOREACH_ARRAY(u, unit_infos, n) { r = automount_info_add(bus, u, &automounts, &n_automounts); if (r < 0) return r; @@ -995,7 +995,7 @@ static int path_info_compare(const PathInfo *a, const PathInfo *b) { static void path_info_array_free(PathInfo *paths, size_t n_paths) { assert(paths || n_paths == 0); - for (PathInfo *p = paths; p < paths + n_paths; p++) { + FOREACH_ARRAY(p, paths, n_paths) { free(p->condition); free(p->path); strv_free(p->triggered); @@ -1096,7 +1096,7 @@ static int output_paths_list(const PathInfo *paths, size_t n_paths) { table_set_ersatz_string(table, TABLE_ERSATZ_DASH); - for (const PathInfo *p = paths; p < paths + n_paths; p++) { + FOREACH_ARRAY(p, paths, n_paths) { _cleanup_free_ char *unit = NULL; unit = format_unit_id(p->id, p->machine); @@ -1153,7 +1153,7 @@ int verb_list_paths(int argc, char *argv[], void *userdata) { if (n < 0) return n; - for (const UnitInfo *u = unit_infos; u < unit_infos + n; u++) { + FOREACH_ARRAY(u, unit_infos, n) { r = path_info_add(bus, u, &paths, &n_paths); if (r < 0) return r; diff --git a/src/test/test-macro.c b/src/test/test-macro.c index aec1f1ecd4..ef74b8273e 100644 --- a/src/test/test-macro.c +++ b/src/test/test-macro.c @@ -584,4 +584,54 @@ TEST(ALIGNED) { #endif } +TEST(FOREACH_ARRAY) { + int a[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + int b[10] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; + int x, n; + + x = n = 0; + FOREACH_ARRAY(i, a, 10) { + x += *i; + n++; + } + assert_se(x == 45); + assert_se(n == 10); + + x = n = 0; + FOREACH_ARRAY(i, a, 10) + FOREACH_ARRAY(j, b, 10) { + x += (*i) * (*j); + n++; + } + assert_se(x == 45 * 45); + assert_se(n == 10 * 10); + + x = n = 0; + FOREACH_ARRAY(i, a, 5) + FOREACH_ARRAY(j, b, 5) { + x += (*i) * (*j); + n++; + } + assert_se(x == 10 * 35); + assert_se(n == 5 * 5); + + x = n = 0; + FOREACH_ARRAY(i, a, 0) + FOREACH_ARRAY(j, b, 0) { + x += (*i) * (*j); + n++; + } + assert_se(x == 0); + assert_se(n == 0); + + x = n = 0; + FOREACH_ARRAY(i, a, -1) + FOREACH_ARRAY(j, b, -1) { + x += (*i) * (*j); + n++; + } + assert_se(x == 0); + assert_se(n == 0); +} + DEFINE_TEST_MAIN(LOG_INFO);