From 8d90197913f1c5d813b43854f5f769bade5296a8 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Sun, 23 Sep 2018 03:12:51 +0300 Subject: [PATCH] initial commit --- .gitignore | 5 ++ Makefile | 28 ++++++ src/assman.c | 251 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/assman.h | 53 +++++++++++ src/assman_impl.h | 38 ++++++++ src/mod_path.c | 45 ++++++++++ 6 files changed, 420 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 src/assman.c create mode 100644 src/assman.h create mode 100644 src/assman_impl.h create mode 100644 src/mod_path.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..17859ab --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*.o +*.d +*.swp +*.a +*.so* diff --git a/Makefile b/Makefile new file mode 100644 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 index 0000000..2e263e6 --- /dev/null +++ b/src/assman.c @@ -0,0 +1,251 @@ +#include +#include +#include +#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 + +#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 index 0000000..7161da1 --- /dev/null +++ b/src/assman_impl.h @@ -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 index 0000000..1776ece --- /dev/null +++ b/src/mod_path.c @@ -0,0 +1,45 @@ +#include + +#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); -- 1.7.10.4