// C
#include <assert.h>
+#include <limits.h>
#include <stdbool.h>
static inline void cleanup_dictionary(dictionary **ini)
[INI_FIELD_ARGS] = "args",
[INI_FIELD_ENV] = "env",
[INI_FIELD_FLAG] = "cmdflag",
+ // non-string field: "order"
};
static const size_t MAX_INI_KEY_LEN = 7;
struct extra_dump_item {
// not separate named fields, for convenient iteration
- const char *fields[COUNT_INI_FIELDS];
+ char *fields[COUNT_INI_FIELDS];
+ int order;
+};
+
+void cleanup_extra_dump_item(struct extra_dump_item *edi)
+{
+ for (size_t i = 0; i < ARRAY_SIZE(edi->fields); ++i)
+ free(edi->fields[i]);
+}
+
+struct extra_items_vector {
+ size_t size;
+ struct extra_dump_item *data;
};
bool check_cmdflag(const char *const flag, int argc, char **argv)
typedef int (*handle_ini_section_t)(int out_fd, struct extra_dump_item *, int argc, char **argv);
-static int handle_ini_Nth_section(int out_fd, const dictionary *ini, int n, handle_ini_section_t handle_ini_section, int argc, char **argv)
+static int handle_ini_Nth_section(struct extra_dump_item *item, const dictionary *ini, int n)
{
- assert(out_fd >= 0);
+ assert(item);
assert(ini);
assert(n >= 0);
assert(n < iniparser_getnsec(ini));
- assert(handle_ini_section);
const char *const secname = iniparser_getsecname(ini, n);
assert(secname); // can only be NULL if `ini` is NULL or `n` is outta bounds
memcpy(key_buf, secname, secname_len);
key_buf[secname_len] = ':';
+ int ret = 0;
char *const key_suffix_ptr = key_buf + secname_len + 1;
- struct extra_dump_item item;
- for (size_t i = 0; i < ARRAY_SIZE(item.fields); ++i) {
+ for (size_t i = 0; i < ARRAY_SIZE(item->fields); ++i) {
strcpy(key_suffix_ptr, INI_KEYS[i]);
- item.fields[i] = iniparser_getstring(ini, key_buf, NULL);
+
+ const char *tmp = iniparser_getstring(ini, key_buf, NULL);
+ if (!tmp) {
+ item->fields[i] = NULL;
+ continue;
+ }
+
+ item->fields[i] = strdup(tmp);
+ if (!item->fields[i])
+ ret |= EXIT_ERR;
}
- return handle_ini_section(out_fd, &item, argc, argv);
+ strcpy(key_suffix_ptr, "order");
+ const char *tmp = iniparser_getstring(ini, key_buf, NULL);
+ item->order = tmp ? atoi(tmp) : INT_MAX;
+
+ return ret;
}
-static int handle_extra_ini(int out_fd, const char *ini_path, handle_ini_section_t handle_ini_section, int argc, char **argv)
+static int handle_extra_ini(int out_fd, struct extra_items_vector *eiv, const char *ini_path)
{
assert(out_fd >= 0);
+ assert(eiv);
assert(ini_path);
- assert(handle_ini_section);
__attribute__((cleanup(cleanup_dictionary))) dictionary *ini = iniparser_load(ini_path);
if (!ini) {
const int nsec = iniparser_getnsec(ini);
assert(nsec >= 0); // can only be -1 when ini is NULL
+ const size_t prev_size = eiv->size;
+ struct extra_dump_item *const temp = realloc(eiv->data, (eiv->size + nsec) * sizeof *eiv->data);
+ if (!temp)
+ return EXIT_ERR;
+ eiv->data = temp;
+ eiv->size += nsec;
+
int ret = 0;
for (int i = 0; i < nsec; ++i)
- ret |= handle_ini_Nth_section(out_fd, ini, i, handle_ini_section, argc, argv);
+ ret |= handle_ini_Nth_section(eiv->data + prev_size + i, ini, i);
return ret;
}
return de->d_type == DT_REG && string_ends_with(de->d_name, ".conf");
}
+int handle_items_vector(struct extra_items_vector *eiv, int out_fd, handle_ini_section_t handle_ini_section, int argc, char **argv)
+{
+ inline int cmp(const void *a, const void *b) {
+ return ((struct extra_dump_item *)a)->order - ((struct extra_dump_item *)b)->order;
+ }
+ qsort(eiv->data, eiv->size, sizeof *eiv->data, cmp);
+
+ int ret = 0;
+ for (size_t i = 0; i < eiv->size; ++i)
+ ret |= handle_ini_section(out_fd, eiv->data + i, argc, argv);
+ return ret;
+}
+
+void free_items_vector(struct extra_items_vector *eiv)
+{
+ for (size_t i = 0; i < eiv->size; ++i)
+ cleanup_extra_dump_item(eiv->data + i);
+ free(eiv->data);
+}
+
int handle_extra_dir(int out_fd, char *dir_path, handle_ini_section_t handle_ini_section, int argc, char **argv)
{
assert(out_fd >= 0);
return EXIT_ERR;
}
+ __attribute__((cleanup(free_items_vector))) struct extra_items_vector eiv = {
+ .size = 0,
+ .data = NULL,
+ };
+
int ret = 0;
for (int i = 0; i < entry_count; ++i) {
struct dirent *const de = entries[i];
snprintf(ini_path, sizeof ini_path, "%s/%s", dir_path, de->d_name);
free(de);
- ret |= handle_extra_ini(out_fd, ini_path, handle_ini_section, argc, argv);
+ ret |= handle_extra_ini(out_fd, &eiv, ini_path);
}
+ ret |= handle_items_vector(&eiv, out_fd, handle_ini_section, argc, argv);
+
free(entries);
close(dir_fd);
return ret;