From 2f8fbbccd0cc11db0c151a621236247e4dd3b8e3 Mon Sep 17 00:00:00 2001 From: EuAndreh Date: Wed, 1 Sep 2021 10:41:36 -0300 Subject: mv src/remembering-c.c src/remembering.c --- src/remembering-c.c | 395 ---------------------------------------------------- src/remembering.c | 395 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 395 insertions(+), 395 deletions(-) delete mode 100644 src/remembering-c.c create mode 100644 src/remembering.c (limited to 'src') diff --git a/src/remembering-c.c b/src/remembering-c.c deleted file mode 100644 index 108d246..0000000 --- a/src/remembering-c.c +++ /dev/null @@ -1,395 +0,0 @@ -#ifndef _POSIX_C_SOURCE -#define _POSIX_C_SOURCE 200809L -#endif - -#include -#include -#include -#include -#include -#include - - -#ifdef TEST -#include "unit-test.h" -#include -#include -#endif - - -const int EXIT_ERROR = 1; -const int EXIT_USAGE = 2; - -static int usage(FILE *stream) { - const char *const msg = "Usage: remembering -p PROFILE -c COMMAND\n"; - if (fprintf(stream, msg) < 0) { - perror("usage() - fprintf()"); - return -1; - } - return 0; -} - -static int help(FILE *stream) { - const char *const msg = - "Options:\n" - " -p, PROFILE profile to be used for gathering and storing data\n" - " -c, COMMAND commant to be run, reading from STDIN, writing to STDOUT\n" - " -h, --help show this help\n" - " -V, --version print the version number\n" - "\nSee \"man remembering\" for more information\n"; - if (fprintf(stream, msg) < 0) { - perror("help() - fprint()"); - return -1; - } - return 0; -} - -static int version(FILE *stream) { - const char *const msg = "remembering-" VERSION " " DATE "\n"; - if (fprintf(stream, msg) < 0) { - perror("version() - fprintf()"); - return -1; - } - return 0; -} - -static int missing(FILE *stream, const char *const argument) { - const char *const msg = "Missing option: %s\n"; - if (fprintf(stream, msg, argument) < 0) { - perror("missing() - fprintf()"); - return -1; - } - return 0; -} - -static char *get_profile_file(const char *const profile, FILE *stream) { - char *home = getenv("XDG_DATA_HOME"); - if (!home || (strcmp(home, "") == 0)) { - if (!(home = getenv("HOME"))) { - fprintf(stream, "Unable to get $XDG_DATA_HOME or $HOME environment variables\n"); - return NULL; - } - const char *const suffix = "/.local/share/remembering"; - const size_t home_suffix_size = - strlen(home) + - strlen(suffix) + - sizeof(char); - char *const home_with_suffix = malloc(home_suffix_size); - if (!home_with_suffix) { - perror("get_profile_file() - malloc() - home_with_suffix"); - return NULL; - } - strcpy(home_with_suffix, home); - strcat(home_with_suffix, suffix); - home = home_with_suffix; - } else { - if (!(home = strdup(home))) { - perror("get_profile_file() - strdup()"); - return NULL; - } - } - - size_t size = - strlen(home) + - strlen("/") + - strlen(profile) + - sizeof(char); - char *const profile_file = malloc(size); - if (!profile_file) { - perror("get_profile_file() - malloc() - profile_file"); - free(home); - return NULL; - } - strcpy(profile_file, home); - strcat(profile_file, "/"); - strcat(profile_file, profile); - - free(home); - return profile_file; -} - -#ifdef TEST -static void test_get_profile_file() { - #define EXPECTED_FMT "\nexpected: %s\ngot: %s\n" - FILE *f = fopen("/dev/null", "w"); - assert(f); - - { - testing("get_profile_file() when $XDG_DATA_HOME is *unset*"); - const char *const previous_xdg_data_home = getenv("XDG_DATA_HOME"); - unsetenv("XDG_DATA_HOME"); - - const char *const HOME = getenv("HOME"); - const char *const SUFFIX = "/.local/share/remembering/"; - const char *const A_PROFILE = "A-PROFILE-NAME"; - assert(HOME); - - const size_t expected_size = - strlen(HOME) + - strlen(SUFFIX) + - strlen(A_PROFILE) + - sizeof(char); - char *const expected = malloc(expected_size); - assert(expected); - strcpy(expected, HOME); - strcat(expected, SUFFIX); - strcat(expected, A_PROFILE); - - char *const profile_file = get_profile_file(A_PROFILE, f); - assert(profile_file); - assertf( - strcmp(profile_file, expected) == 0, - EXPECTED_FMT, - expected, - profile_file - ); - - free(profile_file); - free(expected); - if (previous_xdg_data_home) { - setenv("XDG_DATA_HOME", previous_xdg_data_home, true); - } - test_ok(); - } - { - testing("get_profile_file() when $XDG_DATA_HOME is *empty*"); - const char *const previous_xdg_data_home = getenv("XDG_DATA_HOME"); - setenv("XDG_DATA_HOME", "", true); - - const char *const HOME = getenv("HOME"); - const char *const SUFFIX = "/.local/share/remembering/"; - const char *const A_PROFILE = "ANOTHER-PROFILE-NAME"; - assert(HOME); - - const size_t expected_size = - strlen(HOME) + - strlen(SUFFIX) + - strlen(A_PROFILE) + - sizeof(char); - char *const expected = malloc(expected_size); - assert(expected); - strcpy(expected, HOME); - strcat(expected, SUFFIX); - strcat(expected, A_PROFILE); - - char *const profile_file = get_profile_file(A_PROFILE, f); - assert(profile_file); - assertf( - strcmp(profile_file, expected) == 0, - EXPECTED_FMT, - expected, - profile_file - ); - - free(profile_file); - free(expected); - if (previous_xdg_data_home) { - setenv("XDG_DATA_HOME", previous_xdg_data_home, true); - } else { - unsetenv("XDG_DATA_HOME"); - } - test_ok(); - } - { - testing("get_profile_file() when $XDG_DATA_HOME is *set*"); - const char *const previous_xdg_data_home = getenv("XDG_DATA_HOME"); - - const char *const XDG_DATA_HOME = "/a/custom/path"; - const char *const A_PROFILE = "YET-ANOTHER-PROFILE-NAME"; - const char *const EXPECTED = "/a/custom/path/YET-ANOTHER-PROFILE-NAME"; - - setenv("XDG_DATA_HOME", XDG_DATA_HOME, true); - - char *const profile_file = get_profile_file(A_PROFILE, f); - assert(profile_file); - assertf( - strcmp(profile_file, EXPECTED) == 0, - EXPECTED_FMT, - EXPECTED, - profile_file - ); - - free(profile_file); - if (previous_xdg_data_home) { - setenv("XDG_DATA_HOME", previous_xdg_data_home, true); - } else { - unsetenv("XDG_DATA_HOME"); - } - test_ok(); - } - { - testing("get_profile_file() when $HOME is *unset*"); - const char *const previous_home = getenv("HOME"); - const char *const previous_xdg_data_home = getenv("XDG_DATA_HOME"); - unsetenv("XDG_DATA_HOME"); - unsetenv("HOME"); - - assert(get_profile_file("ANY-PROFILE", f) == NULL); - - setenv("HOME", previous_home, true); - if (previous_xdg_data_home) { - setenv("XDG_DATA_HOME", previous_xdg_data_home, true); - } - test_ok(); - } - - fclose(f); -} -#endif - -static int mkdir_p(const char *const path, mode_t mode) { - struct stat s; - int ret; - - if (stat(path, &s) == 0 && S_ISDIR(s.st_mode)) { - return 0; - } - - char *const path_dup = strdup(path); - if (!path_dup) { - perror("mkdir_p() - strdup()"); - return -1; - } - - const char *const parent = dirname(path_dup); - if ((ret = mkdir_p(parent, mode))) { - free(path_dup); - return ret; - } - - free(path_dup); - return mkdir(path, mode); -} - -#ifdef TEST -static void test_mkdir_p() { - { - testing("mkdir_p() with an existing directory is a noop"); - struct stat s; - assert(stat("/tmp", &s) == 0 && S_ISDIR(s.st_mode)); - assert(mkdir_p("/tmp", S_IRWXU | S_IRWXG | S_IRWXO) == 0); - assert(stat("/tmp", &s) == 0 && S_ISDIR(s.st_mode)); - test_ok(); - } - { - testing("mkdir_p() with a new directory creates it"); - struct stat s; - const char *const SUBDIRECTORY_SUFFIX = "/a/b/c/d/e"; - char template[] = "/tmp/remembering.XXXXXX"; - const char *const prefix = mkdtemp(template); - assert(prefix); - - assert(stat(prefix, &s) == 0 && S_ISDIR(s.st_mode)); - - const size_t subdirectory_size = - strlen(prefix) + - strlen(SUBDIRECTORY_SUFFIX) + - sizeof(char); - char *const subdirectory = malloc(subdirectory_size); - assert(subdirectory); - strcpy(subdirectory, prefix); - strcat(subdirectory, SUBDIRECTORY_SUFFIX); - - assert(stat(subdirectory, &s) == -1 && errno == ENOENT); - assert(mkdir_p(subdirectory, S_IRWXU | S_IRWXG | S_IRWXO) == 0); - assert(stat(subdirectory, &s) == 0 && S_ISDIR(s.st_mode)); - - free(subdirectory); - test_ok(); - } -} -#endif - -#ifdef TEST -static void unit_tests() { - test_get_profile_file(); - test_mkdir_p(); -} -#endif - -int main(int argc, char *argv[]) { -#ifdef TEST - unit_tests(); - return EXIT_SUCCESS; -#endif - - for (int i = 0; i < argc; i++) { - if (strcmp("--", argv[i]) == 0) { - break; - } else if (strcmp("--help", argv[i]) == 0) { - if (usage(stdout)) return EXIT_ERROR; - if (help(stdout)) return EXIT_ERROR; - return EXIT_SUCCESS; - } else if (strcmp("--version", argv[i]) == 0) { - if (version(stdout)) return EXIT_ERROR; - return EXIT_SUCCESS; - } - } - - int option; - const char *profile = NULL; - const char *command = NULL; - while ((option = getopt(argc, argv, "p:c:hV")) != -1) { - switch (option) { - case 'p': - profile = optarg; - break; - case 'c': - command = optarg; - break; - case 'h': - if (usage(stdout)) return EXIT_ERROR; - if (help(stdout)) return EXIT_ERROR; - return EXIT_SUCCESS; - case 'V': - if (version(stdout)) return EXIT_ERROR; - return EXIT_SUCCESS; - default: - if (usage(stderr)) return EXIT_ERROR; - return EXIT_USAGE; - } - } - - if (!profile) { - if (missing(stderr, "-p PROFILE")) return EXIT_ERROR; - if (usage(stderr)) return EXIT_ERROR; - return EXIT_USAGE; - } - - if (!command) { - if (missing(stderr, "-c COMMAND")) return EXIT_ERROR; - if (usage(stderr)) return EXIT_ERROR; - return EXIT_USAGE; - } - - /* End getopt() */ - - - int ret = EXIT_SUCCESS; - - char *profile_file = NULL; - if (!(profile_file = get_profile_file(profile, stderr))) { - ret = EXIT_ERROR; - goto cleanup; - } - - char *profile_file_dup = NULL; - if (!(profile_file_dup = strdup(profile_file))) { - perror("main() - strdup()"); - ret = EXIT_ERROR; - goto cleanup; - } - - if ((ret = mkdir_p(dirname(profile_file_dup), S_IRWXU | S_IRWXG | S_IRWXO))) { - goto cleanup; - } - - printf("profile: %s\ncommand: %s\n", profile, command); - printf("profile_file: %s\n", profile_file); - - -cleanup: - free(profile_file_dup); - free(profile_file); - return ret; -} diff --git a/src/remembering.c b/src/remembering.c new file mode 100644 index 0000000..108d246 --- /dev/null +++ b/src/remembering.c @@ -0,0 +1,395 @@ +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L +#endif + +#include +#include +#include +#include +#include +#include + + +#ifdef TEST +#include "unit-test.h" +#include +#include +#endif + + +const int EXIT_ERROR = 1; +const int EXIT_USAGE = 2; + +static int usage(FILE *stream) { + const char *const msg = "Usage: remembering -p PROFILE -c COMMAND\n"; + if (fprintf(stream, msg) < 0) { + perror("usage() - fprintf()"); + return -1; + } + return 0; +} + +static int help(FILE *stream) { + const char *const msg = + "Options:\n" + " -p, PROFILE profile to be used for gathering and storing data\n" + " -c, COMMAND commant to be run, reading from STDIN, writing to STDOUT\n" + " -h, --help show this help\n" + " -V, --version print the version number\n" + "\nSee \"man remembering\" for more information\n"; + if (fprintf(stream, msg) < 0) { + perror("help() - fprint()"); + return -1; + } + return 0; +} + +static int version(FILE *stream) { + const char *const msg = "remembering-" VERSION " " DATE "\n"; + if (fprintf(stream, msg) < 0) { + perror("version() - fprintf()"); + return -1; + } + return 0; +} + +static int missing(FILE *stream, const char *const argument) { + const char *const msg = "Missing option: %s\n"; + if (fprintf(stream, msg, argument) < 0) { + perror("missing() - fprintf()"); + return -1; + } + return 0; +} + +static char *get_profile_file(const char *const profile, FILE *stream) { + char *home = getenv("XDG_DATA_HOME"); + if (!home || (strcmp(home, "") == 0)) { + if (!(home = getenv("HOME"))) { + fprintf(stream, "Unable to get $XDG_DATA_HOME or $HOME environment variables\n"); + return NULL; + } + const char *const suffix = "/.local/share/remembering"; + const size_t home_suffix_size = + strlen(home) + + strlen(suffix) + + sizeof(char); + char *const home_with_suffix = malloc(home_suffix_size); + if (!home_with_suffix) { + perror("get_profile_file() - malloc() - home_with_suffix"); + return NULL; + } + strcpy(home_with_suffix, home); + strcat(home_with_suffix, suffix); + home = home_with_suffix; + } else { + if (!(home = strdup(home))) { + perror("get_profile_file() - strdup()"); + return NULL; + } + } + + size_t size = + strlen(home) + + strlen("/") + + strlen(profile) + + sizeof(char); + char *const profile_file = malloc(size); + if (!profile_file) { + perror("get_profile_file() - malloc() - profile_file"); + free(home); + return NULL; + } + strcpy(profile_file, home); + strcat(profile_file, "/"); + strcat(profile_file, profile); + + free(home); + return profile_file; +} + +#ifdef TEST +static void test_get_profile_file() { + #define EXPECTED_FMT "\nexpected: %s\ngot: %s\n" + FILE *f = fopen("/dev/null", "w"); + assert(f); + + { + testing("get_profile_file() when $XDG_DATA_HOME is *unset*"); + const char *const previous_xdg_data_home = getenv("XDG_DATA_HOME"); + unsetenv("XDG_DATA_HOME"); + + const char *const HOME = getenv("HOME"); + const char *const SUFFIX = "/.local/share/remembering/"; + const char *const A_PROFILE = "A-PROFILE-NAME"; + assert(HOME); + + const size_t expected_size = + strlen(HOME) + + strlen(SUFFIX) + + strlen(A_PROFILE) + + sizeof(char); + char *const expected = malloc(expected_size); + assert(expected); + strcpy(expected, HOME); + strcat(expected, SUFFIX); + strcat(expected, A_PROFILE); + + char *const profile_file = get_profile_file(A_PROFILE, f); + assert(profile_file); + assertf( + strcmp(profile_file, expected) == 0, + EXPECTED_FMT, + expected, + profile_file + ); + + free(profile_file); + free(expected); + if (previous_xdg_data_home) { + setenv("XDG_DATA_HOME", previous_xdg_data_home, true); + } + test_ok(); + } + { + testing("get_profile_file() when $XDG_DATA_HOME is *empty*"); + const char *const previous_xdg_data_home = getenv("XDG_DATA_HOME"); + setenv("XDG_DATA_HOME", "", true); + + const char *const HOME = getenv("HOME"); + const char *const SUFFIX = "/.local/share/remembering/"; + const char *const A_PROFILE = "ANOTHER-PROFILE-NAME"; + assert(HOME); + + const size_t expected_size = + strlen(HOME) + + strlen(SUFFIX) + + strlen(A_PROFILE) + + sizeof(char); + char *const expected = malloc(expected_size); + assert(expected); + strcpy(expected, HOME); + strcat(expected, SUFFIX); + strcat(expected, A_PROFILE); + + char *const profile_file = get_profile_file(A_PROFILE, f); + assert(profile_file); + assertf( + strcmp(profile_file, expected) == 0, + EXPECTED_FMT, + expected, + profile_file + ); + + free(profile_file); + free(expected); + if (previous_xdg_data_home) { + setenv("XDG_DATA_HOME", previous_xdg_data_home, true); + } else { + unsetenv("XDG_DATA_HOME"); + } + test_ok(); + } + { + testing("get_profile_file() when $XDG_DATA_HOME is *set*"); + const char *const previous_xdg_data_home = getenv("XDG_DATA_HOME"); + + const char *const XDG_DATA_HOME = "/a/custom/path"; + const char *const A_PROFILE = "YET-ANOTHER-PROFILE-NAME"; + const char *const EXPECTED = "/a/custom/path/YET-ANOTHER-PROFILE-NAME"; + + setenv("XDG_DATA_HOME", XDG_DATA_HOME, true); + + char *const profile_file = get_profile_file(A_PROFILE, f); + assert(profile_file); + assertf( + strcmp(profile_file, EXPECTED) == 0, + EXPECTED_FMT, + EXPECTED, + profile_file + ); + + free(profile_file); + if (previous_xdg_data_home) { + setenv("XDG_DATA_HOME", previous_xdg_data_home, true); + } else { + unsetenv("XDG_DATA_HOME"); + } + test_ok(); + } + { + testing("get_profile_file() when $HOME is *unset*"); + const char *const previous_home = getenv("HOME"); + const char *const previous_xdg_data_home = getenv("XDG_DATA_HOME"); + unsetenv("XDG_DATA_HOME"); + unsetenv("HOME"); + + assert(get_profile_file("ANY-PROFILE", f) == NULL); + + setenv("HOME", previous_home, true); + if (previous_xdg_data_home) { + setenv("XDG_DATA_HOME", previous_xdg_data_home, true); + } + test_ok(); + } + + fclose(f); +} +#endif + +static int mkdir_p(const char *const path, mode_t mode) { + struct stat s; + int ret; + + if (stat(path, &s) == 0 && S_ISDIR(s.st_mode)) { + return 0; + } + + char *const path_dup = strdup(path); + if (!path_dup) { + perror("mkdir_p() - strdup()"); + return -1; + } + + const char *const parent = dirname(path_dup); + if ((ret = mkdir_p(parent, mode))) { + free(path_dup); + return ret; + } + + free(path_dup); + return mkdir(path, mode); +} + +#ifdef TEST +static void test_mkdir_p() { + { + testing("mkdir_p() with an existing directory is a noop"); + struct stat s; + assert(stat("/tmp", &s) == 0 && S_ISDIR(s.st_mode)); + assert(mkdir_p("/tmp", S_IRWXU | S_IRWXG | S_IRWXO) == 0); + assert(stat("/tmp", &s) == 0 && S_ISDIR(s.st_mode)); + test_ok(); + } + { + testing("mkdir_p() with a new directory creates it"); + struct stat s; + const char *const SUBDIRECTORY_SUFFIX = "/a/b/c/d/e"; + char template[] = "/tmp/remembering.XXXXXX"; + const char *const prefix = mkdtemp(template); + assert(prefix); + + assert(stat(prefix, &s) == 0 && S_ISDIR(s.st_mode)); + + const size_t subdirectory_size = + strlen(prefix) + + strlen(SUBDIRECTORY_SUFFIX) + + sizeof(char); + char *const subdirectory = malloc(subdirectory_size); + assert(subdirectory); + strcpy(subdirectory, prefix); + strcat(subdirectory, SUBDIRECTORY_SUFFIX); + + assert(stat(subdirectory, &s) == -1 && errno == ENOENT); + assert(mkdir_p(subdirectory, S_IRWXU | S_IRWXG | S_IRWXO) == 0); + assert(stat(subdirectory, &s) == 0 && S_ISDIR(s.st_mode)); + + free(subdirectory); + test_ok(); + } +} +#endif + +#ifdef TEST +static void unit_tests() { + test_get_profile_file(); + test_mkdir_p(); +} +#endif + +int main(int argc, char *argv[]) { +#ifdef TEST + unit_tests(); + return EXIT_SUCCESS; +#endif + + for (int i = 0; i < argc; i++) { + if (strcmp("--", argv[i]) == 0) { + break; + } else if (strcmp("--help", argv[i]) == 0) { + if (usage(stdout)) return EXIT_ERROR; + if (help(stdout)) return EXIT_ERROR; + return EXIT_SUCCESS; + } else if (strcmp("--version", argv[i]) == 0) { + if (version(stdout)) return EXIT_ERROR; + return EXIT_SUCCESS; + } + } + + int option; + const char *profile = NULL; + const char *command = NULL; + while ((option = getopt(argc, argv, "p:c:hV")) != -1) { + switch (option) { + case 'p': + profile = optarg; + break; + case 'c': + command = optarg; + break; + case 'h': + if (usage(stdout)) return EXIT_ERROR; + if (help(stdout)) return EXIT_ERROR; + return EXIT_SUCCESS; + case 'V': + if (version(stdout)) return EXIT_ERROR; + return EXIT_SUCCESS; + default: + if (usage(stderr)) return EXIT_ERROR; + return EXIT_USAGE; + } + } + + if (!profile) { + if (missing(stderr, "-p PROFILE")) return EXIT_ERROR; + if (usage(stderr)) return EXIT_ERROR; + return EXIT_USAGE; + } + + if (!command) { + if (missing(stderr, "-c COMMAND")) return EXIT_ERROR; + if (usage(stderr)) return EXIT_ERROR; + return EXIT_USAGE; + } + + /* End getopt() */ + + + int ret = EXIT_SUCCESS; + + char *profile_file = NULL; + if (!(profile_file = get_profile_file(profile, stderr))) { + ret = EXIT_ERROR; + goto cleanup; + } + + char *profile_file_dup = NULL; + if (!(profile_file_dup = strdup(profile_file))) { + perror("main() - strdup()"); + ret = EXIT_ERROR; + goto cleanup; + } + + if ((ret = mkdir_p(dirname(profile_file_dup), S_IRWXU | S_IRWXG | S_IRWXO))) { + goto cleanup; + } + + printf("profile: %s\ncommand: %s\n", profile, command); + printf("profile_file: %s\n", profile_file); + + +cleanup: + free(profile_file_dup); + free(profile_file); + return ret; +} -- cgit v1.2.3