Add support for VFS caching.
[herrie-working.git] / herrie / src / vfs.h
blobfb4998165c94dc2fb4e19c4e5e43edfccde2bd16
1 /*
2 * Copyright (c) 2006-2011 Ed Schouten <ed@80386.nl>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
26 /**
27 * @file vfs.h
28 * @brief Virtual filesystem.
32 * All structures mentioned in this file are only directly dereferenced
33 * in the VFS itself, so we could remove their declaration to a private
34 * header file. The problem is that this results in worse performance,
35 * especially on the vfs_list_* functions.
38 struct vfsref;
39 struct vfsent;
41 /**
42 * @brief List structure that can contain a lot of VFS references.
44 struct vfslist {
45 /**
46 * @brief First item in the list.
48 struct vfsref *first;
49 /**
50 * @brief Last item in the list.
52 struct vfsref *last;
53 /**
54 * @brief The number of items in the list.
56 unsigned int items;
59 /**
60 * @brief Module representing a type of file or directory on disk, containing
61 * functions to read its contents (populate it).
63 struct vfsmodule {
64 /**
65 * @brief Attach the VFS module to a VFS entity
67 int (*match)(struct vfsent *ve, int isdir);
68 /**
69 * @brief Populate the VFS entity with its childs
71 int (*populate)(struct vfsent *ve);
72 /**
73 * @brief Return a FILE* to the file on disk
75 FILE *(*open)(struct vfsent *ve);
77 /**
78 * @brief Does not need an on-disk file
80 char pseudo;
82 /**
83 * @brief Order in which files should be sorted in vfs_dir
85 unsigned char sortorder;
87 /**
88 * @brief Charachter placed behind the character marking the filetype
90 char marking;
93 /**
94 * @brief A VFS entity is an object representing a single file or directory on
95 * disk. Each VFS entity is handled by some kind of VFS module. By
96 * default, a VFS entity only contains the filename and a reference
97 * count. It must be manually populated to get its actual contents.
99 struct vfsent {
101 * @brief The name of the current object (the basename)
103 char *name;
105 * @brief The complete filename of the object (realpath)
107 char *filename;
110 * @brief The reference count of the current object, used to determine
111 * whether it should be deallocated.
113 int refcount;
116 * @brief The VFS module responsible for handling the entity
118 struct vfsmodule *vmod;
120 * @brief References to its children
122 struct vfslist population;
124 * @brief Whether or not we should recurse down this object
126 int recurse;
130 * @brief Reference to a VFS entity including list pointers.
132 struct vfsref {
134 * @brief Pointer to the VFS entity.
136 struct vfsent *ent;
138 * @brief Pointer to the next item in the VFS list.
140 struct vfsref *next;
142 * @brief Pointer to the previous item in the VFS list.
144 struct vfsref *prev;
146 * @brief Indicator that this reference should be drawn in a
147 * different color in the browser/playlist.
149 int marked;
153 * @brief Compiled regular expression or string matching data.
155 struct vfsmatch {
157 * @brief Regular expression pattern.
159 regex_t regex;
161 * @brief Original user input.
163 char *string;
167 * @brief Contents of an empty VFS list structure.
169 #define VFSLIST_INITIALIZER { NULL, NULL, 0 }
172 * @brief Run-time initialize a VFS list structure.
174 static inline void
175 vfs_list_init(struct vfslist *vl)
177 vl->first = vl->last = NULL;
178 vl->items = 0;
182 * @brief Move the contents of one list to another.
184 static inline void
185 vfs_list_move(struct vfslist *vdst, const struct vfslist *vsrc)
187 memcpy(vdst, vsrc, sizeof(struct vfslist));
191 * @brief Return the first item in a VFS list.
193 static inline struct vfsref *
194 vfs_list_first(const struct vfslist *vl)
196 return (vl->first);
200 * @brief Return the last item in a VFS list.
202 static inline struct vfsref *
203 vfs_list_last(const struct vfslist *vl)
205 return (vl->last);
209 * @brief Return whether the VFS list is empty or not.
211 static inline int
212 vfs_list_empty(const struct vfslist *vl)
214 return (vl->first == NULL);
218 * @brief Return the amount of items in the VFS list.
220 static inline unsigned int
221 vfs_list_items(const struct vfslist *vl)
223 return (vl->items);
227 * @brief Return the next item in the VFS list.
229 static inline struct vfsref *
230 vfs_list_next(const struct vfsref *vr)
232 return (vr->next);
236 * @brief Return the preivous item in the VFS list.
238 static inline struct vfsref *
239 vfs_list_prev(const struct vfsref *vr)
241 return (vr->prev);
245 * @brief Loop through all items in the VFS list.
247 #define VFS_LIST_FOREACH(vl, vr) \
248 for (vr = vfs_list_first(vl); vr != NULL; vr = vfs_list_next(vr))
250 * @brief Reverse loop through all items in the VFS list.
252 #define VFS_LIST_FOREACH_REVERSE(vl, vr) \
253 for (vr = vfs_list_last(vl); vr != NULL; vr = vfs_list_prev(vr))
256 * @brief Remove the VFS reference from the VFS list.
258 static inline void
259 vfs_list_remove(struct vfslist *vl, struct vfsref *vr)
261 if (vr->next == NULL) {
262 /* Item was the last in the list */
263 g_assert(vl->last == vr);
264 vl->last = vr->prev;
265 } else {
266 /* There is an item after this one */
267 vr->next->prev = vr->prev;
269 if (vr->prev == NULL) {
270 /* Item was the first in the list */
271 g_assert(vl->first == vr);
272 vl->first = vr->next;
273 } else {
274 /* There is an item before this one */
275 vr->prev->next = vr->next;
277 vl->items--;
281 * @brief Insert the VFS reference at the head of the VFS list.
283 static inline void
284 vfs_list_insert_head(struct vfslist *vl, struct vfsref *vr)
286 vr->prev = NULL;
287 vr->next = vl->first;
288 vl->first = vr;
289 if (vr->next != NULL) {
290 /* Item is stored before other ones */
291 vr->next->prev = vr;
292 } else {
293 /* New item is only item in the list */
294 vl->last = vr;
296 vl->items++;
300 * @brief Insert the VFS reference at the tail of the VFS list.
302 static inline void
303 vfs_list_insert_tail(struct vfslist *vl, struct vfsref *vr)
305 vr->prev = vl->last;
306 vr->next = NULL;
307 vl->last = vr;
308 if (vr->prev != NULL) {
309 /* Item is stored after other ones */
310 vr->prev->next = vr;
311 } else {
312 /* New item is only item in the list */
313 vl->first = vr;
315 vl->items++;
319 * @brief Insert the VFS reference before another one in the VFS list.
321 static inline void
322 vfs_list_insert_before(struct vfslist *vl, struct vfsref *nvr,
323 struct vfsref *lvr)
325 nvr->prev = lvr->prev;
326 nvr->next = lvr;
327 lvr->prev = nvr;
328 if (nvr->prev != NULL) {
329 /* Store item between two others */
330 nvr->prev->next = nvr;
331 } else {
332 /* New item is added before the first one */
333 vl->first = nvr;
335 vl->items++;
339 * @brief Insert the VFS reference after another one in the VFS list.
341 static inline void
342 vfs_list_insert_after(struct vfslist *vl, struct vfsref *nvr,
343 struct vfsref *lvr)
345 nvr->prev = lvr;
346 nvr->next = lvr->next;
347 lvr->next = nvr;
348 if (nvr->next != NULL) {
349 /* Store item between two others */
350 nvr->next->prev = nvr;
351 } else {
352 /* New item is added after the first one */
353 vl->last = nvr;
355 vl->items++;
359 * @brief Try to lock the application in a specified directory on
360 * startup. This function returns an error message.
362 const char *vfs_lockup(void);
365 * @brief Create a VFS reference from a filename. The name argument is
366 * optional. It only allows you to display entities with a
367 * different name (inside playlists). When setting the basepath
368 * variable, all relative pathnames are appended to the basepath.
369 * When unset, it can only open absolute filenames. When forcing
370 * strict pathnames, application-implemented features like ~ are
371 * discarded.
373 struct vfsref *vfs_lookup(const char *filename, const char *name,
374 const char *basepath, int strict);
376 * @brief Duplicate the reference by increasing the reference count.
378 struct vfsref *vfs_dup(const struct vfsref *vr);
380 * @brief Decrease the reference count of the entity and deallocate the
381 * entity when no references are left. The reference itself is also
382 * deallocated.
384 void vfs_close(struct vfsref *vr);
386 * @brief Populate the VFS entity with references to its children.
388 int vfs_populate(const struct vfsref *vr);
390 * @brief Recursively expand a VFS reference to all their usable
391 * children and append them to the specified list.
393 void vfs_unfold(struct vfslist *vl, const struct vfsref *vr);
395 * @brief Recursively search through a VFS reference and add all
396 * matching objects to a list. The VFS reference itself will be
397 * excluded from the results.
399 void vfs_locate(struct vfslist *vl, const struct vfsref *vr,
400 const struct vfsmatch *vm);
402 * @brief Write a VFS list to a PLS file on disk.
404 struct vfsref *vfs_write_playlist(const struct vfslist *vl,
405 const struct vfsref *vr, const char *filename);
407 * @brief Delete a local file. Use with caution. ;-)
409 int vfs_delete(const char *filename);
411 * @brief fopen()-like routine that uses VFS path expansion.
413 FILE *vfs_fopen(const char *filename, const char *mode);
415 * @brief fgets()-like routine that performs newline-stripping.
417 int vfs_fgets(char *str, size_t size, FILE *fp);
419 * @brief Initialize the VFS system cache if enabled.
421 void vfs_cache_init(void);
423 * @brief Add entry to the VFS cache.
425 void vfs_cache_add(const struct vfsref *vr);
427 * @brief Obtain entry from the VFS cache.
429 struct vfsref *vfs_cache_lookup(const char *filename);
431 * @brief Purge the VFS cache.
433 void vfs_cache_purge(void);
436 * @brief Get the friendly name of the current VFS reference.
438 static inline const char *
439 vfs_name(const struct vfsref *vr)
441 return (vr->ent->name);
445 * @brief Get the full pathname of the current VFS reference.
447 static inline const char *
448 vfs_filename(const struct vfsref *vr)
450 return (vr->ent->filename);
454 * @brief Determine if a VFS entity is playable audio.
456 static inline int
457 vfs_playable(const struct vfsref *vr)
459 return (vr->ent->vmod->open != NULL);
463 * @brief Open a new filehandle to the entity.
465 static inline FILE *
466 vfs_open(const struct vfsref *vr)
468 return vr->ent->vmod->open(vr->ent);
472 * @brief Determine if the VFS entity can have population.
474 static inline int
475 vfs_populatable(const struct vfsref *vr)
477 return (vr->ent->vmod->populate != NULL);
481 * @brief Get the character that should be used to mark the file with in
482 * the filebrowser.
484 static inline char
485 vfs_marking(const struct vfsref *vr)
487 return (vr->ent->vmod->marking);
491 * @brief Return a pointer to the VFS list inside the VFS reference.
493 static inline const struct vfslist *
494 vfs_population(const struct vfsref *vr)
496 return (&vr->ent->population);
500 * @brief Return whether the current reference is marked.
502 static inline int
503 vfs_marked(const struct vfsref *vr)
505 return (vr->marked != 0);
509 * @brief Mark the current reference.
511 static inline void
512 vfs_mark(struct vfsref *vr)
514 vr->marked = 1;
518 * @brief Unmark the current reference.
520 static inline void
521 vfs_unmark(struct vfsref *vr)
523 vr->marked = 0;
527 * @brief Compile a regular expression for matching.
529 struct vfsmatch *vfs_match_new(const char *str);
531 * @brief Deallocate a compiled regular expression.
533 void vfs_match_free(struct vfsmatch *vm);
536 * @brief Match a VFS reference with a regular expression.
538 static inline int
539 vfs_match_compare(const struct vfsmatch *vm, const char *name)
541 return (regexec(&vm->regex, name, 0, NULL, 0) == 0);
545 * @brief Return the search string that the user has entered.
547 static inline const char *
548 vfs_match_value(const struct vfsmatch *vm)
550 return (vm->string);