/* Distributed Checksum Clearinghouse
 *
 * Copyright (c) 2005 by Rhyolite Software
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND RHYOLITE SOFTWARE DISCLAIMS ALL
 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL RHYOLITE SOFTWARE
 * 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.
 *
 * Rhyolite Software DCC 1.2.74-1.15 $Revision$
 */

#include "dcc_defs.h"
#ifdef DCC_WIN32
#include <direct.h>
#endif

DCC_PATH dcc_homedir;

DCC_PATH dcc_path_buf;

/* make an obvious pathname from a file name for printing */
const char *
dcc_fnm2path(DCC_PATH path, const char *nm)
{
#ifdef DCC_WIN32
	char *p;
	DWORD lasterror;
#else
	int dir_len, j;
	const char *dir, *p;
#endif

	/* the answer is the input pathname if it is null or absolute */
	if (!nm)
		return "(null)";
	if (*nm == '\0')
		return "";
	if (dcc_homedir[0] == '\0') {
		STRLIMCPY(path, sizeof(DCC_PATH), nm);
		return path;
	}

#ifdef DCC_WIN32
	lasterror = GetLastError();
	GetFullPathName(nm, sizeof(DCC_PATH), path, &p);
	SetLastError(lasterror);
#else
	if (nm[0] == '/') {
		STRLIMCPY(path, sizeof(DCC_PATH), nm);
		return path;
	}

	/* trim trailing slash from input file or pathname */
	dir = dcc_homedir;
	dir_len = strlen(dir);
	while (dir_len > 1 && dir[dir_len-1] == '/')
		--dir_len;

	/* remove extra "../" and "./" */
	for (;;) {
		if (dir_len == 0
		    || (dir_len == 1 && dir[0] == '.'
			&& strcmp(nm, ".")
			&& strcmp(nm, "..")
			&& !strchr(nm, '/'))) {
			STRLIMCPY(path, sizeof(DCC_PATH), nm);
			return path;
		}
		if (!strncmp(nm, "./", 2)
		    || !strcmp(nm, ".")) {
			if (*++nm  != '\0')
				++nm;
		} else if (!strncmp(nm,  "../", 3)
			   || !strcmp(nm,  "..")) {
			p = strrchr(dir, '/');
			if (!p || p >= &dir[dir_len]) {
				if (!strncmp(dir, "..", dir_len))
					break;
				p = dir;
			}
			j = p-dir;
			if (!strncmp(p, "/..", dir_len-j))
				break;
			dir_len = j;
			nm += 2;
			if (*nm != '\0')
				++nm;
		} else {
			break;
		}
		if (*nm == '\0') {
			if (dir_len == 0) {
				dir = ".";
				dir_len = 1;
			}
			snprintf(path, sizeof(DCC_PATH), "%.*s", dir_len, dir);
			return path;
		}
	}

	snprintf(path, sizeof(DCC_PATH), "%.*s/%s", dir_len, dir, nm);
#endif
	return path;
}



/* change to the DCC home directory */
u_char					/* 0=failed 1=ok */
dcc_cdhome(DCC_EMSG emsg, const char *newdir)
{
	if (!newdir)
		newdir = DCC_HOMEDIR;

	if (*newdir == '\0') {
		dcc_pemsg(EX_NOINPUT, emsg,
			  "invalid null DCC home directory");
		return 0;
	}
	if (strlen(newdir) >= ISZ(dcc_homedir)) {
		dcc_pemsg(EX_NOINPUT, emsg,
			  "DCC home directory \"%s\" too long", newdir);
		return 0;
	}
#ifdef DCC_WIN32
	if (!SetCurrentDirectory(newdir)) {
		dcc_pemsg(EX_NOINPUT, emsg, "SetCurrentDirectory(%s): %s" ,
			  DCC_NM2PATH(newdir), ERROR_STR());
		return 0;
	}
	if (!getcwd(dcc_homedir, sizeof(dcc_homedir)))
		BUFCPY(dcc_homedir, DCC_NM2PATH(newdir));
#else
	if (0 > chdir(newdir)) {
		dcc_pemsg(EX_NOINPUT, emsg, "chdir(%s): %s",
			  DCC_NM2PATH(newdir), ERROR_STR());
		return 0;
	}
	if (*newdir == '/'
	    || !getcwd(dcc_homedir, sizeof(dcc_homedir)))
		BUFCPY(dcc_homedir, DCC_NM2PATH(newdir));
#endif
	return 1;
}
