agendafs

A filesystem for your calendar.

git clone git://mccd.space/agendafs
commit ca0f85fa935595c580f5bbedb12c667cc8741eb6
parent 6dcea2c4b6dacd4bc260d6f54de9487adbddc7a1
Author: Marc Coquand <marc@coquand.email>
Date:   Sun, 13 Jul 2025 16:45:37 +0200

Refactor path functionality

Diffstat:
MMakefile | 4++--
Mjournal_entry.c | 89++++++-------------------------------------------------------------------------
Mjournal_entry.h | 3---
Apath.c | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apath.h | 26++++++++++++++++++++++++++
Mutil.c | 9+++++++++
Mutil.h | 3++-
7 files changed, 137 insertions(+), 89 deletions(-)
diff --git a/Makefile b/Makefile
@@ -5,10 +5,10 @@ LIBS = `pkg-config uuid fuse3 libical --cflags --libs`
 
 all: agendafs
 
-agendafs: main.c util.c hashmap.c journal_entry.c tree.c
+agendafs: main.c path.c util.c hashmap.c journal_entry.c tree.c
 	$(CC) $(CFLAGS) *.c -o mount_agendafs $(LIBS)
 
-debug: main.c util.c hashmap.c journal_entry.c tree.c
+debug: main.c path.c util.c hashmap.c journal_entry.c tree.c
 	$(CC) $(CFLAGS_DEBUG) $(DEBUG_FLAGS) *.c -o mount_agendafs-debug $(LIBS)
 
 clean:
diff --git a/journal_entry.c b/journal_entry.c
@@ -1,6 +1,7 @@
 #include "journal_entry.h"
 
 #include "hashmap.h"
+#include "path.h"
 #include "tree.h"
 #include "util.h"
 #include <dirent.h>
@@ -63,30 +64,6 @@ get_node_component(const struct tree_node *node)
 	return entry->component;
 }
 
-int
-get_parent_path(const char *path, char **buffer)
-{
-	char *path_copy = strdup(path);
-
-	char *last_slash = strrchr(path_copy, '/');
-	if (last_slash == NULL) {
-		free(path_copy);
-		return 0;
-	}
-
-	// If they are the same, it means the parent is root
-	if (strcmp(last_slash, path_copy) == 0) {
-		int result = asprintf(buffer, "/");
-		free(path_copy);
-		return result;
-	}
-	*last_slash = '\0';
-	int result = asprintf(buffer, "%s", path_copy);
-	free(path_copy);
-
-	return result;
-}
-
 struct tree_node **
 get_node_children(const struct tree_node *node)
 {
@@ -143,28 +120,6 @@ is_root_node(const struct tree_node *node)
 	return false;
 }
 
-char **
-split_path(const char *path, size_t *count_out)
-{
-	char *path_copy = strdup(path);
-	if (!path_copy)
-		return NULL;
-
-	size_t count = 0;
-	char **segments = NULL;
-
-	char *token = strtok(path_copy, "/");
-	while (token) {
-		segments = xreallocarray(segments, sizeof(char *), (count + 1));
-		segments[count++] = strdup(token);
-		token = strtok(NULL, "/");
-	}
-	free(path_copy);
-
-	*count_out = count;
-	return segments;
-}
-
 void
 set_parent_child_relationship_to_component(icalcomponent *parent,
 					   icalcomponent *child)
@@ -232,14 +187,6 @@ add_child_to_node(struct tree_node *parent, struct tree_node *child)
 	}
 }
 
-void
-free_segments(char **segments, size_t count)
-{
-	for (size_t i = 0; i < count; ++i)
-		free(segments[i]);
-	free(segments);
-}
-
 struct tree_node *
 get_node_by_path(const char *path)
 {
@@ -248,8 +195,8 @@ get_node_by_path(const char *path)
 		return fuse_tree_root;
 	}
 
-	size_t count;
-	char **segments = split_path(path, &count);
+	char **segments = NULL;
+	size_t count = split_path(path, segments);
 	if (!segments)
 		return fuse_tree_root;
 	LOG("Segments are defined");
@@ -280,9 +227,7 @@ get_node_by_path(const char *path)
 char *
 get_original_filepath(const struct journal_entry *entry)
 {
-	char *filepath = NULL;
-	asprintf(&filepath, "%s/%s", ICS_DIR, entry->filename_original);
-	return filepath;
+	return append_path(ICS_DIR, entry->filename_original);
 }
 
 icaltimetype
@@ -307,15 +252,6 @@ free_journal_entry(void *val)
 	free(entry);
 }
 
-char *
-get_filename(const char *full_path)
-{
-	char *base_name = strrchr(full_path, '/');
-	if (!base_name)
-		return (char *)full_path;
-	return base_name + 1;
-}
-
 struct journal_entry *
 get_entry_from_fuse_path(const char *path)
 {
@@ -991,6 +927,7 @@ write_entry_to_ical_file(const struct journal_entry *entry)
 
 	return 0;
 }
