enhanced httpd a bit
This commit is contained in:
@ -20,63 +20,67 @@
|
||||
|
||||
#include <qse/cmn/path.h>
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* MBS IMPLEMENTATION */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
|
||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
||||
# define IS_SEP(c) ((c) == QSE_T('/') || (c) == QSE_T('\\'))
|
||||
# define IS_MSEP(c) ((c) == QSE_MT('/') || (c) == QSE_MT('\\'))
|
||||
#else
|
||||
# define IS_SEP(c) ((c) == QSE_T('/'))
|
||||
# define IS_MSEP(c) ((c) == QSE_MT('/'))
|
||||
#endif
|
||||
|
||||
#define IS_NIL(c) ((c) == QSE_T('\0'))
|
||||
#define IS_SEP_OR_NIL(c) (IS_SEP(c) || IS_NIL(c))
|
||||
#define IS_MNIL(c) ((c) == QSE_MT('\0'))
|
||||
#define IS_MSEP_OR_MNIL(c) (IS_MSEP(c) || IS_MNIL(c))
|
||||
|
||||
#define ISDRIVE(s) \
|
||||
(((s[0] >= QSE_T('A') && s[0] <= QSE_T('Z')) || \
|
||||
(s[0] >= QSE_T('a') && s[0] <= QSE_T('z'))) && \
|
||||
s[1] == QSE_T(':'))
|
||||
#define IS_MDRIVE(s) \
|
||||
(((s[0] >= QSE_MT('A') && s[0] <= QSE_MT('Z')) || \
|
||||
(s[0] >= QSE_MT('a') && s[0] <= QSE_MT('z'))) && \
|
||||
s[1] == QSE_MT(':'))
|
||||
|
||||
int qse_isabspath (const qse_char_t* path)
|
||||
int qse_ismbsabspath (const qse_mchar_t* path)
|
||||
{
|
||||
if (IS_SEP(path[0])) return 1;
|
||||
if (IS_MSEP(path[0])) return 1;
|
||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
||||
/* a drive like c:tmp is absolute in positioning the drive.
|
||||
* but the path within the drive is kind of relative */
|
||||
if (ISDRIVE(path)) return 1;
|
||||
if (IS_MDRIVE(path)) return 1;
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int qse_isdrivepath (const qse_char_t* path)
|
||||
int qse_ismbsdrivepath (const qse_mchar_t* path)
|
||||
{
|
||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
||||
if (ISDRIVE(path)) return 1;
|
||||
if (IS_MDRIVE(path)) return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qse_isdrivecurpath (const qse_char_t* path)
|
||||
int qse_ismbsdrivecurpath (const qse_mchar_t* path)
|
||||
{
|
||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
||||
if (ISDRIVE(path) && path[2] == QSE_T('\0')) return 1;
|
||||
if (IS_MDRIVE(path) && path[2] == QSE_MT('\0')) return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon, int flags)
|
||||
qse_size_t qse_canonmbspath (const qse_mchar_t* path, qse_mchar_t* canon, int flags)
|
||||
{
|
||||
const qse_char_t* ptr;
|
||||
qse_char_t* dst;
|
||||
qse_char_t* non_root_start;
|
||||
const qse_mchar_t* ptr;
|
||||
qse_mchar_t* dst;
|
||||
qse_mchar_t* non_root_start;
|
||||
int has_root = 0;
|
||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
||||
int is_drive = 0;
|
||||
#endif
|
||||
qse_size_t canon_len;
|
||||
|
||||
if (path[0] == QSE_T('\0'))
|
||||
if (path[0] == QSE_MT('\0'))
|
||||
{
|
||||
/* if the source is empty, no translation is needed */
|
||||
canon[0] = QSE_T('\0');
|
||||
canon[0] = QSE_MT('\0');
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -84,31 +88,31 @@ qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon, int flags)
|
||||
dst = canon;
|
||||
|
||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
||||
if (ISDRIVE(ptr))
|
||||
if (IS_MDRIVE(ptr))
|
||||
{
|
||||
/* handle drive letter */
|
||||
*dst++ = *ptr++; /* drive letter */
|
||||
*dst++ = *ptr++; /* colon */
|
||||
|
||||
is_drive = 1;
|
||||
if (IS_SEP(*ptr))
|
||||
if (IS_MSEP(*ptr))
|
||||
{
|
||||
*dst++ = *ptr++; /* root directory */
|
||||
has_root = 1;
|
||||
}
|
||||
}
|
||||
else if (IS_SEP(*ptr))
|
||||
else if (IS_MSEP(*ptr))
|
||||
{
|
||||
*dst++ = *ptr++; /* root directory */
|
||||
has_root = 1;
|
||||
|
||||
#if defined(_WIN32)
|
||||
/* handle UNC path for Windows */
|
||||
if (IS_SEP(*ptr))
|
||||
if (IS_MSEP(*ptr))
|
||||
{
|
||||
*dst++ = *ptr++;
|
||||
|
||||
if (IS_SEP_OR_NIL(*ptr))
|
||||
if (IS_MSEP_OR_MNIL(*ptr))
|
||||
{
|
||||
/* if there is another separator after \\,
|
||||
* it's not an UNC path. */
|
||||
@ -117,14 +121,14 @@ qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon, int flags)
|
||||
else
|
||||
{
|
||||
/* if it starts with \\, process host name */
|
||||
do { *dst++ = *ptr++; } while (!IS_SEP_OR_NIL(*ptr));
|
||||
if (IS_SEP(*ptr)) *dst++ = *ptr++;
|
||||
do { *dst++ = *ptr++; } while (!IS_MSEP_OR_MNIL(*ptr));
|
||||
if (IS_MSEP(*ptr)) *dst++ = *ptr++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
if (IS_SEP(*ptr))
|
||||
if (IS_MSEP(*ptr))
|
||||
{
|
||||
*dst++ = *ptr++; /* root directory */
|
||||
has_root = 1;
|
||||
@ -137,30 +141,30 @@ qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon, int flags)
|
||||
|
||||
do
|
||||
{
|
||||
const qse_char_t* seg;
|
||||
const qse_mchar_t* seg;
|
||||
qse_size_t seglen;
|
||||
|
||||
/* skip duplicate separators */
|
||||
while (IS_SEP(*ptr)) ptr++;
|
||||
while (IS_MSEP(*ptr)) ptr++;
|
||||
|
||||
/* end of path reached */
|
||||
if (*ptr == QSE_T('\0')) break;
|
||||
if (*ptr == QSE_MT('\0')) break;
|
||||
|
||||
/* find the next segment */
|
||||
seg = ptr;
|
||||
while (!IS_SEP_OR_NIL(*ptr)) ptr++;
|
||||
while (!IS_MSEP_OR_MNIL(*ptr)) ptr++;
|
||||
seglen = ptr - seg;
|
||||
|
||||
/* handle the segment */
|
||||
if (seglen == 1 && seg[0] == QSE_T('.'))
|
||||
if (seglen == 1 && seg[0] == QSE_MT('.'))
|
||||
{
|
||||
/* eat up . */
|
||||
}
|
||||
else if (!(flags & QSE_CANONPATH_KEEPDOUBLEDOTS) &&
|
||||
seglen == 2 && seg[0] == QSE_T('.') && seg[1] == QSE_T('.'))
|
||||
seglen == 2 && seg[0] == QSE_MT('.') && seg[1] == QSE_MT('.'))
|
||||
{
|
||||
/* eat up the previous segment */
|
||||
qse_char_t* tmp;
|
||||
qse_mchar_t* tmp;
|
||||
|
||||
tmp = dst;
|
||||
if (tmp > non_root_start)
|
||||
@ -173,7 +177,7 @@ qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon, int flags)
|
||||
while (tmp > non_root_start)
|
||||
{
|
||||
tmp--;
|
||||
if (IS_SEP(*tmp))
|
||||
if (IS_MSEP(*tmp))
|
||||
{
|
||||
tmp++; /* position it next to the separator */
|
||||
break;
|
||||
@ -212,7 +216,7 @@ qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon, int flags)
|
||||
goto normal;
|
||||
}
|
||||
|
||||
if (prevlen == 3 && tmp[0] == QSE_T('.') && tmp[1] == QSE_T('.'))
|
||||
if (prevlen == 3 && tmp[0] == QSE_MT('.') && tmp[1] == QSE_MT('.'))
|
||||
{
|
||||
/* nothing to eat away because the previous segment is ../
|
||||
*
|
||||
@ -234,7 +238,7 @@ qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon, int flags)
|
||||
{
|
||||
normal:
|
||||
while (seg < ptr) *dst++ = *seg++;
|
||||
if (IS_SEP(*ptr))
|
||||
if (IS_MSEP(*ptr))
|
||||
{
|
||||
/* this segment ended with a separator */
|
||||
*dst++ = *seg++; /* copy the separator */
|
||||
@ -244,8 +248,8 @@ qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon, int flags)
|
||||
}
|
||||
while (1);
|
||||
|
||||
if (dst > non_root_start && IS_SEP(dst[-1]) &&
|
||||
((flags & QSE_CANONPATH_DROPTRAILINGSEP) || !IS_SEP(ptr[-1])))
|
||||
if (dst > non_root_start && IS_MSEP(dst[-1]) &&
|
||||
((flags & QSE_CANONPATH_DROPTRAILINGSEP) || !IS_MSEP(ptr[-1])))
|
||||
{
|
||||
/* if the canoncal path composed so far ends with a separator
|
||||
* and the original path didn't end with the separator, delete
|
||||
@ -255,18 +259,18 @@ qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon, int flags)
|
||||
* dst > non_root_start:
|
||||
* there is at least 1 character after the root directory
|
||||
* part.
|
||||
* IS_SEP(dst[-1]):
|
||||
* IS_MSEP(dst[-1]):
|
||||
* the canonical path ends with a separator.
|
||||
* IS_SEP(ptr[-1]):
|
||||
* IS_MSEP(ptr[-1]):
|
||||
* the origial path ends with a separator.
|
||||
*/
|
||||
dst[-1] = QSE_T('\0');
|
||||
dst[-1] = QSE_MT('\0');
|
||||
canon_len = dst - canon - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* just null-terminate the canonical path normally */
|
||||
dst[0] = QSE_T('\0');
|
||||
dst[0] = QSE_MT('\0');
|
||||
canon_len = dst - canon;
|
||||
}
|
||||
|
||||
@ -276,8 +280,8 @@ qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon, int flags)
|
||||
{
|
||||
/* 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[0] = QSE_MT('.');
|
||||
canon[1] = QSE_MT('\0');
|
||||
canon_len = 1;
|
||||
}
|
||||
}
|
||||
@ -302,21 +306,328 @@ qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon, int flags)
|
||||
/* i don't have to retain a trailing separator
|
||||
* if the last segment is double slashes because
|
||||
* the double slahses indicate a directory obviously */
|
||||
if (canon[canon_len-3] == QSE_T('.') &&
|
||||
canon[canon_len-2] == QSE_T('.') &&
|
||||
IS_SEP(canon[canon_len-1]))
|
||||
if (canon[canon_len-3] == QSE_MT('.') &&
|
||||
canon[canon_len-2] == QSE_MT('.') &&
|
||||
IS_MSEP(canon[canon_len-1]))
|
||||
{
|
||||
canon[--canon_len] = QSE_T('\0');
|
||||
canon[--canon_len] = QSE_MT('\0');
|
||||
}
|
||||
}
|
||||
else if (canon_len > adj_base_len)
|
||||
{
|
||||
if (IS_SEP(canon[canon_len-4]) &&
|
||||
canon[canon_len-3] == QSE_T('.') &&
|
||||
canon[canon_len-2] == QSE_T('.') &&
|
||||
IS_SEP(canon[canon_len-1]))
|
||||
if (IS_MSEP(canon[canon_len-4]) &&
|
||||
canon[canon_len-3] == QSE_MT('.') &&
|
||||
canon[canon_len-2] == QSE_MT('.') &&
|
||||
IS_MSEP(canon[canon_len-1]))
|
||||
{
|
||||
canon[--canon_len] = QSE_T('\0');
|
||||
canon[--canon_len] = QSE_MT('\0');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return canon_len;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* WCS IMPLEMENTATION */
|
||||
/* ------------------------------------------------------------------ */
|
||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
||||
# define IS_WSEP(c) ((c) == QSE_WT('/') || (c) == QSE_WT('\\'))
|
||||
#else
|
||||
# define IS_WSEP(c) ((c) == QSE_WT('/'))
|
||||
#endif
|
||||
|
||||
#define IS_WNIL(c) ((c) == QSE_WT('\0'))
|
||||
#define IS_WSEP_OR_WNIL(c) (IS_WSEP(c) || IS_WNIL(c))
|
||||
|
||||
#define IS_WDRIVE(s) \
|
||||
(((s[0] >= QSE_WT('A') && s[0] <= QSE_WT('Z')) || \
|
||||
(s[0] >= QSE_WT('a') && s[0] <= QSE_WT('z'))) && \
|
||||
s[1] == QSE_WT(':'))
|
||||
|
||||
int qse_iswcsabspath (const qse_wchar_t* path)
|
||||
{
|
||||
if (IS_WSEP(path[0])) return 1;
|
||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
||||
/* a drive like c:tmp is absolute in positioning the drive.
|
||||
* but the path within the drive is kind of relative */
|
||||
if (IS_WDRIVE(path)) return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qse_iswcsdrivepath (const qse_wchar_t* path)
|
||||
{
|
||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
||||
if (IS_WDRIVE(path)) return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qse_iswcsdrivecurpath (const qse_wchar_t* path)
|
||||
{
|
||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
||||
if (IS_WDRIVE(path) && path[2] == QSE_WT('\0')) return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
qse_size_t qse_canonwcspath (const qse_wchar_t* path, qse_wchar_t* canon, int flags)
|
||||
{
|
||||
const qse_wchar_t* ptr;
|
||||
qse_wchar_t* dst;
|
||||
qse_wchar_t* non_root_start;
|
||||
int has_root = 0;
|
||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
||||
int is_drive = 0;
|
||||
#endif
|
||||
qse_size_t canon_len;
|
||||
|
||||
if (path[0] == QSE_WT('\0'))
|
||||
{
|
||||
/* if the source is empty, no translation is needed */
|
||||
canon[0] = QSE_WT('\0');
|
||||
return 0;
|
||||
}
|
||||
|
||||
ptr = path;
|
||||
dst = canon;
|
||||
|
||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
||||
if (IS_WDRIVE(ptr))
|
||||
{
|
||||
/* handle drive letter */
|
||||
*dst++ = *ptr++; /* drive letter */
|
||||
*dst++ = *ptr++; /* colon */
|
||||
|
||||
is_drive = 1;
|
||||
if (IS_WSEP(*ptr))
|
||||
{
|
||||
*dst++ = *ptr++; /* root directory */
|
||||
has_root = 1;
|
||||
}
|
||||
}
|
||||
else if (IS_WSEP(*ptr))
|
||||
{
|
||||
*dst++ = *ptr++; /* root directory */
|
||||
has_root = 1;
|
||||
|
||||
#if defined(_WIN32)
|
||||
/* handle UNC path for Windows */
|
||||
if (IS_WSEP(*ptr))
|
||||
{
|
||||
*dst++ = *ptr++;
|
||||
|
||||
if (IS_WSEP_OR_WNIL(*ptr))
|
||||
{
|
||||
/* if there is another separator after \\,
|
||||
* it's not an UNC path. */
|
||||
dst--;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* if it starts with \\, process host name */
|
||||
do { *dst++ = *ptr++; } while (!IS_WSEP_OR_WNIL(*ptr));
|
||||
if (IS_WSEP(*ptr)) *dst++ = *ptr++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
if (IS_WSEP(*ptr))
|
||||
{
|
||||
*dst++ = *ptr++; /* root directory */
|
||||
has_root = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* non_root_start points to the beginning of the canonicalized
|
||||
* path excluding the root directory part. */
|
||||
non_root_start = dst;
|
||||
|
||||
do
|
||||
{
|
||||
const qse_wchar_t* seg;
|
||||
qse_size_t seglen;
|
||||
|
||||
/* skip duplicate separators */
|
||||
while (IS_WSEP(*ptr)) ptr++;
|
||||
|
||||
/* end of path reached */
|
||||
if (*ptr == QSE_WT('\0')) break;
|
||||
|
||||
/* find the next segment */
|
||||
seg = ptr;
|
||||
while (!IS_WSEP_OR_WNIL(*ptr)) ptr++;
|
||||
seglen = ptr - seg;
|
||||
|
||||
/* handle the segment */
|
||||
if (seglen == 1 && seg[0] == QSE_WT('.'))
|
||||
{
|
||||
/* eat up . */
|
||||
}
|
||||
else if (!(flags & QSE_CANONPATH_KEEPDOUBLEDOTS) &&
|
||||
seglen == 2 && seg[0] == QSE_WT('.') && seg[1] == QSE_WT('.'))
|
||||
{
|
||||
/* eat up the previous segment */
|
||||
qse_wchar_t* tmp;
|
||||
|
||||
tmp = dst;
|
||||
if (tmp > non_root_start)
|
||||
{
|
||||
/* there is a previous segment. */
|
||||
|
||||
tmp--; /* skip the separator just before .. */
|
||||
|
||||
/* find the beginning of the previous segment */
|
||||
while (tmp > non_root_start)
|
||||
{
|
||||
tmp--;
|
||||
if (IS_WSEP(*tmp))
|
||||
{
|
||||
tmp++; /* position it next to the separator */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (has_root)
|
||||
{
|
||||
/*
|
||||
* Eat up the previous segment if it exists.
|
||||
*
|
||||
* If it doesn't exist, tmp == dst so dst = tmp
|
||||
* keeps dst unchanged. If it exists,
|
||||
* tmp != dst. so dst = tmp changes dst.
|
||||
*
|
||||
* path /abc/def/..
|
||||
* ^ ^
|
||||
* seg ptr
|
||||
*
|
||||
* canon /abc/def/
|
||||
* ^ ^
|
||||
* tmp dst
|
||||
*/
|
||||
dst = tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
qse_size_t prevlen;
|
||||
|
||||
prevlen = dst - tmp;
|
||||
|
||||
if (/*tmp == non_root_start &&*/ prevlen == 0)
|
||||
{
|
||||
/* there is no previous segment */
|
||||
goto normal;
|
||||
}
|
||||
|
||||
if (prevlen == 3 && tmp[0] == QSE_WT('.') && tmp[1] == QSE_WT('.'))
|
||||
{
|
||||
/* nothing to eat away because the previous segment is ../
|
||||
*
|
||||
* path ../../
|
||||
* ^ ^
|
||||
* seg ptr
|
||||
*
|
||||
* canon ../
|
||||
* ^ ^
|
||||
* tmp dst
|
||||
*/
|
||||
goto normal;
|
||||
}
|
||||
|
||||
dst = tmp;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
normal:
|
||||
while (seg < ptr) *dst++ = *seg++;
|
||||
if (IS_WSEP(*ptr))
|
||||
{
|
||||
/* this segment ended with a separator */
|
||||
*dst++ = *seg++; /* copy the separator */
|
||||
ptr++; /* move forward the pointer */
|
||||
}
|
||||
}
|
||||
}
|
||||
while (1);
|
||||
|
||||
if (dst > non_root_start && IS_WSEP(dst[-1]) &&
|
||||
((flags & QSE_CANONPATH_DROPTRAILINGSEP) || !IS_WSEP(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.
|
||||
* IS_WSEP(dst[-1]):
|
||||
* the canonical path ends with a separator.
|
||||
* IS_WSEP(ptr[-1]):
|
||||
* the origial path ends with a separator.
|
||||
*/
|
||||
dst[-1] = QSE_WT('\0');
|
||||
canon_len = dst - canon - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* just null-terminate the canonical path normally */
|
||||
dst[0] = QSE_WT('\0');
|
||||
canon_len = dst - 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. */
|
||||
canon[0] = QSE_WT('.');
|
||||
canon[1] = QSE_WT('\0');
|
||||
canon_len = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* drop a traling separator if the last segment is
|
||||
* double slashes */
|
||||
|
||||
int adj_base_len = 3;
|
||||
|
||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
||||
if (is_drive && !has_root)
|
||||
{
|
||||
/* A path like A:..\\\ need some adjustment for
|
||||
* finalization below. */
|
||||
adj_base_len += 2;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (canon_len == adj_base_len)
|
||||
{
|
||||
/* i don't have to retain a trailing separator
|
||||
* if the last segment is double slashes because
|
||||
* the double slahses indicate a directory obviously */
|
||||
if (canon[canon_len-3] == QSE_WT('.') &&
|
||||
canon[canon_len-2] == QSE_WT('.') &&
|
||||
IS_WSEP(canon[canon_len-1]))
|
||||
{
|
||||
canon[--canon_len] = QSE_WT('\0');
|
||||
}
|
||||
}
|
||||
else if (canon_len > adj_base_len)
|
||||
{
|
||||
if (IS_WSEP(canon[canon_len-4]) &&
|
||||
canon[canon_len-3] == QSE_WT('.') &&
|
||||
canon[canon_len-2] == QSE_WT('.') &&
|
||||
IS_WSEP(canon[canon_len-1]))
|
||||
{
|
||||
canon[--canon_len] = QSE_WT('\0');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user