home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (c) 1990 Carnegie Mellon University
- * All Rights Reserved.
- *
- * Permission to use, copy, modify and distribute this software and its
- * documentation is hereby granted, provided that both the copyright
- * notice and this permission notice appear in all copies of the
- * software, derivative works or modified versions, and any portions
- * thereof, and that both notices appear in supporting documentation.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND CARNEGIE MELLON UNIVERSITY
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT
- * SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
- * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
- * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * Users of this software agree to return to Carnegie Mellon any
- * improvements or extensions that they make and grant Carnegie the
- * rights to redistribute these changes.
- *
- * Export of this software is permitted only after complying with the
- * regulations of the U.S. Deptartment of Commerce relating to the
- * Export of Technical Data.
- */
- /*
- * abspath -- determine absolute pathname
- *
- * Originally written sometime around 1980 by James Gosling.
- *
- *----------------------------------------------------------------------
- *
- * abspath (name,result)
- * char *name;
- * char *result;
- *
- * Abspath places the absolute pathname of the string name into
- * the string result.
- *
- * Abspath takes a pathname and converts it to an absolute pathname by
- * prepending the name of the current working directory if necessary.
- * Then the absolute pathname is compacted by removing and resolving
- * superfluous steps.
- *
- * Steps of "" (two adjacent slashes) and steps of "." are removed
- * because they have no effect on the meaning of the pathname.
- *
- * Steps of ".." are resolved by removing them together with the
- * preceeding step. However, resolution is not possible if the
- * preceeding step is also ".."
- *
- * Abspath calls getwd to obtain the name of the current working
- * directory when needed. To improve performance, the result from
- * getwd is saved so that getwd need not be invoked again during
- * subsequent calls on abspath. If you change the current working
- * directory (via chdir) you must call abspath(0,0) which causes
- * abspath to flush its saved result from getwd. If you do not do
- * this abspath will continue to use its saved result from getwd
- * and this will most likely cause it to produce erronious results.
- *
- * Abspath returns 0 on success and -1 on failure. The only failure
- * that can happen is a failure of getwd. See the documentation on
- * getwd. Failures in getwd are pretty catastrophic.
- *
- *----------------------------------------------------------------------
- *
- * HISTORY
- * $Log: abspath.c,v $
- * Revision 1.2 90/12/11 17:49:59 mja
- * Add copyright/disclaimer for distribution.
- *
- * 30-Apr-85 Steven Shafer (sas) at Carnegie-Mellon University
- * Adapted for 4.2 BSD UNIX. Changed to new getwd() routine.
- *
- * 15-Nov-82 Tom Rodeheffer (tlr) at Carnegie-Mellon University
- * Redid the rest of the routine so that now it has been completely
- * retouched, although still conserving most of the original design.
- * Increased curwd to 1024 characters to match what getwd can
- * produce. Per suggestions by Steve Shafer, added the ability to
- * flush the remembered current working directory (which you should
- * do after calling chdir) and improved the initial construction of
- * the result so that the current working directory is not obtained
- * if the given pathname is already an absolute pathname.
- *
- * 14-Nov-82 Tom Rodeheffer (tlr) at Carnegie-Mellon University
- * Redid compaction of the absolute path name so that leading steps
- * of ".." are preserved. Also fixed so that the trailing slash
- * is not deleted if it is also the initial slash.
- *
- *----------------------------------------------------------------------
- */
-
-
- #define TRUE 1
- #define FALSE 0
-
- char *getwd();
-
- static char havecurwd = FALSE;
- static char curwd [1024]; /* remember the current working directory */
-
- int abspath (name,result)
-
- char * name;
- char * result;
- {
- register char * src; /* source pointer for copy operations */
- register char * dst; /* destination pointer for copy operations */
- register char * fence; /* pointer to slash that cannot be backed over */
- register char * t; /* scanback pointer in dst when we hit a slash */
-
-
-
- if (name == 0 || result == 0)
- {
- havecurwd = FALSE; /* flush knowledge of current working directory */
- return (0);
- }
-
-
- /*
- * Construct the initial result pathname, which is basically just
- * a concatenation of the current working directory (if the name
- * is a relative pathname) and the name. If we need to know the
- * current working directory but don't have it saved away, we call
- * getwd to figure it out for us.
- */
-
- dst = result;
-
- if (name[0] != '/')
- {
- if (!havecurwd && getwd(curwd) == 0) return (-1);
- havecurwd = TRUE;
-
- src = curwd;
- while ((*dst++ = *src++) != 0) ; /* copy curwd to result */
- dst[-1] = '/'; /* tack on a trailing slash */
- }
-
- src = name;
- while ((*dst++ = *src++) != 0) ; /* copy name to result */
- dst[-1] = '/'; /* tack on a trailing slash */
- *dst = 0; /* make it null-terminated */
-
-
-
- /*
- * Now scan through result and compact the pathname.
- *
- * "//" => "/"
- * "/./" => "/"
- * "/x/../" => "/"
- *
- * where x is a string without a slash. Note that x
- * cannot be "", ".", or ".."
- *
- * There is guaranteed to be a trailing slash on result when
- * we start, so that we don't need any special cases to handle
- * trailing steps--all steps in the pathname end with a slash.
- *
- * The fence points to the most recent slash that ".." cannot
- * back over. Basically, all steps to the left of the fence
- * are ".." Initially the fence points to the first slash. We
- * are paranoid so we scan for the first slash. Any characters
- * coming before the first slash (which must be the result of
- * getwd) are assumed to be magical incantations and we leave
- * them alone. This is never expected to happen, but who knows?
- */
-
- src = result;
- dst = result;
-
- while (*src)
- {
- if ((*dst++ = *src++) == '/')
- {
- fence = dst-1; /* set fence to first slash */
- break;
- }
- }
-
- while (*src)
- {
- if ((*dst++ = *src++) == '/')
- {
- t = dst-1; /* address of slash */
-
-
- switch (*--t)
- {
- case '/': /* found "//" */
- dst = t+1; /* take off "/" */
- break;
-
- case '.':
- switch (*--t)
- {
- case '/': /* found "/./" */
- dst = t+1; /* take off "./" */
- break;
-
- case '.':
- if (*--t == '/')
- { /* found "/../" */
- if (t == fence)
- { /* it is a leading ".." */
- fence = dst-1; /* move fence over it */
- }
- else
- {
- while (*--t != '/') ;
- dst = t+1; /* take off "x/../" */
- }
- }
- break;
- }
- break;
- }
- }
- }
-
- *dst = 0; /* null-terminate the result */
-
-
- /*
- * Now get rid of a trailing slash provided it is not also an
- * initial slash.
- *
- * Note that we tacked on a trailing slash originally and the
- * compaction shouldn't affect it so it should still be there,
- * but we check anyway because we're paranoid.
- */
-
- if (--dst > result && *dst == '/') *dst = 0;
-
-
- return (0);
- }
-