fixed bugs in qse_canonpath()
This commit is contained in:
parent
68537ad16a
commit
b5b23cbc36
45
qse/include/qse/fs/path.h
Normal file
45
qse/include/qse/fs/path.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* $Id
|
||||||
|
*
|
||||||
|
Copyright 2006-2011 Chung, Hyung-Hwan.
|
||||||
|
This file is part of QSE.
|
||||||
|
|
||||||
|
QSE is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as
|
||||||
|
published by the Free Software Foundation, either version 3 of
|
||||||
|
the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
QSE is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with QSE. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _QSE_FS_PATH_H_
|
||||||
|
#define _QSE_FS_PATH_H_
|
||||||
|
|
||||||
|
#include <qse/types.h>
|
||||||
|
#include <qse/macros.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
qse_size_t qse_canonpath (
|
||||||
|
const qse_char_t* path,
|
||||||
|
qse_char_t* canon
|
||||||
|
);
|
||||||
|
|
||||||
|
qse_size_t qse_realpath (
|
||||||
|
const qse_char_t* path,
|
||||||
|
qse_char_t* real
|
||||||
|
);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
@ -18,9 +18,7 @@
|
|||||||
License along with QSE. If not, see <http://www.gnu.org/licenses/>.
|
License along with QSE. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <qse/types.h>
|
#include <qse/fs/path.h>
|
||||||
#include <qse/macros.h>
|
|
||||||
/*#include <qse/fs/path.h>*/
|
|
||||||
|
|
||||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
||||||
# define ISSEP(c) ((c) == QSE_T('/') || (c) == QSE_T('\\'))
|
# define ISSEP(c) ((c) == QSE_T('/') || (c) == QSE_T('\\'))
|
||||||
@ -30,23 +28,37 @@
|
|||||||
|
|
||||||
#define ISSEPNIL(c) (ISSEP(c) || ((c) == QSE_T('\0')))
|
#define ISSEPNIL(c) (ISSEP(c) || ((c) == QSE_T('\0')))
|
||||||
|
|
||||||
int qse_canonpath (const qse_char_t* path)
|
qse_size_t qse_canonpath (const qse_char_t* path, qse_char_t* canon)
|
||||||
{
|
{
|
||||||
const qse_char_t* ptr;
|
const qse_char_t* ptr;
|
||||||
qse_char_t* dst;
|
qse_char_t* dst;
|
||||||
qse_char_t* root = QSE_NULL;
|
qse_char_t* non_root_start;
|
||||||
|
int has_root = 0;
|
||||||
/* TODO: delete this. */
|
|
||||||
qse_char_t* buf = malloc (10000);
|
|
||||||
|
|
||||||
ptr = path;
|
ptr = path;
|
||||||
dst = buf;
|
dst = canon;
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
||||||
|
if (((ptr[0] >= QSE_T('A') && ptr[0] <= QSE_T('Z')) ||
|
||||||
|
(ptr[0] >= QSE_T('a') && ptr[0] <= QSE_T('z'))) &&
|
||||||
|
ptr[1] == QSE_T(':'))
|
||||||
|
{
|
||||||
|
/* handle drive letter */
|
||||||
|
*dst++ = *ptr++; /* drive letter */
|
||||||
|
*dst++ = *ptr++; /* colon */
|
||||||
|
|
||||||
if (ISSEP(*ptr))
|
if (ISSEP(*ptr))
|
||||||
{
|
{
|
||||||
*dst++ = *ptr++;
|
*dst++ = *ptr++; /* root directory */
|
||||||
|
has_root = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ISSEP(*ptr))
|
||||||
|
{
|
||||||
|
*dst++ = *ptr++; /* root directory */
|
||||||
|
has_root = 1;
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
/* handle UNC path */
|
/* handle UNC path */
|
||||||
if (ISSEP(*ptr))
|
if (ISSEP(*ptr))
|
||||||
{
|
{
|
||||||
@ -55,18 +67,29 @@ int qse_canonpath (const qse_char_t* path)
|
|||||||
/* if it starts with \\, process host name */
|
/* if it starts with \\, process host name */
|
||||||
while (!ISSEPNIL(*ptr)) *dst++ = *ptr++;
|
while (!ISSEPNIL(*ptr)) *dst++ = *ptr++;
|
||||||
|
|
||||||
/* \ following the host name */
|
/* \ following the host name. note that
|
||||||
|
* \\\ is treated as if the host name is empty. */
|
||||||
|
|
||||||
if (ISSEP(*ptr)) *dst++ = *ptr++;
|
if (ISSEP(*ptr)) *dst++ = *ptr++;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
if (ISSEP(*ptr))
|
||||||
|
{
|
||||||
|
*dst++ = *ptr++; /* root directory */
|
||||||
|
has_root = 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
root = dst;
|
/* non_root_start points to the beginning of the canonicalized
|
||||||
|
* path excluding the root directory part. */
|
||||||
|
non_root_start = dst;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
const qse_char_t* seg;
|
const qse_char_t* seg;
|
||||||
qse_size_t len;
|
qse_size_t seglen;
|
||||||
|
|
||||||
/* skip duplicate separators */
|
/* skip duplicate separators */
|
||||||
while (ISSEP(*ptr)) ptr++;
|
while (ISSEP(*ptr)) ptr++;
|
||||||
@ -74,54 +97,87 @@ int qse_canonpath (const qse_char_t* path)
|
|||||||
/* end of path reached */
|
/* end of path reached */
|
||||||
if (*ptr == QSE_T('\0')) break;
|
if (*ptr == QSE_T('\0')) break;
|
||||||
|
|
||||||
|
/* find the next segment */
|
||||||
seg = ptr;
|
seg = ptr;
|
||||||
while (!ISSEPNIL(*ptr)) ptr++;
|
while (!ISSEPNIL(*ptr)) ptr++;
|
||||||
|
seglen = ptr - seg;
|
||||||
|
|
||||||
len = ptr - seg;
|
/* handle the segment */
|
||||||
if (len == 1 && seg[0] == QSE_T('.'))
|
if (seglen == 1 && seg[0] == QSE_T('.'))
|
||||||
{
|
{
|
||||||
/* eat up . */
|
/* eat up . */
|
||||||
}
|
}
|
||||||
else if (len == 2 && seg[0] == QSE_T('.') && seg[1] == QSE_T('.'))
|
else if (seglen == 2 && seg[0] == QSE_T('.') && seg[1] == QSE_T('.'))
|
||||||
{
|
{
|
||||||
/* eat up the previous segment */
|
/* eat up the previous segment */
|
||||||
/*if (!root) goto normal;*/
|
qse_char_t* tmp;
|
||||||
const qse_char_t* tmp;
|
|
||||||
|
|
||||||
tmp = dst;
|
tmp = dst;
|
||||||
if (tmp > root) tmp--;
|
if (tmp > non_root_start)
|
||||||
while (tmp > root)
|
{
|
||||||
|
/* there is a previous segment. */
|
||||||
|
|
||||||
|
tmp--; /* skip the separator just before .. */
|
||||||
|
|
||||||
|
/* find the beginning of the previous segment */
|
||||||
|
while (tmp > non_root_start)
|
||||||
{
|
{
|
||||||
tmp--;
|
tmp--;
|
||||||
if (ISSEP(*tmp)) break;
|
if (ISSEP(*tmp))
|
||||||
|
{
|
||||||
|
tmp++; /* position it next to the separator */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root > buf)
|
if (has_root)
|
||||||
{
|
{
|
||||||
/* mean that the path contains the root directory */
|
/*
|
||||||
|
* 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;
|
dst = tmp;
|
||||||
if (tmp == root) tmp++;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (tmp == root) goto normal;
|
qse_size_t prevlen;
|
||||||
|
|
||||||
if (dst - tmp == 3 &&
|
prevlen = dst - tmp;
|
||||||
tmp[0] == QSE_T('.') && tmp[1] == QSE_T('.'))
|
|
||||||
|
if (/*tmp == non_root_start &&*/ prevlen == 0)
|
||||||
{
|
{
|
||||||
/* the previous segment ../ */
|
/* there is no previous segment */
|
||||||
goto normal;
|
|
||||||
}
|
|
||||||
if (dst - tmp == 4 &&
|
|
||||||
ISSEP(tmp[0]) &&
|
|
||||||
tmp[1] == QSE_T('.') &&
|
|
||||||
tmp[2] == QSE_T('.'))
|
|
||||||
{
|
|
||||||
/* the previous segment is /../ */
|
|
||||||
goto normal;
|
goto normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
dst = tmp + 1;
|
if (prevlen == 3 && tmp[0] == QSE_T('.') && tmp[1] == QSE_T('.'))
|
||||||
|
{
|
||||||
|
/* nothing to eat away because the previous segment is ../
|
||||||
|
*
|
||||||
|
* path ../../
|
||||||
|
* ^ ^
|
||||||
|
* seg ptr
|
||||||
|
*
|
||||||
|
* canon ../
|
||||||
|
* ^ ^
|
||||||
|
* tmp dst
|
||||||
|
*/
|
||||||
|
goto normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
dst = tmp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -133,6 +189,32 @@ int qse_canonpath (const qse_char_t* path)
|
|||||||
}
|
}
|
||||||
while (1);
|
while (1);
|
||||||
|
|
||||||
*dst++ = QSE_T('\0');
|
if (dst > non_root_start && ISSEP(dst[-1]) && !ISSEP(ptr[-1]))
|
||||||
return buf;
|
{
|
||||||
|
/* 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.
|
||||||
|
*
|
||||||
|
* dst > non_root_start:
|
||||||
|
* there is at least 1 character after the root directory part.
|
||||||
|
* ISSEP(dst[-1]):
|
||||||
|
* the canonical path ends with a separator.
|
||||||
|
* ISSEP(ptr[-1]):
|
||||||
|
* the origial path ends with a separator
|
||||||
|
*/
|
||||||
|
dst[-1] = QSE_T('\0');
|
||||||
|
return dst - canon - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* just null-terminate the canonical path normally */
|
||||||
|
dst[0] = QSE_T('\0');
|
||||||
|
return dst - canon;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qse_size_t qse_realpath (const qse_char_t* path, qse_char_t* real)
|
||||||
|
{
|
||||||
|
/* TODO: canonicalize path with symbolic links resolved */
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2,16 +2,30 @@
|
|||||||
#include <qse/fs/dir.h>
|
#include <qse/fs/dir.h>
|
||||||
#include <qse/cmn/stdio.h>
|
#include <qse/cmn/stdio.h>
|
||||||
#include <qse/cmn/main.h>
|
#include <qse/cmn/main.h>
|
||||||
|
#include <qse/cmn/str.h>
|
||||||
|
#include <qse/cmn/mem.h>
|
||||||
|
|
||||||
int path_main (int argc, qse_char_t* argv[])
|
int path_main (int argc, qse_char_t* argv[])
|
||||||
{
|
{
|
||||||
|
qse_char_t* canon;
|
||||||
|
qse_size_t len;
|
||||||
|
|
||||||
if (argc != 2)
|
if (argc != 2)
|
||||||
{
|
{
|
||||||
qse_fprintf (QSE_STDERR, QSE_T("Usage: %s <directory>\n"), argv[0]);
|
qse_fprintf (QSE_STDERR, QSE_T("Usage: %s <directory>\n"), argv[0]);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
qse_printf (QSE_T("[%s] => [%s]\n"), argv[1], qse_canonpath (argv[1]));
|
canon = QSE_MMGR_ALLOC (QSE_MMGR_GETDFL(), (qse_strlen(argv[1]) + 1) * QSE_SIZEOF(*canon));
|
||||||
|
if (canon == QSE_NULL)
|
||||||
|
{
|
||||||
|
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);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user