initial commit
authorJohn Tsiombikas <nuclear@member.fsf.org>
Sun, 23 Sep 2018 00:12:51 +0000 (03:12 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Sun, 23 Sep 2018 00:12:51 +0000 (03:12 +0300)
.gitignore [new file with mode: 0644]
Makefile [new file with mode: 0644]
src/assman.c [new file with mode: 0644]
src/assman.h [new file with mode: 0644]
src/assman_impl.h [new file with mode: 0644]
src/mod_path.c [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..17859ab
--- /dev/null
@@ -0,0 +1,5 @@
+*.o
+*.d
+*.swp
+*.a
+*.so*
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..9dfa452
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,28 @@
+src = $(wildcard src/*.c)
+obj = $(src:.c=.o)
+dep = $(obj:.o=.d)
+
+name = assman
+lib_a = lib$(name).a
+
+warn = -pedantic -Wall
+dbg = -g
+opt = -O0
+
+CFLAGS = $(warn) $(dbg) $(opt) $(inc)
+LDFLAGS =
+
+$(lib_a): $(obj)
+       $(AR) rcs $@ $(obj)
+
+%.d: %.c
+       @echo "generating depfile $< -> $@"
+       @$(CPP) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@
+
+.PHONY: clean
+clean:
+       rm -f $(obj) $(bin)
+
+.PHONY: cleandep
+cleandep:
+       rm -f $(dep)
diff --git a/src/assman.c b/src/assman.c
new file mode 100644 (file)
index 0000000..2e263e6
--- /dev/null
@@ -0,0 +1,251 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "assman_impl.h"
+
+static int add_fop(const char *prefix, int type, struct ass_fileops *fop);
+static const char *match_prefix(const char *str, const char *prefix);
+static int add_file(ass_file *file);
+static int remove_file(ass_file *file);
+
+#define DEF_FLAGS      (1 << ASS_OPEN_FALLTHROUGH)
+
+static unsigned int assflags = DEF_FLAGS;
+static struct mount *mlist;
+
+void ass_set_option(int opt, int val)
+{
+       if(val) {
+               assflags |= 1 << opt;
+       } else {
+               assflags &= ~(1 << opt);
+       }
+}
+
+int ass_get_option(int opt)
+{
+       return assflags & (1 << opt);
+}
+
+int ass_add_path(const char *prefix, const char *path)
+{
+       return add_fop(prefix, MOD_PATH, ass_alloc_path(path));
+}
+
+int ass_add_archive(const char *prefix, const char *arfile)
+{
+       return add_fop(prefix, MOD_ARCHIVE, ass_alloc_archive(arfile));
+}
+
+int ass_add_url(const char *prefix, const char *url)
+{
+       return add_fop(prefix, MOD_URL, ass_alloc_url(url));
+}
+
+int ass_add_user(const char *prefix, struct ass_fileops *fop)
+{
+       return add_fop(prefix, MOD_USER, fop);
+}
+
+static int add_fop(const char *prefix, int type, struct ass_fileops *fop)
+{
+       struct mount *m;
+
+       if(!fop) {
+               fprintf(stderr, "assman: failed to allocate asset source\n");
+               return -1;
+       }
+
+       if(!(m = malloc(sizeof *m))) {
+               perror("assman: failed to allocate mount node");
+               return -1;
+       }
+       if(prefix) {
+               if(!(m->prefix = malloc(strlen(prefix) + 1))) {
+                       free(m);
+                       return -1;
+               }
+               strcpy(m->prefix, prefix);
+       } else {
+               m->prefix = 0;
+       }
+       m->fop = fop;
+       m->type = type;
+
+       m->next = mlist;
+       mlist = m;
+       return 0;
+}
+
+void ass_clear(void)
+{
+       while(mlist) {
+               struct mount *m = mlist;
+               mlist = mlist->next;
+
+               switch(m->type) {
+               case MOD_PATH:
+                       ass_free_path(m->fop);
+                       break;
+               case MOD_ARCHIVE:
+                       ass_free_archive(m->fop);
+                       break;
+               case MOD_URL:
+                       ass_free_url(m->fop);
+                       break;
+               default:
+                       break;
+               }
+
+               free(m->prefix);
+               free(m);
+       }
+}
+
+ass_file *ass_fopen(const char *fname, const char *mode)
+{
+       struct mount *m;
+       void *mfile;
+       ass_file *file;
+       FILE *fp;
+
+       m = mlist;
+       while(m) {
+               if(match_prefix(fname, m->prefix)) {
+                       if((mfile = m->fop->open(fname, m->fop->udata))) {
+                               if(!(file = malloc(sizeof *file))) {
+                                       perror("assman: ass_fopen failed to allocate file structure");
+                                       m->fop->close(mfile, m->fop->udata);
+                                       return 0;
+                               }
+                               file->file = mfile;
+                               file->fop = m->fop;
+
+                               if(add_file(file) == -1) {
+                                       m->fop->close(mfile, m->fop->udata);
+                                       free(file);
+                                       return 0;
+                               }
+                               return file;
+                       } else {
+                               if(!(assflags & (1 << ASS_OPEN_FALLTHROUGH))) {
+                                       return 0;
+                               }
+                       }
+               }
+               m = m->next;
+       }
+
+       /* nothing matched, or failed to open, try the filesystem */
+       if((fp = fopen(fname, mode))) {
+               if(!(file = malloc(sizeof *file))) {
+                       perror("assman: ass_fopen failed to allocate file structure");
+                       fclose(fp);
+                       return 0;
+               }
+               file->file = fp;
+               file->fop = 0;
+
+               if(add_file(file) == -1) {
+                       fclose(fp);
+                       free(file);
+                       return 0;
+               }
+               return file;
+       }
+       return 0;
+}
+
+static const char *match_prefix(const char *str, const char *prefix)
+{
+       if(!prefix || !*prefix) return str;     /* match on null or empty prefix */
+
+       while(*prefix) {
+               if(*prefix++ != *str++) {
+                       return 0;
+               }
+       }
+       return str;
+}
+
+void ass_fclose(ass_file *fp)
+{
+       if(fp->fop) {
+               fp->fop->close(fp->file, fp->fop->udata);
+       } else {
+               fclose(fp->file);
+       }
+       remove_file(fp);
+       free(fp);
+}
+
+long ass_fseek(ass_file *fp, long offs, int whence)
+{
+       if(fp->fop) {
+               return fp->fop->seek(fp->file, offs, whence, fp->fop->udata);
+       }
+
+       if(fseek(fp->file, offs, whence) == -1) {
+               return -1;
+       }
+       return ftell(fp->file);
+}
+
+long ass_ftell(ass_file *fp)
+{
+       return ass_fseek(fp, 0, SEEK_CUR);
+}
+
+size_t ass_fread(void *buf, size_t size, size_t count, ass_file *fp)
+{
+       if(fp->fop) {
+               long res = fp->fop->read(fp->file, buf, size * count, fp->fop->udata);
+               if(res <= 0) return 0;
+               return res / size;
+       }
+
+       return fread(buf, size, count, fp->file);
+}
+
+
+/* --- convenience functions --- */
+
+int ass_fgetc(ass_file *fp)
+{
+       unsigned char c;
+
+       if(ass_fread(&c, 1, 1, fp) < 1) {
+               return -1;
+       }
+       return (int)c;
+}
+
+char *ass_fgets(char *s, int size, ass_file *fp)
+{
+       int i, c;
+       char *ptr = s;
+
+       if(!size) return 0;
+
+       for(i=0; i<size - 1; i++) {
+               if((c = ass_fgetc(fp)) == -1) {
+                       break;
+               }
+               *ptr++ = c;
+
+               if(c == '\n') break;
+       }
+       *ptr = 0;
+       return ptr == s ? 0 : s;
+}
+
+
+static int add_file(ass_file *file)
+{
+       return -1;      /* TODO */
+}
+
+static int remove_file(ass_file *file)
+{
+       return -1;      /* TODO */
+}
diff --git a/src/assman.h b/src/assman.h
new file mode 100644 (file)
index 0000000..4daec0d
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef ASSMAN_H_
+#define ASSMAN_H_
+
+#include <stdlib.h>
+
+#ifndef ASSMAN_IMPL_H_
+typedef void ass_file;
+#endif
+
+struct ass_fileops {
+       void *udata;
+       void *(*open)(const char *fname, void *udata);
+       void (*close)(void *fp, void *udata);
+       long (*seek)(void *fp, long offs, int whence, void *udata);
+       long (*read)(void *fp, void *buf, long size, void *udata);
+};
+
+/* options (ass_set_option/ass_get_option) */
+enum {
+       ASS_OPEN_FALLTHROUGH    /* try all matching handlers if the first fails to open the file */
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void ass_set_option(int opt, int val);
+int ass_get_option(int opt);
+
+/* add a handler for a specific path prefixes. 0 matches every path */
+int ass_add_path(const char *prefix, const char *path);
+int ass_add_archive(const char *prefix, const char *arfile);
+int ass_add_url(const char *prefix, const char *url);
+int ass_add_user(const char *prefix, struct ass_fileops *cb);
+void ass_clear(void);
+
+ass_file *ass_fopen(const char *fname, const char *mode);
+void ass_fclose(ass_file *fp);
+long ass_fseek(ass_file *fp, long offs, int whence);
+long ass_ftell(ass_file *fp);
+
+size_t ass_fread(void *buf, size_t size, size_t count, ass_file *fp);
+
+/* convenience functions, derived from the above */
+int ass_fgetc(ass_file *fp);
+char *ass_fgets(char *s, int size, ass_file *fp);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* ASSMAN_H_ */
diff --git a/src/assman_impl.h b/src/assman_impl.h
new file mode 100644 (file)
index 0000000..7161da1
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef ASSMAN_IMPL_H_
+#define ASSMAN_IMPL_H_
+
+typedef struct ass_file ass_file;
+
+#include "assman.h"
+
+struct ass_file {
+       void *file;
+       struct ass_fileops *fop;
+};
+
+struct mount {
+       char *prefix;
+       struct ass_fileops *fop;
+       int type;
+
+       struct mount *next;
+};
+
+enum {
+       MOD_PATH,
+       MOD_ARCHIVE,
+       MOD_URL,
+       MOD_USER
+};
+
+/* implemented in mod_*.c files */
+struct ass_fileops *ass_alloc_path(const char *path);
+void ass_free_path(struct ass_fileops *fop);
+struct ass_fileops *ass_alloc_archive(const char *fname);
+void ass_free_archive(struct ass_fileops *fop);
+struct ass_fileops *ass_alloc_url(const char *url);
+void ass_free_url(struct ass_fileops *fop);
+
+
+
+#endif /* ASSMAN_IMPL_H_ */
diff --git a/src/mod_path.c b/src/mod_path.c
new file mode 100644 (file)
index 0000000..1776ece
--- /dev/null
@@ -0,0 +1,45 @@
+#include <stdlib.h>
+
+#include "assman_impl.h"
+
+
+static void *fop_open(const char *fname, void *udata);
+static void fop_close(void *fp, void *udata);
+static long fop_seek(void *fp, long offs, int whence, void *udata);
+static long fop_read(void *fp, void *buf, long size, void *udata);
+
+
+struct ass_fileops *ass_alloc_path(const char *path)
+{
+       char *p;
+       struct ass_fileops *fop;
+
+       if(!(fop = malloc(sizeof *fop))) {
+               return 0;
+       }
+       if(!(p = malloc(strlen(path) + 1))) {
+               free(fop);
+               return 0;
+       }
+       fop->udata = p;
+
+       while(*path) {
+               *p++ = *path++;
+       }
+       while(p > fop->udata && (p[-1] == '/' || isspace(p[-1]))) p--;
+       *p = 0;
+
+       fop->open = fop_open;
+       fop->close = fop_close;
+       fop->seek = fop_seek;
+       fop->read = fop_read;
+       return fop;
+}
+
+static void *fop_open(const char *fname, void *udata)
+{
+}
+
+static void fop_close(void *fp, void *udata);
+static long fop_seek(void *fp, long offs, int whence, void *udata);
+static long fop_read(void *fp, void *buf, long size, void *udata);