diff options
Diffstat (limited to 'src/compath.c')
-rw-r--r-- | src/compath.c | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/src/compath.c b/src/compath.c new file mode 100644 index 0000000..6726ae1 --- /dev/null +++ b/src/compath.c @@ -0,0 +1,213 @@ +/*=========================================================================== + Copyright (c) 1998-2000, The Santa Cruz Operation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + *Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + *Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + *Neither name of The Santa Cruz Operation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS + IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + DAMAGE. + =========================================================================*/ + +/* + * compath(pathname) + * + * This compresses pathnames. All strings of multiple slashes are + * changed to a single slash. All occurrences of "./" are removed. + * Whenever possible, strings of "/.." are removed together with + * the directory names that they follow. + * + * WARNING: since pathname is altered by this function, it should + * be located in a temporary buffer. This avoids the problem + * of accidently changing strings obtained from makefiles + * and stored in global structures. + */ + +static char const rcsid[] = "$Id: compath.c,v 1.3 2001/07/05 14:31:00 broeker Exp $"; + +#include "global.h" + +#ifndef NULL +#define NULL 0 +#endif + +char * +compath(char *pathname) /*FDEF*/ +{ + char *nextchar; + char *lastchar; + char *sofar; + char *pnend; + + int pnlen; + + /* + * do not change the path if it has no "/" + */ + + if (strchr(pathname, '/') == NULL) + return(pathname); + + /* + * find all strings consisting of more than one '/' + */ + + for (lastchar = pathname + 1; *lastchar != '\0'; lastchar++) + if ((*lastchar == '/') && (*(lastchar - 1) == '/')) + { + + /* + * find the character after the last slash + */ + + nextchar = lastchar; + while (*++lastchar == '/') + { + } + + /* + * eliminate the extra slashes by copying + * everything after the slashes over the slashes + */ + + sofar = nextchar; + while ((*nextchar++ = *lastchar++) != '\0') + ; + lastchar = sofar; + } + + /* + * find all strings of "./" + */ + + for (lastchar = pathname + 1; *lastchar != '\0'; lastchar++) + if ((*lastchar == '/') && (*(lastchar - 1) == '.') && + ((lastchar - 1 == pathname) || (*(lastchar - 2) == '/'))) + { + + /* + * copy everything after the "./" over the "./" + */ + + nextchar = lastchar - 1; + sofar = nextchar; + while ((*nextchar++ = *++lastchar) != '\0') + ; + lastchar = sofar; + } + + /* + * find each occurrence of "/.." + */ + + for (lastchar = pathname + 1; *lastchar != '\0'; lastchar++) + if ((lastchar != pathname) && (*lastchar == '/') && + (*(lastchar + 1) == '.') && (*(lastchar + 2) == '.') && + ((*(lastchar + 3) == '/') || (*(lastchar + 3) == '\0'))) + { + + /* + * find the directory name preceding the "/.." + */ + + nextchar = lastchar - 1; + while ((nextchar != pathname) && + (*(nextchar - 1) != '/')) + --nextchar; + + /* + * make sure the preceding directory's name + * is not "." or ".." + */ + + if ((*nextchar == '.') && + ((*(nextchar + 1) == '/') || + ((*(nextchar + 1) == '.') && (*(nextchar + 2) == '/')))) + /* EMPTY */; + else + { + + /* + * prepare to eliminate either + * "dir_name/../" or "dir_name/.." + */ + + if (*(lastchar + 3) == '/') + lastchar += 4; + else + lastchar += 3; + + /* + * copy everything after the "/.." to + * before the preceding directory name + */ + + sofar = nextchar - 1; + while ((*nextchar++ = *lastchar++) != '\0'); + + lastchar = sofar; + + /* + * if the character before what was taken + * out is '/', set up to check if the + * slash is part of "/.." + */ + + if ((sofar + 1 != pathname) && (*sofar == '/')) + --lastchar; + } + } + + /* + * if the string is more than a character long and ends + * in '/', eliminate the '/'. + */ + + pnlen = strlen(pathname); + pnend = strchr(pathname, '\0') - 1; + + if ((pnlen > 1) && (*pnend == '/')) + { + *pnend-- = '\0'; + pnlen--; + } + + /* + * if the string has more than two characters and ends in + * "/.", remove the "/.". + */ + + if ((pnlen > 2) && (*(pnend - 1) == '/') && (*pnend == '.')) + *--pnend = '\0'; + + /* + * if all characters were deleted, return "."; + * otherwise return pathname + */ + + if (*pathname == '\0') + (void) strcpy(pathname, "."); + + return(pathname); +} |