Mark const return value; correct the comment about valid menu items for the hotkey
[kugel-rb.git] / uisimulator / common / io.c
blob20f5a368f4e4383aa7b2f488e06efcc787f592eb
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 #ifndef WIN32
29 #include <sys/statvfs.h>
30 #endif
32 #ifdef WIN32
33 #include <windows.h>
34 #endif
36 #ifndef _MSC_VER
37 #include <dirent.h>
38 #include <unistd.h>
39 #else
40 #include "dir-win32.h"
41 #endif
43 #define MAX_PATH 260
44 #define MAX_OPEN_FILES 11
46 #include <fcntl.h>
47 #include <SDL.h>
48 #include <SDL_thread.h>
49 #include "thread.h"
50 #include "kernel.h"
51 #include "debug.h"
52 #include "config.h"
53 #include "ata.h" /* for IF_MV2 et al. */
54 #include "thread-sdl.h"
57 /* Windows (and potentially other OSes) distinguish binary and text files.
58 * Define a dummy for the others. */
59 #ifndef O_BINARY
60 #define O_BINARY 0
61 #endif
63 /* Unicode compatibility for win32 */
64 #if defined __MINGW32__
65 /* Rockbox unicode functions */
66 extern const unsigned char* utf8decode(const unsigned char *utf8,
67 unsigned short *ucs);
68 extern unsigned char* utf8encode(unsigned long ucs, unsigned char *utf8);
70 /* Static buffers for the conversion results. This isn't thread safe,
71 * but it's sufficient for rockbox. */
72 static unsigned char convbuf1[3*MAX_PATH];
73 static unsigned char convbuf2[3*MAX_PATH];
75 static wchar_t* utf8_to_ucs2(const unsigned char *utf8, void *buffer)
77 wchar_t *ucs = buffer;
79 while (*utf8)
80 utf8 = utf8decode(utf8, ucs++);
82 *ucs = 0;
83 return buffer;
85 static unsigned char *ucs2_to_utf8(const wchar_t *ucs, unsigned char *buffer)
87 unsigned char *utf8 = buffer;
89 while (*ucs)
90 utf8 = utf8encode(*ucs++, utf8);
92 *utf8 = 0;
93 return buffer;
96 #define UTF8_TO_OS(a) utf8_to_ucs2(a,convbuf1)
97 #define OS_TO_UTF8(a) ucs2_to_utf8(a,convbuf1)
98 #define DIR_T _WDIR
99 #define DIRENT_T struct _wdirent
100 #define STAT_T struct _stat
101 extern int _wmkdir(const wchar_t*);
102 extern int _wrmdir(const wchar_t*);
103 #define MKDIR(a,b) (_wmkdir)(UTF8_TO_OS(a))
104 #define RMDIR(a) (_wrmdir)(UTF8_TO_OS(a))
105 #define OPENDIR(a) (_wopendir)(UTF8_TO_OS(a))
106 #define READDIR(a) (_wreaddir)(a)
107 #define CLOSEDIR(a) (_wclosedir)(a)
108 #define STAT(a,b) (_wstat)(UTF8_TO_OS(a),b)
109 #define OPEN(a,b,c) (_wopen)(UTF8_TO_OS(a),b,c)
110 #define CLOSE(a) (close)(a)
111 #define REMOVE(a) (_wremove)(UTF8_TO_OS(a))
112 #define RENAME(a,b) (_wrename)(UTF8_TO_OS(a),utf8_to_ucs2(b,convbuf2))
114 #else /* !__MINGW32__ */
116 #define UTF8_TO_OS(a) (a)
117 #define OS_TO_UTF8(a) (a)
118 #define DIR_T DIR
119 #define DIRENT_T struct dirent
120 #define STAT_T struct stat
121 #define MKDIR(a,b) (mkdir)(a,b)
122 #define RMDIR(a) (rmdir)(a)
123 #define OPENDIR(a) (opendir)(a)
124 #define READDIR(a) (readdir)(a)
125 #define CLOSEDIR(a) (closedir)(a)
126 #define STAT(a,b) (stat)(a,b)
127 #define OPEN(a,b,c) (open)(a,b,c)
128 #define CLOSE(x) (close)(x)
129 #define REMOVE(a) (remove)(a)
130 #define RENAME(a,b) (rename)(a,b)
132 #endif /* !__MINGW32__ */
135 #ifdef HAVE_DIRCACHE
136 void dircache_remove(const char *name);
137 void dircache_rename(const char *oldname, const char *newname);
138 #endif
141 #define SIMULATOR_DEFAULT_ROOT "simdisk"
142 extern const char *sim_root_dir;
144 static int num_openfiles = 0;
146 struct sim_dirent {
147 unsigned char d_name[MAX_PATH];
148 int attribute;
149 long size;
150 long startcluster;
151 unsigned short wrtdate; /* Last write date */
152 unsigned short wrttime; /* Last write time */
155 struct dirstruct {
156 void *dir; /* actually a DIR* dir */
157 char *name;
158 } SIM_DIR;
160 struct mydir {
161 DIR_T *dir;
162 char *name;
165 typedef struct mydir MYDIR;
167 #if 1 /* maybe this needs disabling for MSVC... */
168 static unsigned int rockbox2sim(int opt)
170 int newopt = O_BINARY;
172 if(opt & 1)
173 newopt |= O_WRONLY;
174 if(opt & 2)
175 newopt |= O_RDWR;
176 if(opt & 4)
177 newopt |= O_CREAT;
178 if(opt & 8)
179 newopt |= O_APPEND;
180 if(opt & 0x10)
181 newopt |= O_TRUNC;
183 return newopt;
185 #endif
187 /** Simulator I/O engine routines **/
188 #define IO_YIELD_THRESHOLD 512
190 enum
192 IO_READ,
193 IO_WRITE,
196 struct sim_io
198 struct mutex sim_mutex; /* Rockbox mutex */
199 int cmd; /* The command to perform */
200 int ready; /* I/O ready flag - 1= ready */
201 int fd; /* The file to read/write */
202 void *buf; /* The buffer to read/write */
203 size_t count; /* Number of bytes to read/write */
204 size_t accum; /* Acculated bytes transferred */
207 static struct sim_io io;
209 int ata_init(void)
211 /* Initialize the rockbox kernel objects on a rockbox thread */
212 mutex_init(&io.sim_mutex);
213 io.accum = 0;
214 return 1;
217 int ata_spinup_time(void)
219 return HZ;
222 static ssize_t io_trigger_and_wait(int cmd)
224 void *mythread = NULL;
225 ssize_t result;
227 if (io.count > IO_YIELD_THRESHOLD ||
228 (io.accum += io.count) >= IO_YIELD_THRESHOLD)
230 /* Allow other rockbox threads to run */
231 io.accum = 0;
232 mythread = thread_sdl_thread_unlock();
235 switch (cmd)
237 case IO_READ:
238 result = read(io.fd, io.buf, io.count);
239 break;
240 case IO_WRITE:
241 result = write(io.fd, io.buf, io.count);
242 break;
245 /* Regain our status as current */
246 if (mythread != NULL)
248 thread_sdl_thread_lock(mythread);
251 return result;
254 #ifndef __PCTOOL__
255 static const char *get_sim_pathname(const char *name)
257 static char buffer[MAX_PATH]; /* sufficiently big */
259 if(name[0] == '/')
261 snprintf(buffer, sizeof(buffer), "%s%s",
262 sim_root_dir != NULL ? sim_root_dir : SIMULATOR_DEFAULT_ROOT, name);
263 return buffer;
265 fprintf(stderr, "WARNING, bad file name lacks slash: %s\n", name);
266 return name;
268 #else
269 #define get_sim_pathname(name) name
270 #endif
272 MYDIR *sim_opendir(const char *name)
274 DIR_T *dir;
276 dir = (DIR_T *) OPENDIR(get_sim_pathname(name));
278 if (dir)
280 MYDIR *my = (MYDIR *)malloc(sizeof(MYDIR));
281 my->dir = dir;
282 my->name = (char *)malloc(strlen(name)+1);
283 strcpy(my->name, name);
285 return my;
287 /* failed open, return NULL */
288 return (MYDIR *)0;
291 struct sim_dirent *sim_readdir(MYDIR *dir)
293 char buffer[MAX_PATH]; /* sufficiently big */
294 static struct sim_dirent secret;
295 STAT_T s;
296 DIRENT_T *x11 = READDIR(dir->dir);
297 struct tm* tm;
299 if(!x11)
300 return (struct sim_dirent *)0;
302 strcpy((char *)secret.d_name, OS_TO_UTF8(x11->d_name));
304 /* build file name */
305 snprintf(buffer, sizeof(buffer), "%s/%s",
306 get_sim_pathname(dir->name), secret.d_name);
307 STAT(buffer, &s); /* get info */
309 #define ATTR_DIRECTORY 0x10
311 secret.attribute = S_ISDIR(s.st_mode)?ATTR_DIRECTORY:0;
312 secret.size = s.st_size;
314 tm = localtime(&(s.st_mtime));
315 secret.wrtdate = ((tm->tm_year - 80) << 9) |
316 ((tm->tm_mon + 1) << 5) |
317 tm->tm_mday;
318 secret.wrttime = (tm->tm_hour << 11) |
319 (tm->tm_min << 5) |
320 (tm->tm_sec >> 1);
321 return &secret;
324 void sim_closedir(MYDIR *dir)
326 free(dir->name);
327 CLOSEDIR(dir->dir);
329 free(dir);
332 int sim_open(const char *name, int o)
334 int opts = rockbox2sim(o);
335 int ret;
337 if (num_openfiles >= MAX_OPEN_FILES)
338 return -2;
340 ret = OPEN(get_sim_pathname(name), opts, 0666);
341 if (ret >= 0)
342 num_openfiles++;
343 return ret;
346 int sim_close(int fd)
348 int ret;
349 ret = CLOSE(fd);
350 if (ret == 0)
351 num_openfiles--;
352 return ret;
355 int sim_creat(const char *name)
357 return OPEN(get_sim_pathname(name), O_BINARY | O_WRONLY | O_CREAT | O_TRUNC, 0666);
360 ssize_t sim_read(int fd, void *buf, size_t count)
362 ssize_t result;
364 mutex_lock(&io.sim_mutex);
366 /* Setup parameters */
367 io.fd = fd;
368 io.buf = buf;
369 io.count = count;
371 result = io_trigger_and_wait(IO_READ);
373 mutex_unlock(&io.sim_mutex);
375 return result;
378 ssize_t sim_write(int fd, const void *buf, size_t count)
380 ssize_t result;
382 mutex_lock(&io.sim_mutex);
384 io.fd = fd;
385 io.buf = (void*)buf;
386 io.count = count;
388 result = io_trigger_and_wait(IO_WRITE);
390 mutex_unlock(&io.sim_mutex);
392 return result;
395 int sim_mkdir(const char *name)
397 return MKDIR(get_sim_pathname(name), 0777);
400 int sim_rmdir(const char *name)
402 return RMDIR(get_sim_pathname(name));
405 int sim_remove(const char *name)
407 #ifdef HAVE_DIRCACHE
408 dircache_remove(name);
409 #endif
410 return REMOVE(get_sim_pathname(name));
413 int sim_rename(const char *oldname, const char *newname)
415 char sim_old[MAX_PATH];
416 char sim_new[MAX_PATH];
417 #ifdef HAVE_DIRCACHE
418 dircache_rename(oldname, newname);
419 #endif
420 // This is needed as get_sim_pathname() has a static buffer
421 strncpy(sim_old, get_sim_pathname(oldname), MAX_PATH);
422 strncpy(sim_new, get_sim_pathname(newname), MAX_PATH);
423 return RENAME(sim_old, sim_new);
426 /* rockbox off_t may be different from system off_t */
427 long sim_lseek(int fildes, long offset, int whence)
429 return lseek(fildes, offset, whence);
432 long sim_filesize(int fd)
434 #ifdef WIN32
435 return _filelength(fd);
436 #else
437 struct stat buf;
439 if (!fstat(fd, &buf))
440 return buf.st_size;
441 else
442 return -1;
443 #endif
446 void fat_size(IF_MV2(int volume,) unsigned long* size, unsigned long* free)
448 #ifdef HAVE_MULTIVOLUME
449 if (volume != 0) {
450 /* debugf("io.c: fat_size(volume=%d); simulator only supports volume 0\n",volume); */
452 if (size) *size = 0;
453 if (free) *free = 0;
454 return;
456 #endif
458 #ifdef WIN32
459 long secperclus, bytespersec, free_clusters, num_clusters;
461 if (GetDiskFreeSpace(NULL, &secperclus, &bytespersec, &free_clusters,
462 &num_clusters)) {
463 if (size)
464 *size = num_clusters * secperclus / 2 * (bytespersec / 512);
465 if (free)
466 *free = free_clusters * secperclus / 2 * (bytespersec / 512);
468 #else
469 struct statvfs vfs;
471 if (!statvfs(".", &vfs)) {
472 DEBUGF("statvfs: frsize=%d blocks=%ld free=%ld\n",
473 (int)vfs.f_frsize, (long)vfs.f_blocks, (long)vfs.f_bfree);
474 if (size)
475 *size = vfs.f_blocks / 2 * (vfs.f_frsize / 512);
476 if (free)
477 *free = vfs.f_bfree / 2 * (vfs.f_frsize / 512);
479 #endif
480 else {
481 if (size)
482 *size = 0;
483 if (free)
484 *free = 0;
488 int sim_fsync(int fd)
490 #ifdef WIN32
491 return _commit(fd);
492 #else
493 return fsync(fd);
494 #endif
497 #ifdef WIN32
498 /* sim-win32 */
499 #define dlopen(_x_, _y_) LoadLibraryW(UTF8_TO_OS(_x_))
500 #define dlsym(_x_, _y_) (void *)GetProcAddress(_x_, _y_)
501 #define dlclose(_x_) FreeLibrary(_x_)
502 #else
503 /* sim-x11 */
504 #include <dlfcn.h>
505 #endif
507 void *sim_codec_load_ram(char* codecptr, int size, void **pd)
509 void *hdr;
510 char name[MAX_PATH];
511 char path[MAX_PATH];
512 int fd;
513 int codec_count;
514 #ifdef WIN32
515 char buf[MAX_PATH];
516 #endif
518 *pd = NULL;
520 /* We have to create the dynamic link library file from ram so we
521 can simulate the codec loading. With voice and crossfade,
522 multiple codecs may be loaded at the same time, so we need
523 to find an unused filename */
524 for (codec_count = 0; codec_count < 10; codec_count++)
526 snprintf(name, sizeof(name), "/_temp_codec%d.dll", codec_count);
527 snprintf(path, sizeof(path), "%s", get_sim_pathname(name));
528 fd = OPEN(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRWXU);
529 if (fd >= 0)
530 break; /* Created a file ok */
532 if (fd < 0)
534 DEBUGF("failed to open for write: %s\n", path);
535 return NULL;
538 if (write(fd, codecptr, size) != size)
540 DEBUGF("write failed");
541 return NULL;
543 close(fd);
545 /* Now load the library. */
546 *pd = dlopen(path, RTLD_NOW);
547 if (*pd == NULL)
549 DEBUGF("failed to load %s\n", path);
550 #ifdef WIN32
551 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
552 buf, sizeof buf, NULL);
553 DEBUGF("dlopen(%s): %s\n", path, buf);
554 #else
555 DEBUGF("dlopen(%s): %s\n", path, dlerror());
556 #endif
557 return NULL;
560 hdr = dlsym(*pd, "__header");
561 if (!hdr)
562 hdr = dlsym(*pd, "___header");
564 return hdr; /* maybe NULL if symbol not present */
567 void sim_codec_close(void *pd)
569 dlclose(pd);
572 void *sim_plugin_load(char *plugin, void **pd)
574 void *hdr;
575 char path[MAX_PATH];
576 #ifdef WIN32
577 char buf[MAX_PATH];
578 #endif
580 snprintf(path, sizeof(path), "%s", get_sim_pathname(plugin));
582 *pd = NULL;
584 *pd = dlopen(path, RTLD_NOW);
585 if (*pd == NULL) {
586 DEBUGF("failed to load %s\n", plugin);
587 #ifdef WIN32
588 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
589 buf, sizeof(buf), NULL);
590 DEBUGF("dlopen(%s): %s\n", path, buf);
591 #else
592 DEBUGF("dlopen(%s): %s\n", path, dlerror());
593 #endif
594 return NULL;
597 hdr = dlsym(*pd, "__header");
598 if (!hdr)
599 hdr = dlsym(*pd, "___header");
601 return hdr; /* maybe NULL if symbol not present */
604 void sim_plugin_close(void *pd)
606 dlclose(pd);
609 #ifdef WIN32
610 static unsigned old_cp;
612 void debug_exit(void)
614 /* Reset console output codepage */
615 SetConsoleOutputCP(old_cp);
618 void debug_init(void)
620 old_cp = GetConsoleOutputCP();
621 /* Set console output codepage to UTF8. Only works
622 * correctly when the console uses a truetype font. */
623 SetConsoleOutputCP(65001);
624 atexit(debug_exit);
626 #else
627 void debug_init(void)
629 /* nothing to be done */
631 #endif
633 void debugf(const char *fmt, ...)
635 va_list ap;
636 va_start( ap, fmt );
637 vfprintf( stderr, fmt, ap );
638 va_end( ap );
641 void ldebugf(const char* file, int line, const char *fmt, ...)
643 va_list ap;
644 va_start( ap, fmt );
645 fprintf( stderr, "%s:%d ", file, line );
646 vfprintf( stderr, fmt, ap );
647 va_end( ap );
650 /* rockbox off_t may be different from system off_t */
651 int sim_ftruncate(int fd, long length)
653 #ifdef WIN32
654 return _chsize(fd, length);
655 #else
656 return ftruncate(fd, length);
657 #endif