/*
 *	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.
 *
 *	"p4 fstat" assimilation.
 */

#include	"defs.h"

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

static void
fstat_func(char * l)
{
	static File *	fp;
	static int	headRev;

	if (strncmp(l, "... clientFile ", 15) == 0)
	{
		if (fp)
			Error(0, "clientFile seen twice in the same entry");

		if (strncmp(&l[15], CurDir, CurDirLen) != 0)
			Error(0, "clientFile is not a decendent of "
				 "the current directory (%s)", &l[15]);

		/*
		 *	Lookup the name using the relative path (strip the
		 *	current directory portion, including the '/').
		 *	Create the entry if it doesn't exist (actually, if
		 *	it exists, something is wrong with "p4 fstat").
		 */
		fp = Lookup(&l[15 + CurDirLen + 1], 1);
		headRev = 0;
	}

	if (fp)
	{
		if (strncmp(l, "... headAction", 14) == 0)
		{
			if (strncmp(l, "... headAction delete", 21) != 0)
				fp->flag |= F_DEPOT;
		}
		else if (strncmp(l, "... haveTime ", 13) == 0)
		{
			/*
			 *	Since 97.2, p4 produces a field called
			 *	"headTime", which is the time the file
			 *	in the client was last submitted.  If the
			 *	client flag "modtime" is set, then this
			 *	time could be used to determine if the file
			 *	had been modified.  If the "modtime" flag
			 *	is set however, it breaks "make".  Also,
			 *	p4 does not guarantee that the modtime of
			 *	the file equals the headTime, even if the
			 *	"modtime" flag is set (I think).
			 *
			 *	What we really need is for perforce to tell
			 *	us that the modtime of the file should be
			 *	based on the last operation that effected
			 *	it (effectively a "haveTime".  This would
			 *	require a database of times for each file
			 *	for each client, something that Perforce
			 *	says is possible (there is already a database
			 *	for stuff for each client for things like
			 *	"haveRev"), but hard, because the database
			 *	file format would have to change as would
			 *	parts of the client/server protocol.  So
			 *	for now, we will try to get the "haveTime",
			 *	and arange for the modtime we store to be
			 *	zero if the "haveTime" field doesn't exist.
			 *	This will degrade to a "p4 diff" being run
			 *	on every file.  Ther performance of this
			 *	diff is fairly good, so this is not too bad.
			 *	If "haveTime" was available, you could expect
			 *	something like a four times speed improvement,
			 *	maybe a lot more.  During a scan, every file
			 *	must be stat'ed, but a "p4 diff" on every
			 *	file requires every file to be read.
			 */
			fp->modtime = atol(&l[13]);
		}
		else if (strncmp(l, "... headRev ", 12) == 0)
			headRev = atoi(&l[12]);
		else if (strncmp(l, "... haveRev ", 12) == 0)
		{
			/*
			 *	"haveRev" means that we have the file.
			 *	If the rev is different than "headRev",
			 *	then the file needs a get.  We rely on
			 *	getting "headRev" before "haveRev".
			 */
			fp->flag |= F_HAVE;
			if (headRev != atoi(&l[12]))
				fp->flag |= F_GET;
		}
		else if (strncmp(l, "... headType symlink", 20) == 0)
			fp->flag |= F_SYMLINK;
		else if (strncmp(l, "... action edit", 15) == 0 ||
		         strncmp(l, "... action add", 14) == 0 ||
		         strncmp(l, "... action branch", 17) == 0)
			fp->flag |= F_OPEN;
		else if (strncmp(l, "... action delete", 17) == 0)
			fp->flag |= F_DELETE;
#if 0
		else if (strncmp(l, "... change ", 11) == 0)
			fp->change = atoi(&l[11]);
#endif
		else if (!*l)		/* Empty line is end of entry */
		{
			fp = (File *)0;
		}
	}
}


void
DoFstat(void)
{
	Command("fstat ...", fstat_func, 0);
	CommandDone();

	PrintTree("fstat");
}
