#include "global.h"
#include <ctype.h>

/* 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)
char *cd;	/* Current working directory */
char *path;	/* Pathname argument */
{
	register char *buf,*cp;
	char *cdtmp,*pathtmp,*strcpy();

	if(cd == NULLCHAR || path == NULLCHAR)
		return NULLCHAR;

#if	(defined(MSDOS) || defined(ATARI_ST))
	/* Make temporary copies of cd and path
	 * with all \'s translated to /'s
	 */
	if ((pathtmp = malloc((unsigned)strlen(path)+1)) == NULLCHAR)
		return NULLCHAR;
	for (cp = path = strcpy(pathtmp,path); *cp != '\0'; cp++)
		if (*cp == '\\')
			*cp = '/';

	if ((cdtmp = malloc((unsigned)strlen(cd)+1)) == NULLCHAR) {
		free(pathtmp);
		return NULLCHAR;
	}
	for (cp = cd = strcpy(cdtmp,cd); *cp != '\0'; cp++)
		if (*cp == '\\')
			*cp = '/';
#endif

	/* Strip any leading white space on args */
	while(*cd == ' ' || *cd == '\t')
		cd++;
	while(*path == ' ' || *path == '\t')
		path++;

	/* Allocate and initialize output buffer; user must free */
	buf = malloc((unsigned)strlen(cd) + strlen(path) + 10); /* fudge factor */
	if (buf == NULLCHAR)
		goto nomem;
	buf[0] = '\0';

	/* Interpret path relative to cd only if it doesn't begin with "/" */
	/* or "D:/" (support for drive names) */
	if(path[0] == '/' && cd[1] == ':') {
		buf[0] = cd[0];		/* start from root on current drv */
		buf[1] = ':';
		buf[2] = '\0';
	}
	if(path[0] != '/' &&
	   !(isalpha(path[0]) && path[1] == ':' && path[2] == '/'))
		crunch(buf,cd);

	crunch(buf,path);

	/* Special case: null final path or drive only means the root directory */
	if(buf[0] == '\0' ||
	   (isalpha(buf[0]) && buf[1] == ':' && buf[2] == '\0'))
		strcat(buf,"/");

nomem:
#if	(defined(MSDOS) || defined(ATARI_ST))
	/* Translate all /'s back to \'s and free temp copies of args */
	for (cp = buf; *cp != '\0'; cp++)
		if (*cp == '/')
			*cp = '\\';
	free(cdtmp);
	free(pathtmp);
#endif
	return buf;
}

/* Process a path name string, starting with and adding to
 * the existing buffer
 */
static
crunch(buf,path)
char *buf;
register char *path;
{
	register char *cp;

	if (isalpha(*path) && path[1] == ':'){ /* drive spec */
		cp = buf;		/* Re-write entire buffer */
		*cp++ = *path++;
		*cp++ = *path++;
		*cp = '\0';
	} else {
		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 = rindex(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';
}
