2 * Copyright (C) 2003-2010 Neverball authors
4 * NEVERBALL is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published
6 * by the Free Software Foundation; either version 2 of the License,
7 * or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
26 * This file implements the high-level virtual file system layer
30 /*---------------------------------------------------------------------------*/
32 static int cmp_dir_items(const void *A, const void *B)
34 const struct dir_item *a = A, *b = B;
35 return strcmp(a->path, b->path);
38 static int is_archive(struct dir_item *item)
40 return strcmp(item->path + strlen(item->path) - 4, ".zip") == 0;
43 static void add_archives(const char *path)
48 if ((archives = dir_scan(path, is_archive, NULL, NULL)))
50 array_sort(archives, cmp_dir_items);
52 for (i = 0; i < array_len(archives); i++)
53 fs_add_path(DIR_ITEM_GET(archives, i)->path);
59 int fs_add_path_with_archives(const char *path)
62 return fs_add_path(path);
65 /*---------------------------------------------------------------------------*/
67 int fs_rename(const char *src, const char *dst)
69 const char *write_dir;
70 char *real_src, *real_dst;
73 if ((write_dir = fs_get_write_dir()))
75 real_src = concat_string(write_dir, "/", src, NULL);
76 real_dst = concat_string(write_dir, "/", dst, NULL);
78 rc = file_rename(real_src, real_dst);
87 /*---------------------------------------------------------------------------*/
89 int fs_getc(fs_file fh)
93 if (fs_read(&c, 1, 1, fh) != 1)
99 int fs_putc(int c, fs_file fh)
101 unsigned char b = (unsigned char) c;
103 if (fs_write(&b, 1, 1, fh) != 1)
109 int fs_puts(const char *src, fs_file fh)
112 if (fs_putc(*src++, fh) < 0)
118 char *fs_gets(char *dst, int count, fs_file fh)
130 if ((c = fs_getc(fh)) >= 0)
136 /* Keep a newline and break. */
144 /* Ignore carriage returns. */
164 /*---------------------------------------------------------------------------*/
167 * Write out a multiline string to a file with appropriately converted
168 * linefeed characters.
170 static int write_lines(const char *start, int length, fs_file fh)
173 static const char crlf[] = "\r\n";
175 static const char crlf[] = "\n";
178 int total_written = 0;
184 while (total_written < length)
186 lf = strchr(start, '\n');
188 datalen = lf ? (int) (lf - start) : length - total_written;
189 written = fs_write(start, 1, datalen, fh);
194 total_written += written;
196 if (written < datalen)
201 if (fs_puts(crlf, fh) < 0)
209 return total_written;
212 /*---------------------------------------------------------------------------*/
215 * Trying to avoid defining a feature test macro for every platform by
216 * declaring vsnprintf with the C99 signature. This is probably bad.
222 extern int vsnprintf(char *, size_t, const char *, va_list);
225 int fs_printf(fs_file fh, const char *fmt, ...)
233 len = vsnprintf(NULL, 0, fmt, ap) + 1;
236 if ((buff = malloc(len)))
241 vsnprintf(buff, len, fmt, ap);
245 * HACK. This assumes fs_printf is always called with the
246 * intention of writing text, and not arbitrary data.
249 written = write_lines(buff, strlen(buff), fh);
259 /*---------------------------------------------------------------------------*/
261 void *fs_load(const char *path, int *datalen)
268 if ((fh = fs_open(path, "r")))
270 if ((*datalen = fs_length(fh)) > 0)
272 if ((data = malloc(*datalen)))
274 if (fs_read(data, *datalen, 1, fh) != 1)
289 /*---------------------------------------------------------------------------*/
291 const char *fs_resolve(const char *path)
296 /* Chop off directories until we have a match. */
298 while ((path = path_next_sep(path)))
300 /* Skip separator. */
311 /*---------------------------------------------------------------------------*/