/*
 *	C4 -- CVS like front end to the Perforce p4 SCM tool.
 *
 * Copyright (c) 1998 - 2000, Neil Russell.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by Neil Russell.
 * 4. The name Neil Russell may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY NEIL RUSSELL ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL NEIL RUSSELL BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 *	Control file and client root.
 */

#include	"defs.h"

/**************************************************/

/*
 *	Read the environment from a .c4 file.
 */
static void
read_environment(char * name)
{
	int		fd;
	char *		p1;
	char *		p2;
	int		x;
	char		vars[4096];

	if ((fd = open(name, O_RDONLY)) == -1)
		Error(1, "cannot open %s", name);

	/*
	 *	Read the file.  The amount of stuff in this
	 *	file is limited to 4KB (sizeof vars) at the
	 *	moment.  There is currently no need for more.
	 */
	x = read(fd, vars, sizeof vars - 1);
	if (x == -1)
		Error(1, "read error on %s", name);
	if (x == sizeof vars - 1)
		Error(0, "contents of file %s is too long (%d byte limit)",
							name, sizeof vars);
	vars[x] = '\0';
	close(fd);

	for (p1 = vars; (p2 = strchr(p1, '\n')); )
	{
		char *		xp;

		*p2 = '\0';
		if ((xp = strchr(p1, '=')) && xp > p1)
		{
			char *		s;

			/*
			 *	Environment variable.
			 */
			s = (char *)Alloc(strlen(p1) + 1);
			strcpy(s, p1);
			putenv(s);
		}
		else if (p1[0] == ':')
		{
			/*
			 *	Ignore specification.
			 */
			IgnoreSpec((Ignore **)0, &p1[1]);
		}
		else
		{
			/*
			 *	Some other sort of variable; it may get
			 *	used at some time in the future.
			 */
		}

		p1 = p2 + 1;
	}
}

/**************************************************/

/*
 *	Locate the root of the client tree and read the ".c4" file.  The
 *	contents are installed in the environment.  If the ".c4" file is
 *	not found, c4 will still operate with standard p4 commands but c4
 *	specific commands will fail.
 */
void
FindRoot(void)
{
	struct stat	rt;
	char		name[1024];
	int		i;

	/*
	 *	Search from the current directory back for a ".c4" file,
	 *	and if found, use its contents to set environment variables
	 *	such as P4CLIENT and P4PORT.
	 */
	if (stat("/", &rt) == -1)
		Error(1, "cannot stat /");

	for (i = 0; ; i++)
	{
		struct stat	st;
		int		l;
		int		x;

		if (i == 0)
			strcpy(name, "./");
		else
		{
			name[0] = '\0';
			for (x = 0; x < i; x++)
				strcat(name, "../");
		}
		l = strlen(name);

		/*
		 *	Check to see if we have reached the root directory
		 *	yet.  If so, we failed.
		 */
		name[l] = '\0';
		strcat(name, ".");
		if (stat(name, &st) == -1)
			Error(1, "cannot stat %s", name);
		if (rt.st_ino == st.st_ino && rt.st_dev == st.st_dev)
			break;

		/*
		 *	Check for a ".c4" file.
		 */
		name[l] = '\0';
		strcat(name, C4TAG);
		if (access(name, R_OK) == 0)
		{
			read_environment(name);
			break;
		}
	}

	/*
	 *	Find the name of the real "p4" command (in the environment
	 *	variable P4COMMAND).
	 */
	{
		extern char *	getenv();
		char *		p;

		if ((p = getenv("P4COMMAND")))
			CmdP4 = p;
	}
}
