Merge branches/ew r7104
thread-safety work in preparation for rewrite to use pthreads Expect no regressions against trunk (r7078), possibly minor performance improvements in update (due to fewer heap allocations), but increased stack usage. Applied the following patches: * maxpath_str for reentrancy (temporary fix, reverted) * path: start working on thread-safe variants of these methods * Re-entrancy work on path/character-set conversions * directory.c: exploreDirectory() use reentrant functions here * directory/update: more use of reentrant functions + cleanups * string_toupper: a strdup-less version of strDupToUpper * get_song_url: a static-variable-free version of getSongUrl() * Use reentrant/thread-safe get_song_url everywhere * replace rmp2amp with the reentrant version, rmp2amp_r * Get rid of the non-reentrant/non-thread-safe rpp2app, too. * buffer2array: assert strdup() returns a usable value in unit tests * replace utf8ToFsCharset and fsCharsetToUtf8 with thread-safe variants * fix storing playlists w/o absolute paths * parent_path(), a reentrant version of parentPath() * parentPath => parent_path for reentrancy and thread-safety * allow "make test" to automatically run embedded unit tests * remove convStrDup() and maxpath_str() * use MPD_PATH_MAX everywhere instead of MAXPATHLEN * path: get rid of appendSlash, pfx_path and just use pfx_dir * get_song_url: fix the ability to play songs in the top-level music_directory git-svn-id: https://svn.musicpd.org/mpd/trunk@7106 09075e82-0dd4-0310-85a5-a0d7c8717e4f
This commit is contained in:
parent
0d26248a0d
commit
b79f6b882a
|
@ -5,5 +5,7 @@ docdir = $(prefix)/share/doc/$(PACKAGE)
|
|||
doc_DATA = README UPGRADING
|
||||
EXTRA_DIST = COPYING $(doc_DATA)
|
||||
|
||||
sparse-check:
|
||||
sparse-check test:
|
||||
$(MAKE) -C src $@
|
||||
|
||||
.PHONY: sparse-check test
|
||||
|
|
|
@ -151,3 +151,15 @@ sparse-check:
|
|||
$(SPARSE) -I. $(mpd_CFLAGS) $(SPARSE_FLAGS) $(srcdir)/$$i || exit; \
|
||||
done
|
||||
|
||||
TEST_CFLAGS = -DUNIT_TEST
|
||||
TEST_FILES := $(shell grep UNIT_TEST $(mpd_SOURCES) | \
|
||||
awk -F: '{print $$1}' | uniq)
|
||||
|
||||
test: $(addprefix test-, $(subst .c,,$(TEST_FILES)))
|
||||
|
||||
test-%: %.c
|
||||
$(CC) $(CFLAGS) $(TEST_CFLAGS) -o $@ $<
|
||||
@./$@
|
||||
@echo $@: OK
|
||||
|
||||
.PHONY: sparse-check test
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
#define AUDIO_DEVICE_STATE "audio_device_state:"
|
||||
#define AUDIO_DEVICE_STATE_LEN 19 /* strlen(AUDIO_DEVICE_STATE) */
|
||||
#define AUDIO_BUFFER_SIZE 2*MAXPATHLEN
|
||||
#define AUDIO_BUFFER_SIZE 2*MPD_PATH_MAX
|
||||
|
||||
static AudioFormat audio_format;
|
||||
|
||||
|
|
|
@ -79,48 +79,56 @@ int main()
|
|||
int max;
|
||||
|
||||
b = strdup("lsinfo \"/some/dir/name \\\"test\\\"\"");
|
||||
assert(b);
|
||||
max = buffer2array(b, a, 4);
|
||||
assert( !strcmp("lsinfo", a[0]) );
|
||||
assert( !strcmp("/some/dir/name \"test\"", a[1]) );
|
||||
assert( !a[2] );
|
||||
|
||||
b = strdup("lsinfo \"/some/dir/name \\\"test\\\" something else\"");
|
||||
assert(b);
|
||||
max = buffer2array(b, a, 4);
|
||||
assert( !strcmp("lsinfo", a[0]) );
|
||||
assert( !strcmp("/some/dir/name \"test\" something else", a[1]) );
|
||||
assert( !a[2] );
|
||||
|
||||
b = strdup("lsinfo \"/some/dir\\\\name\"");
|
||||
assert(b);
|
||||
max = buffer2array(b, a, 4);
|
||||
assert( !strcmp("lsinfo", a[0]) );
|
||||
assert( !strcmp("/some/dir\\name", a[1]) );
|
||||
assert( !a[2] );
|
||||
|
||||
b = strdup("lsinfo \"/some/dir name\"");
|
||||
assert(b);
|
||||
max = buffer2array(b, a, 4);
|
||||
assert( !strcmp("lsinfo", a[0]) );
|
||||
assert( !strcmp("/some/dir name", a[1]) );
|
||||
assert( !a[2] );
|
||||
|
||||
b = strdup("lsinfo \"\\\"/some/dir\\\"\"");
|
||||
assert(b);
|
||||
max = buffer2array(b, a, 4);
|
||||
assert( !strcmp("lsinfo", a[0]) );
|
||||
assert( !strcmp("\"/some/dir\"", a[1]) );
|
||||
assert( !a[2] );
|
||||
|
||||
b = strdup("lsinfo \"\\\"/some/dir\\\" x\"");
|
||||
assert(b);
|
||||
max = buffer2array(b, a, 4);
|
||||
assert( !strcmp("lsinfo", a[0]) );
|
||||
assert( !strcmp("\"/some/dir\" x", a[1]) );
|
||||
assert( !a[2] );
|
||||
|
||||
b = strdup("lsinfo \"single quote\\'d from php magicquotes\"");
|
||||
assert(b);
|
||||
max = buffer2array(b, a, 4);
|
||||
assert( !strcmp("lsinfo", a[0]) );
|
||||
assert( !strcmp("single quote\'d from php magicquotes", a[1]) );
|
||||
assert( !a[2] );
|
||||
|
||||
b = strdup("lsinfo \"double quote\\\"d from php magicquotes\"");
|
||||
assert(b);
|
||||
max = buffer2array(b, a, 4);
|
||||
assert( !strcmp("lsinfo", a[0]) );
|
||||
assert( !strcmp("double quote\"d from php magicquotes", a[1]) );
|
||||
|
|
|
@ -95,26 +95,25 @@ int setCharSetConversion(char *to, char *from)
|
|||
return -1;
|
||||
}
|
||||
|
||||
char *convStrDup(char *string)
|
||||
char *char_conv_str(char *dest, char *string)
|
||||
{
|
||||
if (!char_conv_to)
|
||||
return NULL;
|
||||
|
||||
if (char_conv_same)
|
||||
return xstrdup(string);
|
||||
return strcpy(dest, string);
|
||||
|
||||
#ifdef HAVE_ICONV
|
||||
if (char_conv_use_iconv) {
|
||||
/* not optimized: */
|
||||
char buffer[BUFFER_SIZE];
|
||||
size_t inleft = strlen(string);
|
||||
char *ret;
|
||||
size_t outleft;
|
||||
size_t retlen = 0;
|
||||
size_t err;
|
||||
char *bufferPtr;
|
||||
|
||||
ret = xmalloc(1);
|
||||
ret[0] = '\0';
|
||||
dest[0] = '\0';
|
||||
|
||||
while (inleft) {
|
||||
bufferPtr = buffer;
|
||||
|
@ -124,27 +123,22 @@ char *convStrDup(char *string)
|
|||
&outleft);
|
||||
if (outleft == BUFFER_SIZE
|
||||
|| (err == -1L && errno != E2BIG)) {
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = xrealloc(ret, retlen + BUFFER_SIZE - outleft + 1);
|
||||
memcpy(ret + retlen, buffer, BUFFER_SIZE - outleft);
|
||||
memcpy(dest + retlen, buffer, BUFFER_SIZE - outleft);
|
||||
retlen += BUFFER_SIZE - outleft;
|
||||
ret[retlen] = '\0';
|
||||
dest[retlen] = '\0';
|
||||
}
|
||||
|
||||
return ret;
|
||||
return dest;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (char_conv_latin1ToUtf8) {
|
||||
case 1:
|
||||
return latin1StrToUtf8Dup(string);
|
||||
break;
|
||||
return latin1_to_utf8(dest, string);
|
||||
case -1:
|
||||
return utf8StrToLatin1Dup(string);
|
||||
break;
|
||||
return utf8_to_latin1(dest, string);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
|
|
@ -23,6 +23,6 @@
|
|||
|
||||
int setCharSetConversion(char *to, char *from);
|
||||
|
||||
char *convStrDup(char *string);
|
||||
char *char_conv_str(char *dest, char *string);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -32,8 +32,9 @@
|
|||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <errno.h>
|
||||
#include "path.h"
|
||||
|
||||
#define MAX_STRING_SIZE MAXPATHLEN+80
|
||||
#define MAX_STRING_SIZE MPD_PATH_MAX+80
|
||||
|
||||
#define CONF_COMMENT '#'
|
||||
#define CONF_BLOCK_BEGIN "{"
|
||||
|
|
23
src/decode.c
23
src/decode.c
|
@ -280,29 +280,28 @@ static void decodeStart(PlayerControl * pc, OutputBuffer * cb,
|
|||
int ret;
|
||||
InputStream inStream;
|
||||
InputPlugin *plugin = NULL;
|
||||
char *path;
|
||||
char path_max_tmp[MPD_PATH_MAX];
|
||||
|
||||
if (isRemoteUrl(pc->utf8url))
|
||||
path = utf8StrToLatin1Dup(pc->utf8url);
|
||||
else
|
||||
path = xstrdup(rmp2amp(utf8ToFsCharset(pc->utf8url)));
|
||||
|
||||
if (!path) {
|
||||
/* not actually sure why we convert between latin/UTF8 for URLs */
|
||||
if (isRemoteUrl(pc->utf8url)) {
|
||||
if (!utf8_to_latin1(path_max_tmp, pc->utf8url)) {
|
||||
dc->error = DECODE_ERROR_FILE;
|
||||
dc->state = DECODE_STATE_STOP;
|
||||
dc->start = 0;
|
||||
return;
|
||||
}
|
||||
} else
|
||||
rmp2amp_r(path_max_tmp,
|
||||
utf8_to_fs_charset(path_max_tmp, pc->utf8url));
|
||||
|
||||
copyMpdTagToOutputBuffer(cb, NULL);
|
||||
|
||||
pathcpy_trunc(dc->utf8url, pc->utf8url);
|
||||
|
||||
if (openInputStream(&inStream, path) < 0) {
|
||||
if (openInputStream(&inStream, path_max_tmp) < 0) {
|
||||
dc->error = DECODE_ERROR_FILE;
|
||||
dc->state = DECODE_STATE_STOP;
|
||||
dc->start = 0;
|
||||
free(path);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -321,7 +320,6 @@ static void decodeStart(PlayerControl * pc, OutputBuffer * cb,
|
|||
if (dc->stop) {
|
||||
dc->state = DECODE_STATE_STOP;
|
||||
dc->stop = 0;
|
||||
free(path);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -392,7 +390,8 @@ static void decodeStart(PlayerControl * pc, OutputBuffer * cb,
|
|||
|
||||
if (plugin->fileDecodeFunc) {
|
||||
closeInputStream(&inStream);
|
||||
ret = plugin->fileDecodeFunc(cb, dc, path);
|
||||
ret = plugin->fileDecodeFunc(cb, dc,
|
||||
path_max_tmp);
|
||||
break;
|
||||
} else if (plugin->streamDecodeFunc) {
|
||||
ret = plugin->streamDecodeFunc(cb, dc, &inStream);
|
||||
|
@ -412,8 +411,6 @@ static void decodeStart(PlayerControl * pc, OutputBuffer * cb,
|
|||
dc->stop = 0;
|
||||
dc->state = DECODE_STATE_STOP;
|
||||
}
|
||||
|
||||
free(path);
|
||||
}
|
||||
|
||||
static int decoderInit(PlayerControl * pc, OutputBuffer * cb,
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#define DECODE_H
|
||||
|
||||
#include "../config.h"
|
||||
#include "path.h"
|
||||
#include "tag.h"
|
||||
|
||||
#include "mpd_types.h"
|
||||
|
@ -51,7 +52,7 @@ typedef struct _DecoderControl {
|
|||
volatile mpd_sint8 cycleLogFiles;
|
||||
volatile double seekWhere;
|
||||
AudioFormat audioFormat;
|
||||
char utf8url[MAXPATHLEN + 1];
|
||||
char utf8url[MPD_PATH_MAX];
|
||||
volatile float totalTime;
|
||||
} DecoderControl;
|
||||
|
||||
|
|
222
src/directory.c
222
src/directory.c
|
@ -35,6 +35,7 @@
|
|||
#include "tagTracker.h"
|
||||
#include "utils.h"
|
||||
#include "volume.h"
|
||||
#include "ls.h"
|
||||
|
||||
#include <sys/wait.h>
|
||||
#include <dirent.h>
|
||||
|
@ -296,7 +297,9 @@ static void removeSongFromDirectory(Directory * directory, char *shortname)
|
|||
void *song;
|
||||
|
||||
if (findInList(directory->songs, shortname, &song)) {
|
||||
LOG("removing: %s\n", getSongUrl((Song *) song));
|
||||
char path_max_tmp[MPD_PATH_MAX]; /* wasteful */
|
||||
LOG("removing: %s\n",
|
||||
get_song_url(path_max_tmp, (Song *) song));
|
||||
deleteFromList(directory->songs, shortname);
|
||||
}
|
||||
}
|
||||
|
@ -359,64 +362,40 @@ static int updateInDirectory(Directory * directory, char *shortname, char *name)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* we don't look at hidden files nor files with newlines in them */
|
||||
static int skip_path(const char *path)
|
||||
{
|
||||
return (path[0] == '.' || strchr(path, '\n')) ? 1 : 0;
|
||||
}
|
||||
|
||||
/* return values:
|
||||
-1 -> error
|
||||
0 -> no error, but nothing removed
|
||||
1 -> no error, and stuff removed
|
||||
*/
|
||||
static int removeDeletedFromDirectory(Directory * directory, DIR * dir)
|
||||
static int removeDeletedFromDirectory(char *path_max_tmp, Directory * directory)
|
||||
{
|
||||
char cwd[2];
|
||||
struct dirent *ent;
|
||||
char *dirname = getDirectoryPath(directory);
|
||||
List *entList = makeList(free, 1);
|
||||
void *name;
|
||||
char *s;
|
||||
char *utf8;
|
||||
ListNode *node;
|
||||
ListNode *tmpNode;
|
||||
const char *dirname = (directory && directory->path) ?
|
||||
directory->path : NULL;
|
||||
ListNode *node, *tmpNode;
|
||||
DirectoryList *subdirs = directory->subDirectories;
|
||||
int ret = 0;
|
||||
|
||||
cwd[0] = '.';
|
||||
cwd[1] = '\0';
|
||||
if (dirname == NULL)
|
||||
dirname = cwd;
|
||||
|
||||
while ((ent = readdir(dir))) {
|
||||
if (ent->d_name[0] == '.')
|
||||
continue; /* hide hidden stuff */
|
||||
if (strchr(ent->d_name, '\n'))
|
||||
continue;
|
||||
|
||||
utf8 = fsCharsetToUtf8(ent->d_name);
|
||||
|
||||
if (!utf8)
|
||||
continue;
|
||||
|
||||
if (directory->path) {
|
||||
s = xmalloc(strlen(getDirectoryPath(directory))
|
||||
+ strlen(utf8) + 2);
|
||||
sprintf(s, "%s/%s", getDirectoryPath(directory), utf8);
|
||||
} else
|
||||
s = xstrdup(utf8);
|
||||
insertInList(entList, utf8, s);
|
||||
}
|
||||
|
||||
node = directory->subDirectories->firstNode;
|
||||
node = subdirs->firstNode;
|
||||
while (node) {
|
||||
tmpNode = node->nextNode;
|
||||
if (findInList(entList, node->key, &name)) {
|
||||
if (!isDir((char *)name)) {
|
||||
LOG("removing directory: %s\n", (char *)name);
|
||||
deleteFromList(directory->subDirectories,
|
||||
if (node->key) {
|
||||
if (dirname)
|
||||
sprintf(path_max_tmp, "%s/%s", dirname,
|
||||
node->key);
|
||||
else
|
||||
strcpy(path_max_tmp, node->key);
|
||||
|
||||
if (!isDir(path_max_tmp)) {
|
||||
LOG("removing directory: %s\n", path_max_tmp);
|
||||
deleteFromList(subdirs, node->key);
|
||||
ret = 1;
|
||||
}
|
||||
} else {
|
||||
LOG("removing directory: %s/%s\n",
|
||||
getDirectoryPath(directory), node->key);
|
||||
deleteFromList(directory->subDirectories, node->key);
|
||||
ret = 1;
|
||||
}
|
||||
node = tmpNode;
|
||||
}
|
||||
|
@ -424,40 +403,40 @@ static int removeDeletedFromDirectory(Directory * directory, DIR * dir)
|
|||
node = directory->songs->firstNode;
|
||||
while (node) {
|
||||
tmpNode = node->nextNode;
|
||||
if (findInList(entList, node->key, (void **)&name)) {
|
||||
if (!isMusic(name, NULL, 0)) {
|
||||
if (node->key) {
|
||||
if (dirname)
|
||||
sprintf(path_max_tmp, "%s/%s", dirname,
|
||||
node->key);
|
||||
else
|
||||
strcpy(path_max_tmp, node->key);
|
||||
|
||||
if (!isFile(path_max_tmp, NULL)) {
|
||||
removeSongFromDirectory(directory, node->key);
|
||||
ret = 1;
|
||||
}
|
||||
} else {
|
||||
removeSongFromDirectory(directory, node->key);
|
||||
ret = 1;
|
||||
}
|
||||
node = tmpNode;
|
||||
}
|
||||
|
||||
freeList(entList);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static Directory *addDirectoryPathToDB(char *utf8path, char **shortname)
|
||||
{
|
||||
char path_max_tmp[MPD_PATH_MAX];
|
||||
char *parent;
|
||||
Directory *parentDirectory;
|
||||
void *directory;
|
||||
|
||||
parent = xstrdup(parentPath(utf8path));
|
||||
parent = parent_path(path_max_tmp, utf8path);
|
||||
|
||||
if (strlen(parent) == 0)
|
||||
parentDirectory = (void *)mp3rootDirectory;
|
||||
else
|
||||
parentDirectory = addDirectoryPathToDB(parent, shortname);
|
||||
|
||||
if (!parentDirectory) {
|
||||
free(parent);
|
||||
if (!parentDirectory)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*shortname = utf8path + strlen(parent);
|
||||
while (*(*shortname) && *(*shortname) == '/')
|
||||
|
@ -467,10 +446,9 @@ static Directory *addDirectoryPathToDB(char *utf8path, char **shortname)
|
|||
(parentDirectory->subDirectories, *shortname, &directory)) {
|
||||
struct stat st;
|
||||
if (myStat(utf8path, &st) < 0 ||
|
||||
inodeFoundInParent(parentDirectory, st.st_ino, st.st_dev)) {
|
||||
free(parent);
|
||||
inodeFoundInParent(parentDirectory, st.st_ino, st.st_dev))
|
||||
return NULL;
|
||||
} else {
|
||||
else {
|
||||
directory = newDirectory(utf8path, parentDirectory);
|
||||
insertInList(parentDirectory->subDirectories,
|
||||
*shortname, directory);
|
||||
|
@ -481,34 +459,29 @@ static Directory *addDirectoryPathToDB(char *utf8path, char **shortname)
|
|||
with potentially the same name */
|
||||
removeSongFromDirectory(parentDirectory, *shortname);
|
||||
|
||||
free(parent);
|
||||
|
||||
return (Directory *) directory;
|
||||
}
|
||||
|
||||
static Directory *addParentPathToDB(char *utf8path, char **shortname)
|
||||
{
|
||||
char *parent;
|
||||
char path_max_tmp[MPD_PATH_MAX];
|
||||
Directory *parentDirectory;
|
||||
|
||||
parent = xstrdup(parentPath(utf8path));
|
||||
parent = parent_path(path_max_tmp, utf8path);
|
||||
|
||||
if (strlen(parent) == 0)
|
||||
parentDirectory = (void *)mp3rootDirectory;
|
||||
else
|
||||
parentDirectory = addDirectoryPathToDB(parent, shortname);
|
||||
|
||||
if (!parentDirectory) {
|
||||
free(parent);
|
||||
if (!parentDirectory)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*shortname = utf8path + strlen(parent);
|
||||
while (*(*shortname) && *(*shortname) == '/')
|
||||
(*shortname)++;
|
||||
|
||||
free(parent);
|
||||
|
||||
return (Directory *) parentDirectory;
|
||||
}
|
||||
|
||||
|
@ -526,6 +499,7 @@ static int updatePath(char *utf8path)
|
|||
char *path = sanitizePathDup(utf8path);
|
||||
time_t mtime;
|
||||
int ret = 0;
|
||||
char path_max_tmp[MPD_PATH_MAX];
|
||||
|
||||
if (NULL == path)
|
||||
return -1;
|
||||
|
@ -563,7 +537,8 @@ static int updatePath(char *utf8path)
|
|||
else if (0 == inodeFoundInParent(parentDirectory->parent,
|
||||
parentDirectory->stat->inode,
|
||||
parentDirectory->stat->device)
|
||||
&& song && isMusic(getSongUrl(song), &mtime, 0)) {
|
||||
&& song &&
|
||||
isMusic(get_song_url(path_max_tmp, song), &mtime, 0)) {
|
||||
free(path);
|
||||
if (song->mtime == mtime)
|
||||
return 0;
|
||||
|
@ -606,6 +581,14 @@ static int updatePath(char *utf8path)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static const char *opendir_path(char *path_max_tmp, char *dirname)
|
||||
{
|
||||
if (*dirname != '\0')
|
||||
return rmp2amp_r(path_max_tmp,
|
||||
utf8_to_fs_charset(path_max_tmp, dirname));
|
||||
return musicDir;
|
||||
}
|
||||
|
||||
/* return values:
|
||||
-1 -> error
|
||||
0 -> no error, but nothing updated
|
||||
|
@ -614,59 +597,39 @@ static int updatePath(char *utf8path)
|
|||
static int updateDirectory(Directory * directory)
|
||||
{
|
||||
DIR *dir;
|
||||
char cwd[2];
|
||||
struct dirent *ent;
|
||||
char *s;
|
||||
char *utf8;
|
||||
char *dirname = getDirectoryPath(directory);
|
||||
struct dirent *ent;
|
||||
char path_max_tmp[MPD_PATH_MAX];
|
||||
int ret = 0;
|
||||
|
||||
{
|
||||
if (!directory->stat && statDirectory(directory) < 0) {
|
||||
if (!directory->stat && statDirectory(directory) < 0)
|
||||
return -1;
|
||||
} else if (inodeFoundInParent(directory->parent,
|
||||
else if (inodeFoundInParent(directory->parent,
|
||||
directory->stat->inode,
|
||||
directory->stat->device)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
cwd[0] = '.';
|
||||
cwd[1] = '\0';
|
||||
if (dirname == NULL)
|
||||
dirname = cwd;
|
||||
|
||||
if ((dir = opendir(rmp2amp(utf8ToFsCharset(dirname)))) == NULL)
|
||||
directory->stat->device))
|
||||
return -1;
|
||||
|
||||
if (removeDeletedFromDirectory(directory, dir) > 0)
|
||||
dir = opendir(opendir_path(path_max_tmp, dirname));
|
||||
if (!dir)
|
||||
return -1;
|
||||
|
||||
if (removeDeletedFromDirectory(path_max_tmp, directory) > 0)
|
||||
ret = 1;
|
||||
|
||||
rewinddir(dir);
|
||||
|
||||
while ((ent = readdir(dir))) {
|
||||
if (ent->d_name[0] == '.')
|
||||
continue; /* hide hidden stuff */
|
||||
if (strchr(ent->d_name, '\n'))
|
||||
char *utf8;
|
||||
if (skip_path(ent->d_name))
|
||||
continue;
|
||||
|
||||
utf8 = fsCharsetToUtf8(ent->d_name);
|
||||
|
||||
utf8 = fs_charset_to_utf8(path_max_tmp, ent->d_name);
|
||||
if (!utf8)
|
||||
continue;
|
||||
|
||||
utf8 = xstrdup(utf8);
|
||||
|
||||
if (directory->path) {
|
||||
s = xmalloc(strlen(getDirectoryPath(directory)) +
|
||||
strlen(utf8) + 2);
|
||||
sprintf(s, "%s/%s", getDirectoryPath(directory), utf8);
|
||||
} else
|
||||
s = xstrdup(utf8);
|
||||
if (updateInDirectory(directory, utf8, s) > 0)
|
||||
if (directory->path)
|
||||
utf8 = pfx_dir(path_max_tmp, utf8, strlen(utf8),
|
||||
dirname, strlen(dirname));
|
||||
if (updateInDirectory(directory, utf8, path_max_tmp) > 0)
|
||||
ret = 1;
|
||||
free(utf8);
|
||||
free(s);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
@ -682,48 +645,35 @@ static int updateDirectory(Directory * directory)
|
|||
static int exploreDirectory(Directory * directory)
|
||||
{
|
||||
DIR *dir;
|
||||
char cwd[2];
|
||||
struct dirent *ent;
|
||||
char *s;
|
||||
char *utf8;
|
||||
char *dirname = getDirectoryPath(directory);
|
||||
struct dirent *ent;
|
||||
char path_max_tmp[MPD_PATH_MAX];
|
||||
int ret = 0;
|
||||
|
||||
cwd[0] = '.';
|
||||
cwd[1] = '\0';
|
||||
if (dirname == NULL)
|
||||
dirname = cwd;
|
||||
|
||||
DEBUG("explore: attempting to opendir: %s\n", dirname);
|
||||
if ((dir = opendir(rmp2amp(utf8ToFsCharset(dirname)))) == NULL)
|
||||
|
||||
dir = opendir(opendir_path(path_max_tmp, dirname));
|
||||
if (!dir)
|
||||
return -1;
|
||||
|
||||
DEBUG("explore: %s\n", dirname);
|
||||
|
||||
while ((ent = readdir(dir))) {
|
||||
if (ent->d_name[0] == '.')
|
||||
continue; /* hide hidden stuff */
|
||||
if (strchr(ent->d_name, '\n'))
|
||||
char *utf8;
|
||||
if (skip_path(ent->d_name))
|
||||
continue;
|
||||
|
||||
utf8 = fsCharsetToUtf8(ent->d_name);
|
||||
|
||||
utf8 = fs_charset_to_utf8(path_max_tmp, ent->d_name);
|
||||
if (!utf8)
|
||||
continue;
|
||||
|
||||
utf8 = xstrdup(utf8);
|
||||
|
||||
DEBUG("explore: found: %s (%s)\n", ent->d_name, utf8);
|
||||
|
||||
if (directory->path) {
|
||||
s = xmalloc(strlen(getDirectoryPath(directory)) +
|
||||
strlen(utf8) + 2);
|
||||
sprintf(s, "%s/%s", getDirectoryPath(directory), utf8);
|
||||
} else
|
||||
s = xstrdup(utf8);
|
||||
if (addToDirectory(directory, utf8, s) > 0)
|
||||
if (directory->path)
|
||||
utf8 = pfx_dir(path_max_tmp, utf8, strlen(utf8),
|
||||
dirname, strlen(dirname));
|
||||
if (addToDirectory(directory, utf8, path_max_tmp) > 0)
|
||||
ret = 1;
|
||||
free(utf8);
|
||||
free(s);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
@ -735,10 +685,8 @@ static int statDirectory(Directory * dir)
|
|||
{
|
||||
struct stat st;
|
||||
|
||||
if (myStat(getDirectoryPath(dir) ? getDirectoryPath(dir) : "", &st) < 0)
|
||||
{
|
||||
if (myStat(getDirectoryPath(dir), &st) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
dir->stat = newDirectoryStat(&st);
|
||||
|
||||
|
@ -953,8 +901,8 @@ static void writeDirectoryInfo(FILE * fp, Directory * directory)
|
|||
|
||||
static void readDirectoryInfo(FILE * fp, Directory * directory)
|
||||
{
|
||||
char buffer[MAXPATHLEN * 2];
|
||||
int bufferSize = MAXPATHLEN * 2;
|
||||
char buffer[MPD_PATH_MAX * 2];
|
||||
int bufferSize = MPD_PATH_MAX * 2;
|
||||
char *key;
|
||||
Directory *subDirectory;
|
||||
int strcmpRet;
|
||||
|
|
15
src/locate.c
15
src/locate.c
|
@ -16,8 +16,8 @@
|
|||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "path.h"
|
||||
#include "locate.h"
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#define LOCATE_TAG_FILE_KEY "file"
|
||||
|
@ -127,14 +127,14 @@ static int strstrSearchTag(Song * song, int type, char *str)
|
|||
int ret = 0;
|
||||
|
||||
if (type == LOCATE_TAG_FILE_TYPE || type == LOCATE_TAG_ANY_TYPE) {
|
||||
dup = strDupToUpper(getSongUrl(song));
|
||||
if (strstr(dup, str))
|
||||
char path_max_tmp[MPD_PATH_MAX];
|
||||
|
||||
string_toupper(get_song_url(path_max_tmp, song));
|
||||
if (strstr(path_max_tmp, str))
|
||||
ret = 1;
|
||||
free(dup);
|
||||
if (ret == 1 || type == LOCATE_TAG_FILE_TYPE) {
|
||||
if (ret == 1 || type == LOCATE_TAG_FILE_TYPE)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (!song->tag)
|
||||
return 0;
|
||||
|
@ -173,7 +173,8 @@ static int tagItemFoundAndMatches(Song * song, int type, char *str)
|
|||
int i;
|
||||
|
||||
if (type == LOCATE_TAG_FILE_TYPE || type == LOCATE_TAG_ANY_TYPE) {
|
||||
if (0 == strcmp(str, getSongUrl(song)))
|
||||
char path_max_tmp[MPD_PATH_MAX];
|
||||
if (0 == strcmp(str, get_song_url(path_max_tmp, song)))
|
||||
return 1;
|
||||
if (type == LOCATE_TAG_FILE_TYPE)
|
||||
return 0;
|
||||
|
|
29
src/ls.c
29
src/ls.c
|
@ -108,22 +108,24 @@ int lsPlaylists(int fd, char *utf8path)
|
|||
struct dirent *ent;
|
||||
char *dup;
|
||||
char *utf8;
|
||||
char s[MAXPATHLEN + 1];
|
||||
char s[MPD_PATH_MAX];
|
||||
char path_max_tmp[MPD_PATH_MAX];
|
||||
List *list = NULL;
|
||||
ListNode *node = NULL;
|
||||
char *path = utf8ToFsCharset(utf8path);
|
||||
char *actualPath = rpp2app(path);
|
||||
char *actualPath = rpp2app_r(path_max_tmp,
|
||||
utf8_to_fs_charset(path_max_tmp,
|
||||
utf8path));
|
||||
int actlen = strlen(actualPath) + 1;
|
||||
int maxlen = MAXPATHLEN - actlen;
|
||||
int maxlen = MPD_PATH_MAX - actlen;
|
||||
int suflen = strlen(PLAYLIST_FILE_SUFFIX) + 1;
|
||||
int suff;
|
||||
|
||||
if (actlen > MAXPATHLEN - 1 || (dir = opendir(actualPath)) == NULL) {
|
||||
if (actlen > MPD_PATH_MAX - 1 || (dir = opendir(actualPath)) == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
s[MAXPATHLEN] = '\0';
|
||||
/* this is safe, notice actlen > MAXPATHLEN-1 above */
|
||||
s[MPD_PATH_MAX - 1] = '\0';
|
||||
/* this is safe, notice actlen > MPD_PATH_MAX-1 above */
|
||||
strcpy(s, actualPath);
|
||||
strcat(s, "/");
|
||||
|
||||
|
@ -138,16 +140,18 @@ int lsPlaylists(int fd, char *utf8path)
|
|||
memcpy(s + actlen, ent->d_name, len);
|
||||
if (stat(s, &st) == 0) {
|
||||
if (S_ISREG(st.st_mode)) {
|
||||
char path_max_tmp[MPD_PATH_MAX];
|
||||
if (list == NULL)
|
||||
list = makeList(NULL, 1);
|
||||
dup[suff] = '\0';
|
||||
if ((utf8 = fsCharsetToUtf8(dup))) {
|
||||
utf8 = fs_charset_to_utf8(path_max_tmp,
|
||||
dup);
|
||||
if (utf8)
|
||||
insertInList(list, utf8, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
|
@ -181,16 +185,17 @@ int lsPlaylists(int fd, char *utf8path)
|
|||
|
||||
int myStat(char *utf8file, struct stat *st)
|
||||
{
|
||||
char *file = utf8ToFsCharset(utf8file);
|
||||
char path_max_tmp[MPD_PATH_MAX];
|
||||
char *file = utf8_to_fs_charset(path_max_tmp, utf8file);
|
||||
char *actualFile = file;
|
||||
|
||||
if (actualFile[0] != '/')
|
||||
actualFile = rmp2amp(file);
|
||||
actualFile = rmp2amp_r(path_max_tmp, file);
|
||||
|
||||
return stat(actualFile, st);
|
||||
}
|
||||
|
||||
static int isFile(char *utf8file, time_t * mtime)
|
||||
int isFile(char *utf8file, time_t * mtime)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
|
|
2
src/ls.h
2
src/ls.h
|
@ -49,4 +49,6 @@ InputPlugin *isMusic(char *utf8file, time_t * mtime, unsigned int next);
|
|||
|
||||
int printRemoteUrlHandlers(int fd);
|
||||
|
||||
int isFile(char *utf8file, time_t * mtime);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -208,10 +208,10 @@ static void parseOptions(int argc, char **argv, Options * options)
|
|||
} else if (argcLeft == 1) {
|
||||
struct stat st;
|
||||
char *homedir = getenv("HOME");
|
||||
char userfile[MAXPATHLEN + 1] = "";
|
||||
char userfile[MPD_PATH_MAX] = "";
|
||||
if (homedir && (strlen(homedir) +
|
||||
strlen(USER_CONFIG_FILE_LOCATION)) <
|
||||
MAXPATHLEN) {
|
||||
MPD_PATH_MAX) {
|
||||
strcpy(userfile, homedir);
|
||||
strcat(userfile, USER_CONFIG_FILE_LOCATION);
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define BUFFER_LENGTH MAXPATHLEN+1024
|
||||
#define BUFFER_LENGTH MPD_PATH_MAX+1024
|
||||
|
||||
static void blockingWrite(const int fd, const char *string, size_t len)
|
||||
{
|
||||
|
|
116
src/path.c
116
src/path.c
|
@ -40,39 +40,25 @@
|
|||
|
||||
const char *musicDir;
|
||||
static const char *playlistDir;
|
||||
static size_t music_dir_len;
|
||||
static size_t playlist_dir_len;
|
||||
static char *fsCharset;
|
||||
|
||||
static char *pathConvCharset(char *to, char *from, char *str, char *ret)
|
||||
static char *path_conv_charset(char *dest, char *to, char *from, char *str)
|
||||
{
|
||||
if (ret)
|
||||
free(ret);
|
||||
return setCharSetConversion(to, from) ? NULL : convStrDup(str);
|
||||
return setCharSetConversion(to, from) ? NULL : char_conv_str(dest, str);
|
||||
}
|
||||
|
||||
char *fsCharsetToUtf8(char *str)
|
||||
char *fs_charset_to_utf8(char *dst, char *str)
|
||||
{
|
||||
static char *ret;
|
||||
|
||||
ret = pathConvCharset("UTF-8", fsCharset, str, ret);
|
||||
|
||||
if (ret && !validUtf8String(ret)) {
|
||||
free(ret);
|
||||
ret = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
char *ret = path_conv_charset(dst, "UTF-8", fsCharset, str);
|
||||
return (ret && !validUtf8String(ret)) ? NULL : ret;
|
||||
}
|
||||
|
||||
char *utf8ToFsCharset(char *str)
|
||||
char *utf8_to_fs_charset(char *dst, char *str)
|
||||
{
|
||||
static char *ret;
|
||||
|
||||
ret = pathConvCharset(fsCharset, "UTF-8", str, ret);
|
||||
|
||||
if (!ret)
|
||||
ret = xstrdup(str);
|
||||
|
||||
return ret;
|
||||
char *ret = path_conv_charset(dst, fsCharset, "UTF-8", str);
|
||||
return ret ? ret : strcpy(dst, str);
|
||||
}
|
||||
|
||||
void setFsCharset(char *charset)
|
||||
|
@ -111,23 +97,6 @@ char *getFsCharset(void)
|
|||
return fsCharset;
|
||||
}
|
||||
|
||||
static char *appendSlash(char **path)
|
||||
{
|
||||
char *temp = *path;
|
||||
int len = strlen(temp);
|
||||
|
||||
if (temp[len - 1] != '/') {
|
||||
temp = xmalloc(len + 2);
|
||||
memset(temp, 0, len + 2);
|
||||
memcpy(temp, *path, len);
|
||||
temp[len] = '/';
|
||||
free(*path);
|
||||
*path = temp;
|
||||
}
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
void initPaths(void)
|
||||
{
|
||||
ConfigParam *musicParam = parseConfigFilePath(CONF_MUSIC_DIR, 1);
|
||||
|
@ -138,8 +107,11 @@ void initPaths(void)
|
|||
char *originalLocale;
|
||||
DIR *dir;
|
||||
|
||||
musicDir = appendSlash(&(musicParam->value));
|
||||
playlistDir = appendSlash(&(playlistParam->value));
|
||||
musicDir = xstrdup(musicParam->value);
|
||||
playlistDir = xstrdup(playlistParam->value);
|
||||
|
||||
music_dir_len = strlen(musicDir);
|
||||
playlist_dir_len = strlen(playlistDir);
|
||||
|
||||
if ((dir = opendir(playlistDir)) == NULL) {
|
||||
FATAL("cannot open %s \"%s\" (config line %i): %s\n",
|
||||
|
@ -205,36 +177,35 @@ void finishPaths(void)
|
|||
fsCharset = NULL;
|
||||
}
|
||||
|
||||
static char *pfx_path(const char *path, const char *pfx, const size_t pfx_len)
|
||||
char *pfx_dir(char *dst,
|
||||
const char *path, const size_t path_len,
|
||||
const char *pfx, const size_t pfx_len)
|
||||
{
|
||||
static char ret[MAXPATHLEN+1];
|
||||
size_t rp_len = strlen(path);
|
||||
if (mpd_unlikely((pfx_len + path_len + 1) >= MPD_PATH_MAX))
|
||||
FATAL("Cannot prefix '%s' to '%s', PATH_MAX: %d\n",
|
||||
pfx, path, MPD_PATH_MAX);
|
||||
|
||||
/* check for the likely condition first: */
|
||||
if (mpd_likely((pfx_len + rp_len) < MAXPATHLEN)) {
|
||||
memcpy(ret, pfx, pfx_len);
|
||||
memcpy(ret + pfx_len, path, rp_len + 1);
|
||||
return ret;
|
||||
}
|
||||
/* memmove allows dst == path */
|
||||
memmove(dst + pfx_len + 1, path, path_len + 1);
|
||||
memcpy(dst, pfx, pfx_len);
|
||||
dst[pfx_len] = '/';
|
||||
|
||||
/* unlikely, return an empty string because truncating would
|
||||
* also be wrong... break early and break loudly (the system
|
||||
* headers are likely screwed, not mpd) */
|
||||
ERROR("Cannot prefix '%s' to '%s', max: %d\n", pfx, path, MAXPATHLEN);
|
||||
ret[0] = '\0';
|
||||
return ret;
|
||||
/* this is weird, but directory.c can use it more safely/efficiently */
|
||||
return (dst + pfx_len + 1);
|
||||
}
|
||||
|
||||
char *rmp2amp(char *relativePath)
|
||||
char *rmp2amp_r(char *dst, const char *rel_path)
|
||||
{
|
||||
size_t pfx_len = strlen(musicDir);
|
||||
return pfx_path(relativePath, musicDir, pfx_len);
|
||||
pfx_dir(dst, rel_path, strlen(rel_path),
|
||||
(const char *)musicDir, music_dir_len);
|
||||
return dst;
|
||||
}
|
||||
|
||||
char *rpp2app(char *relativePath)
|
||||
char *rpp2app_r(char *dst, const char *rel_path)
|
||||
{
|
||||
size_t pfx_len = strlen(playlistDir);
|
||||
return pfx_path(relativePath, playlistDir, pfx_len);
|
||||
pfx_dir(dst, rel_path, strlen(rel_path),
|
||||
(const char *)playlistDir, playlist_dir_len);
|
||||
return dst;
|
||||
}
|
||||
|
||||
/* this is actually like strlcpy (OpenBSD), but we don't actually want to
|
||||
|
@ -244,29 +215,28 @@ void pathcpy_trunc(char *dest, const char *src)
|
|||
{
|
||||
size_t len = strlen(src);
|
||||
|
||||
if (mpd_unlikely(len > MAXPATHLEN))
|
||||
len = MAXPATHLEN;
|
||||
if (mpd_unlikely(len >= MPD_PATH_MAX))
|
||||
len = MPD_PATH_MAX - 1;
|
||||
memcpy(dest, src, len);
|
||||
dest[len] = '\0';
|
||||
}
|
||||
|
||||
char *parentPath(char *path)
|
||||
char *parent_path(char *path_max_tmp, const char *path)
|
||||
{
|
||||
static char parentPath[MAXPATHLEN+1];
|
||||
char *c;
|
||||
|
||||
pathcpy_trunc(parentPath, path);
|
||||
c = strrchr(parentPath,'/');
|
||||
pathcpy_trunc(path_max_tmp, path);
|
||||
c = strrchr(path_max_tmp,'/');
|
||||
|
||||
if (c == NULL)
|
||||
parentPath[0] = '\0';
|
||||
path_max_tmp[0] = '\0';
|
||||
else {
|
||||
while ((parentPath <= c) && *(--c) == '/') /* nothing */
|
||||
while ((path_max_tmp <= c) && *(--c) == '/') /* nothing */
|
||||
;
|
||||
c[1] = '\0';
|
||||
}
|
||||
|
||||
return parentPath;
|
||||
return path_max_tmp;
|
||||
}
|
||||
|
||||
char *sanitizePathDup(char *path)
|
||||
|
|
46
src/path.h
46
src/path.h
|
@ -22,6 +22,17 @@
|
|||
#include "../config.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <limits.h>
|
||||
|
||||
#if !defined(MPD_PATH_MAX)
|
||||
# if defined(MAXPATHLEN)
|
||||
# define MPD_PATH_MAX MAXPATHLEN
|
||||
# elif defined(PATH_MAX)
|
||||
# define MPD_PATH_MAX PATH_MAX
|
||||
# else
|
||||
# define MPD_PATH_MAX 256
|
||||
# endif
|
||||
#endif
|
||||
|
||||
extern const char *musicDir;
|
||||
|
||||
|
@ -29,33 +40,34 @@ void initPaths(void);
|
|||
|
||||
void finishPaths(void);
|
||||
|
||||
/* utf8ToFsCharset() and fsCharsetToUtf8()
|
||||
* Each returns a static pointer to a dynamically allocated buffer
|
||||
* which means:
|
||||
* - Do not manually free the return value of these functions, it'll be
|
||||
* automatically freed the next time it is called.
|
||||
* - They are not reentrant, xstrdup the return value immediately if
|
||||
* you expect to call one of these functions again, but still need the
|
||||
* previous result.
|
||||
* - The static pointer is unique to each function.
|
||||
*/
|
||||
char *utf8ToFsCharset(char *str);
|
||||
char *fsCharsetToUtf8(char *str);
|
||||
char *fs_charset_to_utf8(char *dst, char *str);
|
||||
|
||||
char *utf8_to_fs_charset(char *dst, char *str);
|
||||
|
||||
void setFsCharset(char *charset);
|
||||
|
||||
char *getFsCharset(void);
|
||||
|
||||
/*
|
||||
* pfx_dir - sets dst="$pfx/$path" and returns a pointer to path inside * dst
|
||||
* this will unconditionally put a '/' between pfx and path unlike
|
||||
* the static pfx_path() function in path.c
|
||||
* dst is assumed to be MAXPATHLEN in size
|
||||
* dst can point to the same location as path, but not pfx, which makes
|
||||
* this better than sprintf(3) in some cases
|
||||
*/
|
||||
char *pfx_dir(char *dst,
|
||||
const char *path, const size_t path_len,
|
||||
const char *pfx, const size_t pfx_len);
|
||||
|
||||
/* relative music path to absolute music path
|
||||
* char * passed is a static variable, so don't free it
|
||||
*/
|
||||
char *rmp2amp(char *file);
|
||||
char *rmp2amp_r(char *dst, const char *rel_path);
|
||||
|
||||
/* static char * returned */
|
||||
char *rpp2app(char *file);
|
||||
char *rpp2app_r(char *dst, const char *rel_path);
|
||||
|
||||
/* static char * returned */
|
||||
char *parentPath(char *path);
|
||||
char *parent_path(char *path_max_tmp, const char *path);
|
||||
|
||||
/* strips extra "///" and leading "/" and trailing "/" */
|
||||
char *sanitizePathDup(char *path);
|
||||
|
|
11
src/player.c
11
src/player.c
|
@ -222,7 +222,7 @@ int playerPlay(int fd, Song * song)
|
|||
|
||||
copyMpdTagToMetadataChunk(song->tag, &(pc->fileMetadataChunk));
|
||||
|
||||
pathcpy_trunc(pc->utf8url, getSongUrl(song));
|
||||
get_song_url(pc->utf8url, song);
|
||||
|
||||
pc->play = 1;
|
||||
if (playerInit() < 0) {
|
||||
|
@ -337,7 +337,7 @@ int getPlayerError(void)
|
|||
char *getPlayerErrorStr(void)
|
||||
{
|
||||
static char *error;
|
||||
int errorlen = MAXPATHLEN + 1024;
|
||||
int errorlen = MPD_PATH_MAX + 1024;
|
||||
PlayerControl *pc = &(getPlayerData()->playerControl);
|
||||
|
||||
error = xrealloc(error, errorlen);
|
||||
|
@ -395,7 +395,7 @@ int queueSong(Song * song)
|
|||
PlayerControl *pc = &(getPlayerData()->playerControl);
|
||||
|
||||
if (pc->queueState == PLAYER_QUEUE_BLANK) {
|
||||
pathcpy_trunc(pc->utf8url, getSongUrl(song));
|
||||
get_song_url(pc->utf8url, song);
|
||||
|
||||
if (song->tag)
|
||||
pc->fileTime = song->tag->time;
|
||||
|
@ -454,6 +454,7 @@ void playerQueueUnlock(void)
|
|||
int playerSeek(int fd, Song * song, float time)
|
||||
{
|
||||
PlayerControl *pc = &(getPlayerData()->playerControl);
|
||||
char path_max_tmp[MPD_PATH_MAX];
|
||||
|
||||
if (pc->state == PLAYER_STATE_STOP) {
|
||||
commandError(fd, ACK_ERROR_PLAYER_SYNC,
|
||||
|
@ -461,7 +462,7 @@ int playerSeek(int fd, Song * song, float time)
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (strcmp(pc->utf8url, getSongUrl(song)) != 0) {
|
||||
if (strcmp(pc->utf8url, get_song_url(path_max_tmp, song)) != 0) {
|
||||
if (song->tag)
|
||||
pc->fileTime = song->tag->time;
|
||||
else
|
||||
|
@ -469,7 +470,7 @@ int playerSeek(int fd, Song * song, float time)
|
|||
|
||||
copyMpdTagToMetadataChunk(song->tag, &(pc->fileMetadataChunk));
|
||||
|
||||
pathcpy_trunc(pc->utf8url, getSongUrl(song));
|
||||
strcpy(pc->utf8url, path_max_tmp);
|
||||
}
|
||||
|
||||
if (pc->error == PLAYER_ERROR_NOERROR) {
|
||||
|
|
|
@ -71,9 +71,9 @@ typedef struct _PlayerControl {
|
|||
volatile float totalTime;
|
||||
volatile float elapsedTime;
|
||||
volatile float fileTime;
|
||||
char utf8url[MAXPATHLEN + 1];
|
||||
char currentUrl[MAXPATHLEN + 1];
|
||||
char erroredUrl[MAXPATHLEN + 1];
|
||||
char utf8url[MPD_PATH_MAX];
|
||||
char currentUrl[MPD_PATH_MAX];
|
||||
char erroredUrl[MPD_PATH_MAX];
|
||||
volatile mpd_sint8 queueState;
|
||||
volatile mpd_sint8 queueLockState;
|
||||
volatile mpd_sint8 lockQueue;
|
||||
|
|
|
@ -130,9 +130,9 @@ void initPlayerData(void)
|
|||
playerData_pd->playerControl.queueLockState = PLAYER_QUEUE_UNLOCKED;
|
||||
playerData_pd->playerControl.seek = 0;
|
||||
playerData_pd->playerControl.closeAudio = 0;
|
||||
memset(playerData_pd->playerControl.utf8url, 0, MAXPATHLEN + 1);
|
||||
memset(playerData_pd->playerControl.erroredUrl, 0, MAXPATHLEN + 1);
|
||||
memset(playerData_pd->playerControl.currentUrl, 0, MAXPATHLEN + 1);
|
||||
memset(playerData_pd->playerControl.utf8url, 0, MPD_PATH_MAX);
|
||||
memset(playerData_pd->playerControl.erroredUrl, 0, MPD_PATH_MAX);
|
||||
memset(playerData_pd->playerControl.currentUrl, 0, MPD_PATH_MAX);
|
||||
playerData_pd->playerControl.crossFade = crossfade;
|
||||
playerData_pd->playerControl.softwareVolume = 1000;
|
||||
playerData_pd->playerControl.totalPlayTime = 0;
|
||||
|
@ -145,7 +145,7 @@ void initPlayerData(void)
|
|||
playerData_pd->decoderControl.state = DECODE_STATE_STOP;
|
||||
playerData_pd->decoderControl.seek = 0;
|
||||
playerData_pd->decoderControl.error = DECODE_ERROR_NOERROR;
|
||||
memset(playerData_pd->decoderControl.utf8url, 0, MAXPATHLEN + 1);
|
||||
memset(playerData_pd->decoderControl.utf8url, 0, MPD_PATH_MAX);
|
||||
}
|
||||
|
||||
PlayerData *getPlayerData(void)
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
#define PLAYLIST_STATE_FILE_STATE_PAUSE "pause"
|
||||
#define PLAYLIST_STATE_FILE_STATE_STOP "stop"
|
||||
|
||||
#define PLAYLIST_BUFFER_SIZE 2*MAXPATHLEN
|
||||
#define PLAYLIST_BUFFER_SIZE 2*MPD_PATH_MAX
|
||||
|
||||
#define PLAYLIST_HASH_MULT 4
|
||||
|
||||
|
@ -244,9 +244,11 @@ int clearStoredPlaylist(int fd, char *utf8file)
|
|||
int showPlaylist(int fd)
|
||||
{
|
||||
int i;
|
||||
char path_max_tmp[MPD_PATH_MAX];
|
||||
|
||||
for (i = 0; i < playlist.length; i++) {
|
||||
fdprintf(fd, "%i:%s\n", i, getSongUrl(playlist.songs[i]));
|
||||
fdprintf(fd, "%i:%s\n", i,
|
||||
get_song_url(path_max_tmp, playlist.songs[i]));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -499,6 +501,8 @@ static void swapSongs(int song1, int song2)
|
|||
|
||||
static void queueNextSongInPlaylist(void)
|
||||
{
|
||||
char path_max_tmp[MPD_PATH_MAX];
|
||||
|
||||
if (playlistQueue->numberOfNodes != 0) {
|
||||
int i;
|
||||
/* we need to find where in order[] is first song from queue */
|
||||
|
@ -511,7 +515,8 @@ static void queueNextSongInPlaylist(void)
|
|||
playlist.queued = i;
|
||||
DEBUG("playlist: queue song %i:\"%s\"\n",
|
||||
playlist.queued,
|
||||
getSongUrl(playlist.
|
||||
get_song_url(path_max_tmp,
|
||||
playlist.
|
||||
songs[playlist.order[playlist.queued]]));
|
||||
|
||||
if (queueSong(playlist.songs[playlist.order[playlist.queued]]) <
|
||||
|
@ -524,7 +529,8 @@ static void queueNextSongInPlaylist(void)
|
|||
playlist.queued = playlist.current + 1;
|
||||
DEBUG("playlist: queue song %i:\"%s\"\n",
|
||||
playlist.queued,
|
||||
getSongUrl(playlist.
|
||||
get_song_url(path_max_tmp,
|
||||
playlist.
|
||||
songs[playlist.order[playlist.queued]]));
|
||||
if (queueSong(playlist.songs[playlist.order[playlist.queued]]) <
|
||||
0) {
|
||||
|
@ -539,7 +545,8 @@ static void queueNextSongInPlaylist(void)
|
|||
playlist.queued = 0;
|
||||
DEBUG("playlist: queue song %i:\"%s\"\n",
|
||||
playlist.queued,
|
||||
getSongUrl(playlist.
|
||||
get_song_url(path_max_tmp,
|
||||
playlist.
|
||||
songs[playlist.order[playlist.queued]]));
|
||||
if (queueSong(playlist.songs[playlist.order[playlist.queued]]) <
|
||||
0) {
|
||||
|
@ -897,6 +904,8 @@ int stopPlaylist(int fd)
|
|||
|
||||
static int playPlaylistOrderNumber(int fd, int orderNum)
|
||||
{
|
||||
char path_max_tmp[MPD_PATH_MAX];
|
||||
|
||||
if (playerStop(fd) < 0)
|
||||
return -1;
|
||||
|
||||
|
@ -906,7 +915,8 @@ static int playPlaylistOrderNumber(int fd, int orderNum)
|
|||
playlist_queueError = 0;
|
||||
|
||||
DEBUG("playlist: play %i:\"%s\"\n", orderNum,
|
||||
getSongUrl(playlist.songs[playlist.order[orderNum]]));
|
||||
get_song_url(path_max_tmp,
|
||||
playlist.songs[playlist.order[orderNum]]));
|
||||
|
||||
if (playerPlay(fd, (playlist.songs[playlist.order[orderNum]])) < 0) {
|
||||
stopPlaylist(fd);
|
||||
|
@ -1003,6 +1013,7 @@ static void syncCurrentPlayerDecodeMetadata(void)
|
|||
Song *songPlayer = playerCurrentDecodeSong();
|
||||
Song *song;
|
||||
int songNum;
|
||||
char path_max_tmp[MPD_PATH_MAX];
|
||||
|
||||
if (!songPlayer)
|
||||
return;
|
||||
|
@ -1014,7 +1025,7 @@ static void syncCurrentPlayerDecodeMetadata(void)
|
|||
song = playlist.songs[songNum];
|
||||
|
||||
if (song->type == SONG_TYPE_URL &&
|
||||
0 == strcmp(getSongUrl(song), songPlayer->url) &&
|
||||
0 == strcmp(get_song_url(path_max_tmp, song), songPlayer->url) &&
|
||||
!mpdTagsAreEqual(song->tag, songPlayer->tag)) {
|
||||
if (song->tag)
|
||||
freeMpdTag(song->tag);
|
||||
|
@ -1376,7 +1387,8 @@ int shufflePlaylist(int fd)
|
|||
|
||||
int deletePlaylist(int fd, char *utf8file)
|
||||
{
|
||||
char *file = utf8ToFsCharset(utf8file);
|
||||
char path_max_tmp[MPD_PATH_MAX];
|
||||
char *file = utf8_to_fs_charset(path_max_tmp, utf8file);
|
||||
char *rfile = xmalloc(strlen(file) + strlen(".") +
|
||||
strlen(PLAYLIST_FILE_SUFFIX) + 1);
|
||||
char *actualFile;
|
||||
|
@ -1385,7 +1397,8 @@ int deletePlaylist(int fd, char *utf8file)
|
|||
strcat(rfile, ".");
|
||||
strcat(rfile, PLAYLIST_FILE_SUFFIX);
|
||||
|
||||
if ((actualFile = rpp2app(rfile)) && isPlaylist(actualFile))
|
||||
actualFile = rpp2app_r(path_max_tmp, rfile);
|
||||
if (isPlaylist(actualFile))
|
||||
free(rfile);
|
||||
else {
|
||||
free(rfile);
|
||||
|
|
63
src/song.c
63
src/song.c
|
@ -66,9 +66,11 @@ Song *newSong(char *url, int type, Directory * parentDir)
|
|||
if (song->type == SONG_TYPE_FILE) {
|
||||
InputPlugin *plugin;
|
||||
unsigned int next = 0;
|
||||
char *song_url = getSongUrl(song);
|
||||
char *abs_path = rmp2amp(utf8ToFsCharset(song_url));
|
||||
while (!song->tag && (plugin = isMusic(song_url,
|
||||
char path_max_tmp[MPD_PATH_MAX];
|
||||
char *abs_path = rmp2amp_r(path_max_tmp,
|
||||
get_song_url(path_max_tmp, song));
|
||||
|
||||
while (!song->tag && (plugin = isMusic(abs_path,
|
||||
&(song->mtime),
|
||||
next++))) {
|
||||
song->tag = plugin->tagDupFunc(abs_path);
|
||||
|
@ -94,7 +96,6 @@ void freeJustSong(Song * song)
|
|||
if (song->tag)
|
||||
freeMpdTag(song->tag);
|
||||
free(song);
|
||||
getSongUrl(NULL);
|
||||
}
|
||||
|
||||
SongList *newSongList(void)
|
||||
|
@ -231,8 +232,8 @@ static int matchesAnMpdTagItemKey(char *buffer, int *itemType)
|
|||
|
||||
void readSongInfoIntoList(FILE * fp, SongList * list, Directory * parentDir)
|
||||
{
|
||||
char buffer[MAXPATHLEN + 1024];
|
||||
int bufferSize = MAXPATHLEN + 1024;
|
||||
char buffer[MPD_PATH_MAX + 1024];
|
||||
int bufferSize = MPD_PATH_MAX + 1024;
|
||||
Song *song = NULL;
|
||||
ListNode *nextSongNode = list->firstNode;
|
||||
ListNode *nodeTemp;
|
||||
|
@ -292,15 +293,16 @@ int updateSongInfo(Song * song)
|
|||
if (song->type == SONG_TYPE_FILE) {
|
||||
InputPlugin *plugin;
|
||||
unsigned int next = 0;
|
||||
char *song_url = getSongUrl(song);
|
||||
char *abs_path = rmp2amp(song_url);
|
||||
char path_max_tmp[MPD_PATH_MAX];
|
||||
char *abs_path = rmp2amp_r(path_max_tmp,
|
||||
get_song_url(path_max_tmp, song));
|
||||
|
||||
if (song->tag)
|
||||
freeMpdTag(song->tag);
|
||||
|
||||
song->tag = NULL;
|
||||
|
||||
while (!song->tag && (plugin = isMusic(song_url,
|
||||
while (!song->tag && (plugin = isMusic(abs_path,
|
||||
&(song->mtime),
|
||||
next++))) {
|
||||
song->tag = plugin->tagDupFunc(abs_path);
|
||||
|
@ -312,42 +314,15 @@ int updateSongInfo(Song * song)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* pass song = NULL to reset, we do this freeJustSong(), so that if
|
||||
* we free and recreate this memory we make sure to print it correctly*/
|
||||
char *getSongUrl(Song * song)
|
||||
char *get_song_url(char *path_max_tmp, Song *song)
|
||||
{
|
||||
static char *buffer;
|
||||
static int bufferSize;
|
||||
static Song *lastSong;
|
||||
int slen;
|
||||
int dlen;
|
||||
int size;
|
||||
|
||||
if (!song) {
|
||||
lastSong = song;
|
||||
if (!song)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!song->parentDir || !song->parentDir->path)
|
||||
return song->url;
|
||||
|
||||
/* be careful with this! */
|
||||
if (song == lastSong)
|
||||
return buffer;
|
||||
|
||||
slen = strlen(song->url);
|
||||
dlen = strlen(getDirectoryPath(song->parentDir));
|
||||
|
||||
size = slen + dlen + 2;
|
||||
|
||||
if (size > bufferSize) {
|
||||
buffer = xrealloc(buffer, size);
|
||||
bufferSize = size;
|
||||
}
|
||||
|
||||
strcpy(buffer, getDirectoryPath(song->parentDir));
|
||||
buffer[dlen] = '/';
|
||||
strcpy(buffer + dlen + 1, song->url);
|
||||
|
||||
return buffer;
|
||||
strcpy(path_max_tmp, song->url);
|
||||
else
|
||||
pfx_dir(path_max_tmp, song->url, strlen(song->url),
|
||||
getDirectoryPath(song->parentDir),
|
||||
strlen(getDirectoryPath(song->parentDir)));
|
||||
return path_max_tmp;
|
||||
}
|
||||
|
|
|
@ -74,6 +74,6 @@ int updateSongInfo(Song * song);
|
|||
|
||||
void printSongUrl(int fd, Song * song);
|
||||
|
||||
char *getSongUrl(Song * song);
|
||||
char *get_song_url(char *path_max_tmp, Song * song);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -34,6 +34,7 @@ static char *utf8pathToFsPathInStoredPlaylist(const char *utf8path, int fd)
|
|||
char *file;
|
||||
char *rfile;
|
||||
char *actualFile;
|
||||
static char path_max_tmp[MPD_PATH_MAX]; /* should be MT-safe */
|
||||
|
||||
if (strstr(utf8path, "/")) {
|
||||
commandError(fd, ACK_ERROR_ARG, "playlist name \"%s\" is "
|
||||
|
@ -42,8 +43,7 @@ static char *utf8pathToFsPathInStoredPlaylist(const char *utf8path, int fd)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
file = utf8ToFsCharset((char *)utf8path);
|
||||
|
||||
file = utf8_to_fs_charset(path_max_tmp, (char *)utf8path);
|
||||
rfile = xmalloc(strlen(file) + strlen(".") +
|
||||
strlen(PLAYLIST_FILE_SUFFIX) + 1);
|
||||
|
||||
|
@ -51,7 +51,7 @@ static char *utf8pathToFsPathInStoredPlaylist(const char *utf8path, int fd)
|
|||
strcat(rfile, ".");
|
||||
strcat(rfile, PLAYLIST_FILE_SUFFIX);
|
||||
|
||||
actualFile = rpp2app(rfile);
|
||||
actualFile = rpp2app_r(path_max_tmp, rfile);
|
||||
|
||||
free(rfile);
|
||||
|
||||
|
@ -100,7 +100,10 @@ static ListNode *nodeOfStoredPlaylist(StoredPlaylist *sp, int index)
|
|||
|
||||
static void appendSongToStoredPlaylist(StoredPlaylist *sp, Song *song)
|
||||
{
|
||||
insertInListWithoutKey(sp->list, xstrdup(getSongUrl(song)));
|
||||
char path_max_tmp[MPD_PATH_MAX];
|
||||
|
||||
get_song_url(path_max_tmp, song);
|
||||
insertInListWithoutKey(sp->list, xstrdup(path_max_tmp));
|
||||
}
|
||||
|
||||
StoredPlaylist *newStoredPlaylist(const char *utf8name, int fd, int ignoreExisting)
|
||||
|
@ -138,10 +141,13 @@ StoredPlaylist *loadStoredPlaylist(const char *utf8path, int fd)
|
|||
char *filename;
|
||||
StoredPlaylist *sp;
|
||||
FILE *file;
|
||||
char s[MAXPATHLEN + 1];
|
||||
char s[MPD_PATH_MAX];
|
||||
char path_max_tmp[MPD_PATH_MAX];
|
||||
char path_max_tmp2[MPD_PATH_MAX]; /* TODO: cleanup */
|
||||
char path_max_tmp3[MPD_PATH_MAX]; /* TODO: cleanup */
|
||||
int slength = 0;
|
||||
char *temp = utf8ToFsCharset((char *)utf8path);
|
||||
char *parent = parentPath(temp);
|
||||
char *temp = utf8_to_fs_charset(path_max_tmp2, (char *)utf8path);
|
||||
char *parent = parent_path(path_max_tmp3, temp);
|
||||
int parentlen = strlen(parent);
|
||||
int tempInt;
|
||||
int commentCharFound = 0;
|
||||
|
@ -169,15 +175,18 @@ StoredPlaylist *loadStoredPlaylist(const char *utf8path, int fd)
|
|||
s[slength] = '\0';
|
||||
if (s[0] == PLAYLIST_COMMENT)
|
||||
commentCharFound = 1;
|
||||
if (strncmp(s, musicDir, strlen(musicDir)) == 0) {
|
||||
strcpy(s, &(s[strlen(musicDir)]));
|
||||
if (!strncmp(s, musicDir, strlen(musicDir)) &&
|
||||
s[strlen(musicDir)] == '/') {
|
||||
memmove(s, &(s[strlen(musicDir) + 1]),
|
||||
strlen(&(s[strlen(musicDir) + 1])) + 1);
|
||||
printf("s: <%s>\n", s);
|
||||
} else if (parentlen) {
|
||||
temp = xstrdup(s);
|
||||
memset(s, 0, MAXPATHLEN + 1);
|
||||
memset(s, 0, MPD_PATH_MAX);
|
||||
strcpy(s, parent);
|
||||
strncat(s, "/", MAXPATHLEN - parentlen);
|
||||
strncat(s, temp, MAXPATHLEN - parentlen - 1);
|
||||
if (strlen(s) >= MAXPATHLEN) {
|
||||
strncat(s, "/", MPD_PATH_MAX - parentlen);
|
||||
strncat(s, temp, MPD_PATH_MAX - parentlen - 1);
|
||||
if (strlen(s) >= MPD_PATH_MAX) {
|
||||
commandError(sp->fd,
|
||||
ACK_ERROR_PLAYLIST_LOAD,
|
||||
"\"%s\" is too long", temp);
|
||||
|
@ -189,7 +198,7 @@ StoredPlaylist *loadStoredPlaylist(const char *utf8path, int fd)
|
|||
free(temp);
|
||||
}
|
||||
slength = 0;
|
||||
temp = fsCharsetToUtf8(s);
|
||||
temp = fs_charset_to_utf8(path_max_tmp, s);
|
||||
if (temp && !commentCharFound) {
|
||||
song = getSongFromDB(temp);
|
||||
if (song) {
|
||||
|
@ -206,7 +215,7 @@ StoredPlaylist *loadStoredPlaylist(const char *utf8path, int fd)
|
|||
freeJustSong(song);
|
||||
}
|
||||
}
|
||||
} else if (slength == MAXPATHLEN) {
|
||||
} else if (slength == (MPD_PATH_MAX - 1)) {
|
||||
s[slength] = '\0';
|
||||
commandError(sp->fd, ACK_ERROR_PLAYLIST_LOAD,
|
||||
"line \"%s\" in playlist \"%s\" "
|
||||
|
@ -401,11 +410,11 @@ static int writeStoredPlaylistToPath(StoredPlaylist *sp, const char *fspath)
|
|||
|
||||
node = sp->list->firstNode;
|
||||
while (node != NULL) {
|
||||
s = (char *)node->data;
|
||||
if (isValidRemoteUtf8Url(s) || !playlist_saveAbsolutePaths)
|
||||
s = utf8ToFsCharset(s);
|
||||
else
|
||||
s = rmp2amp(utf8ToFsCharset(s));
|
||||
char path_max_tmp[MPD_PATH_MAX];
|
||||
|
||||
s = utf8_to_fs_charset(path_max_tmp, (char *)node->data);
|
||||
if (playlist_saveAbsolutePaths && !isValidRemoteUtf8Url(s))
|
||||
s = rmp2amp_r(path_max_tmp, s);
|
||||
fprintf(file, "%s\n", s);
|
||||
node = node->nextNode;
|
||||
}
|
||||
|
@ -424,6 +433,8 @@ int appendSongToStoredPlaylistByPath(int fd, const char *utf8path, Song *song)
|
|||
char *filename;
|
||||
FILE *file;
|
||||
char *s;
|
||||
char path_max_tmp[MPD_PATH_MAX];
|
||||
char path_max_tmp2[MPD_PATH_MAX];
|
||||
|
||||
filename = utf8pathToFsPathInStoredPlaylist(utf8path, fd);
|
||||
if (!filename)
|
||||
|
@ -436,10 +447,10 @@ int appendSongToStoredPlaylistByPath(int fd, const char *utf8path, Song *song)
|
|||
return -1;
|
||||
}
|
||||
|
||||
s = utf8_to_fs_charset(path_max_tmp2, get_song_url(path_max_tmp, song));
|
||||
|
||||
if (playlist_saveAbsolutePaths && song->type == SONG_TYPE_FILE)
|
||||
s = rmp2amp(utf8ToFsCharset(getSongUrl(song)));
|
||||
else
|
||||
s = utf8ToFsCharset(getSongUrl(song));
|
||||
s = rmp2amp_r(path_max_tmp, s);
|
||||
|
||||
fprintf(file, "%s\n", s);
|
||||
|
||||
|
|
|
@ -157,7 +157,8 @@ static id3_utf8_t * processID3FieldString (int is_id3v1, const id3_ucs4_t *ucs4,
|
|||
return NULL;
|
||||
}
|
||||
setCharSetConversion("UTF-8", encoding);
|
||||
utf8 = (id3_utf8_t *)convStrDup((char *)isostr);
|
||||
utf8 = xmalloc(strlen((char *)isostr) + 1);
|
||||
utf8 = (id3_utf8_t *)char_conv_str((char *)utf8, (char *)isostr);
|
||||
if (!utf8) {
|
||||
DEBUG("Unable to convert %s string to UTF-8: "
|
||||
"'%s'\n", encoding, isostr);
|
||||
|
|
85
src/utf8.c
85
src/utf8.c
|
@ -23,51 +23,42 @@
|
|||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static char *latin1ToUtf8(char c)
|
||||
char *latin1_to_utf8(char *dest, char *in_latin1)
|
||||
{
|
||||
static unsigned char utf8[3];
|
||||
unsigned char uc = c;
|
||||
unsigned char *cp = (unsigned char *)dest;
|
||||
unsigned char *latin1 = (unsigned char *)in_latin1;
|
||||
|
||||
memset(utf8, 0, 3);
|
||||
|
||||
if (uc < 128)
|
||||
utf8[0] = uc;
|
||||
else if (uc < 192) {
|
||||
utf8[0] = 194;
|
||||
utf8[1] = uc;
|
||||
while (*latin1) {
|
||||
if (*latin1 < 128)
|
||||
*(cp++) = *latin1;
|
||||
else {
|
||||
if (*latin1 < 192) {
|
||||
*(cp++) = 194;
|
||||
*(cp++) = *latin1;
|
||||
} else {
|
||||
utf8[0] = 195;
|
||||
utf8[1] = uc - 64;
|
||||
*(cp++) = 195;
|
||||
*(cp++) = (*latin1) - 64;
|
||||
}
|
||||
}
|
||||
++latin1;
|
||||
}
|
||||
|
||||
return (char *)utf8;
|
||||
*cp = '\0';
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
char *latin1StrToUtf8Dup(char *latin1)
|
||||
{
|
||||
/* utf8 should have at most two char's per latin1 char */
|
||||
int len = strlen(latin1) * 2 + 1;
|
||||
char *ret = xmalloc(len);
|
||||
char *cp = ret;
|
||||
char *utf8;
|
||||
char *ret = xmalloc(strlen(latin1) * 2 + 1);
|
||||
|
||||
memset(ret, 0, len);
|
||||
ret = latin1_to_utf8(ret, latin1);
|
||||
|
||||
len = 0;
|
||||
|
||||
while (*latin1) {
|
||||
utf8 = latin1ToUtf8(*latin1);
|
||||
while (*utf8) {
|
||||
*(cp++) = *(utf8++);
|
||||
len++;
|
||||
}
|
||||
latin1++;
|
||||
}
|
||||
|
||||
return xrealloc(ret, len + 1);
|
||||
return ((ret) ? xrealloc(ret, strlen((char *)ret) + 1) : NULL);
|
||||
}
|
||||
|
||||
static char utf8ToLatin1(char *inUtf8)
|
||||
static char utf8_to_latin1_char(char *inUtf8)
|
||||
{
|
||||
unsigned char c = 0;
|
||||
unsigned char *utf8 = (unsigned char *)inUtf8;
|
||||
|
@ -124,14 +115,10 @@ int validUtf8String(char *string)
|
|||
char *utf8StrToLatin1Dup(char *utf8)
|
||||
{
|
||||
/* utf8 should have at most two char's per latin1 char */
|
||||
int len = strlen(utf8) + 1;
|
||||
char *ret = xmalloc(len);
|
||||
char *ret = xmalloc(strlen(utf8) + 1);
|
||||
char *cp = ret;
|
||||
int count;
|
||||
|
||||
memset(ret, 0, len);
|
||||
|
||||
len = 0;
|
||||
size_t len = 0;
|
||||
|
||||
while (*utf8) {
|
||||
count = validateUtf8Char(utf8);
|
||||
|
@ -139,10 +126,32 @@ char *utf8StrToLatin1Dup(char *utf8)
|
|||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
*(cp++) = utf8ToLatin1(utf8);
|
||||
*(cp++) = utf8_to_latin1_char(utf8);
|
||||
utf8 += count;
|
||||
len++;
|
||||
}
|
||||
|
||||
*cp = '\0';
|
||||
|
||||
return xrealloc(ret, len + 1);
|
||||
}
|
||||
|
||||
char *utf8_to_latin1(char *dest, char *utf8)
|
||||
{
|
||||
char *cp = dest;
|
||||
int count;
|
||||
size_t len = 0;
|
||||
|
||||
while (*utf8) {
|
||||
count = validateUtf8Char(utf8);
|
||||
if (count) {
|
||||
*(cp++) = utf8_to_latin1_char(utf8);
|
||||
utf8 += count;
|
||||
len++;
|
||||
} else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*cp = '\0';
|
||||
return dest;
|
||||
}
|
||||
|
|
|
@ -25,4 +25,9 @@ char *utf8StrToLatin1Dup(char *utf8);
|
|||
|
||||
int validUtf8String(char *string);
|
||||
|
||||
char *utf8_to_latin1(char *dest, char *utf8);
|
||||
|
||||
char *latin1_to_utf8(char *dest, char *utf8);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
18
src/utils.c
18
src/utils.c
|
@ -30,6 +30,8 @@
|
|||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
char *myFgets(char *buffer, int bufferSize, FILE * fp)
|
||||
{
|
||||
|
@ -43,15 +45,21 @@ char *myFgets(char *buffer, int bufferSize, FILE * fp)
|
|||
return ret;
|
||||
}
|
||||
|
||||
char *strDupToUpper(char *str)
|
||||
char *string_toupper(char *str)
|
||||
{
|
||||
char *ret = xstrdup(str);
|
||||
int i;
|
||||
int i = strlen(str);
|
||||
char *ret = str;
|
||||
|
||||
for (i = 0; i < strlen(str); i++)
|
||||
ret[i] = toupper((int)ret[i]);
|
||||
for (; --i >= 0; ++str)
|
||||
*str = toupper((int)(*str));
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
char *strDupToUpper(char *str)
|
||||
{
|
||||
return string_toupper(xstrdup(str));
|
||||
}
|
||||
|
||||
void stripReturnChar(char *string)
|
||||
|
|
|
@ -34,7 +34,9 @@
|
|||
|
||||
char *myFgets(char *buffer, int bufferSize, FILE * fp);
|
||||
|
||||
char *strDupToUpper(char *str);
|
||||
char *string_toupper(char *str);
|
||||
|
||||
char *strDupToUpper(char *str); /* avoid, use string_toupper instead */
|
||||
|
||||
void stripReturnChar(char *string);
|
||||
|
||||
|
|
Loading…
Reference in New Issue