2 * Copyright (c) 2006-2011 Ed Schouten <ed@80386.nl>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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
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.
42 * @brief List structure that can contain a lot of VFS references.
46 * @brief First item in the list.
50 * @brief Last item in the list.
54 * @brief The number of items in the list.
60 * @brief Module representing a type of file or directory on disk, containing
61 * functions to read its contents (populate it).
65 * @brief Attach the VFS module to a VFS entity
67 int (*match
)(struct vfsent
*ve
, int isdir
);
69 * @brief Populate the VFS entity with its childs
71 int (*populate
)(struct vfsent
*ve
);
73 * @brief Return a FILE* to the file on disk
75 FILE *(*open
)(struct vfsent
*ve
);
78 * @brief Does not need an on-disk file
83 * @brief Order in which files should be sorted in vfs_dir
85 unsigned char sortorder
;
88 * @brief Charachter placed behind the character marking the filetype
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.
101 * @brief The name of the current object (the basename)
105 * @brief The complete filename of the object (realpath)
110 * @brief The reference count of the current object, used to determine
111 * whether it should be deallocated.
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
130 * @brief Reference to a VFS entity including list pointers.
134 * @brief Pointer to the VFS entity.
138 * @brief Pointer to the next item in the VFS list.
142 * @brief Pointer to the previous item in the VFS list.
146 * @brief Indicator that this reference should be drawn in a
147 * different color in the browser/playlist.
153 * @brief Compiled regular expression or string matching data.
157 * @brief Regular expression pattern.
161 * @brief Original user input.
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.
175 vfs_list_init(struct vfslist
*vl
)
177 vl
->first
= vl
->last
= NULL
;
182 * @brief Move the contents of one list to another.
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
)
200 * @brief Return the last item in a VFS list.
202 static inline struct vfsref
*
203 vfs_list_last(const struct vfslist
*vl
)
209 * @brief Return whether the VFS list is empty or not.
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
)
227 * @brief Return the next item in the VFS list.
229 static inline struct vfsref
*
230 vfs_list_next(const struct vfsref
*vr
)
236 * @brief Return the preivous item in the VFS list.
238 static inline struct vfsref
*
239 vfs_list_prev(const struct vfsref
*vr
)
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.
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
);
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
;
274 /* There is an item before this one */
275 vr
->prev
->next
= vr
->next
;
281 * @brief Insert the VFS reference at the head of the VFS list.
284 vfs_list_insert_head(struct vfslist
*vl
, struct vfsref
*vr
)
287 vr
->next
= vl
->first
;
289 if (vr
->next
!= NULL
) {
290 /* Item is stored before other ones */
293 /* New item is only item in the list */
300 * @brief Insert the VFS reference at the tail of the VFS list.
303 vfs_list_insert_tail(struct vfslist
*vl
, struct vfsref
*vr
)
308 if (vr
->prev
!= NULL
) {
309 /* Item is stored after other ones */
312 /* New item is only item in the list */
319 * @brief Insert the VFS reference before another one in the VFS list.
322 vfs_list_insert_before(struct vfslist
*vl
, struct vfsref
*nvr
,
325 nvr
->prev
= lvr
->prev
;
328 if (nvr
->prev
!= NULL
) {
329 /* Store item between two others */
330 nvr
->prev
->next
= nvr
;
332 /* New item is added before the first one */
339 * @brief Insert the VFS reference after another one in the VFS list.
342 vfs_list_insert_after(struct vfslist
*vl
, struct vfsref
*nvr
,
346 nvr
->next
= lvr
->next
;
348 if (nvr
->next
!= NULL
) {
349 /* Store item between two others */
350 nvr
->next
->prev
= nvr
;
352 /* New item is added after the first one */
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
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
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.
457 vfs_playable(const struct vfsref
*vr
)
459 return (vr
->ent
->vmod
->open
!= NULL
);
463 * @brief Open a new filehandle to the entity.
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.
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
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.
503 vfs_marked(const struct vfsref
*vr
)
505 return (vr
->marked
!= 0);
509 * @brief Mark the current reference.
512 vfs_mark(struct vfsref
*vr
)
518 * @brief Unmark the current reference.
521 vfs_unmark(struct vfsref
*vr
)
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.
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
)