aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile5
-rw-r--r--src/config.h15
-rw-r--r--src/main.c125
-rw-r--r--src/utils.c107
-rw-r--r--src/utils.h39
5 files changed, 166 insertions, 125 deletions
diff --git a/Makefile b/Makefile
index c20fb08..adec8b4 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/src/main.c b/src/main.c
index 2976931..a8e4176 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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