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)
|
||||
#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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
* 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.
|
||||
@ -267,11 +270,14 @@ qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon)
|
||||
|
||||
if (canon_len <= 0)
|
||||
{
|
||||
/* when resolving to a single dot, a trailing separator is not
|
||||
* retained though the orignal path name contains it. */
|
||||
canon[0] = QSE_T('.');
|
||||
canon[1] = QSE_T('\0');
|
||||
canon_len = 1;
|
||||
if (!(flags & QSE_CANONPATH_EMPTYSINGLEDOT))
|
||||
{
|
||||
/* when resolving to a single dot, a trailing separator is not
|
||||
* retained though the orignal path name contains it. */
|
||||
canon[0] = QSE_T('.');
|
||||
canon[1] = QSE_T('\0');
|
||||
canon_len = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user