Manual: Correct clip/clip+ pitchscreen button table. Closes FS#11671.
[maemo-rb.git] / uisimulator / common / io.c
blob3591905e32fa3cdb1e93baaf143be069d4d24d4f
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))
32 #if HAVE_STATVFS
33 #include <sys/statvfs.h>
34 #endif
36 #ifdef WIN32
37 #include <windows.h>
38 #endif
40 #ifndef _MSC_VER
41 #include <dirent.h>
42 #include <unistd.h>
43 #else
44 #include "dir-win32.h"
45 #endif
47 #include <fcntl.h>
48 #include <SDL.h>
49 #include <SDL_thread.h>
50 #include "thread-sdl.h"
51 #include "thread.h"
52 #include "kernel.h"
53 #include "debug.h"
54 #include "ata.h" /* for IF_MV2 et al. */
55 #include "rbpaths.h"
56 #include "load_code.h"
58 /* keep this in sync with file.h! */
59 #undef MAX_PATH /* this avoids problems when building simulator */
60 #define MAX_PATH 260
61 #define MAX_OPEN_FILES 11
63 /* Windows (and potentially other OSes) distinguish binary and text files.
64 * Define a dummy for the others. */
65 #ifndef O_BINARY
66 #define O_BINARY 0
67 #endif
69 /* Unicode compatibility for win32 */
70 #if defined __MINGW32__
71 /* Rockbox unicode functions */
72 extern const unsigned char* utf8decode(const unsigned char *utf8,
73 unsigned short *ucs);
74 extern unsigned char* utf8encode(unsigned long ucs, unsigned char *utf8);
76 /* Static buffers for the conversion results. This isn't thread safe,
77 * but it's sufficient for rockbox. */
78 static unsigned char convbuf1[3*MAX_PATH];
79 static unsigned char convbuf2[3*MAX_PATH];
81 static wchar_t* utf8_to_ucs2(const unsigned char *utf8, void *buffer)
83 wchar_t *ucs = buffer;
85 while (*utf8)
86 utf8 = utf8decode(utf8, ucs++);
88 *ucs = 0;
89 return buffer;
91 static unsigned char *ucs2_to_utf8(const wchar_t *ucs, unsigned char *buffer)
93 unsigned char *utf8 = buffer;
95 while (*ucs)
96 utf8 = utf8encode(*ucs++, utf8);
98 *utf8 = 0;
99 return buffer;
102 #define UTF8_TO_OS(a) utf8_to_ucs2(a,convbuf1)
103 #define OS_TO_UTF8(a) ucs2_to_utf8(a,convbuf1)
104 #define DIR_T _WDIR
105 #define DIRENT_T struct _wdirent
106 #define STAT_T struct _stat
107 extern int _wmkdir(const wchar_t*);
108 extern int _wrmdir(const wchar_t*);
109 #define MKDIR(a,b) (_wmkdir)(UTF8_TO_OS(a))
110 #define RMDIR(a) (_wrmdir)(UTF8_TO_OS(a))
111 #define OPENDIR(a) (_wopendir)(UTF8_TO_OS(a))
112 #define READDIR(a) (_wreaddir)(a)
113 #define CLOSEDIR(a) (_wclosedir)(a)
114 #define STAT(a,b) (_wstat)(UTF8_TO_OS(a),b)
115 /* empty variable parameter list doesn't work for variadic macros,
116 * so pretend the second parameter is variable too */
117 #define OPEN(a,...) (_wopen)(UTF8_TO_OS(a), __VA_ARGS__)
118 #define CLOSE(a) (close)(a)
119 #define REMOVE(a) (_wremove)(UTF8_TO_OS(a))
120 #define RENAME(a,b) (_wrename)(UTF8_TO_OS(a),utf8_to_ucs2(b,convbuf2))
122 #else /* !__MINGW32__ */
124 #define UTF8_TO_OS(a) (a)
125 #define OS_TO_UTF8(a) (a)
126 #define DIR_T DIR
127 #define DIRENT_T struct dirent
128 #define STAT_T struct stat
129 #define MKDIR(a,b) (mkdir)(a,b)
130 #define RMDIR(a) (rmdir)(a)
131 #define OPENDIR(a) (opendir)(a)
132 #define READDIR(a) (readdir)(a)
133 #define CLOSEDIR(a) (closedir)(a)
134 #define STAT(a,b) (stat)(a,b)
135 /* empty variable parameter list doesn't work for variadic macros,
136 * so pretend the second parameter is variable too */
137 #define OPEN(a, ...) (open)(a, __VA_ARGS__)
138 #define CLOSE(x) (close)(x)
139 #define REMOVE(a) (remove)(a)
140 #define RENAME(a,b) (rename)(a,b)
142 #endif /* !__MINGW32__ */
145 #ifdef HAVE_DIRCACHE
146 void dircache_remove(const char *name);
147 void dircache_rename(const char *oldname, const char *newname);
148 #endif
151 #define SIMULATOR_DEFAULT_ROOT "simdisk"
152 extern const char *sim_root_dir;
154 static int num_openfiles = 0;
156 /* from dir.h */
157 struct dirinfo {
158 int attribute;
159 long size;
160 unsigned short wrtdate;
161 unsigned short wrttime;
164 struct sim_dirent {
165 unsigned char d_name[MAX_PATH];
166 struct dirinfo info;
167 long startcluster;
170 struct dirstruct {
171 void *dir; /* actually a DIR* dir */
172 char *name;
173 } SIM_DIR;
175 struct mydir {
176 DIR_T *dir;
177 char *name;
180 typedef struct mydir MYDIR;
182 static unsigned int rockbox2sim(int opt)
184 #if 0
185 /* this shouldn't be needed since we use the host's versions */
186 int newopt = O_BINARY;
188 if(opt & 1)
189 newopt |= O_WRONLY;
190 if(opt & 2)
191 newopt |= O_RDWR;
192 if(opt & 4)
193 newopt |= O_CREAT;
194 if(opt & 8)
195 newopt |= O_APPEND;
196 if(opt & 0x10)
197 newopt |= O_TRUNC;
199 return newopt;
200 #else
201 return opt|O_BINARY;
202 #endif
205 /** Simulator I/O engine routines **/
206 #define IO_YIELD_THRESHOLD 512
208 enum io_dir
210 IO_READ,
211 IO_WRITE,
214 struct sim_io
216 struct mutex sim_mutex; /* Rockbox mutex */
217 int cmd; /* The command to perform */
218 int ready; /* I/O ready flag - 1= ready */
219 int fd; /* The file to read/write */
220 void *buf; /* The buffer to read/write */
221 size_t count; /* Number of bytes to read/write */
222 size_t accum; /* Acculated bytes transferred */
225 static struct sim_io io;
227 int ata_init(void)
229 /* Initialize the rockbox kernel objects on a rockbox thread */
230 mutex_init(&io.sim_mutex);
231 io.accum = 0;
232 return 1;
235 int ata_spinup_time(void)
237 return HZ;
240 static ssize_t io_trigger_and_wait(enum io_dir cmd)
242 void *mythread = NULL;
243 ssize_t result;
245 if (io.count > IO_YIELD_THRESHOLD ||
246 (io.accum += io.count) >= IO_YIELD_THRESHOLD)
248 /* Allow other rockbox threads to run */
249 io.accum = 0;
250 mythread = sim_thread_unlock();
253 switch (cmd)
255 case IO_READ:
256 result = read(io.fd, io.buf, io.count);
257 break;
258 case IO_WRITE:
259 result = write(io.fd, io.buf, io.count);
260 break;
261 /* shut up gcc */
262 default:
263 result = -1;
266 /* Regain our status as current */
267 if (mythread != NULL)
269 sim_thread_lock(mythread);
272 return result;
275 #if !defined(__PCTOOL__) && !defined(APPLICATION)
276 static const char *get_sim_pathname(const char *name)
278 static char buffer[MAX_PATH]; /* sufficiently big */
280 if(name[0] == '/')
282 snprintf(buffer, sizeof(buffer), "%s%s",
283 sim_root_dir != NULL ? sim_root_dir : SIMULATOR_DEFAULT_ROOT, name);
284 return buffer;
286 fprintf(stderr, "WARNING, bad file name lacks slash: %s\n", name);
287 return name;
289 #else
290 #define get_sim_pathname(name) name
291 #endif
293 MYDIR *sim_opendir(const char *name)
295 DIR_T *dir;
297 dir = (DIR_T *) OPENDIR(get_sim_pathname(name));
299 if (dir)
301 MYDIR *my = (MYDIR *)malloc(sizeof(MYDIR));
302 my->dir = dir;
303 my->name = (char *)malloc(strlen(name)+1);
304 strcpy(my->name, name);
306 return my;
308 /* failed open, return NULL */
309 return (MYDIR *)0;
312 struct sim_dirent *sim_readdir(MYDIR *dir)
314 char buffer[MAX_PATH]; /* sufficiently big */
315 static struct sim_dirent secret;
316 STAT_T s;
317 DIRENT_T *x11 = READDIR(dir->dir);
318 struct tm* tm;
320 if(!x11)
321 return (struct sim_dirent *)0;
323 strcpy((char *)secret.d_name, OS_TO_UTF8(x11->d_name));
325 /* build file name */
326 snprintf(buffer, sizeof(buffer), "%s/%s",
327 get_sim_pathname(dir->name), secret.d_name);
328 STAT(buffer, &s); /* get info */
330 #define ATTR_DIRECTORY 0x10
332 secret.info.attribute = S_ISDIR(s.st_mode)?ATTR_DIRECTORY:0;
333 secret.info.size = s.st_size;
335 tm = localtime(&(s.st_mtime));
336 secret.info.wrtdate = ((tm->tm_year - 80) << 9) |
337 ((tm->tm_mon + 1) << 5) |
338 tm->tm_mday;
339 secret.info.wrttime = (tm->tm_hour << 11) |
340 (tm->tm_min << 5) |
341 (tm->tm_sec >> 1);
342 return &secret;
345 void sim_closedir(MYDIR *dir)
347 free(dir->name);
348 CLOSEDIR(dir->dir);
350 free(dir);
353 int sim_open(const char *name, int o, ...)
355 int opts = rockbox2sim(o);
356 int ret;
357 if (num_openfiles >= MAX_OPEN_FILES)
358 return -2;
360 if (opts & O_CREAT)
362 va_list ap;
363 va_start(ap, o);
364 mode_t mode = va_arg(ap, unsigned int);
365 ret = OPEN(get_sim_pathname(name), opts, mode);
366 va_end(ap);
368 else
369 ret = OPEN(get_sim_pathname(name), opts);
371 if (ret >= 0)
372 num_openfiles++;
373 return ret;
376 int sim_close(int fd)
378 int ret;
379 ret = CLOSE(fd);
380 if (ret == 0)
381 num_openfiles--;
382 return ret;
385 int sim_creat(const char *name, mode_t mode)
387 return OPEN(get_sim_pathname(name), O_BINARY | O_WRONLY | O_CREAT | O_TRUNC, mode);
390 ssize_t sim_read(int fd, void *buf, size_t count)
392 ssize_t result;
394 mutex_lock(&io.sim_mutex);
396 /* Setup parameters */
397 io.fd = fd;
398 io.buf = buf;
399 io.count = count;
401 result = io_trigger_and_wait(IO_READ);
403 mutex_unlock(&io.sim_mutex);
405 return result;
408 ssize_t sim_write(int fd, const void *buf, size_t count)
410 ssize_t result;
412 mutex_lock(&io.sim_mutex);
414 io.fd = fd;
415 io.buf = (void*)buf;
416 io.count = count;
418 result = io_trigger_and_wait(IO_WRITE);
420 mutex_unlock(&io.sim_mutex);
422 return result;
425 int sim_mkdir(const char *name)
427 return MKDIR(get_sim_pathname(name), 0777);
430 int sim_rmdir(const char *name)
432 return RMDIR(get_sim_pathname(name));
435 int sim_remove(const char *name)
437 #ifdef HAVE_DIRCACHE
438 dircache_remove(name);
439 #endif
440 return REMOVE(get_sim_pathname(name));
443 int sim_rename(const char *oldname, const char *newname)
445 char sim_old[MAX_PATH];
446 char sim_new[MAX_PATH];
447 #ifdef HAVE_DIRCACHE
448 dircache_rename(oldname, newname);
449 #endif
450 // This is needed as get_sim_pathname() has a static buffer
451 strncpy(sim_old, get_sim_pathname(oldname), MAX_PATH);
452 strncpy(sim_new, get_sim_pathname(newname), MAX_PATH);
453 return RENAME(sim_old, sim_new);
456 /* rockbox off_t may be different from system off_t */
457 long sim_lseek(int fildes, long offset, int whence)
459 return lseek(fildes, offset, whence);
462 long sim_filesize(int fd)
464 #ifdef WIN32
465 return _filelength(fd);
466 #else
467 struct stat buf;
469 if (!fstat(fd, &buf))
470 return buf.st_size;
471 else
472 return -1;
473 #endif
476 void fat_size(IF_MV2(int volume,) unsigned long* size, unsigned long* free)
478 #ifdef HAVE_MULTIVOLUME
479 if (volume != 0) {
480 /* debugf("io.c: fat_size(volume=%d); simulator only supports volume 0\n",volume); */
482 if (size) *size = 0;
483 if (free) *free = 0;
484 return;
486 #endif
488 #ifdef WIN32
489 long secperclus, bytespersec, free_clusters, num_clusters;
491 if (GetDiskFreeSpace(NULL, &secperclus, &bytespersec, &free_clusters,
492 &num_clusters)) {
493 if (size)
494 *size = num_clusters * secperclus / 2 * (bytespersec / 512);
495 if (free)
496 *free = free_clusters * secperclus / 2 * (bytespersec / 512);
498 #elif HAVE_STATVFS
499 struct statvfs vfs;
501 if (!statvfs(".", &vfs)) {
502 DEBUGF("statvfs: frsize=%d blocks=%ld free=%ld\n",
503 (int)vfs.f_frsize, (long)vfs.f_blocks, (long)vfs.f_bfree);
504 if (size)
505 *size = vfs.f_blocks / 2 * (vfs.f_frsize / 512);
506 if (free)
507 *free = vfs.f_bfree / 2 * (vfs.f_frsize / 512);
508 } else
509 #endif
511 if (size)
512 *size = 0;
513 if (free)
514 *free = 0;
518 int sim_fsync(int fd)
520 #ifdef WIN32
521 return _commit(fd);
522 #else
523 return fsync(fd);
524 #endif
527 #ifndef __PCTOOL__
529 void *lc_open(const char *filename, unsigned char *buf, size_t buf_size)
531 const char *sim_path = get_sim_pathname(filename);
532 void *handle = _lc_open(UTF8_TO_OS(sim_path), buf, buf_size);
534 if (handle == NULL)
536 DEBUGF("failed to load %s\n", filename);
537 DEBUGF("lc_open(%s): %s\n", filename, lc_last_error());
539 return handle;
542 void *lc_get_header(void *handle)
544 return _lc_get_header(handle);
547 void lc_close(void *handle)
549 _lc_close(handle);
552 #endif /* __PCTOOL__ */
553 #ifdef WIN32
554 static unsigned old_cp;
556 void debug_exit(void)
558 /* Reset console output codepage */
559 SetConsoleOutputCP(old_cp);
562 void debug_init(void)
564 old_cp = GetConsoleOutputCP();
565 /* Set console output codepage to UTF8. Only works
566 * correctly when the console uses a truetype font. */
567 SetConsoleOutputCP(65001);
568 atexit(debug_exit);
570 #else
571 void debug_init(void)
573 /* nothing to be done */
575 #endif
577 void debugf(const char *fmt, ...)
579 va_list ap;
580 va_start( ap, fmt );
581 vfprintf( stderr, fmt, ap );
582 va_end( ap );
585 void ldebugf(const char* file, int line, const char *fmt, ...)
587 va_list ap;
588 va_start( ap, fmt );
589 fprintf( stderr, "%s:%d ", file, line );
590 vfprintf( stderr, fmt, ap );
591 va_end( ap );
594 /* rockbox off_t may be different from system off_t */
595 int sim_ftruncate(int fd, long length)
597 #ifdef WIN32
598 return _chsize(fd, length);
599 #else
600 return ftruncate(fd, length);
601 #endif