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