rcsci.cc #1

  • //
  • guest/
  • perforce_software/
  • p4/
  • 2016-1/
  • rcs/
  • rcsci.cc
  • View
  • Commits
  • Open Download .zip Download (5 KB)
/*
 * Copyright 1995, 1996 Perforce Software.  All rights reserved.
 *
 * This file is part of the Library RCS.  See rcstest.c.
 */

/*
 * rcsci.c - update RcsArchive with a new revision
 *
 * Classes defined:
 *
 *	RcsCkin - control block for checkin operation
 *
 * Public methods:
 *
 *	RcsCkin::RcsCkin() - create/repalce a head/post-head revision
 *	RcsCkin::~RcsCkin() - free up resources created by RcsCkin()
 *
 * Internal routines:
 *
 *	ReadFileChunk() - open a file and point a chunk at it
 *
 * History:
 *	2-18-97 (seiwald) - translated to C++.
 */

# define NEED_FILE
# define NEED_TYPES

# include <stdhdrs.h>

# include <error.h>
# include <debug.h>
# include <strbuf.h>
# include <readfile.h>
# include <filesys.h>

# include "rcsdebug.h"
# include "rcsarch.h"
# include "rcsci.h"
# include "rcsdiff.h"
# include "rcsdate.h"
# include "rcsrev.h"
# include <msglbr.h>

/*
 * RcsCkinChunk -- a rev chunk, either diff or whole
 */

RcsCkinChunk::RcsCkinChunk()
{
	diffFile = 0;
	diffFileBinary = 0;
}

/*
 * RcsCkinChunk::~RcsCkinChunk() - free up resources 
 *
 * This should only be done after the RcsArchive has been written
 * with RcsGenerate, as the RcsArchive now has chunks pointing to
 * files opened by RcsCkin().
 */

RcsCkinChunk::~RcsCkinChunk()
{
	delete file;
	delete diffFile;
	delete diffFileBinary;
}

/*
 * RcsCkinChunk::Diff() - produce a diff chunk between newFile and revName
 */

void
RcsCkinChunk::Diff( 
	RcsArchive *archive,
	const char *revName,
	FileSys *newFile,
	int flags,
	Error *e )
{
	/* Create temp file name */

	diffFile = FileSys::CreateGlobalTemp( FST_TEXT );

	/* Pipe previous revision through diff and into temp file */

	RcsDiff( archive, revName, newFile, diffFile->Name(), 
		flags|RCS_DIFF_RCSN, e );

	if( e->Test() )
	    return;

	/* Make currRev now a diff chunk */
	/* First we need to create a new FileSys, so when */
	/* we read the file we read it binary. */

	diffFileBinary = FileSys::Create( FST_BINARY );
	diffFileBinary->Set( diffFile->Name() );

	Save( diffFileBinary, e );

	if( e->Test() )
	    return;

	if( !file->Size() && archive->GetChunkCnt() != 0 )
	    e->Set( MsgLbr::Mangled ) << "empty";

	/* Make sure it looks like diff output, and not */
	/* "binary files differ" */

	if( !file->Eof() && 
	     file->Char() != 'a' && 
	     file->Char() != 'd' )
	{
	    char buf[ 128 ];

	    int l = file->Memccpy( buf, '\n', sizeof( buf )-1 );
	    
	    if( l && buf[ l - 1 ] == '\n' ) --l;
	    buf[ l ] = 0;
	    e->Set( MsgLbr::Mangled ) << buf;
	}

	return;
}

/*
 * RcsCkin::RcsCkin() - create a post-head revision/replace the head revision
 *
 * Takes a file containing the new text and the new revision's name
 * and doctors the RcsArchive structure to make that revision the
 * new head.  This currently supports replacing the head, but doesn't
 * allow checkins on branches and it doesn't validate the revision number.
 */

RcsCkin::RcsCkin(
	RcsArchive *archive,
	FileSys *newFile,
	const char *newRev,
	RcsChunk *log,
	const char *author,
	const char *state,
	time_t modTime,
	Error *e )
{
	RcsDate date;
	RcsRevPlace place;

	/*
	 * Use RcsRevPlace to figure out this rev's relationship to 
	 * existing revs.  The 'place' flag says whether its on the trunk
	 * or on a branch.  The three fields prevRev, currRev, and nextRev 
	 * point to the previous, current, and following revisions in terms 
	 * of RCS lineage.  
	 */

	if( !place.Locate( archive, newRev, e ) )
	    goto fail;

	if( DEBUG_CKIN )
	    p4debug.printf( "checkin new %s following %s\n",
		place.currRev ? place.currRev->revName.text : "none",
		place.nextRev ? place.nextRev->revName.text : "none" );

	/*
	 * If there is no current rev entry, create one.
	 */

	if( !place.currRev )
	    place.currRev = archive->AddRevision( newRev, 0, place.prevRev, e );

	if( e->Test() )
	    goto fail;

	/* 
	 * Fill in the new rev with the new stuff: point its chunk
	 * at the new file.
	 */

	if( !*author || !*state )
	{
	    e->Set( MsgLbr::Empty );
	    goto fail;
	}

	if( modTime )
	    date.Set( modTime );
	else
	    date.Now();
	place.currRev->date.Save( date.Text(), "date" );
	place.currRev->author.Save( author, "author" );
	place.currRev->state.Save( state, "state" );
	place.currRev->log = *log;

	/*
	 * Create chunk for nextRev.
	 *
	 * It will be the diff between the newFile and the nextRev.
	 */

	if( place.nextRev )
	{
	    nextChunk.Diff( archive, place.nextRev->revName.text, 
		    newFile, RCS_DIFF_REVERSE, e );
	    place.nextRev->text = nextChunk;
	}

	/* 
	 * Create chunk for current rev.
	 *
	 * If it is a new head, its contents will be the whole file.
	 * If it follows an existing rev, its contents will be a diff.
	 */

	if( !place.prevRev )
	{
	    currChunk.Save( newFile, e );
	    place.currRev->text = currChunk;
	}
	else
	{
	    currChunk.Diff( archive, place.prevRev->revName.text, 
			newFile, RCS_DIFF_NORMAL, e );
	    place.currRev->text = currChunk;
	}


	if( e->Test() )
	    goto fail;

	/* 
	 * Touch up the head/next pointers along the way.
	 */

	if( place.prevRev )
	{
	    place.prevRev->next.Save( place.currRev->revName, "next" );
	}
	else
	{
	    archive->headRev.Save( place.currRev->revName, "head" );
	}

	if( place.nextRev )
	{
	    place.currRev->next.Save( place.nextRev->revName, "next" );
	}

fail:
	if( e->Test() )
	    e->Set( MsgLbr::Checkin ) << newFile->Name() << newRev;
}

# Change User Description Committed
#1 19472 Liz Lam Initial add of the 2016.1 p4/p4api source code.