diff options
| author | Tristan Riehs <tristan.riehs@inria.fr> | 2026-04-26 12:07:39 +0200 |
|---|---|---|
| committer | Tristan Riehs <tristan.riehs@inria.fr> | 2026-04-26 12:07:39 +0200 |
| commit | 2991c0b3560781344488680625954aa3ef0893c6 (patch) | |
| tree | b5bc2048e83453e8c7b5a2d2677161c4cc4847f2 | |
| parent | d2fb6a8aac6abe5bfe4b4ea7f2528d119afbc8c6 (diff) | |
Create a "utils" module
Also put configuration macros in a dedicated header. In the future the
configuration will be read at execution time.
| -rw-r--r-- | Makefile | 5 | ||||
| -rw-r--r-- | src/config.h | 15 | ||||
| -rw-r--r-- | src/main.c | 125 | ||||
| -rw-r--r-- | src/utils.c | 107 | ||||
| -rw-r--r-- | src/utils.h | 39 |
5 files changed, 166 insertions, 125 deletions
@@ -27,7 +27,7 @@ export __LIBS := $(shell pkg-config --libs sqlite3) all: $(PROG) -$(PROG): src/main.o src/system.o +$(PROG): src/main.o src/system.o src/utils.o $(CC) -o $@ $^ $(__LIBS) $(LDFLAGS) $(LIBS) # Create cache and config directories at compile time since they will be used by # the user who compiled ftag @@ -35,8 +35,9 @@ $(PROG): src/main.o src/system.o mkdir -p $(FTAG_CACHE_DIR) mkdir -p $(FTAG_CONFIG_DIR) -src/main.o: src/main.c src/system.h +src/main.o: src/main.c src/system.h src/utils.h src/system.o: src/system.c src/system.h +src/utils.o: src/utils.c src/system.h src/utils.h .c.o: $(CC) $(__CFLAGS) $(CFLAGS) -o $@ -c $< diff --git a/src/config.h b/src/config.h new file mode 100644 index 0000000..82ffd6a --- /dev/null +++ b/src/config.h @@ -0,0 +1,15 @@ +#ifndef CONFIG_H +#define CONFIG_H + +#ifndef FTAG_REMOTE_HOST +#define FTAG_REMOTE_HOST "localhost" +#endif + +#ifndef FTAG_REMOTE_ROOT +/* HOME on remote host */ +#define FTAG_REMOTE_ROOT "ftag" +#endif + +#define DATABASE_PATH FTAG_CACHE_DIR "/ftag.sqlite3" + +#endif @@ -10,18 +10,9 @@ #include <time.h> #include <unistd.h> +#include "config.h" #include "system.h" - -#ifndef FTAG_REMOTE_HOST -#define FTAG_REMOTE_HOST "localhost" -#endif - -#ifndef FTAG_REMOTE_ROOT -/* HOME on remote host */ -#define FTAG_REMOTE_ROOT "ftag" -#endif - -#define DATABASE_PATH FTAG_CACHE_DIR "/ftag.sqlite3" +#include "utils.h" /* TODO: read the configuration from a file @@ -62,23 +53,6 @@ static void __sqlite3_check(int rc, sqlite3 *db, const char *file, int line, con #define sqlite3_check(RC, DB) \ __sqlite3_check(RC, DB, __FILE__, __LINE__, __func__) -static void assert_db_exists(void) -{ - if (file_exists(DATABASE_PATH)) - return; - - if (errno == ENOENT) { - fprintf(stderr, - "ftag: database not found at \"%s\", " - "have you run \"ftag init\"?\n", - DATABASE_PATH); - } - else { - perror(DATABASE_PATH); - } - exit(EXIT_FAILURE); -} - /* Prompt the user for yes or no (default is yes). Before calling, a prompt * should be printed to stdout, eventually not with an ending newline. */ static int prompt_yes_no(void) @@ -135,101 +109,6 @@ static void sanitize_sql_str(char **str) *str = new_str; } -/* Safely create a formatted string and write it to BUF. BUF shall be a buffer - * of size at least SIZE. BUF can be stack-allocated. If the formatting cannot - * be performed, exit(3) is called. This function is not meant to be called - * directly: the macro strbuild should be used. The code is adapted from the - * make_message function of the vsnprintf(3) manual page, section "examples". */ -static void __strbuild(char *buf, int size, - const char *file, int line, - const char *fmt, ...) -{ - va_list ap; - int len; - - va_start(ap, fmt); - len = vsnprintf(NULL, 0, fmt, ap); - va_end(ap); - - if (len < 0) { - fprintf(stderr, "%s:%d: ", file, line); - perror(""); - exit(EXIT_FAILURE); - } - if (len >= size) { - fprintf(stderr, "%s:%d: error: not enough space, " - "have %d, need at least %d\n", - file, line, - size, len + 1); - exit(EXIT_FAILURE); - } - - va_start(ap, fmt); - len = vsnprintf(buf, size, fmt, ap); - va_end(ap); - - assert(len >= 0); -} - -/* Convenience wrappers for __strbuild. */ -#define strbuild(buf, fmt, ...) \ - __strbuild(buf, sizeof(buf), __FILE__, __LINE__, fmt, __VA_ARGS__) -#define strbuild_with_size(buf, size, fmt, ...) \ - __strbuild(buf, size, __FILE__, __LINE__, fmt, __VA_ARGS__) - -static int str_has_suffix(const char *str, const char *suffix) -{ - int str_len = strlen(str); - int suffix_len = strlen(suffix); - return ((str_len > suffix_len) - && (strcmp(str + str_len - suffix_len, suffix) == 0)); -} - -/* Compute something that identifies the content of FILE. Algorithm by Dan - * Bernstein from http://www.cse.yorku.ca/~oz/hash.html via - * https://stackoverflow.com/a/7666577/20138083. */ -static uint32_t sum(const char *file) -{ - FILE *stream = fopen(file, "r"); - uint8_t buf[4096]; - size_t buf_len; - uint32_t sum = 5381; - if (!file) { - fprintf(stderr, "fopen: \"%s\": ", file); - perror(""); - exit(EXIT_FAILURE); - } - while ((buf_len = fread(&buf, 1, sizeof(buf), stream)) != 0) { - for (int i = 0; i < buf_len; i++) { - uint8_t next = buf[i]; - sum = sum*33 + next; - } - } - if (ferror(stream)) { - fprintf(stderr, "fread: \"%s\": ", file); - perror(""); - exit(EXIT_FAILURE); - } - fclose(stream); - return sum; -} - -/* Return an integer timestamp from a date string of the format YYYY-MM-DD. */ -static time_t time_from_str(const char *str) -{ - int rc; - struct tm tm; - memset(&tm, 0, sizeof(tm)); - rc = sscanf(str, "%d-%d-%d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday); - if (rc <= 0) { - perror("sscanf"); - exit(EXIT_FAILURE); - } - tm.tm_year -= 1900; - tm.tm_mon -= 1; - return mktime(&tm); -} - /* Write an id to *_ID, used by table_next_id. Write -1 if no id is found. */ static int table_next_id_callback(void *_id, int, char **cols, char **) { diff --git a/src/utils.c b/src/utils.c new file mode 100644 index 0000000..a1fc5b9 --- /dev/null +++ b/src/utils.c @@ -0,0 +1,107 @@ +#include <assert.h> +#include <errno.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "config.h" +#include "system.h" +#include "utils.h" + +void __strbuild(char *buf, int size, + const char *file, int line, + const char *fmt, ...) +{ + va_list ap; + int len; + + va_start(ap, fmt); + len = vsnprintf(NULL, 0, fmt, ap); + va_end(ap); + + if (len < 0) { + fprintf(stderr, "%s:%d: ", file, line); + perror(""); + exit(EXIT_FAILURE); + } + if (len >= size) { + fprintf(stderr, "%s:%d: error: not enough space, " + "have %d, need at least %d\n", + file, line, + size, len + 1); + exit(EXIT_FAILURE); + } + + va_start(ap, fmt); + len = vsnprintf(buf, size, fmt, ap); + va_end(ap); + + assert(len >= 0); +} + +int str_has_suffix(const char *str, const char *suffix) +{ + int str_len = strlen(str); + int suffix_len = strlen(suffix); + return ((str_len > suffix_len) + && (strcmp(str + str_len - suffix_len, suffix) == 0)); +} + +void assert_db_exists(void) +{ + if (file_exists(DATABASE_PATH)) + return; + + if (errno == ENOENT) { + fprintf(stderr, + "ftag: database not found at \"%s\", " + "have you run \"ftag init\"?\n", + DATABASE_PATH); + } + else { + perror(DATABASE_PATH); + } + exit(EXIT_FAILURE); +} + +uint32_t sum(const char *file) +{ + FILE *stream = fopen(file, "r"); + uint8_t buf[4096]; + size_t buf_len; + uint32_t sum = 5381; + if (!file) { + fprintf(stderr, "fopen: \"%s\": ", file); + perror(""); + exit(EXIT_FAILURE); + } + while ((buf_len = fread(&buf, 1, sizeof(buf), stream)) != 0) { + for (int i = 0; i < buf_len; i++) { + uint8_t next = buf[i]; + sum = sum*33 + next; + } + } + if (ferror(stream)) { + fprintf(stderr, "fread: \"%s\": ", file); + perror(""); + exit(EXIT_FAILURE); + } + fclose(stream); + return sum; +} + +time_t time_from_str(const char *str) +{ + int rc; + struct tm tm; + memset(&tm, 0, sizeof(tm)); + rc = sscanf(str, "%d-%d-%d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday); + if (rc <= 0) { + perror("sscanf"); + exit(EXIT_FAILURE); + } + tm.tm_year -= 1900; + tm.tm_mon -= 1; + return mktime(&tm); +} diff --git a/src/utils.h b/src/utils.h new file mode 100644 index 0000000..e382ace --- /dev/null +++ b/src/utils.h @@ -0,0 +1,39 @@ +#ifndef UTILS_H +#define UTILS_H + +/* Utility functions for manipulating strings, time, and error codes. */ + +#include <stdio.h> +#include <stdint.h> +#include <time.h> + +/* Internals of strbuild. */ +void __strbuild(char *buf, int size, + const char *file, int line, + const char *fmt, ...); + +/* Safely create a formatted string and write it to BUF. BUF shall be a buffer + * of size at least SIZE. BUF can be stack-allocated. If the formatting cannot + * be performed, exit(3) is called. This function is not meant to be called + * directly: the macro strbuild should be used. The code is adapted from the + * make_message function of the vsnprintf(3) manual page, section "examples". */ +#define strbuild(buf, fmt, ...) \ + __strbuild(buf, sizeof(buf), __FILE__, __LINE__, fmt, __VA_ARGS__) + +#define strbuild_with_size(buf, size, fmt, ...) \ + __strbuild(buf, size, __FILE__, __LINE__, fmt, __VA_ARGS__) + +int str_has_suffix(const char *str, const char *suffix); + +/* Abort if the database does not exist. */ +void assert_db_exists(void); + +/* Compute something that identifies the content of FILE. Algorithm by Dan + * Bernstein from http://www.cse.yorku.ca/~oz/hash.html via + * https://stackoverflow.com/a/7666577/20138083. */ +uint32_t sum(const char *file); + +/* Return an integer timestamp from a date string of the format YYYY-MM-DD. */ +time_t time_from_str(const char *str); + +#endif |
