added QSE_CANONPATH_EMPTYSINGLEDOT, QSE_CANONPATH_KEEPDOUBLESLASHES, QSE_CANONDROPTRAILINGSEP

This commit is contained in:
hyung-hwan 2011-10-26 00:19:20 +00:00
parent e31e2c41ec
commit 4eb8cb62ee
5 changed files with 77 additions and 24 deletions

View File

@ -39,6 +39,16 @@
# define qse_basename(path) qse_wcsbasename(path)
#endif
enum qse_canonpath_flag_t
{
/** if the final output is . logically, return an empty path */
QSE_CANONPATH_EMPTYSINGLEDOT = (1 << 0),
/** keep the .. segment in the path name */
QSE_CANONPATH_KEEPDOUBLEDOTS = (1 << 1),
/** drop a trailing separator even if the source contains one */
QSE_CANONPATH_DROPTRAILINGSEP = (1 << 2)
};
#ifdef __cplusplus
extern "C" {
#endif
@ -100,10 +110,14 @@ int qse_isdrivecurpath (
* qse_printf (QSE_T("%s\n")); // prints /usr/bin/sh
* @endcode
*
* Note that the output is empty returning 0 if the input @a path is empty,
* whereas a single period is produced if canonicalization results in the
* current directory logically without a single period in the input @a path.
* For example, dir/.. is canonicalized to a single period.
* If #QSE_CANONPATH_EMPTYSINGLEDOT is clear in the @a flags, a single dot
* is produced if the input @path resolves to the current directory logically.
* For example, dir/.. is canonicalized to a single period; If it is set,
* an empty string is produced. Even a single period as an input produces
* an empty string if it is set.
*
* The output is empty returning 0 regardless of @a flags if the input
* @a path is empty.
*
* The caller must ensure that it is large enough to hold the resulting
* canonical path before calling because this function does not check the
@ -117,7 +131,8 @@ int qse_isdrivecurpath (
*/
qse_size_t qse_canonpath (
const qse_char_t* path,
qse_char_t* canon
qse_char_t* canon,
int flags
);
#ifdef __cplusplus

View File

@ -67,6 +67,15 @@ struct qse_dir_t
typedef struct qse_dir_t qse_dir_t;
enum qse_dir_option_t
{
/**< don't follow a symbolic link in qse_dir_change() */
QSE_DIR_NOFOLLOW = (1 << 0),
/**< check directories against file system in qse_dir_change() */
QSE_DIR_REALPATH = (1 << 1)
};
#ifdef __cplusplus
extern "C" {
#endif

View File

@ -61,7 +61,7 @@ int qse_isdrivecurpath (const qse_char_t* path)
return 0;
}
qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon)
qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon, int flags)
{
const qse_char_t* ptr;
qse_char_t* dst;
@ -155,7 +155,8 @@ qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon)
{
/* eat up . */
}
else if (seglen == 2 && seg[0] == QSE_T('.') && seg[1] == QSE_T('.'))
else if (!(flags & QSE_CANONPATH_KEEPDOUBLEDOTS) &&
seglen == 2 && seg[0] == QSE_T('.') && seg[1] == QSE_T('.'))
{
/* eat up the previous segment */
qse_char_t* tmp;
@ -242,11 +243,13 @@ qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon)
}
while (1);
if (dst > non_root_start && ISSEP(dst[-1]) && !ISSEP(ptr[-1]))
if (dst > non_root_start && ISSEP(dst[-1]) &&
((flags & QSE_CANONPATH_DROPTRAILINGSEP) || !ISSEP(ptr[-1])))
{
/* if the canoncal path composed so far ends with a separator
* and the original path didn't end with the separator, delete
* the ending separator.
* also delete it if QSE_CANONPATH_DROPTRAILINGSEP is set.
*
* dst > non_root_start:
* there is at least 1 character after the root directory part.
@ -266,6 +269,8 @@ qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon)
}
if (canon_len <= 0)
{
if (!(flags & QSE_CANONPATH_EMPTYSINGLEDOT))
{
/* when resolving to a single dot, a trailing separator is not
* retained though the orignal path name contains it. */
@ -273,6 +278,7 @@ qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon)
canon[1] = QSE_T('\0');
canon_len = 1;
}
}
else
{
/* drop a traling separator if the last segment is

View File

@ -264,7 +264,7 @@ int qse_dir_change (qse_dir_t* dir, const qse_char_t* name)
return -1;
}
idx = qse_canonpath (dirname, dirname);
idx = qse_canonpath (dirname, dirname, 0);
/* Put an asterisk after canonicalization to prevent side-effects.
* otherwise, .\* would be transformed to * by qse_canonpath() */
dirname[idx-1] = QSE_T('*');
@ -323,7 +323,7 @@ int qse_dir_change (qse_dir_t* dir, const qse_char_t* name)
return -1;
}
qse_canonpath (dirname, dirname);
qse_canonpath (dirname, dirname, 0);
#if defined(QSE_CHAR_IS_MCHAR)
mdirname = dirname;

