cdesktopenv/cde/lib/DtSvc/DtCodelibs/pathcollapse.C

185 lines
4.0 KiB
C

/*
* CDE - Common Desktop Environment
*
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they 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 these librararies and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
/*
* $XConsortium: pathcollapse.C /main/5 1996/06/21 17:36:32 ageorge $
*
* (c) Copyright 1996 Digital Equipment Corporation.
* (c) Copyright 1993,1994,1996 Hewlett-Packard Company.
* (c) Copyright 1993,1994,1996 International Business Machines Corp.
* (c) Copyright 1993,1994,1996 Sun Microsystems, Inc.
* (c) Copyright 1993,1994,1996 Novell, Inc.
* (c) Copyright 1996 FUJITSU LIMITED.
* (c) Copyright 1996 Hitachi.
*/
#ifdef DOMAIN_ALLOW_MALLOC_OVERRIDE
#include "/usr/include/apollo/shlib.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/param.h>
#include <codelibs/nl_hack.h>
#include <codelibs/pathutils.h>
#define SEP(P) (CHARAT(P) == '\0' || CHARAT(P) == '/')
#define DOT(P) (CHARAT(P) == '.' && SEP((P) + 1))
#define DOTDOT(P) (CHARAT(P) == '.' && DOT((P) + 1))
#ifdef __cplusplus
extern "C"
#endif
char *
pathcollapse(const char *src, char *dst, boolean show_dir)
{
int ch;
const char *srcp;
char *dstp, *sep;
char *components[MAXPATHLEN / 2 + 1];
char **comp = components;
int length = src == NULL ? 0 : strlen(src);
int dir_comp; /* TRUE if last component was . or .. */
#ifdef apollo
int double_slash = 0;
#endif
wchar_t __nlh_char[1];
if (length == 0 || length > MAXPATHLEN)
{
errno = EINVAL;
return NULL;
}
if (dst == NULL)
if ((dst = (char *)malloc(length + 1)) == NULL)
return NULL;
#ifdef apollo
/*
* On apollo, a leading double-slash must be preserved, so we
* copy the first slash and hide it from the rest of the code.
*/
if (CHARAT(src) == '/' && CHARAT(src + 1) == '/')
{
*dst++ = '/';
src++;
double_slash = 1;
}
#endif
srcp = src;
dstp = dst;
do /* for each component of src */
{
*comp = dstp;
/* copy the component and trailing separator to dst */
do
{
ch = (int)CHARAT(srcp);
sep = dstp;
WCHARADV(ch, dstp);
if (ch == '\0')
break;
ADVANCE(srcp);
} while (ch != '/');
dir_comp = ch == '/'; /* true if trailing '/' */
/* skip all adjacent '/' characters [the first is preserved] */
while (CHARAT(srcp) == '/')
ADVANCE(srcp);
/* remove redundant trailing slash */
if (CHARAT(srcp) == '\0')
if (sep > dst)
*sep = ch = '\0';
if (DOT(*comp))
{
dir_comp = 1;
dstp = *comp;
if (dstp > dst)
{
sep = dstp - 1;
*dstp = '\0';
}
continue;
}
else if (DOTDOT(*comp))
{
dir_comp = 1;
if (*comp > dst)
{
comp--;
if (!DOTDOT(*comp))
{
dstp = *comp;
if (dstp > dst)
{
sep = dstp - 1;
*dstp = '\0';
}
else
{
if (CHARAT(dst) == '/')
{
/* /.. is same as / */
dstp = dst + 1;
*dstp = '\0';
comp++;
}
else
dst[0] = '.';
sep = dst + 1;
*sep = '\0';
}
continue;
}
}
}
comp++;
} while (ch != '\0');
if (show_dir)
{
if (dir_comp && (sep > dst + 1 || dst[0] != '/'))
{
*sep++ = '/';
*sep = '\0';
}
}
else if (sep > dst)
*sep = '\0'; /* remove trailing '/' */
#ifdef apollo
if (double_slash)
dst--;
#endif
return dst;
}