aboutsummaryrefslogtreecommitdiff
path: root/src/remembering.c
diff options
context:
space:
mode:
authorEuAndreh <eu@euandre.org>2021-06-07 22:58:36 -0300
committerEuAndreh <eu@euandre.org>2021-06-07 22:58:36 -0300
commit0c47cb09c55cdb5cc0e0f061a881eee670e3c8a9 (patch)
treeed3b609d30acd7234319dfbbbf381f001eadec4a /src/remembering.c
parentREADME.md: Update for latest standards (diff)
downloadremembering-0c47cb09c55cdb5cc0e0f061a881eee670e3c8a9.tar.gz
remembering-0c47cb09c55cdb5cc0e0f061a881eee670e3c8a9.tar.xz
src/remembering.c: Use tabs over spaces
Diffstat (limited to '')
-rw-r--r--src/remembering.c1419
1 files changed, 735 insertions, 684 deletions
diff --git a/src/remembering.c b/src/remembering.c
index ad69c30..17993ee 100644
--- a/src/remembering.c
+++ b/src/remembering.c
@@ -20,242 +20,292 @@
#include <assert.h>
static void testing(const char *message) {
- fprintf(stderr, "testing: %s...", message);
+ fprintf(stderr, "testing: %s...", message);
}
-static void test_ok() { fprintf(stderr, " OK.\n"); }
+static void test_ok() {
+ fprintf(stderr, " OK.\n");
+}
-/* static */ FILE *tmpfile() {
- char filename[] = "remembering-test.XXXXXX";
+static FILE *testfile() {
+ char filename[] = "remembering-test.XXXXXX";
- errno = 0;
- int fd = mkstemp(filename);
- if (fd == -1) {
- perror("tmpfile mkstemp");
- return NULL;
- }
+ errno = 0;
+ int fd = mkstemp(filename);
+ if (fd == -1) {
+ perror("tmpfile mkstemp");
+ return NULL;
+ }
- errno = 0;
- FILE *f = fdopen(fd, "w");
- if (!f) {
- perror("tmpfile fdopen");
- close(fd);
- return NULL;
- }
+ errno = 0;
+ FILE *f = fdopen(fd, "w");
+ if (!f) {
+ perror("tmpfile fdopen");
+ close(fd);
+ return NULL;
+ }
- return f;
+ return f;
}
-// static
-char *tmpdir() {
- char dirname[] = "remembering-test.XXXXXX";
+static char *testdir() {
+ char dirname[] = "remembering-test.XXXXXX";
+
+ errno = 0;
+ char *dircpy = malloc(strlen(dirname) + 1);
+ if (!dircpy) {
+ perror("malloc");
+ return NULL;
+ }
- errno = 0;
- char *dircpy = malloc(strlen(dirname) + 1);
- if (!dircpy) {
- perror("malloc");
- return NULL;
- }
+ errno = 0;
+ char *dir = mkdtemp(dirname);
+ if (!dir) {
+ perror("mkdtemp");
+ free(dircpy);
+ return NULL;
+ }
- errno = 0;
- char *dir = mkdtemp(dirname);
- if (!dir) {
- perror("mkdtemp");
- free(dircpy);
- return NULL;
- }
+ strcpy(dircpy, dir);
+
+ return dircpy;
+}
- strcpy(dircpy, dir);
+static void assert_file_contents(const char *const filename, const char *const contents) {
- return dircpy;
}
#endif
-static void print_usage(FILE *stream, char *name) {
- fprintf(stream, "Usage: %s -p PROFILE -c 'COMMAND'\n",
- name ? name : "remembering");
+static int print_usage(FILE *stream, char *name) {
+ errno = 0;
+ fprintf(stream, "Usage: %s -p PROFILE -c 'COMMAND'\n",
+ name ? name : "remembering");
+ if (errno) {
+ perror("fprintf");
+ return -1;
+ }
+ return 0;
}
+#ifdef TEST
+static void print_usage_test() {
+ {
+ testing("print_usage a-name");
+ FILE *f = testfile();
+ if (!f) {
+ exit(EXIT_FAILURE);
+ }
+
+ int ret = print_usage(f, "a-name");
+ fclose(f);
+ if (ret) {
+ exit(EXIT_FAILURE);
+ }
+
+ assert_file_contents(f, "Usage: a-name -p PROFILE -c 'COMMAND'\n");
+
+ test_ok();
+ }
+ {
+ testing("print_usage NULL");
+ FILE *f = testfile();
+ if (!f) {
+ exit(EXIT_FAILURE);
+ }
+
+ int ret = print_usage(f, NULL);
+ fclose(f);
+ if (ret) {
+ exit(EXIT_FAILURE);
+ }
+
+ assert_file_contents(f, "Usage: remembering -p PROFILE -c 'COMMAND'\n");
+
+ test_ok();
+ }
+}
+#endif
+
static void print_help(FILE *stream) {
- const char *help_text =
- "\n"
- "Options:\n"
- " -p PROFILE profile to be used for gathering and storing data\n"
- " -c 'COMMAND' command to be run, reading from STDIN, writing to "
- "STDOUT\n"
- " -h show this help\n"
- " -V print program version\n"
- "See remembering(1) manpages for more information.\n";
- fprintf(stream, "%s", help_text);
+ const char *help_text =
+ "\n"
+ "Options:\n"
+ " -p PROFILE profile to be used for gathering and storing data\n"
+ " -c 'COMMAND' command to be run, reading from STDIN, writing to "
+ "STDOUT\n"
+ " -h show this help\n"
+ " -V print program version\n"
+ "See remembering(1) manpages for more information.\n";
+ fprintf(stream, "%s", help_text);
}
static void print_missing(FILE *stream, char *text) {
- fprintf(stream, "Missing option: %s\n", text);
+ fprintf(stream, "Missing option: %s\n", text);
}
static void print_version(FILE *stream) {
- fprintf(stream, "remembering-%s %s\n", VERSION, DATE);
+ fprintf(stream, "remembering-%s %s\n", VERSION, DATE);
}
static int get_options(FILE *out, FILE *err, int argc, char *argv[],
- char **command, char **profile) {
- for (int i = 0; i < argc; i++) {
- if (strcmp(argv[i], "--help") == 0) {
- print_usage(out, argv[0]);
- print_help(out);
- return 1;
- } else if (strcmp(argv[i], "--version")) {
- print_version(out);
- return 1;
- }
- }
-
- char *profilearg = NULL;
- char *commandarg = NULL;
- int option;
- while ((option = getopt(argc, argv, "c:p:hV")) != -1) {
- switch (option) {
- case 'c':
- commandarg = optarg;
- break;
- case 'p':
- profilearg = optarg;
- break;
- case 'h':
- print_usage(out, argv[0]);
- print_help(out);
- return 1;
- case 'V':
- print_version(out);
- return 1;
- }
- }
-
- if (!commandarg) {
- print_missing(err, "-c 'COMMAND'");
- print_usage(err, argv[0]);
- return -1;
- }
-
- if (!profilearg) {
- print_missing(err, "-p 'PROFILE'");
- print_usage(err, argv[0]);
- return 1;
- }
-
- *command = strdup(commandarg);
- if (!*command) {
- perror("strdup");
- return -1;
- }
- *profile = strdup(profilearg);
- if (!*profile) {
- perror("strdup");
- free(*command);
- return -1;
- }
-
- return 0;
+ char **command, char **profile) {
+ for (int i = 0; i < argc; i++) {
+ if (strcmp(argv[i], "--help") == 0) {
+ print_usage(out, argv[0]);
+ print_help(out);
+ return 1;
+ } else if (strcmp(argv[i], "--version")) {
+ print_version(out);
+ return 1;
+ }
+ }
+
+ char *profilearg = NULL;
+ char *commandarg = NULL;
+ int option;
+ while ((option = getopt(argc, argv, "c:p:hV")) != -1) {
+ switch (option) {
+ case 'c':
+ commandarg = optarg;
+ break;
+ case 'p':
+ profilearg = optarg;
+ break;
+ case 'h':
+ print_usage(out, argv[0]);
+ print_help(out);
+ return 1;
+ case 'V':
+ print_version(out);
+ return 1;
+ }
+ }
+
+ if (!commandarg) {
+ print_missing(err, "-c 'COMMAND'");
+ print_usage(err, argv[0]);
+ return -1;
+ }
+
+ if (!profilearg) {
+ print_missing(err, "-p 'PROFILE'");
+ print_usage(err, argv[0]);
+ return 1;
+ }
+
+ *command = strdup(commandarg);
+ if (!*command) {
+ perror("strdup");
+ return -1;
+ }
+ *profile = strdup(profilearg);
+ if (!*profile) {
+ perror("strdup");
+ free(*command);
+ return -1;
+ }
+
+ return 0;
}
#ifdef FALLIBLE
static int fallible_get_options(FILE *out, FILE *err, int argc, char *argv[],
- char **command, char **profile,
- const char *const filename, int lineno) {
- if (fallible_should_fail(filename, lineno)) {
- return -1;
- }
- return get_options(out, err, argc, argv, command, profile);
+ char **command, char **profile,
+ const char *const filename, int lineno) {
+ if (fallible_should_fail(filename, lineno)) {
+ return -1;
+ }
+ return get_options(out, err, argc, argv, command, profile);
}
-#define get_options(out, err, argc, argv, command, profile) \
- fallible_get_options(out, err, argc, argv, command, profile, __FILE__, \
- __LINE__)
+#define get_options(out, err, argc, argv, command, profile) \
+ fallible_get_options(out, err, argc, argv, command, profile, __FILE__, \
+ __LINE__)
#endif
#ifdef TEST
int arrlen(char **argv) {
- int count = 0;
- while (argv[count] != NULL) {
- count++;
- }
- return count;
+ int count = 0;
+ while (argv[count] != NULL) {
+ count++;
+ }
+ return count;
}
void get_options_test() {
- {
- testing("get_options when given -h, -V and --help");
- FILE *f = tmpfile();
- if (!f) {
- exit(EXIT_FAILURE);
- }
-
- char *argvs[13][6] = {
- {"--help", NULL},
- {"other", "arguments before", "--help", NULL},
- {"some", "--help", "arguments after", NULL},
- {"--help", "all", "arguments after", NULL},
- {"-h", NULL},
- {"-V", NULL},
- {"-hc", "1", NULL},
- {"-hp", "2", NULL},
- {"-hV", NULL},
- {"-Vh", NULL},
- {"-p", "p", "-h", NULL},
- {"-p", "p", "-c", "c", "-h", NULL},
- {NULL},
- };
- int rows = 0;
- while (argvs[rows][0] != NULL) {
- rows++;
- }
+ {
+ testing("get_options when given -h, -V and --help");
+ FILE *f = tmpfile();
+ if (!f) {
+ exit(EXIT_FAILURE);
+ }
+
+ char *argvs[13][6] = {
+ {"--help", NULL},
+ {"other", "arguments before", "--help", NULL},
+ {"some", "--help", "arguments after", NULL},
+ {"--help", "all", "arguments after", NULL},
+ {"-h", NULL},
+ {"-V", NULL},
+ {"-hc", "1", NULL},
+ {"-hp", "2", NULL},
+ {"-hV", NULL},
+ {"-Vh", NULL},
+ {"-p", "p", "-h", NULL},
+ {"-p", "p", "-c", "c", "-h", NULL},
+ {NULL},
+ };
+ int rows = 0;
+ while (argvs[rows][0] != NULL) {
+ rows++;
+ }
#ifdef DISABLE
- int ret;
- char *command = NULL;
- char *profile = NULL;
- for (int i = 0; i < rows; i++) {
- char **argv = argvs[i];
- ret = get_options(f, f, arrlen(argvs[i]), argv, &command, &profile);
- if (ret == -1) {
- fclose(f);
- exit(EXIT_FAILURE);
- }
-
- assert(command == NULL);
- assert(profile == NULL);
- assert(ret == 1);
- }
+ int ret;
+ char *command = NULL;
+ char *profile = NULL;
+ for (int i = 0; i < rows; i++) {
+ char **argv = argvs[i];
+ ret = get_options(f, f, arrlen(argvs[i]), argv, &command, &profile);
+ if (ret == -1) {
+ fclose(f);
+ exit(EXIT_FAILURE);
+ }
+
+ assert(command == NULL);
+ assert(profile == NULL);
+ assert(ret == 1);
+ }
#endif
- fclose(f);
- test_ok();
- }
- // { "" },
+ fclose(f);
+ test_ok();
+ }
+ // { "" },
}
#endif
static int mkdir_p(char *path, mode_t mode) {
- struct stat s;
- if (stat(path, &s) == 0 && S_ISDIR(s.st_mode)) {
- return 0;
- }
+ struct stat s;
+ if (stat(path, &s) == 0 && S_ISDIR(s.st_mode)) {
+ return 0;
+ }
- char *parent = dirname(path);
- int ret = mkdir_p(parent, mode);
- if (ret) {
- return ret;
- }
- return mkdir(path, mode);
+ char *parent = dirname(path);
+ int ret = mkdir_p(parent, mode);
+ if (ret) {
+ return ret;
+ }
+ return mkdir(path, mode);
}
#ifdef FALLIBLE
static int fallible_mkdir_p(char *path, mode_t mode, const char *const filename,
- int lineno) {
- if (fallible_should_fail(filename, lineno)) {
- return -1;
- }
- return mkdir_p(path, mode);
+ int lineno) {
+ if (fallible_should_fail(filename, lineno)) {
+ return -1;
+ }
+ return mkdir_p(path, mode);
}
#define mkdir_p(path, mode) fallible_mkdir_p(path, mode, __FILE__, __LINE__)
@@ -263,7 +313,7 @@ static int fallible_mkdir_p(char *path, mode_t mode, const char *const filename,
#ifdef TEST
static void mkdir_p_test() {
- /*
+ /*
{
testing("mkdir_p a single directory");
@@ -281,8 +331,8 @@ exit(EXIT_FAILURE);
free(dir);
test_ok();
}
- */
- /*
+ */
+ /*
{
testing("mkdir_p nested directories");
@@ -292,93 +342,93 @@ if (!dir_prefix) {
exit(EXIT_FAILURE);
}
- char *dir = malloc(strlen(dir_prefix) + strlen(dir_suffix) + 1);
- if (!dir) {
- free(dir_prefix);
- exit(EXIT_FAILURE);
- }
+ char *dir = malloc(strlen(dir_prefix) + strlen(dir_suffix) + 1);
+ if (!dir) {
+ free(dir_prefix);
+ exit(EXIT_FAILURE);
+ }
- strcpy(dir, dir_prefix);
- strcat(dir, dir_suffix);
+ strcpy(dir, dir_prefix);
+ strcat(dir, dir_suffix);
int ret = mkdir_p(dir, 0755);
if (ret) {
- free(dir);
- free(dir_prefix);
+ free(dir);
+ free(dir_prefix);
exit(EXIT_FAILURE);
}
- free(dir);
- free(dir_prefix);
+ free(dir);
+ free(dir_prefix);
test_ok();
}
- */
+ */
}
#endif
static char *expand_profile_name(const char *const profile_name) {
- char *prefix = NULL;
- char *env_prefix = getenv("XDG_DATA_HOME");
- if (env_prefix) {
- prefix = strdup(env_prefix);
- if (!prefix) {
- return NULL;
- }
- } else {
- char *home = getenv("HOME");
- char *path = "/.local/share/remembering";
- prefix = malloc(strlen(home) + strlen(path) + 1);
- if (!prefix) {
- return NULL;
- }
- strcpy(prefix, home);
- strcat(prefix, path);
- }
- char *separator = "/";
- char *expanded_profile =
- malloc(strlen(prefix) + strlen(separator) + strlen(profile_name) + 1);
- if (!expanded_profile) {
- free(prefix);
- return NULL;
- }
- strcpy(expanded_profile, prefix);
- strcat(expanded_profile, separator);
- strcat(expanded_profile, profile_name);
-
- free(prefix);
-
- errno = 0;
- int ret = mkdir_p(dirname(expanded_profile), 0755);
- if (ret) {
- perror("mkdir_p");
- return NULL;
- }
- return expanded_profile;
+ char *prefix = NULL;
+ char *env_prefix = getenv("XDG_DATA_HOME");
+ if (env_prefix) {
+ prefix = strdup(env_prefix);
+ if (!prefix) {
+ return NULL;
+ }
+ } else {
+ char *home = getenv("HOME");
+ char *path = "/.local/share/remembering";
+ prefix = malloc(strlen(home) + strlen(path) + 1);
+ if (!prefix) {
+ return NULL;
+ }
+ strcpy(prefix, home);
+ strcat(prefix, path);
+ }
+ char *separator = "/";
+ char *expanded_profile =
+ malloc(strlen(prefix) + strlen(separator) + strlen(profile_name) + 1);
+ if (!expanded_profile) {
+ free(prefix);
+ return NULL;
+ }
+ strcpy(expanded_profile, prefix);
+ strcat(expanded_profile, separator);
+ strcat(expanded_profile, profile_name);
+
+ free(prefix);
+
+ errno = 0;
+ int ret = mkdir_p(dirname(expanded_profile), 0755);
+ if (ret) {
+ perror("mkdir_p");
+ return NULL;
+ }
+ return expanded_profile;
}
#ifdef FALLIBLE
static char *fallible_expand_profile_name(const char *const profile_name,
- const char *const filename,
- int lineno) {
- if (fallible_should_fail(filename, lineno)) {
- return NULL;
- }
- return expand_profile_name(profile_name);
+ const char *const filename,
+ int lineno) {
+ if (fallible_should_fail(filename, lineno)) {
+ return NULL;
+ }
+ return expand_profile_name(profile_name);
}
-#define expand_profile_name(profile_name) \
- fallible_expand_profile_name(profile_name, __FILE__, __LINE__)
+#define expand_profile_name(profile_name) \
+ fallible_expand_profile_name(profile_name, __FILE__, __LINE__)
#endif
#ifdef TEST
static void expand_profile_name_test() {
- {
- testing("expand_profile_name");
- if (0) {
- expand_profile_name("oij");
- }
- test_ok();
- }
+ {
+ testing("expand_profile_name");
+ if (0) {
+ expand_profile_name("oij");
+ }
+ test_ok();
+ }
}
#endif
@@ -386,507 +436,508 @@ static const size_t RANKINGS_INITIAL_SIZE = 100;
static const int RANKINGS_GROWTH_MULTIPLIER = 2;
struct Rankings {
- size_t count;
- size_t size;
- char **values;
- int *ranks;
+ size_t count;
+ size_t size;
+ char **values;
+ int *ranks;
};
static struct Rankings *rankings_new() {
- struct Rankings *r = malloc(sizeof(struct Rankings));
- if (!r) {
- return NULL;
- }
- r->count = 0;
- r->size = RANKINGS_INITIAL_SIZE;
- r->values = malloc(r->size * sizeof(char *));
- if (!r->values) {
- free(r);
- return NULL;
- }
- r->ranks = malloc(r->size * sizeof(int));
- if (!r->ranks) {
- free(r->values);
- free(r);
- return NULL;
- }
- return r;
+ struct Rankings *r = malloc(sizeof(struct Rankings));
+ if (!r) {
+ return NULL;
+ }
+ r->count = 0;
+ r->size = RANKINGS_INITIAL_SIZE;
+ r->values = malloc(r->size * sizeof(char *));
+ if (!r->values) {
+ free(r);
+ return NULL;
+ }
+ r->ranks = malloc(r->size * sizeof(int));
+ if (!r->ranks) {
+ free(r->values);
+ free(r);
+ return NULL;
+ }
+ return r;
}
#ifdef FALLIBLE
static struct Rankings *fallible_rankings_new(const char *const filename,
- int lineno) {
- if (fallible_should_fail(filename, lineno)) {
- return NULL;
- }
- return rankings_new();
+ int lineno) {
+ if (fallible_should_fail(filename, lineno)) {
+ return NULL;
+ }
+ return rankings_new();
}
#define rankings_new() fallible_rankings_new(__FILE__, __LINE__)
#endif
static void rankings_free(struct Rankings *r) {
- if (!r) {
- return;
- }
- for (size_t i = 0; i < r->count; i++) {
- free(r->values[i]);
- }
- free(r->values);
- free(r->ranks);
- free(r);
+ if (!r) {
+ return;
+ }
+ for (size_t i = 0; i < r->count; i++) {
+ free(r->values[i]);
+ }
+ free(r->values);
+ free(r->ranks);
+ free(r);
}
static int rankings_insert(struct Rankings *r, char *value, int rank) {
- if (r->count == r->size) {
- r->size *= RANKINGS_GROWTH_MULTIPLIER;
- char **new_values = realloc(r->values, r->size * sizeof(char *));
- if (!new_values) {
- return -1;
- }
- r->values = new_values;
- int *new_ranks = realloc(r->ranks, r->size * sizeof(int));
- if (!new_ranks) {
- return -1;
- }
- r->ranks = new_ranks;
- }
- r->values[r->count] = value;
- r->ranks[r->count] = rank;
- r->count++;
- return 0;
+ if (r->count == r->size) {
+ r->size *= RANKINGS_GROWTH_MULTIPLIER;
+ char **new_values = realloc(r->values, r->size * sizeof(char *));
+ if (!new_values) {
+ return -1;
+ }
+ r->values = new_values;
+ int *new_ranks = realloc(r->ranks, r->size * sizeof(int));
+ if (!new_ranks) {
+ return -1;
+ }
+ r->ranks = new_ranks;
+ }
+ r->values[r->count] = value;
+ r->ranks[r->count] = rank;
+ r->count++;
+ return 0;
}
#ifdef FALLIBLE
static int fallible_rankings_insert(struct Rankings *r, char *value, int rank,
- const char *const filename, int lineno) {
- if (fallible_should_fail(filename, lineno)) {
- return -1;
- }
- return rankings_insert(r, value, rank);
+ const char *const filename, int lineno) {
+ if (fallible_should_fail(filename, lineno)) {
+ return -1;
+ }
+ return rankings_insert(r, value, rank);
}
-#define rankings_insert(r, value, rank) \
- fallible_rankings_insert(r, value, rank, __FILE__, __LINE__)
+#define rankings_insert(r, value, rank) \
+ fallible_rankings_insert(r, value, rank, __FILE__, __LINE__)
#endif
#ifdef TEST
static void rankings_test() {
- {
- testing("struct Rankings expands its size when needed");
- struct Rankings *r = rankings_new();
- if (!r) {
- exit(EXIT_FAILURE);
- }
- size_t some_limit = RANKINGS_INITIAL_SIZE + 1;
- int ret;
- for (size_t i = 0; i < some_limit; i++) {
- char *s = strdup("some string");
- ret = rankings_insert(r, s, i);
- if (ret) {
- free(s);
- rankings_free(r);
- exit(EXIT_FAILURE);
- }
- }
-
- assert(r->size == RANKINGS_INITIAL_SIZE * RANKINGS_GROWTH_MULTIPLIER);
- assert(r->count == some_limit);
-
- rankings_free(r);
- test_ok();
- }
-
- {
- testing("an empty Rankings doesn't leak");
- struct Rankings *r = rankings_new();
- if (!r) {
- exit(EXIT_FAILURE);
- }
-
- assert(r->size == RANKINGS_INITIAL_SIZE);
- assert(r->count == 0);
-
- rankings_free(r);
- test_ok();
- }
+ {
+ testing("struct Rankings expands its size when needed");
+ struct Rankings *r = rankings_new();
+ if (!r) {
+ exit(EXIT_FAILURE);
+ }
+ size_t some_limit = RANKINGS_INITIAL_SIZE + 1;
+ int ret;
+ for (size_t i = 0; i < some_limit; i++) {
+ char *s = strdup("some string");
+ ret = rankings_insert(r, s, i);
+ if (ret) {
+ free(s);
+ rankings_free(r);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ assert(r->size == RANKINGS_INITIAL_SIZE * RANKINGS_GROWTH_MULTIPLIER);
+ assert(r->count == some_limit);
+
+ rankings_free(r);
+ test_ok();
+ }
+
+ {
+ testing("an empty Rankings doesn't leak");
+ struct Rankings *r = rankings_new();
+ if (!r) {
+ exit(EXIT_FAILURE);
+ }
+
+ assert(r->size == RANKINGS_INITIAL_SIZE);
+ assert(r->count == 0);
+
+ rankings_free(r);
+ test_ok();
+ }
}
#endif
static const char RANKING_DELIMITER = ':';
int parse_ranked_line(FILE *stream, const char *entry, char **value,
- int *rank) {
- char *value_substr = strchr(entry, RANKING_DELIMITER);
- if (value_substr == NULL) {
- fprintf(stream, "WARN: Missing delimiter ('%c') in line: %s\n",
- RANKING_DELIMITER, entry);
- return -1;
- }
-
- int rank_strlen = value_substr - entry;
- char *rank_str = strndup(entry, rank_strlen);
- if (!rank_str) {
- return -1;
- }
- *rank = atoi(rank_str);
- free(rank_str);
-
- *value = malloc(strlen(value_substr) + 1);
- if (!*value) {
- return -1;
- }
- strcpy(*value, entry + (rank_strlen + 1 /* RANKING_DELIMITER */));
-
- return 0;
+ int *rank) {
+ char *value_substr = strchr(entry, RANKING_DELIMITER);
+ if (value_substr == NULL) {
+ fprintf(stream, "WARN: Missing delimiter ('%c') in line: %s\n",
+ RANKING_DELIMITER, entry);
+ return -1;
+ }
+
+ int rank_strlen = value_substr - entry;
+ char *rank_str = strndup(entry, rank_strlen);
+ if (!rank_str) {
+ return -1;
+ }
+ *rank = atoi(rank_str);
+ free(rank_str);
+
+ *value = malloc(strlen(value_substr) + 1);
+ if (!*value) {
+ return -1;
+ }
+ strcpy(*value, entry + (rank_strlen + 1 /* RANKING_DELIMITER */));
+
+ return 0;
}
#ifdef FALLIBLE
int fallible_parse_ranked_line(FILE *stream, const char *entry, char **value,
- int *rank, const char *const filename,
- int lineno) {
- if (fallible_should_fail(filename, lineno)) {
- return -1;
- }
- return parse_ranked_line(stream, entry, value, rank);
+ int *rank, const char *const filename,
+ int lineno) {
+ if (fallible_should_fail(filename, lineno)) {
+ return -1;
+ }
+ return parse_ranked_line(stream, entry, value, rank);
}
-#define parse_ranked_line(stream, entry, value, rank) \
- fallible_parse_ranked_line(stream, entry, value, rank, __FILE__, __LINE__)
+#define parse_ranked_line(stream, entry, value, rank) \
+ fallible_parse_ranked_line(stream, entry, value, rank, __FILE__, __LINE__)
#endif
#ifdef TEST
static void parse_ranked_line_test() {
- {
- testing("parse_ranked_line with an empty string");
- FILE *f = tmpfile();
- if (!f) {
- exit(EXIT_FAILURE);
- }
-
- char *value;
- int rank;
- int ret = parse_ranked_line(f, "", &value, &rank);
- assert(ret == -1);
- fclose(f);
- test_ok();
- }
- {
- testing("parse_ranked_line when RANKING DELIMITER is missing");
- FILE *f = tmpfile();
- if (!f) {
- exit(EXIT_FAILURE);
- }
-
- char *value;
- int rank, ret;
-
- ret = parse_ranked_line(f, "0 command", &value, &rank);
- assert(ret == -1);
-
- ret = parse_ranked_line(f, "1", &value, &rank);
- assert(ret == -1);
-
- fclose(f);
- test_ok();
- }
- {
- testing("parse_ranked_line with a happy path examples");
- char *value;
- int rank;
- int ret;
-
- ret = parse_ranked_line(stderr, "0:command", &value, &rank);
- if (ret) {
- exit(EXIT_FAILURE);
- }
- assert(ret == 0);
- assert(strcmp(value, "command") == 0);
- assert(rank == 0);
- free(value);
-
- ret = parse_ranked_line(stderr, "10:another command", &value, &rank);
- if (ret) {
- exit(EXIT_FAILURE);
- }
- assert(ret == 0);
- assert(strcmp(value, "another command") == 0);
- assert(rank == 10);
- free(value);
-
- ret = parse_ranked_line(stderr, "123:123", &value, &rank);
- if (ret) {
- exit(EXIT_FAILURE);
- }
- assert(ret == 0);
- assert(strcmp(value, "123") == 0);
- assert(rank == 123);
- free(value);
-
- ret = parse_ranked_line(stderr, "-123:command", &value, &rank);
- if (ret) {
- exit(EXIT_FAILURE);
- }
- assert(ret == 0);
- assert(strcmp(value, "command") == 0);
- assert(rank == -123);
- free(value);
-
- ret = parse_ranked_line(stderr, "0:0", &value, &rank);
- if (ret) {
- exit(EXIT_FAILURE);
- }
- assert(ret == 0);
- assert(strcmp(value, "0") == 0);
- assert(rank == 0);
- free(value);
-
- ret = parse_ranked_line(stderr, "0:command with : in the middle", &value,
- &rank);
- if (ret) {
- exit(EXIT_FAILURE);
- }
- assert(ret == 0);
- assert(strcmp(value, "command with : in the middle") == 0);
- assert(rank == 0);
- free(value);
-
- ret = parse_ranked_line(
- stderr, "0:::command:with:multiple:::in:the:middle:", &value, &rank);
- if (ret) {
- exit(EXIT_FAILURE);
- }
- assert(ret == 0);
- assert(strcmp(value, "::command:with:multiple:::in:the:middle:") == 0);
- assert(rank == 0);
- free(value);
-
- test_ok();
- }
- {
- testing("parse_ranked_line with an empty command");
- char *value;
- int rank;
-
- int ret = parse_ranked_line(stderr, "0:", &value, &rank);
- if (ret) {
- exit(EXIT_FAILURE);
- }
- assert(ret == 0);
- assert(strcmp(value, "") == 0);
- assert(rank == 0);
- free(value);
-
- test_ok();
- }
- {
- testing("parse_ranked_line with a bad rank numbers");
- char *value;
- int rank;
- int ret;
-
- ret = parse_ranked_line(stderr, ":command", &value, &rank);
- if (ret) {
- exit(EXIT_FAILURE);
- }
- assert(ret == 0);
- assert(strcmp(value, "command") == 0);
- assert(rank == 0);
- free(value);
-
- ret = parse_ranked_line(stderr, "1 2 3:command", &value, &rank);
- if (ret) {
- exit(EXIT_FAILURE);
- }
- assert(ret == 0);
- assert(strcmp(value, "command") == 0);
- assert(rank == 1);
- free(value);
-
- ret = parse_ranked_line(stderr, ".1:command", &value, &rank);
- if (ret) {
- exit(EXIT_FAILURE);
- }
- assert(ret == 0);
- assert(strcmp(value, "command") == 0);
- assert(rank == 0);
- free(value);
-
- ret = parse_ranked_line(stderr, "3.14:command", &value, &rank);
- if (ret) {
- exit(EXIT_FAILURE);
- }
- assert(ret == 0);
- assert(strcmp(value, "command") == 0);
- assert(rank == 3);
- free(value);
-
- ret = parse_ranked_line(stderr, ":5:command", &value, &rank);
- if (ret) {
- exit(EXIT_FAILURE);
- }
- assert(ret == 0);
- assert(strcmp(value, "5:command") == 0);
- assert(rank == 0);
- free(value);
-
- ret = parse_ranked_line(stderr, "command:command", &value, &rank);
- if (ret) {
- exit(EXIT_FAILURE);
- }
- assert(ret == 0);
- assert(strcmp(value, "command") == 0);
- assert(rank == 0);
- free(value);
-
- test_ok();
- }
+ {
+ testing("parse_ranked_line with an empty string");
+ FILE *f = tmpfile();
+ if (!f) {
+ exit(EXIT_FAILURE);
+ }
+
+ char *value;
+ int rank;
+ int ret = parse_ranked_line(f, "", &value, &rank);
+ assert(ret == -1);
+ fclose(f);
+ test_ok();
+ }
+ {
+ testing("parse_ranked_line when RANKING DELIMITER is missing");
+ FILE *f = tmpfile();
+ if (!f) {
+ exit(EXIT_FAILURE);
+ }
+
+ char *value;
+ int rank, ret;
+
+ ret = parse_ranked_line(f, "0 command", &value, &rank);
+ assert(ret == -1);
+
+ ret = parse_ranked_line(f, "1", &value, &rank);
+ assert(ret == -1);
+
+ fclose(f);
+ test_ok();
+ }
+ {
+ testing("parse_ranked_line with a happy path examples");
+ char *value;
+ int rank;
+ int ret;
+
+ ret = parse_ranked_line(stderr, "0:command", &value, &rank);
+ if (ret) {
+ exit(EXIT_FAILURE);
+ }
+ assert(ret == 0);
+ assert(strcmp(value, "command") == 0);
+ assert(rank == 0);
+ free(value);
+
+ ret = parse_ranked_line(stderr, "10:another command", &value, &rank);
+ if (ret) {
+ exit(EXIT_FAILURE);
+ }
+ assert(ret == 0);
+ assert(strcmp(value, "another command") == 0);
+ assert(rank == 10);
+ free(value);
+
+ ret = parse_ranked_line(stderr, "123:123", &value, &rank);
+ if (ret) {
+ exit(EXIT_FAILURE);
+ }
+ assert(ret == 0);
+ assert(strcmp(value, "123") == 0);
+ assert(rank == 123);
+ free(value);
+
+ ret = parse_ranked_line(stderr, "-123:command", &value, &rank);
+ if (ret) {
+ exit(EXIT_FAILURE);
+ }
+ assert(ret == 0);
+ assert(strcmp(value, "command") == 0);
+ assert(rank == -123);
+ free(value);
+
+ ret = parse_ranked_line(stderr, "0:0", &value, &rank);
+ if (ret) {
+ exit(EXIT_FAILURE);
+ }
+ assert(ret == 0);
+ assert(strcmp(value, "0") == 0);
+ assert(rank == 0);
+ free(value);
+
+ ret = parse_ranked_line(stderr, "0:command with : in the middle", &value,
+ &rank);
+ if (ret) {
+ exit(EXIT_FAILURE);
+ }
+ assert(ret == 0);
+ assert(strcmp(value, "command with : in the middle") == 0);
+ assert(rank == 0);
+ free(value);
+
+ ret = parse_ranked_line(
+ stderr, "0:::command:with:multiple:::in:the:middle:", &value, &rank);
+ if (ret) {
+ exit(EXIT_FAILURE);
+ }
+ assert(ret == 0);
+ assert(strcmp(value, "::command:with:multiple:::in:the:middle:") == 0);
+ assert(rank == 0);
+ free(value);
+
+ test_ok();
+ }
+ {
+ testing("parse_ranked_line with an empty command");
+ char *value;
+ int rank;
+
+ int ret = parse_ranked_line(stderr, "0:", &value, &rank);
+ if (ret) {
+ exit(EXIT_FAILURE);
+ }
+ assert(ret == 0);
+ assert(strcmp(value, "") == 0);
+ assert(rank == 0);
+ free(value);
+
+ test_ok();
+ }
+ {
+ testing("parse_ranked_line with a bad rank numbers");
+ char *value;
+ int rank;
+ int ret;
+
+ ret = parse_ranked_line(stderr, ":command", &value, &rank);
+ if (ret) {
+ exit(EXIT_FAILURE);
+ }
+ assert(ret == 0);
+ assert(strcmp(value, "command") == 0);
+ assert(rank == 0);
+ free(value);
+
+ ret = parse_ranked_line(stderr, "1 2 3:command", &value, &rank);
+ if (ret) {
+ exit(EXIT_FAILURE);
+ }
+ assert(ret == 0);
+ assert(strcmp(value, "command") == 0);
+ assert(rank == 1);
+ free(value);
+
+ ret = parse_ranked_line(stderr, ".1:command", &value, &rank);
+ if (ret) {
+ exit(EXIT_FAILURE);
+ }
+ assert(ret == 0);
+ assert(strcmp(value, "command") == 0);
+ assert(rank == 0);
+ free(value);
+
+ ret = parse_ranked_line(stderr, "3.14:command", &value, &rank);
+ if (ret) {
+ exit(EXIT_FAILURE);
+ }
+ assert(ret == 0);
+ assert(strcmp(value, "command") == 0);
+ assert(rank == 3);
+ free(value);
+
+ ret = parse_ranked_line(stderr, ":5:command", &value, &rank);
+ if (ret) {
+ exit(EXIT_FAILURE);
+ }
+ assert(ret == 0);
+ assert(strcmp(value, "5:command") == 0);
+ assert(rank == 0);
+ free(value);
+
+ ret = parse_ranked_line(stderr, "command:command", &value, &rank);
+ if (ret) {
+ exit(EXIT_FAILURE);
+ }
+ assert(ret == 0);
+ assert(strcmp(value, "command") == 0);
+ assert(rank == 0);
+ free(value);
+
+ test_ok();
+ }
}
#endif
struct GetlineParams {
- char *line;
- size_t len;
- ssize_t read;
- FILE *stream;
+ char *line;
+ size_t len;
+ ssize_t read;
+ FILE *stream;
};
int get_stdin(struct GetlineParams *s_params, struct GetlineParams *p_params,
- struct Rankings *p_rankings) {
- s_params->read = getline(&s_params->line, &s_params->len, s_params->stream);
- if (s_params->read == -1) {
- while ((p_params->read = getline(&p_params->line, &p_params->len,
- p_params->stream)) != -1) {
- char *value;
- int rank;
- int ret;
- if ((ret = parse_ranked_line(stderr, p_params->line, &value, &rank)) ==
- -1) {
- return ret;
- }
- if ((ret = rankings_insert(p_rankings, value, rank)) == -1) {
- return ret;
- }
- }
- return 1;
- }
- return 0;
+ struct Rankings *p_rankings) {
+ s_params->read = getline(&s_params->line, &s_params->len, s_params->stream);
+ if (s_params->read == -1) {
+ while ((p_params->read = getline(&p_params->line, &p_params->len,
+ p_params->stream)) != -1) {
+ char *value;
+ int rank;
+ int ret;
+ if ((ret = parse_ranked_line(stderr, p_params->line, &value, &rank)) ==
+ -1) {
+ return ret;
+ }
+ if ((ret = rankings_insert(p_rankings, value, rank)) == -1) {
+ return ret;
+ }
+ }
+ return 1;
+ }
+ return 0;
}
int get_profile(struct GetlineParams *s_params, struct GetlineParams *p_params,
- struct Rankings *s_rankings, struct Rankings *p_rankings) {
- p_params->read = getline(&p_params->line, &p_params->len, p_params->stream);
- if (p_params->read == -1) {
- while ((s_params->read = getline(&s_params->line, &s_params->len,
- s_params->stream)) != -1) {
- char *s_value_copy = strdup(s_params->line);
- if (!s_value_copy) {
- return -1;
- }
- char *p_value_copy = strdup(s_params->line);
- if (!p_value_copy) {
- free(s_value_copy);
- return -1;
- }
-
- int ret;
- if ((ret = rankings_insert(s_rankings, s_value_copy, 0)) == -1) {
- free(s_value_copy);
- free(p_value_copy);
- return -1;
- }
-
- // profile grows with stdin entries
- if ((ret = rankings_insert(p_rankings, p_value_copy, 0)) == -1) {
- free(s_value_copy);
- free(p_value_copy);
- return -1;
- }
- }
- return 1;
- }
- return 0;
+ struct Rankings *s_rankings, struct Rankings *p_rankings) {
+ p_params->read = getline(&p_params->line, &p_params->len, p_params->stream);
+ if (p_params->read == -1) {
+ while ((s_params->read = getline(&s_params->line, &s_params->len,
+ s_params->stream)) != -1) {
+ char *s_value_copy = strdup(s_params->line);
+ if (!s_value_copy) {
+ return -1;
+ }
+ char *p_value_copy = strdup(s_params->line);
+ if (!p_value_copy) {
+ free(s_value_copy);
+ return -1;
+ }
+
+ int ret;
+ if ((ret = rankings_insert(s_rankings, s_value_copy, 0)) == -1) {
+ free(s_value_copy);
+ free(p_value_copy);
+ return -1;
+ }
+
+ // profile grows with stdin entries
+ if ((ret = rankings_insert(p_rankings, p_value_copy, 0)) == -1) {
+ free(s_value_copy);
+ free(p_value_copy);
+ return -1;
+ }
+ }
+ return 1;
+ }
+ return 0;
}
/*
int merge_stdin_with_profile(char *profile_name, struct Rankings *s_rankings,
- struct Rankings *p_rankings) {
- FILE *profile = fopen(profile_name, "r");
- struct GetlineParams s_params = {
- .line = NULL, .len = 0, .read = 0, .stream = stdin};
- struct GetlineParams p_params = {
- .line = NULL, .len = 0, .read = 0, .stream = profile};
-
- int stop = get_stdin(&s_params, &p_params, p_rankings) ||
- get_profile(&s_params, &p_params, s_rankings, p_rankings);
- while (!stop) {
- char *value;
- int rank;
- parse_ranked_line(stderr, p_params.line, &value, &rank);
- int cmp = strcmp(s_params.line, value);
-
- if (cmp == 0) {
- rankings_insert(s_rankings, value, rank);
- rankings_insert(p_rankings, value, rank); // double free
- stop = get_stdin(&s_params, &p_params, p_rankings) ||
- get_profile(&s_params, &p_params, s_rankings, p_rankings);
- continue;
- }
-
- if (cmp < 0) {
- char *value_copy = malloc(strlen(s_params.line) + 1);
- strcpy(value_copy, s_params.line);
- int *rank = malloc(sizeof(int));
- *rank = 0;
- rankings_insert(s_rankings, value_copy, rank);
- rankings_insert(p_rankings, value_copy, rank);
- stop = get_stdin(&s_params, &p_params, p_rankings);
- tuple_free(&t);
- continue;
- }
-
- if (cmp > 0) {
- rankings_insert(p_rankings, t.first, t.second);
- stop = get_profile(&s_params, &p_params, s_rankings, p_rankings);
- tuple_free(&t);
- continue;
- }
- }
-
- free(s_params.line);
- free(p_params.line);
- fclose(profile);
-
- if (stop == -1) {
- return stop;
- }
- return 0;
+ struct Rankings *p_rankings) {
+ FILE *profile = fopen(profile_name, "r");
+ struct GetlineParams s_params = {
+ .line = NULL, .len = 0, .read = 0, .stream = stdin};
+ struct GetlineParams p_params = {
+ .line = NULL, .len = 0, .read = 0, .stream = profile};
+
+ int stop = get_stdin(&s_params, &p_params, p_rankings) ||
+ get_profile(&s_params, &p_params, s_rankings, p_rankings);
+ while (!stop) {
+ char *value;
+ int rank;
+ parse_ranked_line(stderr, p_params.line, &value, &rank);
+ int cmp = strcmp(s_params.line, value);
+
+ if (cmp == 0) {
+ rankings_insert(s_rankings, value, rank);
+ rankings_insert(p_rankings, value, rank); // double free
+ stop = get_stdin(&s_params, &p_params, p_rankings) ||
+ get_profile(&s_params, &p_params, s_rankings, p_rankings);
+ continue;
+ }
+
+ if (cmp < 0) {
+ char *value_copy = malloc(strlen(s_params.line) + 1);
+ strcpy(value_copy, s_params.line);
+ int *rank = malloc(sizeof(int));
+ *rank = 0;
+ rankings_insert(s_rankings, value_copy, rank);
+ rankings_insert(p_rankings, value_copy, rank);
+ stop = get_stdin(&s_params, &p_params, p_rankings);
+ tuple_free(&t);
+ continue;
+ }
+
+ if (cmp > 0) {
+ rankings_insert(p_rankings, t.first, t.second);
+ stop = get_profile(&s_params, &p_params, s_rankings, p_rankings);
+ tuple_free(&t);
+ continue;
+ }
+ }
+
+ free(s_params.line);
+ free(p_params.line);
+ fclose(profile);
+
+ if (stop == -1) {
+ return stop;
+ }
+ return 0;
}
*/
#ifdef TEST
static void unit_tests() {
- get_options_test();
- mkdir_p_test();
- expand_profile_name_test();
- rankings_test();
- parse_ranked_line_test();
+ print_usage_test();
+ get_options_test();
+ mkdir_p_test();
+ expand_profile_name_test();
+ rankings_test();
+ parse_ranked_line_test();
}
#endif
int main(int argc, char *argv[]) {
#ifdef TEST
- unit_tests();
- return EXIT_SUCCESS;
+ unit_tests();
+ return EXIT_SUCCESS;
#endif
- int ret;
+ int ret;
- char *command, *profile;
- ret = get_options(stdout, stderr, argc, argv, &command, &profile);
- if (ret == -1) {
- return EXIT_FAILURE;
- } else if (ret) {
- return EXIT_SUCCESS;
- }
+ char *command, *profile;
+ ret = get_options(stdout, stderr, argc, argv, &command, &profile);
+ if (ret == -1) {
+ return EXIT_FAILURE;
+ } else if (ret) {
+ return EXIT_SUCCESS;
+ }
}