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) # define qse_basename(path) qse_wcsbasename(path)
#endif #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 #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -100,10 +110,14 @@ int qse_isdrivecurpath (
* qse_printf (QSE_T("%s\n")); // prints /usr/bin/sh * qse_printf (QSE_T("%s\n")); // prints /usr/bin/sh
* @endcode * @endcode
* *
* Note that the output is empty returning 0 if the input @a path is empty, * If #QSE_CANONPATH_EMPTYSINGLEDOT is clear in the @a flags, a single dot
* whereas a single period is produced if canonicalization results in the * is produced if the input @path resolves to the current directory logically.
* current directory logically without a single period in the input @a path. * For example, dir/.. is canonicalized to a single period; If it is set,
* For example, dir/.. is canonicalized to a single period. * 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 * The caller must ensure that it is large enough to hold the resulting
* canonical path before calling because this function does not check the * canonical path before calling because this function does not check the
@ -117,7 +131,8 @@ int qse_isdrivecurpath (
*/ */
qse_size_t qse_canonpath ( qse_size_t qse_canonpath (
const qse_char_t* path, const qse_char_t* path,
qse_char_t* canon qse_char_t* canon,
int flags
); );
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -67,6 +67,15 @@ struct qse_dir_t
typedef struct qse_dir_t 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 #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif

View File

@ -61,7 +61,7 @@ int qse_isdrivecurpath (const qse_char_t* path)
return 0; 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; const qse_char_t* ptr;
qse_char_t* dst; qse_char_t* dst;
@ -155,7 +155,8 @@ qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon)
{ {
/* eat up . */ /* 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 */ /* eat up the previous segment */
qse_char_t* tmp; qse_char_t* tmp;
@ -242,11 +243,13 @@ qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon)
} }
while (1); 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 /* if the canoncal path composed so far ends with a separator
* and the original path didn't end with the separator, delete * and the original path didn't end with the separator, delete
* the ending separator. * the ending separator.
* also delete it if QSE_CANONPATH_DROPTRAILINGSEP is set.
* *
* dst > non_root_start: * dst > non_root_start:
* there is at least 1 character after the root directory part. * 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 (canon_len <= 0)
{
if (!(flags & QSE_CANONPATH_EMPTYSINGLEDOT))
{ {
/* when resolving to a single dot, a trailing separator is not /* when resolving to a single dot, a trailing separator is not
* retained though the orignal path name contains it. */ * 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[1] = QSE_T('\0');
canon_len = 1; canon_len = 1;
} }
}
else else
{ {
/* drop a traling separator if the last segment is /* 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; return -1;
} }
idx = qse_canonpath (dirname, dirname); idx = qse_canonpath (dirname, dirname, 0);
/* Put an asterisk after canonicalization to prevent side-effects. /* Put an asterisk after canonicalization to prevent side-effects.
* otherwise, .\* would be transformed to * by qse_canonpath() */ * otherwise, .\* would be transformed to * by qse_canonpath() */
dirname[idx-1] = QSE_T('*'); dirname[idx-1] = QSE_T('*');
@ -323,7 +323,7 @@ int qse_dir_change (qse_dir_t* dir, const qse_char_t* name)
return -1; return -1;
} }
qse_canonpath (dirname, dirname); qse_canonpath (dirname, dirname, 0);
#if defined(QSE_CHAR_IS_MCHAR) #if defined(QSE_CHAR_IS_MCHAR)
mdirname = dirname; mdirname = dirname;

View File

@ -9,6 +9,18 @@ int path_main (int argc, qse_char_t* argv[])
{ {
qse_char_t* canon; qse_char_t* canon;
qse_size_t len; 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) if (argc != 2)
{ {
@ -16,21 +28,32 @@ int path_main (int argc, qse_char_t* argv[])
return -1; return -1;
} }
/* canon = QSE_MMGR_ALLOC (
canon = QSE_MMGR_ALLOC (QSE_MMGR_GETDFL(), (qse_strlen(argv[1]) + 1) * QSE_SIZEOF(*canon)); QSE_MMGR_GETDFL(), (qse_strlen(argv[1]) + 1) * QSE_SIZEOF(*canon));
if (canon == QSE_NULL) if (!canon)
{ {
QSE_MMGR_FREE (QSE_MMGR_GETDFL(), canon);
qse_fprintf (QSE_STDERR, QSE_T("Error: out of memory\n")); qse_fprintf (QSE_STDERR, QSE_T("Error: out of memory\n"));
return -1; 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]); 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); qse_printf (QSE_T("[%s] %d chars\n"), argv[1], (int)len);
#endif
return 0; return 0;
} }