diff --git a/apps/misc.c b/apps/misc.c index d7a64b3..481dc2a 100644 --- a/apps/misc.c +++ b/apps/misc.c @@ -27,9 +27,7 @@ #ifdef __PCTOOL__ #include #include -#ifdef WPSEDITOR -#include "string.h" -#endif +#include #else #include "sprintf.h" #include "appevents.h" @@ -765,26 +763,6 @@ char* strrsplt(char* str, int c) return s; } -/* Test file existence, using dircache of possible */ -bool file_exists(const char *file) -{ - int fd; - - if (!file || strlen(file) <= 0) - return false; - -#ifdef HAVE_DIRCACHE - if (dircache_is_enabled()) - return (dircache_get_entry_ptr(file) != NULL); -#endif - - fd = open(file, O_RDONLY); - if (fd < 0) - return false; - close(fd); - return true; -} - bool dir_exists(const char *path) { DIR* d = opendir(path); @@ -838,6 +816,26 @@ char* skip_whitespace(char* const str) return s; } +/* Test file existence, using dircache of possible */ +bool file_exists(const char *file) +{ + int fd; + + if (!file || strlen(file) <= 0) + return false; + +#ifdef HAVE_DIRCACHE + if (dircache_is_enabled()) + return (dircache_get_entry_ptr(file) != NULL); +#endif + + fd = open(file, O_RDONLY); + if (fd < 0) + return false; + close(fd); + return true; +} + /* Format time into buf. * * buf - buffer to format to. diff --git a/apps/tagcache.c b/apps/tagcache.c index 84e8875..043b42d 100644 --- a/apps/tagcache.c +++ b/apps/tagcache.c @@ -62,12 +62,9 @@ #include #include "config.h" #include "ata_idle_notify.h" -#include "thread.h" -#include "kernel.h" #include "system.h" #include "logf.h" #include "string.h" -#include "usb.h" #include "metadata.h" #include "metadata.h" #include "tagcache.h" @@ -82,11 +79,14 @@ #ifndef __PCTOOL__ #include "lang.h" #include "eeprom_settings.h" +#include "thread.h" +#include "kernel.h" +#include "usb.h" #endif #ifdef __PCTOOL__ #define yield() do { } while(0) -#define sim_sleep(timeout) do { } while(0) +#define sleep(timeout) do { } while(0) #define do_timed_yield() do { } while(0) #endif @@ -328,7 +328,7 @@ static int open_tag_fd(struct tagcache_header *hdr, int tag, bool write) snprintf(buf, sizeof buf, TAGCACHE_FILE_INDEX, tag); - fd = open(buf, write ? O_RDWR : O_RDONLY); + fd = db_open(buf, write ? O_RDWR : O_RDONLY); if (fd < 0) { logf("tag file open failed: tag=%d write=%d file=%s", tag, write, buf); @@ -354,7 +354,7 @@ static int open_master_fd(struct master_header *hdr, bool write) int fd; int rc; - fd = open(TAGCACHE_FILE_MASTER, write ? O_RDWR : O_RDONLY); + fd = db_open(TAGCACHE_FILE_MASTER, write ? O_RDWR : O_RDONLY); if (fd < 0) { logf("master file open failed for R/W"); @@ -690,7 +690,7 @@ static bool open_files(struct tagcache_search *tcs, int tag) char fn[MAX_PATH]; snprintf(fn, sizeof fn, TAGCACHE_FILE_INDEX, tag); - tcs->idxfd[tag] = open(fn, O_RDONLY); + tcs->idxfd[tag] = db_open(fn, O_RDONLY); } if (tcs->idxfd[tag] < 0) @@ -1153,17 +1153,24 @@ static void remove_files(void) tc_stat.ready = false; tc_stat.ramcache = false; tc_stat.econ = false; - remove(TAGCACHE_FILE_MASTER); + db_remove(TAGCACHE_FILE_MASTER); for (i = 0; i < TAG_COUNT; i++) { if (tagcache_is_numeric_tag(i)) continue; snprintf(buf, sizeof buf, TAGCACHE_FILE_INDEX, i); - remove(buf); + db_remove(buf); } } +#ifdef __PCTOOL__ +void tagcache_remove_database(void) +{ + remove_files(); + db_remove(TAGCACHE_FILE_TEMP); +} +#endif static bool check_all_headers(void) { @@ -1306,7 +1313,7 @@ bool tagcache_search_add_clause(struct tagcache_search *tcs, char buf[MAX_PATH]; snprintf(buf, sizeof buf, TAGCACHE_FILE_INDEX, clause->tag); - tcs->idxfd[clause->tag] = open(buf, O_RDONLY); + tcs->idxfd[clause->tag] = db_open(buf, O_RDONLY); } tcs->clause[tcs->clause_count] = clause; @@ -2459,7 +2466,7 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd) * anything whether the index type is sorted or not. */ snprintf(buf, sizeof buf, TAGCACHE_FILE_INDEX, index_type); - fd = open(buf, O_WRONLY | O_CREAT | O_TRUNC); + fd = db_open(buf, O_WRONLY | O_CREAT | O_TRUNC); if (fd < 0) { logf("%s open fail", buf); @@ -2481,12 +2488,12 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd) /* Loading the tag lookup file as "master file". */ logf("Loading index file"); - masterfd = open(TAGCACHE_FILE_MASTER, O_RDWR); + masterfd = db_open(TAGCACHE_FILE_MASTER, O_RDWR); if (masterfd < 0) { logf("Creating new DB"); - masterfd = open(TAGCACHE_FILE_MASTER, O_WRONLY | O_CREAT | O_TRUNC); + masterfd = db_open(TAGCACHE_FILE_MASTER, O_WRONLY | O_CREAT | O_TRUNC); if (masterfd < 0) { @@ -2804,7 +2811,7 @@ static bool commit(void) while (write_lock) sleep(1); - tmpfd = open(TAGCACHE_FILE_TEMP, O_RDONLY); + tmpfd = db_open(TAGCACHE_FILE_TEMP, O_RDONLY); if (tmpfd < 0) { logf("nothing to commit"); @@ -2820,7 +2827,7 @@ static bool commit(void) { logf("incorrect header"); close(tmpfd); - remove(TAGCACHE_FILE_TEMP); + db_remove(TAGCACHE_FILE_TEMP); return false; } @@ -2828,7 +2835,7 @@ static bool commit(void) { logf("nothing to commit"); close(tmpfd); - remove(TAGCACHE_FILE_TEMP); + db_remove(TAGCACHE_FILE_TEMP); return true; } @@ -2923,7 +2930,7 @@ static bool commit(void) } close(tmpfd); - remove(TAGCACHE_FILE_TEMP); + db_remove(TAGCACHE_FILE_TEMP); tc_stat.commit_step = 0; @@ -3019,6 +3026,7 @@ static bool modify_numeric_entry(int masterfd, int idx_id, int tag, long data) return write_index(masterfd, idx_id, &idx); } +#endif #if 0 bool tagcache_modify_numeric_entry(struct tagcache_search *tcs, @@ -3036,6 +3044,7 @@ bool tagcache_modify_numeric_entry(struct tagcache_search *tcs, } #endif +#ifndef __PCTOOL__ #define COMMAND_QUEUE_IS_EMPTY (command_queue_ridx == command_queue_widx) static bool command_queue_is_full(void) @@ -3161,7 +3170,6 @@ void tagcache_update_numeric(int idx_id, int tag, long data) { queue_command(CMD_UPDATE_NUMERIC, idx_id, tag, data); } -#endif /* !__PCTOOL__ */ long tagcache_get_serial(void) { @@ -3172,6 +3180,7 @@ long tagcache_get_commitid(void) { return current_tcmh.commitid; } +#endif /* !__PCTOOL__ */ static bool write_tag(int fd, const char *tagstr, const char *datastr) { @@ -3820,7 +3829,7 @@ static bool load_tagcache(void) logf("loading tagcache to ram..."); - fd = open(TAGCACHE_FILE_MASTER, O_RDONLY); + fd = db_open(TAGCACHE_FILE_MASTER, O_RDONLY); if (fd < 0) { logf("tagcache open failed"); @@ -4035,7 +4044,7 @@ static bool check_deleted_files(void) logf("reverse scan..."); snprintf(buf, sizeof buf, TAGCACHE_FILE_INDEX, tag_filename); - fd = open(buf, O_RDONLY); + fd = db_open(buf, O_RDONLY); if (fd < 0) { @@ -4194,7 +4203,7 @@ void tagcache_build(const char *path) logf("updating tagcache"); - cachefd = open(TAGCACHE_FILE_TEMP, O_RDONLY); + cachefd = db_open(TAGCACHE_FILE_TEMP, O_RDONLY); if (cachefd >= 0) { logf("skipping, cache already waiting for commit"); @@ -4202,7 +4211,7 @@ void tagcache_build(const char *path) return ; } - cachefd = open(TAGCACHE_FILE_TEMP, O_RDWR | O_CREAT | O_TRUNC); + cachefd = db_open(TAGCACHE_FILE_TEMP, O_RDWR | O_CREAT | O_TRUNC); if (cachefd < 0) { logf("master file open failed: %s", TAGCACHE_FILE_TEMP); @@ -4249,7 +4258,7 @@ void tagcache_build(const char *path) #endif if (commit()) { - remove(TAGCACHE_FILE_TEMP); + db_remove(TAGCACHE_FILE_TEMP); logf("tagcache built!"); } #ifdef __PCTOOL__ @@ -4346,7 +4355,7 @@ static void tagcache_thread(void) case Q_REBUILD: remove_files(); - remove(TAGCACHE_FILE_TEMP); + db_remove(TAGCACHE_FILE_TEMP); tagcache_build("/"); break; diff --git a/apps/tagcache.h b/apps/tagcache.h index e995784..9b16c3a 100644 --- a/apps/tagcache.h +++ b/apps/tagcache.h @@ -179,6 +179,7 @@ void tagcache_build(const char *path); #ifdef __PCTOOL__ void tagcache_reverse_scan(void); +void tagcache_remove_database(void); #endif const char* tagcache_tag_to_str(int tag); @@ -231,4 +232,10 @@ bool tagcache_update(void); bool tagcache_rebuild(void); int tagcache_get_max_commit_step(void); #endif + +#ifndef __PCTOOL__ +#define db_open(x,y) open(x,y) +#define db_remove(x) remove(x) +#endif + #endif diff --git a/firmware/common/unicode.c b/firmware/common/unicode.c index 61989e5..25db0f9 100644 --- a/firmware/common/unicode.c +++ b/firmware/common/unicode.c @@ -36,15 +36,19 @@ #define O_BINARY 0 #endif +#ifndef CODEPAGE_FILES_IS_NOT_USED #define CODEPAGE_DIR ROCKBOX_DIR"/codepages" +#endif + static int default_codepage = 0; static int loaded_cp_table = 0; -#ifdef HAVE_LCD_BITMAP +#if defined(HAVE_LCD_BITMAP) || defined(__PCTOOL__) #define MAX_CP_TABLE_SIZE 32768 #define NUM_TABLES 5 +#ifndef CODEPAGE_FILES_IS_NOT_USED static const char *filename[NUM_TABLES] = { CODEPAGE_DIR"/iso.cp", @@ -53,6 +57,7 @@ static const char *filename[NUM_TABLES] = CODEPAGE_DIR"/949.cp", /* KSX1001 */ CODEPAGE_DIR"/950.cp" /* BIG5 */ }; +#endif static const char cp_2_table[NUM_CODEPAGES] = { @@ -83,9 +88,11 @@ static const char *name_codepages[NUM_CODEPAGES+1] = #define MAX_CP_TABLE_SIZE 640 #define NUM_TABLES 1 +#ifndef CODEPAGE_FILES_IS_NOT_USED static const char *filename[NUM_TABLES] = { CODEPAGE_DIR"/isomini.cp" }; +#endif static const char cp_2_table[NUM_CODEPAGES] = { @@ -116,14 +123,16 @@ static const unsigned char utf8comp[6] = /* Load codepage file into memory */ static int load_cp_table(int cp) { - int i=0; int table = cp_2_table[cp]; - int file, tablesize; - unsigned char tmp[2]; if (table == 0 || table == loaded_cp_table) return 1; +#ifndef CODEPAGE_FILES_IS_NOT_USED + int i=0; + int file, tablesize; + unsigned char tmp[2]; + file = open(filename[table-1], O_RDONLY|O_BINARY); if (file < 0) { @@ -148,9 +157,12 @@ static int load_cp_table(int cp) } codepage_table[i++] = (tmp[1] << 8) | tmp[0]; } + close(file); +#else + set_codepage_data(cp, codepage_table); +#endif loaded_cp_table = table; - close(file); return 1; } @@ -194,7 +206,7 @@ unsigned char* iso_decode(const unsigned char *iso, unsigned char *utf8, case ISO_8859_9: /* Turkish */ case ISO_8859_2: /* Latin Extended */ case WIN_1250: /* Central European */ -#ifdef HAVE_LCD_BITMAP +#if defined(HAVE_LCD_BITMAP) || defined(__PCTOOL__) case ISO_8859_8: /* Hebrew */ case ISO_8859_11: /* Thai */ case WIN_1256: /* Arabic */ @@ -203,7 +215,7 @@ unsigned char* iso_decode(const unsigned char *iso, unsigned char *utf8, ucs = codepage_table[tmp]; break; -#ifdef HAVE_LCD_BITMAP +#if defined(HAVE_LCD_BITMAP) || defined(__PCTOOL__) case SJIS: /* Japanese */ if (*iso > 0xA0 && *iso < 0xE0) { tmp = *iso++ | (0xA100 - 0x8000); diff --git a/firmware/export/system.h b/firmware/export/system.h index b44600d..54f53ef 100644 --- a/firmware/export/system.h +++ b/firmware/export/system.h @@ -24,7 +24,11 @@ #include "cpu.h" #include "stdbool.h" +#ifndef THREAD_IS_NOT_USED #include "kernel.h" +#else +#include +#endif extern void system_reboot (void); /* Called from any UIE handler and panicf - wait for a key and return @@ -228,9 +232,9 @@ enum { MAXMEMGUARD }; -#ifndef SIMULATOR +#if !defined(SIMULATOR) && !defined(__PCTOOL__) #include "system-target.h" -#else /* SIMULATOR */ +#else /* SIMULATOR and __PCTOOL__ */ static inline uint16_t swap16(uint16_t value) /* @@ -264,7 +268,7 @@ static inline uint32_t swap_odd_even32(uint32_t value) return (t >> 8) | ((t ^ value) << 8); } -#endif /* !SIMULATOR */ +#endif /* !SIMULATOR and __PCTOOL__ */ /* Declare this as HIGHEST_IRQ_LEVEL if they don't differ */ #ifndef DISABLE_INTERRUPTS diff --git a/firmware/include/_ansi.h b/firmware/include/_ansi.h index 0002816..52c16e5 100644 --- a/firmware/include/_ansi.h +++ b/firmware/include/_ansi.h @@ -9,8 +9,8 @@ "comment out" the non-ANSI parts of the ANSI header files (non-ANSI header files aren't affected). */ -#ifndef _ANSIDECL_H_ -#define _ANSIDECL_H_ +#ifndef _ANSI_DECL_H_ +#define _ANSI_DECL_H_ /* First try to figure out whether we really are in an ANSI C environment. */ /* FIXME: This probably needs some work. Perhaps sys/config.h can be @@ -75,4 +75,4 @@ #define ATTRIBUTE_PRINTF(fmt, arg1) _ATTRIBUTE( ( format( printf, fmt, arg1 ) ) ) #define ATTRIBUTE_SCANF(fmt, arg1) _ATTRIBUTE( ( format( scanf, fmt, arg1 ) ) ) -#endif /* _ANSIDECL_H_ */ +#endif /* _ANSI_DECL_H_ */ diff --git a/firmware/include/dir_uncached.h b/firmware/include/dir_uncached.h index e198833..9c5302f 100644 --- a/firmware/include/dir_uncached.h +++ b/firmware/include/dir_uncached.h @@ -32,7 +32,7 @@ #define ATTR_ARCHIVE 0x20 #define ATTR_VOLUME 0x40 /* this is a volume, not a real directory */ -#ifdef SIMULATOR +#if defined(SIMULATOR) || defined(__PCTOOL__) #define dirent_uncached sim_dirent #define DIR_UNCACHED SIM_DIR #define opendir_uncached sim_opendir @@ -57,7 +57,7 @@ struct dirent_uncached { #include "fat.h" typedef struct { -#ifndef SIMULATOR +#if !defined(SIMULATOR) && !defined(__PCTOOL__) bool busy; long startcluster; struct fat_dir fatdir; diff --git a/firmware/include/rbunicode.h b/firmware/include/rbunicode.h index 39fe253..1953c63 100644 --- a/firmware/include/rbunicode.h +++ b/firmware/include/rbunicode.h @@ -35,7 +35,7 @@ #define MASK 0xC0 /* 11000000 */ #define COMP 0x80 /* 10x */ -#ifdef HAVE_LCD_BITMAP +#if defined(HAVE_LCD_BITMAP) || defined(__PCTOOL__) enum codepages { ISO_8859_1 = 0, ISO_8859_7, ISO_8859_8, WIN_1251, @@ -62,4 +62,7 @@ const unsigned char* utf8decode(const unsigned char *utf8, unsigned short *ucs); void set_codepage(int cp); int utf8seek(const unsigned char* utf8, int offset); const char* get_codepage_name(int cp); +#ifdef CODEPAGE_FILES_IS_NOT_USED +extern void set_codepage_data(int cp, unsigned short *table); +#endif #endif /* _RBUNICODE_H_ */ diff --git a/tools/codepages.c b/tools/codepages.c index 9c21439..57a41a2 100644 --- a/tools/codepages.c +++ b/tools/codepages.c @@ -29,9 +29,7 @@ static const int mini_index[6] = { 0, 1, 3, 6, 7, 8 }; -static unsigned short iso_table[MAX_TABLE_SIZE]; - -unsigned short iso_decode(unsigned char *latin1, int cp, int count) +unsigned short iso2ucs(unsigned char *latin1, int cp, int count) { unsigned short ucs = 0; @@ -157,6 +155,7 @@ unsigned short iso_decode(unsigned char *latin1, int cp, int count) return ucs; } +#ifndef __PCTOOL__ int writeshort(FILE *f, unsigned short s) { putc(s, f); @@ -202,9 +201,6 @@ int main(int argc, char **argv) } } - for (i=0; i < MAX_TABLE_SIZE; i++) - iso_table[i] = 0; - if (mini) { of = fopen("isomini.cp", "wb"); if (!of) return 1; @@ -213,7 +209,7 @@ int main(int argc, char **argv) for (j=0; j<128; j++) { k = (unsigned char)j + 128; - uni = iso_decode(&k, mini_index[i], 1); + uni = iso2ucs(&k, mini_index[i], 1); writeshort(of, uni); } } @@ -227,7 +223,7 @@ int main(int argc, char **argv) for (j=0; j<128; j++) { k = (unsigned char)j + 128; - uni = iso_decode(&k, i, 1); + uni = iso2ucs(&k, i, 1); writeshort(of, uni); } } @@ -260,3 +256,4 @@ int main(int argc, char **argv) return 0; } +#endif diff --git a/utils/songdb/Makefile b/utils/songdb/Makefile new file mode 100644 index 0000000..0e684cb --- /dev/null +++ b/utils/songdb/Makefile @@ -0,0 +1,131 @@ +# __________ __ ___. +# Open \______ \ ____ ____ | | _\_ |__ _______ ___ +# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +# \/ \/ \/ \/ \/ +# $Id$ +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +ifndef V +SILENT:=@ +endif +CC:=gcc +MAKE:=make +RM:=rm +AR:=ar + +ifneq "$(MAKECMDGOALS)" "clean" + VERSION:=$(shell ../../tools/version.sh ../../) + BUILDDATE:=$(shell date -u +'-DYEAR=%Y -DMONTH=%m -DDAY=%d') +endif + +GCC_VER := $(shell $(CC) -dumpversion | sed -e 's/\..*//') + +GCCOPTS := -O -W -Wall -fno-builtin +DEBUG := -g +DEFINES := -D__PCTOOL__ -DHAVE_TAGCACHE -DCONFIG_CODEC=1 -DTHREAD_IS_NOT_USED -DCODEPAGE_FILES_IS_NOT_USED +INCLUDES := -I. -I../../apps -I../../apps/metadata -I../../firmware/export -I../../firmware/include +LIBS := -lsdb + +ifeq ($(findstring CYGWIN,$(shell uname)),CYGWIN) + ifneq "$(GCC_VER)" "4" + GCCOPTS += -mno-cygwin + endif +else + ifneq ($(findstring MINGW,$(shell uname)),MINGW) + LIBS += -ldl + endif +endif +ifeq "$(GCC_VER)" "4" + GCCOPTS += -Wno-pointer-sign +endif + +# set the endian of the build environment +ifdef ROCKBOX_BUILD_ENDIAN + DEFINES += -D$(ROCKBOX_BUILD_ENDIAN) +else + # checked the endian of the build environment. + # It is necessary to install perl. + # Please execute make after exporting ROCKBOX_BUILD_ENDIAN=ROCKBOX_BIG_ENDIAN + # or ROCKBOX_BUILD_ENDIAN=ROCKBOX_LITTLE_ENDIAN when you make songdb + # in the environment in which perl is not installed. + ENDIAN := $(shell perl -e 'print unpack("I*", "\x00\x00\x00\x01")') + ifeq "$(ENDIAN)" "1" + DEFINES += -DROCKBOX_BIG_ENDIAN + else + DEFINES += -DROCKBOX_LITTLE_ENDIAN + endif +endif + +APP_CFLAGS := $(GCCOPTS) $(DEBUG) $(DEFINES) -DAPP_VERSION=\"$(VERSION)\" $(BUILDDATE) -I. -L. +LIB_CFLAGS := $(GCCOPTS) $(DEBUG) $(DEFINES) $(INCLUDES) + +.PHONY: all clean +all: songdb + +APP_SRCS := ../../tools/codepages.c \ +file.c \ +songdb.c +LIB_SRCS := ../../firmware/common/crc32.c \ +../../firmware/common/ctype.c \ +../../firmware/common/errno.c \ +../../firmware/common/strcasestr.c \ +../../firmware/common/structec.c \ +../../firmware/common/unicode.c \ +../../apps/metadata.c \ +../../apps/misc.c \ +../../apps/mp3data.c \ +../../apps/replaygain.c \ +../../apps/tagcache.c \ +../../tools/codepage_tables.c \ +codepage.c + +# append metadata files +LIB_SRCS += $(wildcard ../../apps/metadata/*.c) + +APP_OBJS := $(patsubst %.c,%.o, $(notdir $(APP_SRCS))) +LIB_OBJS := $(patsubst %.c,%.o, $(notdir $(LIB_SRCS))) + +DEPFILE = songdb.d + +$(DEPFILE): $(SRCS) + $(SILENT)(for each in $(APP_SRCS); do \ + obj=`echo $$each | sed -e 's/\.c/.o/' -e 's/^.*\///'`; \ + $(CC) -MG -MM -MT "$$obj" $(APP_CFLAGS) $$each 2>/dev/null; \ + done) >> $(DEPFILE) + $(SILENT)(for each in $(LIB_SRCS); do \ + obj=`echo $$each | sed -e 's/\.c/.o/' -e 's/^.*\///'`; \ + $(CC) -MG -MM -MT "$$obj" $(LIB_CFLAGS) $$each 2>/dev/null; \ + done) >> $(DEPFILE) + + +songdb: libsdb.a $(APP_OBJS) + @echo LD songdb + $(SILENT)$(CC) $(APP_CFLAGS) -o $@ $(APP_OBJS) $(LIBS) + +libsdb.a: $(LIB_OBJS) + @echo AR libsdb.a + $(SILENT)$(AR) ruv $@ $+ > /dev/null 2>&1 + +$(APP_OBJS):%.o: $(shell grep %.c $(APP_SRCS)) + @echo CC $( ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2009 Yoshihisa Uchida + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include +#include "rbunicode.h" +#include "../../tools/codepage_tables.h" + +extern unsigned short iso2ucs(unsigned char *latin1, int cp, int count); + +static const unsigned short *codetable_map[] = +{ + cp932_table, + cp936_table, + cp949_table, + cp950_table, +}; + +void set_codepage_data(int cp, unsigned short *table) +{ + int i; + int j; + unsigned char k; + + if (cp >= SJIS) + { + memcpy(table, codetable_map[cp - SJIS], sizeof(unsigned short) << 15); + return; + } + + for (i = 1; i < 9; i++) + { + for (j = 0; j < 128; j++) + { + k = (unsigned char)j + 128; + table[((i-1) << 7) + j] = iso2ucs(&k, i, 1); + } + } +} + +int get_codepage(const char *cp) +{ + int code; + const char *name; + + for (code = 0; code < NUM_CODEPAGES; code++) + { + name = get_codepage_name(code); + if (strcasecmp(cp, name) == 0) + return code; + } + + return -1; +} diff --git a/utils/songdb/codepage.h b/utils/songdb/codepage.h new file mode 100755 index 0000000..bae1e9c --- /dev/null +++ b/utils/songdb/codepage.h @@ -0,0 +1,22 @@ +/**************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2009 Yoshihisa Uchida + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +void set_codepage_data(int cp, unsigned short *table); +int get_codepage(const char *cp); diff --git a/utils/songdb/file.c b/utils/songdb/file.c new file mode 100644 index 0000000..5f32d4f --- /dev/null +++ b/utils/songdb/file.c @@ -0,0 +1,435 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2009 Yoshihisa Uchida + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +/* + * the following wrapper functions based on uisimulator/common/io.c + */ + +#include +#include +#include +#include +#include +#include +#include +#ifdef __FreeBSD__ +#include +#include +#elif defined(__APPLE__) +#include +#include +#elif !defined(WIN32) +#include +#endif + +#include +#include +#include + +#ifndef MAX_PATH +#define MAX_PATH 260 +#endif + +/* Windows (and potentially other OSes) distinguish binary and text files. + * Define a dummy for the others. */ +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +/* Unicode compatibility for win32 */ +#if defined __MINGW32__ +/* Rockbox unicode functions */ +extern const unsigned char* utf8decode(const unsigned char *utf8, + unsigned short *ucs); +extern unsigned char* utf8encode(unsigned long ucs, unsigned char *utf8); + +/* Static buffers for the conversion results. This isn't thread safe, + * but it's sufficient for rockbox. */ +static unsigned char convbuf[3*MAX_PATH]; + +static wchar_t* utf8_to_ucs2(const unsigned char *utf8, void *buffer) +{ + wchar_t *ucs = buffer; + + while (*utf8) + utf8 = utf8decode(utf8, ucs++); + + *ucs = 0; + return buffer; +} +static unsigned char *ucs2_to_utf8(const wchar_t *ucs, unsigned char *buffer) +{ + unsigned char *utf8 = buffer; + + while (*ucs) + utf8 = utf8encode(*ucs++, utf8); + + *utf8 = 0; + return buffer; +} + +#define UTF8_TO_OS(a) utf8_to_ucs2(a,convbuf) +#define OS_TO_UTF8(a) ucs2_to_utf8(a,convbuf) +#define DIR_T _WDIR +#define DIRENT_T struct _wdirent +#define STAT_T struct _stat +extern int _wmkdir(const wchar_t*); +extern int _wrmdir(const wchar_t*); +#define MKDIR(a,b) (_wmkdir)(UTF8_TO_OS(a)) +#define OPENDIR(a) (_wopendir)(UTF8_TO_OS(a)) +#define READDIR(a) (_wreaddir)(a) +#define CLOSEDIR(a) (_wclosedir)(a) +#define STAT(a,b) (_wstat)(UTF8_TO_OS(a),b) +#define OPEN(a,b,c) (_wopen)(UTF8_TO_OS(a),b,c) +#define CLOSE(a) (close)(a) +#define REMOVE(a) (_wremove)(UTF8_TO_OS(a)) + +#else /* !__MINGW32__ */ + +#define UTF8_TO_OS(a) (a) +#define OS_TO_UTF8(a) (a) +#define DIR_T DIR +#define DIRENT_T struct dirent +#define STAT_T struct stat +#define MKDIR(a,b) (mkdir)(a,b) +#define OPENDIR(a) (opendir)(a) +#define READDIR(a) (readdir)(a) +#define CLOSEDIR(a) (closedir)(a) +#define STAT(a,b) (stat)(a,b) +#define OPEN(a,b,c) (open)(a,b,c) +#define CLOSE(x) (close)(x) +#define REMOVE(a) (remove)(a) + +#endif /* !__MINGW32__ */ + +extern const char *sim_root_dir; +extern const char *sim_rockbox_dir; + +#define PCTOOL_DEFAULT_ROOT "./" +#define PCTOOL_DEFAULT_ROCKBOX_DIR "/.rockbox" + +struct sim_dirent { + unsigned char d_name[MAX_PATH]; + int attribute; + long size; + long startcluster; + unsigned short wrtdate; /* Last write date */ + unsigned short wrttime; /* Last write time */ +}; + +struct dirstruct { + void *dir; /* actually a DIR* dir */ + char *name; +} SIM_DIR; + +struct mydir { + DIR_T *dir; + char *name; +}; + +typedef struct mydir MYDIR; + +static unsigned int rockbox2sim(int opt) +{ + int newopt = O_BINARY; + + if(opt & 1) + newopt |= O_WRONLY; + if(opt & 2) + newopt |= O_RDWR; + if(opt & 4) + newopt |= O_CREAT; + if(opt & 8) + newopt |= O_APPEND; + if(opt & 0x10) + newopt |= O_TRUNC; + + return newopt; +} + +static const char *get_sim_pathname(const char *name) +{ + static char buffer[MAX_PATH]; /* sufficiently big */ + + if(name[0] == '/') + { + snprintf(buffer, sizeof(buffer), "%s%s", + sim_root_dir != NULL ? sim_root_dir : PCTOOL_DEFAULT_ROOT, name); + } + else + { + snprintf(buffer, sizeof(buffer), "%s%s/%s", + sim_root_dir != NULL ? sim_root_dir : PCTOOL_DEFAULT_ROOT, + sim_rockbox_dir != NULL ? sim_rockbox_dir : PCTOOL_DEFAULT_ROCKBOX_DIR, + name); + } + return buffer; +} + +/* + * disk I/O wrapper functions + */ + +MYDIR *sim_opendir(const char *name) +{ + DIR_T *dir; + + dir = (DIR_T *) OPENDIR(get_sim_pathname(name)); + + if (dir) + { + MYDIR *my = (MYDIR *)malloc(sizeof(MYDIR)); + my->dir = dir; + my->name = (char *)malloc(strlen(name)+1); + strcpy(my->name, name); + + return my; + } + /* failed open, return NULL */ + return (MYDIR *)0; +} + +struct sim_dirent *sim_readdir(MYDIR *dir) +{ + char buffer[MAX_PATH]; /* sufficiently big */ + static struct sim_dirent secret; + STAT_T s; + DIRENT_T *x11 = READDIR(dir->dir); + struct tm* tm; + + if(!x11) + return (struct sim_dirent *)0; + + strcpy((char *)secret.d_name, OS_TO_UTF8(x11->d_name)); + + /* build file name */ + snprintf(buffer, sizeof(buffer), "%s/%s", + get_sim_pathname(dir->name), secret.d_name); + STAT(buffer, &s); /* get info */ + +#define ATTR_DIRECTORY 0x10 + + secret.attribute = S_ISDIR(s.st_mode)?ATTR_DIRECTORY:0; + secret.size = s.st_size; + + tm = localtime(&(s.st_mtime)); + secret.wrtdate = ((tm->tm_year - 80) << 9) | + ((tm->tm_mon + 1) << 5) | + tm->tm_mday; + secret.wrttime = (tm->tm_hour << 11) | + (tm->tm_min << 5) | + (tm->tm_sec >> 1); + return &secret; +} + +void sim_closedir(MYDIR *dir) +{ + free(dir->name); + CLOSEDIR(dir->dir); + + free(dir); +} + +int sim_open(const char *name, int o) +{ + return OPEN(get_sim_pathname(name), rockbox2sim(o), 0666); +} + +int sim_close(int fd) +{ + return CLOSE(fd); +} + +ssize_t sim_read(int fd, void *buf, size_t count) +{ + return read(fd, buf, count); +} + +ssize_t sim_write(int fd, const void *buf, size_t count) +{ + return write(fd, buf, count); +} + +int sim_mkdir(const char *name) +{ + return MKDIR(get_sim_pathname(name), 0777); +} + +int sim_remove(const char *name) +{ + return REMOVE(get_sim_pathname(name)); +} + +/* rockbox off_t may be different from system off_t */ +long sim_lseek(int fildes, long offset, int whence) +{ + return lseek(fildes, offset, whence); +} + +long sim_filesize(int fd) +{ +#ifdef WIN32 + return _filelength(fd); +#else + struct stat buf; + + if (!fstat(fd, &buf)) + return buf.st_size; + else + return -1; +#endif +} + +/* + * convenience functions + */ + +bool mkdirs(const char *path) +{ + int i; + int len = strlen(path); + char parent[MAX_PATH]; + STAT_T sbuf; + + if (!STAT(path, &sbuf)) + { + if (S_ISDIR(sbuf.st_mode)) + return true; + + fprintf(stderr, "%s: does not directory\n", path); + return false; + } + + for (i = len-1; i > 0; i--) + { +#ifdef __MINGW32__ + if (path[i] == '\\' || path[i] == '/') +#else + if (path[i] == '/') +#endif + { + strncpy(parent, path, i); + parent[i] = '\0'; + if (!mkdirs(parent)) + return false; + break; + } + } + + MKDIR(path, 0777); + + if (STAT(path, &sbuf)) + { + fprintf(stderr, "%s: does not create directories\n", path); + return false; + } + return true; +} + +static bool copy_file(const char *src, const char *dst, const char *file) +{ + char buf[4096]; + char spath[MAX_PATH]; + char dpath[MAX_PATH]; + FILE *sfp; + FILE *dfp; + size_t rsz; + + snprintf(spath, MAX_PATH, "%s/%s", src, file); + snprintf(dpath, MAX_PATH, "%s/%s", dst, file); + + sfp = fopen(spath, "rb"); + if (sfp == NULL) + { + fprintf(stderr, "%s/%s: does not open.\n", src, file); + return false; + } + + dfp = fopen(dpath, "wb"); + if (dfp == NULL) + { + fclose(sfp); + fprintf(stderr, "%s/%s: does not open.\n", dst, file); + return false; + } + + do { + rsz = fread(buf, 1, sizeof(buf), sfp); + fwrite(buf, 1, rsz, dfp); + } while (rsz == sizeof(buf)); + + fclose(sfp); + fclose(dfp); + + return true; +} + +bool copy_database_files(const char *src, const char *dst) +{ + DIR *dir = opendir(src); + struct dirent *dp; + int len; + + if (dir == NULL) + { + fprintf(stderr, "%s: No such directory exists\n", src); + return false; + } + + while ((dp = readdir(dir)) != NULL) + { + len = strlen(dp->d_name); + if (len > 5 && strcmp(dp->d_name + len - 4, ".tcd") == 0) + copy_file(src, dst, dp->d_name); + } + closedir(dir); + return true; +} + +/* + * database files access helper functions + */ + +static unsigned char root_path[MAX_PATH]; + +void set_db_root_path(const unsigned char *path) +{ + strncpy(root_path, path, MAX_PATH-1); +} + +static const char *db_path(const char *name) +{ + static char path[MAX_PATH]; + + snprintf(path, MAX_PATH, "%s/%s", root_path, name); + + return path; +} + +int db_open(const char *name, int o) +{ + return open(db_path(name), rockbox2sim(o), 0666); +} + +int db_remove(const char *name) +{ + return remove(db_path(name)); +} diff --git a/utils/songdb/file.h b/utils/songdb/file.h new file mode 100644 index 0000000..4dc9004 --- /dev/null +++ b/utils/songdb/file.h @@ -0,0 +1,77 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 by Björn Stenberg + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef _FILE_H_ +#define _FILE_H_ + +#include +#include + +#undef MAX_PATH +#define MAX_PATH 260 + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +#ifndef O_RDONLY +#define O_RDONLY 0 +#define O_WRONLY 1 +#define O_RDWR 2 +#define O_CREAT 4 +#define O_APPEND 8 +#define O_TRUNC 0x10 +#endif + +#define open(x,y) sim_open(x,y) +#define remove(x) sim_remove(x) +#define filesize(x) sim_filesize(x) +#define lseek(x,y,z) sim_lseek(x,y,z) +#define read(x,y,z) sim_read(x,y,z) +#define write(x,y,z) sim_write(x,y,z) +#define close(x) sim_close(x) + +typedef int (*open_func)(const char* pathname, int flags); +typedef ssize_t (*read_func)(int fd, void *buf, size_t count); +typedef ssize_t (*write_func)(int fd, const void *buf, size_t count); + +extern int open(const char* pathname, int flags); +extern int close(int fd); +extern ssize_t read(int fd, void *buf, size_t count); +extern off_t lseek(int fildes, off_t offset, int whence); +extern ssize_t write(int fd, const void *buf, size_t count); +extern int remove(const char* pathname); +extern off_t filesize(int fd); + +extern int db_open(const char *name, int o); +extern int db_remove(const char *name); + +void set_db_root_path(const unsigned char *path); +bool mkdirs(const char *path); +bool copy_database_files(const char *src, const char *dst); + +#endif diff --git a/utils/songdb/readme.txt b/utils/songdb/readme.txt new file mode 100644 index 0000000..75e12b4 --- /dev/null +++ b/utils/songdb/readme.txt @@ -0,0 +1,146 @@ + __________ __ ___. + Open \______ \ ____ ____ | | _\_ |__ _______ ___ + Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + \/ \/ \/ \/ \/ +$Id$ + +Copyright (C) 2009 Yoshihisa Uchida + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + KIND, either express or implied. + +========================================================================== +songdb + Create the song database (database_*.tcd) application. + + +================================================= +Usage +================================================= +songdb -r|--root-path + -m|--mode + [-s|--song-directory ] + [-c|--codepage ] + [-i|--input-path ] + [-o|--output-path ] + [-h|--help] + [-V|--version] + +-r|--root-path + set root path. + If does not begin with a "/" or the drive letter, then it considered + the relative path from the directory that executes the songdb. + + When the songdb is used on Windows, the drive letter is written + Windows style (such as "C:\path\of\root" or "C:/path/of/root"). + + When using songdb on MinGW+MSYS shell, it should be set not /foo but //foo. + +-m|--mode + create: build database newly. + + update: Files not registered in the database are added to the database. + And deleted files are deleted from the database. + + append: Files not registered in the database are added to the database. + But deleted files are not deleted from the database. + +-s|--song-directory + set song storage directory. + If begins with a "/", then it looks for the song file + from <--root-path>/. + If does not begin with a "/", then it looks for the song + file from <--root-path>/.rockbox/. + + If this option is not given, then = "/". + + When using songdb on MinGW+MSYS shell, it should be set not /foo but //foo. + +-c|--codepage + set metadata codepage. + If this option is not given, then metadata codepage is "ISO-8859-1". + When the player is the codepage not supported, "ISO-8859-1" is selected. + + codepage list + option value codepage + ----------------------------------------------- + ISO-8859-1 Latin1 (ISO-8859-1) + ISO-8859-2 Latin Extended (ISO-8859-2) + ISO-8859-7 Greek (ISO-8859-7) + ISO-8859-8 Hebrew (ISO-8859-8) + ISO-8859-9 Turkish (ISO-8859-9) + ISO-8859-11 Thai (ISO-8859-11) + CP1250 Central European (CP1250) + CP1251 Cyrillic (CP1251) + CP1256 Arabic (CP1256) + SJIS Japanese (SJIS) + GB-2312 Simple Chinese (GB2312) + KSX-1001 Korean (KSX1001) + BIG-5 Traditional Chinese (BIG5) + UTF-8 Unicode (UTF-8) + +-i|--input-path + The path where database files read when <--mode> is update or append. + If does not begin with a "/" or the drive letter, then it considered + the relative path from the directory that executes the songdb. + + If this option is not given, song database (database_*.tcd) are read from + <--root-path>/.rockbox directory. + +-o|--output-path + The path of output of database files. + If does not begin with a "/" or the drive letter, then it considered + the relative path from the directory that executes the songdb. + + If this option is not given, song database (database_*.tcd) are saved in + <--root-path>/.rockbox directory. + +-h|--help + show help message and exit. + +-V|--version + show version information and exit. + +================================================= +Requirement +================================================= +OS + 1) Windows + - Cygwin + When the songdb is built by using gcc 3.X.X on Cygwin, + to execute the songdb, cygwin1.dll is not needed. + But if it is built by using gcc 4.X.X, cygwin1.dll is needed. + + - MinGW + It is necessary to install msys. + The following applications need. + GNU Coreutils + GNU make [optional] + grep + perl [optional] + sed + subversion (or git) [optional] + + 2) Linux + + Other OS do not checked. + +When the songdb does not use the SDL library, then the SDL library +may not be installed. + +================================================= +Build +================================================= +1) make + +When the build environment does not install perl, +please execute export ROCKBOX_BUILD_ENDIAN=ROCKBOX_BIG_ENDIAN or +export ROCKBOX_BUILD_ENDIAN=ROCKBOX_LITTLE_ENDIAN +after executing make. diff --git a/utils/songdb/songdb.c b/utils/songdb/songdb.c new file mode 100644 index 0000000..f8c3fb3 --- /dev/null +++ b/utils/songdb/songdb.c @@ -0,0 +1,273 @@ +/**************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2009 Yoshihisa Uchida + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include +#include +#include "codepage.h" +#include "file.h" + +/* Rockbox functions */ + +/* implemented by firmware/common/unicode.c */ +extern void set_codepage(int cp); + +/* implemented by apps/tagcache.c */ +extern void tagcache_build(const char *path); +extern void tagcache_init(void); +extern void tagcache_remove_database(void); +extern void tagcache_reverse_scan(void); + +#define DEFAULT_ROCKBOX_DIRECTORY "/.rockbox" + +const char *sim_root_dir = NULL; +const char *sim_rockbox_dir = DEFAULT_ROCKBOX_DIRECTORY; + + +#define DB_MODE_CREATE_STR "create" +#define DB_MODE_UPDATE_STR "update" +#define DB_MODE_APPEND_STR "append" + +enum {DB_MODE_CREATE, DB_MODE_UPDATE, DB_MODE_APPEND}; + +const unsigned char *usage_messages[] = +{ + "Usage: songdb -r|--root-path \n", + " -m|--mode \n", + " [-s|--song-directory ]\n", + " [-c|--codepage ]\n", + " [-i|--input-path ]\n", + " [-o|--output-path ]\n", + " [-h|--help]\n", + " [-V|--version]\n", + "\n", + "Options\n", + " -r|--root-path \n", + " Rockbox root path.\n", + " -m|--mode \n", + " create: build database newly.\n", + " update: update database.\n", + " append: append non registered files.\n", + " -s|--song-directory \n", + " song storage directory.\n", + " -c|--codepage \n", + " metadata codepage\n", + " -i|--input-path \n", + " database input path\n", + " -o|--output-path \n", + " database output path\n", + " -h|--help\n", + " show this help message and exit.\n", + " -V|--version\n", + " show version information and exit.\n", + NULL, +}; + +struct songdb_params +{ + int mode; + char rootdir[MAX_PATH]; + char songdir[MAX_PATH]; + int cp; + char db_input_path[MAX_PATH]; + char db_output_path[MAX_PATH]; + bool is_show_usage; + bool is_show_version; +}; + +static struct songdb_params param; + +static void show_usage(void) +{ + int i; + + for (i = 0; usage_messages[i] != NULL; i++) + fprintf(stdout, usage_messages[i]); + return; +} + +static void show_version(void) +{ + fprintf(stdout, "songdb version %s\n", APP_VERSION); + fprintf(stdout, "Copyright (C) 2009 The Rockbox Team., Yoshihisa Uchida\n"); + fprintf(stdout, "Released under the GNU General Public License v2+\n"); + return; +} + +static bool check_opt(const char *arg, const char *short_opt, const char *long_opt) +{ + return (strcmp(arg, short_opt) == 0) || (strcmp(arg, long_opt) == 0); +} + +static bool check_path(int argc, char **argv, int idx, const char *opt_name, + char *value) +{ + if ((idx == argc-1) || (argv[idx+1][0] == '-')) + return false; + + if (strlen(argv[idx+1]) >= MAX_PATH) + { + fprintf(stderr, "%s is too long.\n", opt_name); + param.is_show_usage = false; + return false; + } + strcpy(value, argv[idx+1]); + return true; +} + +static bool get_params(int argc, char **argv) +{ + int idx = 0; + + param.mode = -1; + param.rootdir[0] = '\0'; + strcpy(param.songdir, "/"); + param.cp = 0; /* ISO-8859-1 */ + param.db_input_path[0] = '\0'; + param.db_output_path[0] = '\0'; + param.is_show_usage = true; + param.is_show_version = false; + + for (idx = 1; idx < argc; idx++) + { + if (check_opt(argv[idx], "-h", "--help")) + return true; + else if (check_opt(argv[idx], "-V", "--version")) + { + param.is_show_version = true; + return true; + } + else if (check_opt(argv[idx], "-r", "--root-path")) + { + if (!check_path(argc, argv, idx++, "root path", param.rootdir)) + return false; + } + else if (check_opt(argv[idx], "-s", "--song-directory")) + { + if (!check_path(argc, argv, idx++, "song storage directory", + param.songdir)) + return false; + } + else if (check_opt(argv[idx], "-m", "--mode")) + { + if (idx == argc-1) + return false; + + idx++; + if (strcmp(argv[idx],DB_MODE_CREATE_STR)==0) + param.mode = DB_MODE_CREATE; + else if (strcmp(argv[idx],DB_MODE_UPDATE_STR)==0) + param.mode = DB_MODE_UPDATE; + else if (strcmp(argv[idx],DB_MODE_APPEND_STR)==0) + param.mode = DB_MODE_APPEND; + else + { + fprintf(stderr, "%s: --mode is invalid.\n", argv[idx]); + param.is_show_usage = false; + return false; + } + } + else if (check_opt(argv[idx], "-c", "--codepage")) + { + if (idx == argc-1) + return false; + + param.cp = get_codepage(argv[++idx]); + if (param.cp < 0) + { + fprintf(stderr, "%s: codepage is invalid.\n", argv[idx]); + param.is_show_usage = false; + return false; + } + } + else if (check_opt(argv[idx], "-i", "--input-path")) + { + if (!check_path(argc, argv, idx++, "database input path", + param.db_input_path)) + return false; + } + else if (check_opt(argv[idx], "-o", "--output-path")) + { + if (!check_path(argc, argv, idx++, "database output path", + param.db_output_path)) + return false; + } + else + return false; + } + + if (param.rootdir[0] == '\0' || param.mode < 0) + return false; + + param.is_show_usage = false; + return true; +} + +int main(int argc, char **argv) +{ + if (!get_params(argc, argv) || param.is_show_usage) + { + show_usage(); + return 1; + } + + if (param.is_show_version) + { + show_version(); + return 0; + } + + sim_root_dir = param.rootdir; + + if (param.db_input_path[0] == '\0') + snprintf(param.db_input_path, MAX_PATH, "%s%s", + param.rootdir, DEFAULT_ROCKBOX_DIRECTORY); + + if (param.db_output_path[0] == '\0') + snprintf(param.db_output_path, MAX_PATH, "%s%s", + param.rootdir, DEFAULT_ROCKBOX_DIRECTORY); + + mkdirs(param.db_output_path); + + if (param.mode != DB_MODE_CREATE) + copy_database_files(param.db_input_path, param.db_output_path); + + set_db_root_path(param.db_output_path); + + set_codepage(param.cp); + + tagcache_init(); + + if (param.mode == DB_MODE_CREATE) + { + tagcache_remove_database(); + tagcache_build(param.songdir); + } + else if (param.mode == DB_MODE_UPDATE) + { + tagcache_build(param.songdir); + tagcache_reverse_scan(); + } + else if (param.mode == DB_MODE_APPEND) + { + tagcache_build(param.songdir); + } + + return 0; +}