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