BBN-Vax-TCP/src/libbbn/dotpath.c

/*
 * char *dotpath(relpath, low, top)
 * Take any legal pathname, relpath, and put the equivalent most
 * reduced pathname that can be obtained without accessing any
 * file systems in the area pointed to by low, but not exceeding top.
 * A pointer to the null of the resultant string is returned.
 *
 * The resultant string starts with one of "/", ".", or "...".
 * If it starts with "/", all occurences of "." and ".." have been
 * removed (there was no "...") and the pathname is absolute and
 * condensed as much as possible.  If it starts with "." or "...",
 * all other occurences of "." or "..." have been removed, as have
 * all occurences of ".." which would not involve backing past the
 * initial "." or "...".  In any case, all multiple adjacent slashes
 * have been reduced to one, and any trailing slash has been removed.
 *
 * There are no possible errors except lack of space to put the string.
 */

char   *dotpath (relpath, low, top)
char   *relpath;
char   *low;
char   *top;
{
    register char  *cp,
                   *path;
    char   *ep,
           *slash,
           *root,
           *dot,
           *dotdot,
           *dotdotdot;
    char   *start;
    int slength (), smatch (), stokeq ();
    char *sskip (), *sfind (), *scopy (), *safter ();
    char *sbskip (), *sbfind (), *sbcopy ();

    root = "/";
    slash = "/";
    dot = ".";
    dotdot = "..";
    dotdotdot = "...";
    cp = relpath;
    path = low;
    if (smatch (cp, root) == slength (root))
    {
	start = path;
	path = scopy (root, path, top);
	cp = sskip (safter (cp, root), slash);
    }
    else
    {
	path = scopy (dot, path, top);
	path = scopy (slash, path, top);
	start = path;
    }
    ep = path;
    while (*cp)
    {
	if (stokeq (cp, slash, dot))
	{		     /* just ignore dot */
	    cp = sskip (sfind (cp, slash), slash);
	}
	else
	    if (stokeq (cp, slash, dotdot)
		    && (path > start) && !stokeq (ep, slash, dotdot))
	    {		     /* back up */
		cp = sskip (sfind (cp, slash), slash);
		path = ep;
		if (sbskip (ep, low, slash) > start)
		{
		    ep = sbfind (sbskip (ep, low, slash), low, slash);
		}
	    }
	    else
		if (stokeq (cp, slash, dotdotdot))
		{	     /* start over */
		    cp = sskip (sfind (cp, slash), slash);
		    path = scopy (dotdotdot, low, top);
		    start = ep = path = scopy (slash, path, top);
		}
		else
		{
		    ep = path;
		    path = scopy (cp, path, &path[sfind (cp, slash) - cp]);
		    if (!seq (low, root))
			path = scopy (slash, path, top);
		    cp = sskip (sfind (cp, slash), slash);
		}
	*path = 0;
    }
    if (!seq (low, root))
    {			     /* wipe out trailing slash */
	path = sbskip (path, low, slash);
	*path = 0;
    }
    return (path);
}