added qse_wcsatombsdup()
This commit is contained in:
@ -252,8 +252,8 @@ int qse_fio_init (
|
||||
const qse_mchar_t* path_mb = path;
|
||||
#else
|
||||
qse_mchar_t path_mb[CCHMAXPATH];
|
||||
if (qse_wcstombs_strict (path,
|
||||
path_mb, QSE_COUNTOF(path_mb)) == -1) return -1;
|
||||
if (qse_wcstombsrigid (path,
|
||||
path_mb, QSE_COUNTOF(path_mb)) <= -1) return -1;
|
||||
#endif
|
||||
|
||||
zero.ulLo = 0;
|
||||
@ -342,8 +342,8 @@ int qse_fio_init (
|
||||
const qse_mchar_t* path_mb = path;
|
||||
#else
|
||||
qse_mchar_t path_mb[_MAX_PATH];
|
||||
if (qse_wcstombs_strict (path,
|
||||
path_mb, QSE_COUNTOF(path_mb)) == -1) return -1;
|
||||
if (qse_wcstombsrigid (path,
|
||||
path_mb, QSE_COUNTOF(path_mb)) <= -1) return -1;
|
||||
#endif
|
||||
|
||||
if (flags & QSE_FIO_APPEND)
|
||||
@ -395,8 +395,8 @@ int qse_fio_init (
|
||||
const qse_mchar_t* path_mb = path;
|
||||
#else
|
||||
qse_mchar_t path_mb[PATH_MAX + 1];
|
||||
if (qse_wcstombs_strict (path,
|
||||
path_mb, QSE_COUNTOF(path_mb)) == -1) return -1;
|
||||
if (qse_wcstombsrigid (path,
|
||||
path_mb, QSE_COUNTOF(path_mb)) <= -1) return -1;
|
||||
#endif
|
||||
/*
|
||||
* rwa -> RDWR | APPEND
|
||||
|
@ -34,10 +34,13 @@ const qse_char_t* qse_fs_geterrmsg (qse_fs_t* fs)
|
||||
|
||||
QSE_T("insufficient memory"),
|
||||
QSE_T("invalid parameter or data"),
|
||||
QSE_T("permission denied"),
|
||||
QSE_T("access denied"),
|
||||
QSE_T("operation not permitted"),
|
||||
QSE_T("no such entry"),
|
||||
QSE_T("no working fsectory set"),
|
||||
QSE_T("already exists"),
|
||||
QSE_T("no working directory set"),
|
||||
QSE_T("operation not permitted on directory"),
|
||||
QSE_T("entry already exists"),
|
||||
QSE_T("cross-device operation not allowed"),
|
||||
QSE_T("system error")
|
||||
};
|
||||
|
||||
@ -78,20 +81,28 @@ qse_fs_errnum_t qse_fs_syserrtoerrnum (qse_fs_t* fs, qse_fs_syserr_t e)
|
||||
case EINVAL:
|
||||
return QSE_FS_EINVAL;
|
||||
|
||||
case ENOMEM:
|
||||
return QSE_FS_ENOMEM;
|
||||
|
||||
case EACCES:
|
||||
case EPERM:
|
||||
return QSE_FS_EACCES;
|
||||
|
||||
case EPERM:
|
||||
return QSE_FS_EPERM;
|
||||
|
||||
case ENOENT:
|
||||
case ENOTDIR:
|
||||
return QSE_FS_ENOENT;
|
||||
|
||||
case ENOMEM:
|
||||
return QSE_FS_ENOMEM;
|
||||
case EISDIR:
|
||||
return QSE_FS_EISDIR;
|
||||
|
||||
case EEXIST:
|
||||
return QSE_FS_EEXIST;
|
||||
|
||||
case EXDEV:
|
||||
return QSE_FS_EXDEV;
|
||||
|
||||
default:
|
||||
return QSE_FS_ESYSTEM;
|
||||
}
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include "fs.h"
|
||||
#include <qse/cmn/str.h>
|
||||
#include <qse/cmn/path.h>
|
||||
#include "mem.h"
|
||||
|
||||
|
||||
@ -29,6 +30,33 @@ QSE_FS_MOVE_UPDATE
|
||||
QSE_FS_MOVE_BACKUP_SIMPLE
|
||||
QSE_FS_MOVE_BACKUP_NUMBERED
|
||||
*/
|
||||
enum fop_flag_t
|
||||
{
|
||||
FOP_OLD_STAT = (1 << 0),
|
||||
FOP_NEW_STAT = (1 << 1),
|
||||
|
||||
FOP_CROSS_DEV = (1 << 2)
|
||||
};
|
||||
|
||||
struct fop_t
|
||||
{
|
||||
int flags;
|
||||
|
||||
qse_lstat_t old_stat;
|
||||
qse_lstat_t new_stat;
|
||||
|
||||
#if defined(_WIN32)
|
||||
qse_wchar_t* old_path;
|
||||
qse_wchar_t* new_path;
|
||||
qse_wchar_t* new_path2;
|
||||
#else
|
||||
qse_mchar_t* old_path;
|
||||
qse_mchar_t* new_path;
|
||||
qse_mchar_t* new_path2;
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef struct fop_t fop_t;
|
||||
|
||||
int qse_fs_move (
|
||||
qse_fs_t* fs, const qse_char_t* oldpath, const qse_char_t* newpath)
|
||||
@ -64,31 +92,22 @@ int qse_fs_move (
|
||||
# error NOT IMPLEMENTED
|
||||
#else
|
||||
|
||||
const qse_mchar_t* mbsoldpath;
|
||||
const qse_mchar_t* mbsnewpath;
|
||||
fop_t fop;
|
||||
|
||||
#if 0
|
||||
struct file_stat_t
|
||||
{
|
||||
int oldst_ok;
|
||||
int newst_ok;
|
||||
qse_lstat_t oldst;
|
||||
qse_lstat_t newst;
|
||||
};
|
||||
#endif
|
||||
QSE_MEMSET (&fop, 0, QSE_SIZEOF(fop));
|
||||
|
||||
#if defined(QSE_CHAR_IS_MCHAR)
|
||||
mbsoldpath = oldpath;
|
||||
mbsnewpath = newpath;
|
||||
fop.old_path = oldpath;
|
||||
fop.new_path = newpath;
|
||||
#else
|
||||
mbsoldpath = qse_wcstombsdup (oldpath, fs->mmgr);
|
||||
mbsnewpath = qse_wcstombsdup (newpath, fs->mmgr);
|
||||
|
||||
if (mbsoldpath == QSE_NULL || mbsnewpath == QSE_NULL)
|
||||
fop.old_path = qse_wcstombsdup (oldpath, fs->mmgr);
|
||||
fop.new_path = qse_wcstombsdup (newpath, fs->mmgr);
|
||||
if (fop.old_path == QSE_NULL || fop.old_path == QSE_NULL)
|
||||
{
|
||||
fs->errnum = QSE_FS_ENOMEM;
|
||||
goto oops;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* TOOD: implement confirmatio
|
||||
if (overwrite_callback is set)
|
||||
@ -101,63 +120,130 @@ int qse_fs_move (
|
||||
}
|
||||
*/
|
||||
|
||||
#if 0
|
||||
if (opt)
|
||||
/* use lstat because we need to move the symbolic link
|
||||
* itself if the file is a symbolic link */
|
||||
if (QSE_LSTAT (fop.old_path, &fop.old_stat) == -1)
|
||||
{
|
||||
/* use lstat because we need to move the symbolic link
|
||||
* itself if the file is a symbolic link */
|
||||
if (QSE_LSTAT (mboldpath, &oldst) == -1)
|
||||
{
|
||||
fs->errnum = qse_fs_syserrtoerrnum (fs, errno);
|
||||
goto oops;
|
||||
}
|
||||
fs->errnum = qse_fs_syserrtoerrnum (fs, errno);
|
||||
goto oops;
|
||||
}
|
||||
else fop.flags |= FOP_OLD_STAT;
|
||||
|
||||
if (QSE_LSTAT (mbnewpath, &newst) == -1)
|
||||
if (QSE_LSTAT (fop.new_path, &fop.new_stat) == -1)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
{
|
||||
/* entry doesn't exist */
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else fop.flags |= FOP_NEW_STAT;
|
||||
|
||||
/* TODO: make it better to be able to move non-empty diretories
|
||||
improve it to be able to move by copy/delete across volume */
|
||||
if (QSE_RENAME (mbsoldpath, mbsnewpath) == -1)
|
||||
if (fop.flags & FOP_NEW_STAT)
|
||||
{
|
||||
if (errno == EXDEV)
|
||||
/* destination file exits */
|
||||
if (fop.old_stat.st_dev != fop.new_stat.st_dev)
|
||||
{
|
||||
/* TODO: move it by copy and delete intead of returnign error... */
|
||||
fs->errnum = qse_fs_syserrtoerrnum (fs, errno);
|
||||
goto oops;
|
||||
/* cross-device */
|
||||
fop.flags |= FOP_CROSS_DEV;
|
||||
}
|
||||
else
|
||||
{
|
||||
fs->errnum = qse_fs_syserrtoerrnum (fs, errno);
|
||||
goto oops;
|
||||
if (fop.old_stat.st_ino == fop.new_stat.st_ino)
|
||||
{
|
||||
/* both source and destination are the same.
|
||||
* this operation is not allowed */
|
||||
fs->errnum = QSE_FS_EPERM;
|
||||
goto oops;
|
||||
}
|
||||
|
||||
/* TODO: destination should point to an actual file or directory for this check to work */
|
||||
/* TOOD: ask to overwrite the source */
|
||||
if (S_ISDIR(fop.new_stat.st_mode))
|
||||
{
|
||||
/* the destination is a directory. move the source file
|
||||
* into the destination directory */
|
||||
const qse_wchar_t* arr[4];
|
||||
|
||||
arr[0] = newpath;
|
||||
arr[1] = QSE_T("/");
|
||||
arr[2] = qse_basename(oldpath);
|
||||
arr[3] = QSE_NULL;
|
||||
#if defined(QSE_CHAR_IS_MCHAR)
|
||||
fop.new_path2 = qse_stradup (arr, fs->mmgr);
|
||||
#else
|
||||
fop.new_path2 = qse_wcsatombsdup (arr, fs->mmgr);
|
||||
#endif
|
||||
if (fop.new_path2 == QSE_NULL)
|
||||
{
|
||||
fs->errnum = QSE_FS_ENOMEM;
|
||||
goto oops;
|
||||
}
|
||||
qse_printf (QSE_T("new_path2 => [%S]\n"), fop.new_path2);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* the destination file is not directory, unlink first
|
||||
* TODO: but is this necessary? RENAME will do it */
|
||||
QSE_UNLINK (fop.new_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(fop.flags & FOP_CROSS_DEV))
|
||||
{
|
||||
/* TODO: make it better to be able to move non-empty diretories
|
||||
improve it to be able to move by copy/delete across volume */
|
||||
if (QSE_RENAME (fop.old_path, fop.new_path) == -1)
|
||||
{
|
||||
if (errno != EXDEV)
|
||||
{
|
||||
fs->errnum = qse_fs_syserrtoerrnum (fs, errno);
|
||||
goto oops;
|
||||
}
|
||||
|
||||
fop.flags |= FOP_CROSS_DEV;
|
||||
}
|
||||
else goto done;
|
||||
}
|
||||
|
||||
QSE_ASSERT (fop.flags & FOP_CROSS_DEV);
|
||||
|
||||
if (!S_ISDIR(fop.old_stat.st_mode))
|
||||
{
|
||||
/* copy a single file */
|
||||
qse_printf (QSE_T("TODO: cross-device copy....\n"));
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (!recursive)
|
||||
{
|
||||
fs->errnum = QSE_FS_E....;
|
||||
goto oops;
|
||||
}
|
||||
|
||||
copy recursively...
|
||||
#endif
|
||||
|
||||
done:
|
||||
#if defined(QSE_CHAR_IS_MCHAR)
|
||||
/* nothing to free */
|
||||
if (fop.new_path2) QSE_MMGR_FREE (fs->mmgr, fop.new_path2);
|
||||
#else
|
||||
QSE_MMGR_FREE (fs->mmgr, mbsoldpath);
|
||||
QSE_MMGR_FREE (fs->mmgr, mbsnewpath);
|
||||
if (fop.new_path2) QSE_MMGR_FREE (fs->mmgr, fop.new_path2);
|
||||
QSE_MMGR_FREE (fs->mmgr, fop.old_path);
|
||||
QSE_MMGR_FREE (fs->mmgr, fop.new_path);
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
oops:
|
||||
#if defined(QSE_CHAR_IS_MCHAR)
|
||||
/* nothing to free */
|
||||
if (fop.new_path2) QSE_MMGR_FREE (fs->mmgr, fop.new_path2);
|
||||
#else
|
||||
if (mbsoldpath) QSE_MMGR_FREE (fs->mmgr, mbsoldpath);
|
||||
if (mbsnewpath) QSE_MMGR_FREE (fs->mmgr, mbsnewpath);
|
||||
if (fop.new_path2) QSE_MMGR_FREE (fs->mmgr, fop.new_path2);
|
||||
if (fop.old_path) QSE_MMGR_FREE (fs->mmgr, fop.old_path);
|
||||
if (fop.new_path) QSE_MMGR_FREE (fs->mmgr, fop.new_path);
|
||||
#endif
|
||||
|
||||
return -1;
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
@ -363,9 +363,10 @@ qse_size_t qse_wcsntombsn (
|
||||
return p - wcs;
|
||||
}
|
||||
|
||||
int qse_mbstowcs_strict (
|
||||
int qse_mbstowcsrigid (
|
||||
const qse_mchar_t* mbs, qse_wchar_t* wcs, qse_size_t wcslen)
|
||||
{
|
||||
/* no truncation is allowed in this function for any reasons */
|
||||
qse_size_t n;
|
||||
qse_size_t wn = wcslen;
|
||||
|
||||
@ -380,15 +381,16 @@ int qse_mbstowcs_strict (
|
||||
if (mbs[n] != QSE_MT('\0'))
|
||||
{
|
||||
/* incomplete sequence or invalid sequence */
|
||||
return -1;
|
||||
return -2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qse_wcstombs_strict (
|
||||
int qse_wcstombsrigid (
|
||||
const qse_wchar_t* wcs, qse_mchar_t* mbs, qse_size_t mbslen)
|
||||
{
|
||||
/* no truncation is allowed in this function for any reasons */
|
||||
qse_size_t n;
|
||||
qse_size_t mn = mbslen;
|
||||
|
||||
@ -405,14 +407,13 @@ int qse_wcstombs_strict (
|
||||
/* if qse_wcstombs() processed all wide characters,
|
||||
* the character at position 'n' should be a null character
|
||||
* as 'n' is the number of wide characters processed. */
|
||||
return -1;
|
||||
return -2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
qse_wchar_t* qse_mbstowcsdup (
|
||||
const qse_mchar_t* mbs, qse_mmgr_t* mmgr)
|
||||
qse_wchar_t* qse_mbstowcsdup (const qse_mchar_t* mbs, qse_mmgr_t* mmgr)
|
||||
{
|
||||
qse_size_t n, req;
|
||||
qse_wchar_t* wcs;
|
||||
@ -429,8 +430,7 @@ qse_wchar_t* qse_mbstowcsdup (
|
||||
return wcs;
|
||||
}
|
||||
|
||||
qse_mchar_t* qse_wcstombsdup (
|
||||
const qse_wchar_t* wcs, qse_mmgr_t* mmgr)
|
||||
qse_mchar_t* qse_wcstombsdup (const qse_wchar_t* wcs, qse_mmgr_t* mmgr)
|
||||
{
|
||||
qse_size_t n, req;
|
||||
qse_mchar_t* mbs;
|
||||
@ -447,6 +447,38 @@ qse_mchar_t* qse_wcstombsdup (
|
||||
return mbs;
|
||||
}
|
||||
|
||||
|
||||
qse_mchar_t* qse_wcsatombsdup (const qse_wchar_t* wcs[], qse_mmgr_t* mmgr)
|
||||
{
|
||||
qse_mchar_t* buf, * ptr;
|
||||
qse_size_t i;
|
||||
qse_size_t capa = 0;
|
||||
qse_size_t wl, ml;
|
||||
|
||||
QSE_ASSERT (mmgr != QSE_NULL);
|
||||
|
||||
for (i = 0; wcs[i]; i++)
|
||||
{
|
||||
wl = qse_wcstombslen(wcs[i], &ml);
|
||||
if (wcs[i][wl] != QSE_WT('\0')) return QSE_NULL;
|
||||
capa += ml;
|
||||
}
|
||||
|
||||
buf = (qse_mchar_t*) QSE_MMGR_ALLOC (mmgr, (capa+1)*QSE_SIZEOF(*buf));
|
||||
if (buf == QSE_NULL) return QSE_NULL;
|
||||
|
||||
ptr = buf;
|
||||
for (i = 0; wcs[i]; i++)
|
||||
{
|
||||
ml = capa + 1;
|
||||
wl = qse_wcstombs (wcs[i], ptr, &ml);
|
||||
ptr += ml;
|
||||
capa -= ml;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* case conversion */
|
||||
|
||||
qse_size_t qse_mbslwr (qse_mchar_t* str)
|
||||
|
@ -292,6 +292,7 @@
|
||||
#if defined(SYS_rename)
|
||||
# define QSE_RENAME(oldpath,newpath) syscall(SYS_rename,oldpath,newpath)
|
||||
#else
|
||||
int rename(const char *oldpath, const char *newpath); /* not to include stdio.h */
|
||||
# define QSE_RENAME(oldpath,newpath) rename(oldpath,newpath)
|
||||
#endif
|
||||
|
||||
|
Reference in New Issue
Block a user