View File

@ -9,6 +9,18 @@ int path_main (int argc, qse_char_t* argv[])
{
qse_char_t* canon;
qse_size_t len;
int i;
int options[] =
{
0,
QSE_CANONPATH_EMPTYSINGLEDOT,
QSE_CANONPATH_KEEPDOUBLEDOTS,
QSE_CANONPATH_DROPTRAILINGSEP,
QSE_CANONPATH_EMPTYSINGLEDOT | QSE_CANONPATH_KEEPDOUBLEDOTS,
QSE_CANONPATH_EMPTYSINGLEDOT | QSE_CANONPATH_DROPTRAILINGSEP,
QSE_CANONPATH_KEEPDOUBLEDOTS | QSE_CANONPATH_DROPTRAILINGSEP,
QSE_CANONPATH_EMPTYSINGLEDOT | QSE_CANONPATH_KEEPDOUBLEDOTS | QSE_CANONPATH_DROPTRAILINGSEP
};
if (argc != 2)
{
@ -16,21 +28,32 @@ int path_main (int argc, qse_char_t* argv[])
return -1;
}
/*
canon = QSE_MMGR_ALLOC (QSE_MMGR_GETDFL(), (qse_strlen(argv[1]) + 1) * QSE_SIZEOF(*canon));
if (canon == QSE_NULL)
canon = QSE_MMGR_ALLOC (
QSE_MMGR_GETDFL(), (qse_strlen(argv[1]) + 1) * QSE_SIZEOF(*canon));
if (!canon)
{
QSE_MMGR_FREE (QSE_MMGR_GETDFL(), canon);
qse_fprintf (QSE_STDERR, QSE_T("Error: out of memory\n"));
return -1;
}
len = qse_canonpath (argv[1], canon);
qse_printf (QSE_T("[%s] => [%s] %d chars\n"), argv[1], canon, (int)len);
QSE_MMGR_FREE (QSE_MMGR_GETDFL(), canon);
*/
for (i = 0; i < QSE_COUNTOF(options); i++)
{
len = qse_canonpath (argv[1], canon, options[i]);
qse_printf (QSE_T("OPT[%c%c%c] [%s]: [%5d] [%s]\n"),
((options[i] & QSE_CANONPATH_EMPTYSINGLEDOT)? QSE_T('E'): QSE_T(' ')),
((options[i] & QSE_CANONPATH_KEEPDOUBLEDOTS)? QSE_T('K'): QSE_T(' ')),
((options[i] & QSE_CANONPATH_DROPTRAILINGSEP)? QSE_T('D'): QSE_T(' ')),
argv[1], (int)len, canon);
}
QSE_MMGR_FREE (QSE_MMGR_GETDFL(), canon);
#if 0
qse_printf (QSE_T("[%s] => "), argv[1]);
len = qse_canonpath (argv[1], argv[1]);
len = qse_canonpath (argv[1], argv[1], 0);
qse_printf (QSE_T("[%s] %d chars\n"), argv[1], (int)len);
#endif
return 0;
}