+
 size_t
 load_agendafs_environment(char *ics_dir_env)
 {
@@ -1148,7 +1085,6 @@ create_vjournal_directory(char *summary)
 	icalcomponent_add_property(calendar,
 				   icalproperty_new_prodid("-//caldavfs//EN"));
 
-	// Step 2: Create a VJOURNAL entry
 	icalcomponent *journal = icalcomponent_new_vjournal();
 	char *id = create_new_unique_ics_uid();
 
@@ -1171,18 +1107,6 @@ create_vjournal_directory(char *summary)
 	return calendar;
 }
 
-void
-remove_file_extension(char *path)
-{
-	char *last_dot = strrchr(path, '.');
-	char *last_slash = strrchr(path, '/');
-
-	// Only remove the extension if dot is after last slash
-	if (last_dot && (!last_slash || last_dot > last_slash)) {
-		*last_dot = '\0';
-	}
-}
-
 bool
 match_by_uid(icalcomponent *component, const char *target_uuid)
 {
@@ -1202,8 +1126,7 @@ create_entry_from_fuse(const char *fuse_path)
 	char *new_basename = strrchr(fuse_path, '/');
 	new_basename++;
 
-	char *without_extension = strdup(new_basename);
-	remove_file_extension(without_extension);
+	path *without_extension = remove_file_extension(new_basename);
 
 	struct journal_entry *new_entry =
 	    xcalloc(1, sizeof(struct journal_entry));
diff --git a/journal_entry.h b/journal_entry.h
@@ -179,9 +179,6 @@ gid_t
 get_node_gid(const struct tree_node *node);
 
 void
-remove_file_extension(char *path);
-
-void
 update_or_create_fuse_entry_from_original(const char *filename);
 
 int
diff --git a/path.c b/path.c
@@ -0,0 +1,92 @@
+#include "path.h"
+#include "util.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+path *
+remove_file_extension(const path *p)
+{
+	char *cpy = xstrdup(p);
+	char *last_dot = strrchr(cpy, '.');
+	char *last_slash = strrchr(cpy, '/');
+
+	// Only remove the extension if dot is after last slash
+	if (last_dot && (!last_slash || last_dot > last_slash)) {
+		*last_dot = '\0';
+	}
+
+	return cpy;
+}
+
+void
+free_segments(char **segments, size_t count)
+{
+	for (size_t i = 0; i < count; ++i)
+		free(segments[i]);
+	free(segments);
+}
+
+path *
+append_path(path *parentp, char *childp)
+{
+	char *filepath = NULL;
+	if (asprintf(&filepath, "%s/%s", parentp, childp) == -1) {
+		LOG("Memory alloc failed");
+		exit(1);
+	}
+	return filepath;
+}
+
+path *
+get_filename(const char *full_path)
+{
+	char *base_name = strrchr(full_path, '/');
+	if (!base_name)
+		return (char *)full_path;
+	return base_name + 1;
+}
+
+size_t
+get_parent_path(const char *path, char **buffer)
+{
+	char *path_copy = strdup(path);
+
+	char *last_slash = strrchr(path_copy, '/');
+	if (last_slash == NULL) {
+		free(path_copy);
+		return 0;
+	}
+
+	// If they are the same, it means the parent is root
+	if (strcmp(last_slash, path_copy) == 0) {
+		int result = asprintf(buffer, "/");
+		free(path_copy);
+		return result;
+	}
+	*last_slash = '\0';
+	int result = asprintf(buffer, "%s", path_copy);
+	free(path_copy);
+
+	return result;
+}
+
+size_t
+split_path(const path *p, char **segments)
+{
+	char *path_copy = xstrdup(p);
+
+	size_t count = 0;
+	char *segment;
+
+	char *saveptr;
+	segment = strtok_r(path_copy, "/", &saveptr);
+	while (segment) {
+		segments[count++] = strdup(segment);
+		segment = strtok_r(NULL, "/", &saveptr);
+	}
+	free(path_copy);
+
+	return count;
+}
+
diff --git a/path.h b/path.h
@@ -0,0 +1,26 @@
+#ifndef path_h_INCLUDED
+#define path_h_INCLUDED
+#include "util.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef char path;
+
+path *
+remove_file_extension(const path *);
+
+void
+free_segments(path **, size_t);
+
+path *
+append_path(path *, char *);
+
+path *
+get_filename(const path *);
+
+size_t
+get_parent_path(const char *, char **);
+size_t
+split_path(const path *, char **);
+#endif // path_h_INCLUDED
diff --git a/util.c b/util.c
@@ -33,6 +33,15 @@ xcalloc(size_t memb, size_t s)
 	return buf;
 }
 
+char *
+xstrdup(const char *s)
+{
+	char *cpy = strdup(s);
+	if (!cpy)
+		exit(1);
+	return cpy;
+}
+
 void *
 reallocarray(void *buf, size_t n, size_t m)
 {
diff --git a/util.h b/util.h
@@ -14,5 +14,6 @@ void *
 xmalloc(size_t);
 void *
 xcalloc(size_t, size_t);
-
+char *
+xstrdup(const char *s);
 #endif