added QSE_CANONPATH_EMPTYSINGLEDOT, QSE_CANONPATH_KEEPDOUBLESLASHES, QSE_CANONDROPTRAILINGSEP
This commit is contained in:
parent
e31e2c41ec
commit
4eb8cb62ee
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user