Fix compiler warnings ('variable set ut not used') with GCC 4.6.0.
[kugel-rb.git] / uisimulator / common / io.c
blob3212fa50fed639d45606f29d4ea8cd6464e661b5
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 Daniel Stenberg
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdarg.h>
26 #include <sys/stat.h>
27 #include <time.h>
28 #include "config.h"
30 #define HAVE_STATVFS (!defined(WIN32))
31 #define HAVE_LSTAT (!defined(WIN32))
33 #if HAVE_STATVFS
34 #include <sys/statvfs.h>
35 #endif
37 #ifdef WIN32
38 #include <windows.h>
39 #endif
41 #ifndef _MSC_VER
42 #include <dirent.h>
43 #include <unistd.h>
44 #else
45 #include "dir-win32.h"
46 #endif
48 #include <fcntl.h>
49 #ifdef HAVE_SDL_THREADS
50 #include "thread-sdl.h"
51 #else
52 #define sim_thread_unlock() NULL
53 #define sim_thread_lock(a)
54 #endif
55 #include "thread.h"
56 #include "kernel.h"
57 #include "debug.h"
58 #include "ata.h" /* for IF_MV2 et al. */
59 #include "rbpaths.h"
60 #include "load_code.h"
62 /* keep this in sync with file.h! */
63 #undef MAX_PATH /* this avoids problems when building simulator */
64 #define MAX_PATH 260
65 #define MAX_OPEN_FILES 11
67 /* Windows (and potentially other OSes) distinguish binary and text files.
68 * Define a dummy for the others. */
69 #ifndef O_BINARY
70 #define O_BINARY 0
71 #endif
73 /* Unicode compatibility for win32 */
74 #if defined __MINGW32__
75 /* Rockbox unicode functions */
76 extern const unsigned char* utf8decode(const unsigned char *utf8,
77 unsigned short *ucs);
78 extern unsigned char* utf8encode(unsigned long ucs, unsigned char *utf8);
80 /* Static buffers for the conversion results. This isn't thread safe,
81 * but it's sufficient for rockbox. */
82 static unsigned char convbuf1[3*MAX_PATH];
83 static unsigned char convbuf2[3*MAX_PATH];
85 static wchar_t* utf8_to_ucs2(const unsigned char *utf8, void *buffer)
87 wchar_t *ucs = buffer;
89 while (*utf8)
90 utf8 = utf8decode(utf8, ucs++);
92 *ucs = 0;
93 return buffer;
95 static unsigned char *ucs2_to_utf8(const wchar_t *ucs, unsigned char *buffer)
97 unsigned char *utf8 = buffer;
99 while (*ucs)
100 utf8 = utf8encode(*ucs++, utf8);
102 *utf8 = 0;
103 return buffer;
106 #define UTF8_TO_OS(a) utf8_to_ucs2(a,convbuf1)
107 #define OS_TO_UTF8(a) ucs2_to_utf8(a,convbuf1)
108 #define DIR_T _WDIR
109 #define DIRENT_T struct _wdirent
110 #define STAT_T struct _stat
111 extern int _wmkdir(const wchar_t*);
112 extern int _wrmdir(const wchar_t*);
113 #define MKDIR(a,b) (_wmkdir)(UTF8_TO_OS(a))
114 #define RMDIR(a) (_wrmdir)(UTF8_TO_OS(a))
115 #define OPENDIR(a) (_wopendir)(UTF8_TO_OS(a))
116 #define READDIR(a) (_wreaddir)(a)
117 #define CLOSEDIR(a) (_wclosedir)(a)
118 #define STAT(a,b) (_wstat)(UTF8_TO_OS(a),b)
119 /* empty variable parameter list doesn't work for variadic macros,
120 * so pretend the second parameter is variable too */
121 #define OPEN(a,...) (_wopen)(UTF8_TO_OS(a), __VA_ARGS__)
122 #define CLOSE(a) (close)(a)
123 #define REMOVE(a) (_wremove)(UTF8_TO_OS(a))
124 #define RENAME(a,b) (_wrename)(UTF8_TO_OS(a),utf8_to_ucs2(b,convbuf2))
126 #else /* !__MINGW32__ */
128 #define UTF8_TO_OS(a) (a)
129 #define OS_TO_UTF8(a) (a)
130 #define DIR_T DIR
131 #define DIRENT_T struct dirent
132 #define STAT_T struct stat
133 #define MKDIR(a,b) (mkdir)(a,b)
134 #define RMDIR(a) (rmdir)(a)
135 #define OPENDIR(a) (opendir)(a)
136 #define READDIR(a) (readdir)(a)
137 #define CLOSEDIR(a) (closedir)(a)
138 #define STAT(a,b) (stat)(a,b)
139 /* empty variable parameter list doesn't work for variadic macros,
140 * so pretend the second parameter is variable too */
141 #define OPEN(a, ...) (open)(a, __VA_ARGS__)
142 #define CLOSE(x) (close)(x)
143 #define REMOVE(a) (remove)(a)
144 #define RENAME(a,b) (rename)(a,b)
146 #endif /* !__MINGW32__ */
149 #ifdef HAVE_DIRCACHE
150 struct dircache_entry;
151 const struct dircache_entry *dircache_get_entry_ptr(const char *filename);
152 void dircache_add_file(const char *name, long startcluster);
153 void dircache_remove(const char *name);
154 void dircache_rename(const char *oldname, const char *newname);
155 #endif
158 #define SIMULATOR_DEFAULT_ROOT "simdisk"
159 extern const char *sim_root_dir;
161 static int num_openfiles = 0;
163 /* from dir.h */
164 struct dirinfo {
165 int attribute;
166 long size;
167 unsigned short wrtdate;
168 unsigned short wrttime;
171 struct sim_dirent {
172 unsigned char d_name[MAX_PATH];
173 struct dirinfo info;
174 long startcluster;
177 struct dirstruct {
178 void *dir; /* actually a DIR* dir */
179 char *name;
180 } SIM_DIR;
182 struct mydir {
183 DIR_T *dir;
184 char *name;
187 typedef struct mydir MYDIR;
189 static unsigned int rockbox2sim(int opt)
191 #if 0
192 /* this shouldn't be needed since we use the host's versions */
193 int newopt = O_BINARY;
195 if(opt & 1)
196 newopt |= O_WRONLY;
197 if(opt & 2)
198 newopt |= O_RDWR;
199 if(opt & 4)
200 newopt |= O_CREAT;
201 if(opt & 8)
202 newopt |= O_APPEND;
203 if(opt & 0x10)
204 newopt |= O_TRUNC;
206 return newopt;
207 #else
208 return opt|O_BINARY;
209 #endif
212 /** Simulator I/O engine routines **/
213 #define IO_YIELD_THRESHOLD 512
215 enum io_dir
217 IO_READ,
218 IO_WRITE,
221 struct sim_io
223 struct mutex sim_mutex; /* Rockbox mutex */
224 int cmd; /* The command to perform */
225 int ready; /* I/O ready flag - 1= ready */
226 int fd; /* The file to read/write */
227 void *buf; /* The buffer to read/write */
228 size_t count; /* Number of bytes to read/write */
229 size_t accum; /* Acculated bytes transferred */
232 static struct sim_io io;
234 int ata_init(void)
236 /* Initialize the rockbox kernel objects on a rockbox thread */
237 mutex_init(&io.sim_mutex);
238 io.accum = 0;
239 return 1;
242 int ata_spinup_time(void)
244 return HZ;
247 static ssize_t io_trigger_and_wait(enum io_dir cmd)
249 void *mythread = NULL;
250 ssize_t result;
252 if (io.count > IO_YIELD_THRESHOLD ||
253 (io.accum += io.count) >= IO_YIELD_THRESHOLD)
255 /* Allow other rockbox threads to run */
256 io.accum = 0;
257 mythread = sim_thread_unlock();
260 switch (cmd)
262 case IO_READ:
263 result = read(io.fd, io.buf, io.count);
264 break;
265 case IO_WRITE:
266 result = write(io.fd, io.buf, io.count);
267 break;
268 /* shut up gcc */
269 default:
270 result = -1;
273 /* Regain our status as current */
274 if (mythread != NULL)
276 sim_thread_lock(mythread);
279 return result;
282 #if !defined(__PCTOOL__) && !defined(APPLICATION)
283 static const char *get_sim_pathname(const char *name)
285 static char buffer[MAX_PATH]; /* sufficiently big */
287 if(name[0] == '/')
289 snprintf(buffer, sizeof(buffer), "%s%s",
290 sim_root_dir != NULL ? sim_root_dir : SIMULATOR_DEFAULT_ROOT, name);
291 return buffer;
293 fprintf(stderr, "WARNING, bad file name lacks slash: %s\n", name);
294 return name;
296 #else
297 #define get_sim_pathname(name) name
298 #endif
300 MYDIR *sim_opendir(const char *name)
302 DIR_T *dir;
303 dir = (DIR_T *) OPENDIR(get_sim_pathname(name));
305 if (dir)
307 MYDIR *my = (MYDIR *)malloc(sizeof(MYDIR));
308 my->dir = dir;
309 my->name = (char *)malloc(strlen(name)+1);
310 strcpy(my->name, name);
312 return my;
314 /* failed open, return NULL */
315 return (MYDIR *)0;
318 #if defined(WIN32)
319 static inline struct tm* localtime_r (const time_t *clock, struct tm *result) {
320 if (!clock || !result) return NULL;
321 memcpy(result,localtime(clock),sizeof(*result));
322 return result;
324 #endif
326 struct sim_dirent *sim_readdir(MYDIR *dir)
328 char buffer[MAX_PATH]; /* sufficiently big */
329 static struct sim_dirent secret;
330 STAT_T s;
331 DIRENT_T *x11 = READDIR(dir->dir);
332 struct tm tm;
334 if(!x11)
335 return (struct sim_dirent *)0;
337 strcpy((char *)secret.d_name, OS_TO_UTF8(x11->d_name));
339 /* build file name */
340 snprintf(buffer, sizeof(buffer), "%s/%s",
341 get_sim_pathname(dir->name), secret.d_name);
342 if (STAT(buffer, &s)) /* get info */
343 return NULL;
345 #define ATTR_DIRECTORY 0x10
347 secret.info.attribute = 0;
349 if (S_ISDIR(s.st_mode))
350 secret.info.attribute = ATTR_DIRECTORY;
352 secret.info.size = s.st_size;
354 if (localtime_r(&(s.st_mtime), &tm) == NULL)
355 return NULL;
356 secret.info.wrtdate = ((tm.tm_year - 80) << 9) |
357 ((tm.tm_mon + 1) << 5) |
358 tm.tm_mday;
359 secret.info.wrttime = (tm.tm_hour << 11) |
360 (tm.tm_min << 5) |
361 (tm.tm_sec >> 1);
363 #if HAVE_LSTAT
364 #define ATTR_LINK 0x80
365 if (!lstat(buffer, &s) && S_ISLNK(s.st_mode))
367 secret.info.attribute |= ATTR_LINK;
369 #endif
371 return &secret;
374 void sim_closedir(MYDIR *dir)
376 free(dir->name);
377 CLOSEDIR(dir->dir);
379 free(dir);
382 int sim_open(const char *name, int o, ...)
384 int opts = rockbox2sim(o);
385 int ret;
386 if (num_openfiles >= MAX_OPEN_FILES)
387 return -2;
389 if (opts & O_CREAT)
391 va_list ap;
392 va_start(ap, o);
393 mode_t mode = va_arg(ap, unsigned int);
394 ret = OPEN(get_sim_pathname(name), opts, mode);
395 #ifdef HAVE_DIRCACHE
396 if (ret >= 0 && !dircache_get_entry_ptr(name))
397 dircache_add_file(name, 0);
398 #endif
399 va_end(ap);
401 else
402 ret = OPEN(get_sim_pathname(name), opts);
404 if (ret >= 0)
405 num_openfiles++;
406 return ret;
409 int sim_close(int fd)
411 int ret;
412 ret = CLOSE(fd);
413 if (ret == 0)
414 num_openfiles--;
415 return ret;
418 int sim_creat(const char *name, mode_t mode)
420 int ret = OPEN(get_sim_pathname(name),
421 O_BINARY | O_WRONLY | O_CREAT | O_TRUNC, mode);
422 #ifdef HAVE_DIRCACHE
423 if (ret >= 0 && !dircache_get_entry_ptr(name))
424 dircache_add_file(name, 0);
425 #endif
426 return ret;
429 ssize_t sim_read(int fd, void *buf, size_t count)
431 ssize_t result;
433 mutex_lock(&io.sim_mutex);
435 /* Setup parameters */
436 io.fd = fd;
437 io.buf = buf;
438 io.count = count;
440 result = io_trigger_and_wait(IO_READ);
442 mutex_unlock(&io.sim_mutex);
444 return result;
447 ssize_t sim_write(int fd, const void *buf, size_t count)
449 ssize_t result;
451 mutex_lock(&io.sim_mutex);
453 io.fd = fd;
454 io.buf = (void*)buf;
455 io.count = count;
457 result = io_trigger_and_wait(IO_WRITE);
459 mutex_unlock(&io.sim_mutex);
461 return result;
464 int sim_mkdir(const char *name)
466 return MKDIR(get_sim_pathname(name), 0777);
469 int sim_rmdir(const char *name)
471 return RMDIR(get_sim_pathname(name));
474 int sim_remove(const char *name)
476 int ret = REMOVE(get_sim_pathname(name));
477 #ifdef HAVE_DIRCACHE
478 if (ret >= 0)
479 dircache_remove(name);
480 #endif
481 return ret;
484 int sim_rename(const char *oldname, const char *newname)
486 char sim_old[MAX_PATH];
487 char sim_new[MAX_PATH];
488 #ifdef HAVE_DIRCACHE
489 dircache_rename(oldname, newname);
490 #endif
491 // This is needed as get_sim_pathname() has a static buffer
492 strncpy(sim_old, get_sim_pathname(oldname), MAX_PATH);
493 strncpy(sim_new, get_sim_pathname(newname), MAX_PATH);
494 return RENAME(sim_old, sim_new);
497 /* rockbox off_t may be different from system off_t */
498 long sim_lseek(int fildes, long offset, int whence)
500 return lseek(fildes, offset, whence);
503 long sim_filesize(int fd)
505 #ifdef WIN32
506 return _filelength(fd);
507 #else
508 struct stat buf;
510 if (!fstat(fd, &buf))
511 return buf.st_size;
512 else
513 return -1;
514 #endif
517 void fat_size(IF_MV2(int volume,) unsigned long* size, unsigned long* free)
519 #ifdef HAVE_MULTIVOLUME
520 if (volume != 0) {
521 /* debugf("io.c: fat_size(volume=%d); simulator only supports volume 0\n",volume); */
523 if (size) *size = 0;
524 if (free) *free = 0;
525 return;
527 #endif
529 #ifdef WIN32
530 long secperclus, bytespersec, free_clusters, num_clusters;
532 if (GetDiskFreeSpace(NULL, &secperclus, &bytespersec, &free_clusters,
533 &num_clusters)) {
534 if (size)
535 *size = num_clusters * secperclus / 2 * (bytespersec / 512);
536 if (free)
537 *free = free_clusters * secperclus / 2 * (bytespersec / 512);
539 #elif HAVE_STATVFS
540 struct statvfs vfs;
542 if (!statvfs(".", &vfs)) {
543 DEBUGF("statvfs: frsize=%d blocks=%ld free=%ld\n",
544 (int)vfs.f_frsize, (long)vfs.f_blocks, (long)vfs.f_bfree);
545 if (size)
546 *size = vfs.f_blocks / 2 * (vfs.f_frsize / 512);
547 if (free)
548 *free = vfs.f_bfree / 2 * (vfs.f_frsize / 512);
549 } else
550 #endif
552 if (size)
553 *size = 0;
554 if (free)
555 *free = 0;
559 int sim_fsync(int fd)
561 #ifdef WIN32
562 return _commit(fd);
563 #else
564 return fsync(fd);
565 #endif
568 #ifndef __PCTOOL__
570 void *lc_open(const char *filename, unsigned char *buf, size_t buf_size)
572 const char *sim_path = get_sim_pathname(filename);
573 void *handle = _lc_open(UTF8_TO_OS(sim_path), buf, buf_size);
575 if (handle == NULL)
577 DEBUGF("failed to load %s\n", filename);
578 DEBUGF("lc_open(%s): %s\n", filename, lc_last_error());
580 return handle;
583 void *lc_get_header(void *handle)
585 return _lc_get_header(handle);
588 void lc_close(void *handle)
590 _lc_close(handle);
593 #endif /* __PCTOOL__ */
594 #ifdef WIN32
595 static unsigned old_cp;
597 void debug_exit(void)
599 /* Reset console output codepage */
600 SetConsoleOutputCP(old_cp);
603 void debug_init(void)
605 old_cp = GetConsoleOutputCP();
606 /* Set console output codepage to UTF8. Only works
607 * correctly when the console uses a truetype font. */
608 SetConsoleOutputCP(65001);
609 atexit(debug_exit);
611 #else
612 void debug_init(void)
614 /* nothing to be done */
616 #endif
618 void debugf(const char *fmt, ...)
620 va_list ap;
621 va_start( ap, fmt );
622 vfprintf( stderr, fmt, ap );
623 va_end( ap );
626 void ldebugf(const char* file, int line, const char *fmt, ...)
628 va_list ap;
629 va_start( ap, fmt );
630 fprintf( stderr, "%s:%d ", file, line );
631 vfprintf( stderr, fmt, ap );
632 va_end( ap );
635 /* rockbox off_t may be different from system off_t */
636 int sim_ftruncate(int fd, long length)
638 #ifdef WIN32
639 return _chsize(fd, length);
640 #else
641 return ftruncate(fd, length);
642 #endif