/* Convert relative to absolute pathnames
 * Copyright 1991 Phil Karn, KA9Q
 */
#include "global.h"
#include "commands.h"
#include "dirutil.h"
#ifdef CALLSERVER
extern char *CDROM; /* buckbook.c: defines CDROM drive letter e.g. "s:"  */
#endif

#if !defined(_lint)
static char rcsid[] OPTIONAL = "$Id: pathname.c,v 1.12 1996/09/04 01:34:13 root Exp $";
#endif

void crunch (char *buf,const char *path);

/* Given a working directory and an arbitrary pathname, resolve them into
 * an absolute pathname. Memory is allocated for the result, which
 * the caller must free
 */
char *
pathname (cd, path)
const char *cd;	/* Current working directory */
const char *path;	/* Pathname argument */
{
register char *buf;
#ifdef	MSDOS
char *cp,c;
char *tbuf = NULLCHAR;
int tflag = 0;
#endif
#ifdef CALLSERVER
int drive = 0;  /* is there a drive spec to preserve? */
#endif

	if(cd == NULLCHAR || path == NULLCHAR)
		return NULLCHAR;

#ifdef	MSDOS
	/* If path has any backslashes, make a local copy with them
	 * translated into forward slashes
	 */
	if (strchr (path, '\\') != NULLCHAR){
		tflag = 1;
		cp = tbuf = strdup (path);
		while ((c = *path++) != '\0'){
			if(c == '\\')
				*cp++ = '/';
			else
				*cp++ = c;
		}
		*cp = '\0';
		path = tbuf;
	}
#endif

	/* Strip any leading white space on args */
	cd = skipwhite (cd);
	path = skipwhite (path);

#ifdef CALLSERVER
	if (CDROM != NULLCHAR && strncmp (path, CDROM, 2) == 0)  {
		buf = strdup (path);
		return buf;
	}
	if (CDROM != NULLCHAR &&  strncmp(cd, CDROM, 2) == 0)
		drive = 1;
                                                            /* make a note  */
#endif
    /* Allocate and initialize output buffer; user must free */
	buf = mallocw ((unsigned)strlen (cd) + strlen (path) + 10);	/* fudge factor */
	buf[0] = '\0';

	/* Interpret path relative to cd only if it doesn't begin with "/" */
	if (path[0] != '/')	{
		if (cd[0] != '/' && cd[0] != '.')
			strcpy (buf, ".");
		crunch (buf, cd);
	}

#ifdef CALLSERVER
	else
		drive = 0;
#endif
	crunch (buf, path);

	/* Special case: null final path means the root directory */
	if (buf[0] == '\0'){
		buf[0] = '/';
		buf[1] = '\0';
	}
#ifdef	MSDOS
	if (tflag && tbuf)
		free (tbuf);
#endif
#ifdef CALLSERVER
	if (drive)  {
		cp = buf;
		while (*cp != '\0')
			*cp = *(cp++ + 1);
	}
#endif
	return buf;
}


/* Process a path name string, starting with and adding to
 * the existing buffer
 */
void
crunch (buf, path)
char *buf;
register const char *path;
{
register char *cp;
	

	if (!strncmp ("./", path, 2) || !strncmp ("../", path, 3))	{
		strcpy (buf, path);
		return;
	}
	cp = buf + strlen (buf);	/* Start write at end of current buffer */
	
	/* Now start crunching the pathname argument */
	for ( ; ; )	{
		/* Strip leading /'s; one will be written later */
		while (*path == '/')
			path++;
		if (*path == '\0')
			break;		/* no more, all done */
		/* Look for parent directory references, either at the end
		 * of the path or imbedded in it
		 */
		if (strcmp (path, "..") == 0 || strncmp (path, "../", 3) == 0){
			/* Hop up a level */
			if ((cp = strrchr (buf, '/')) == NULLCHAR)
				cp = buf;	/* Don't back up beyond root */
			*cp = '\0';		/* In case there's another .. */
			path += 2;		/* Skip ".." */
			while (*path == '/')	/* Skip one or more slashes */
				path++;
		/* Look for current directory references, either at the end
		 * of the path or imbedded in it
		 */
		} else if (strcmp (path, ".") == 0 || strncmp (path, "./", 2) == 0){
			/* "no op" */
			path++;			/* Skip "." */
			while (*path == '/')	/* Skip one or more slashes */
				path++;
		} else {
			/* Ordinary name, copy up to next '/' or end of path */
			*cp++ = '/';
			while (*path != '/' && *path != '\0')
				*cp++ = *path++;
		}
	}
	*cp++ = '\0';
}
