2e263e64dd3251b06b8f4761b5492c63e2731bb2
[assman] / src / assman.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include "assman_impl.h"
5
6 static int add_fop(const char *prefix, int type, struct ass_fileops *fop);
7 static const char *match_prefix(const char *str, const char *prefix);
8 static int add_file(ass_file *file);
9 static int remove_file(ass_file *file);
10
11 #define DEF_FLAGS       (1 << ASS_OPEN_FALLTHROUGH)
12
13 static unsigned int assflags = DEF_FLAGS;
14 static struct mount *mlist;
15
16 void ass_set_option(int opt, int val)
17 {
18         if(val) {
19                 assflags |= 1 << opt;
20         } else {
21                 assflags &= ~(1 << opt);
22         }
23 }
24
25 int ass_get_option(int opt)
26 {
27         return assflags & (1 << opt);
28 }
29
30 int ass_add_path(const char *prefix, const char *path)
31 {
32         return add_fop(prefix, MOD_PATH, ass_alloc_path(path));
33 }
34
35 int ass_add_archive(const char *prefix, const char *arfile)
36 {
37         return add_fop(prefix, MOD_ARCHIVE, ass_alloc_archive(arfile));
38 }
39
40 int ass_add_url(const char *prefix, const char *url)
41 {
42         return add_fop(prefix, MOD_URL, ass_alloc_url(url));
43 }
44
45 int ass_add_user(const char *prefix, struct ass_fileops *fop)
46 {
47         return add_fop(prefix, MOD_USER, fop);
48 }
49
50 static int add_fop(const char *prefix, int type, struct ass_fileops *fop)
51 {
52         struct mount *m;
53
54         if(!fop) {
55                 fprintf(stderr, "assman: failed to allocate asset source\n");
56                 return -1;
57         }
58
59         if(!(m = malloc(sizeof *m))) {
60                 perror("assman: failed to allocate mount node");
61                 return -1;
62         }
63         if(prefix) {
64                 if(!(m->prefix = malloc(strlen(prefix) + 1))) {
65                         free(m);
66                         return -1;
67                 }
68                 strcpy(m->prefix, prefix);
69         } else {
70                 m->prefix = 0;
71         }
72         m->fop = fop;
73         m->type = type;
74
75         m->next = mlist;
76         mlist = m;
77         return 0;
78 }
79
80 void ass_clear(void)
81 {
82         while(mlist) {
83                 struct mount *m = mlist;
84                 mlist = mlist->next;
85
86                 switch(m->type) {
87                 case MOD_PATH:
88                         ass_free_path(m->fop);
89                         break;
90                 case MOD_ARCHIVE:
91                         ass_free_archive(m->fop);
92                         break;
93                 case MOD_URL:
94                         ass_free_url(m->fop);
95                         break;
96                 default:
97                         break;
98                 }
99
100                 free(m->prefix);
101                 free(m);
102         }
103 }
104
105 ass_file *ass_fopen(const char *fname, const char *mode)
106 {
107         struct mount *m;
108         void *mfile;
109         ass_file *file;
110         FILE *fp;
111
112         m = mlist;
113         while(m) {
114                 if(match_prefix(fname, m->prefix)) {
115                         if((mfile = m->fop->open(fname, m->fop->udata))) {
116                                 if(!(file = malloc(sizeof *file))) {
117                                         perror("assman: ass_fopen failed to allocate file structure");
118                                         m->fop->close(mfile, m->fop->udata);
119                                         return 0;
120                                 }
121                                 file->file = mfile;
122                                 file->fop = m->fop;
123
124                                 if(add_file(file) == -1) {
125                                         m->fop->close(mfile, m->fop->udata);
126                                         free(file);
127                                         return 0;
128                                 }
129                                 return file;
130                         } else {
131                                 if(!(assflags & (1 << ASS_OPEN_FALLTHROUGH))) {
132                                         return 0;
133                                 }
134                         }
135                 }
136                 m = m->next;
137         }
138
139         /* nothing matched, or failed to open, try the filesystem */
140         if((fp = fopen(fname, mode))) {
141                 if(!(file = malloc(sizeof *file))) {
142                         perror("assman: ass_fopen failed to allocate file structure");
143                         fclose(fp);
144                         return 0;
145                 }
146                 file->file = fp;
147                 file->fop = 0;
148
149                 if(add_file(file) == -1) {
150                         fclose(fp);
151                         free(file);
152                         return 0;
153                 }
154                 return file;
155         }
156         return 0;
157 }
158
159 static const char *match_prefix(const char *str, const char *prefix)
160 {
161         if(!prefix || !*prefix) return str;     /* match on null or empty prefix */
162
163         while(*prefix) {
164                 if(*prefix++ != *str++) {
165                         return 0;
166                 }
167         }
168         return str;
169 }
170
171 void ass_fclose(ass_file *fp)
172 {
173         if(fp->fop) {
174                 fp->fop->close(fp->file, fp->fop->udata);
175         } else {
176                 fclose(fp->file);
177         }
178         remove_file(fp);
179         free(fp);
180 }
181
182 long ass_fseek(ass_file *fp, long offs, int whence)
183 {
184         if(fp->fop) {
185                 return fp->fop->seek(fp->file, offs, whence, fp->fop->udata);
186         }
187
188         if(fseek(fp->file, offs, whence) == -1) {
189                 return -1;
190         }
191         return ftell(fp->file);
192 }
193
194 long ass_ftell(ass_file *fp)
195 {
196         return ass_fseek(fp, 0, SEEK_CUR);
197 }
198
199 size_t ass_fread(void *buf, size_t size, size_t count, ass_file *fp)
200 {
201         if(fp->fop) {
202                 long res = fp->fop->read(fp->file, buf, size * count, fp->fop->udata);
203                 if(res <= 0) return 0;
204                 return res / size;
205         }
206
207         return fread(buf, size, count, fp->file);
208 }
209
210
211 /* --- convenience functions --- */
212
213 int ass_fgetc(ass_file *fp)
214 {
215         unsigned char c;
216
217         if(ass_fread(&c, 1, 1, fp) < 1) {
218                 return -1;
219         }
220         return (int)c;
221 }
222
223 char *ass_fgets(char *s, int size, ass_file *fp)
224 {
225         int i, c;
226         char *ptr = s;
227
228         if(!size) return 0;
229
230         for(i=0; i<size - 1; i++) {
231                 if((c = ass_fgetc(fp)) == -1) {
232                         break;
233                 }
234                 *ptr++ = c;
235
236                 if(c == '\n') break;
237         }
238         *ptr = 0;
239         return ptr == s ? 0 : s;
240 }
241
242
243 static int add_file(ass_file *file)
244 {
245         return -1;      /* TODO */
246 }
247
248 static int remove_file(ass_file *file)
249 {
250         return -1;      /* TODO */
251 }