ftp.nice.ch/pub/next/unix/developer/cvs.950905.s.tar.gz#/cvs-1.5.1/src/classify.c

This is classify.c in view mode; [Download] [Up]

/*
 * Copyright (c) 1992, Brian Berliner and Jeff Polk
 * Copyright (c) 1989-1992, Brian Berliner
 * 
 * You may distribute under the terms of the GNU General Public License as
 * specified in the README file that comes with the CVS 1.4 kit.
 * 
 */

#include "cvs.h"

#ifndef lint
static const char rcsid[] = "$CVSid: @(#)classify.c 1.17 94/10/07 $";
USE(rcsid)
#endif

#ifdef SERVER_SUPPORT
static void sticky_ck PROTO((char *file, int aflag, Vers_TS * vers,
			     List * entries,
			     char *repository, char *update_dir));
#else
static void sticky_ck PROTO((char *file, int aflag, Vers_TS * vers, List * entries));
#endif

/*
 * Classify the state of a file
 */
Ctype
Classify_File (file, tag, date, options, force_tag_match, aflag, repository,
	       entries, srcfiles, versp, update_dir, pipeout)
    char *file;
    char *tag;
    char *date;
    char *options;
    int force_tag_match;
    int aflag;
    char *repository;
    List *entries;
    List *srcfiles;
    Vers_TS **versp;
    char *update_dir;
    int pipeout;
{
    Vers_TS *vers;
    Ctype ret;
    char *fullname;

    fullname = xmalloc (strlen (update_dir) + strlen (file) + 10);
    if (update_dir[0] == '\0')
	strcpy (fullname, file);
    else
	sprintf (fullname, "%s/%s", update_dir, file);

    /* get all kinds of good data about the file */
    vers = Version_TS (repository, options, tag, date, file,
		       force_tag_match, 0, entries, srcfiles);

    if (vers->vn_user == NULL)
    {
	/* No entry available, ts_rcs is invalid */
	if (vers->vn_rcs == NULL)
	{
	    /* there is no RCS file either */
	    if (vers->ts_user == NULL)
	    {
		/* there is no user file */
		if (!force_tag_match || !(vers->tag || vers->date))
		    if (!really_quiet)
			error (0, 0, "nothing known about %s", fullname);
		ret = T_UNKNOWN;
	    }
	    else
	    {
		/* there is a user file */
		if (!force_tag_match || !(vers->tag || vers->date))
		    if (!really_quiet)
			error (0, 0, "use `cvs add' to create an entry for %s",
			       fullname);
		ret = T_UNKNOWN;
	    }
	}
#ifdef DEATH_SUPPORT
	else if (RCS_isdead (vers->srcfile, vers->vn_rcs))
	{
	    if (vers->ts_user == NULL)
		/*
		 * Logically seems to me this should be T_UPTODATE.
		 * But the joining code in update.c seems to expect
		 * T_CHECKOUT, and that is what has traditionally been
		 * returned for this case.
		 */
		ret = T_CHECKOUT;
	    else
	    {
		error (0, 0, "use `cvs add' to create an entry for %s",
		       fullname);
		ret = T_UNKNOWN;
	    }
	}
#endif
	else
	{
	    /* there is an rcs file */

	    if (vers->ts_user == NULL)
	    {
		/* There is no user file; needs checkout */
		ret = T_CHECKOUT;
	    }
	    else
	    {
		if (pipeout)
		{
		    /*
		     * The user file doesn't necessarily have anything
		     * to do with this.
		     */
		    ret = T_CHECKOUT;
		}
		/*
		 * There is a user file; print a warning and add it to the
		 * conflict list, only if it is indeed different from what we
		 * plan to extract
		 */
		else if (No_Difference (file, vers, entries,
					repository, update_dir))
		{
		    /* the files were different so it is a conflict */
		    if (!really_quiet)
			error (0, 0, "move away %s; it is in the way",
			       fullname);
		    ret = T_CONFLICT;
		}
		else
		    /* since there was no difference, still needs checkout */
		    ret = T_CHECKOUT;
	    }
	}
    }
    else if (strcmp (vers->vn_user, "0") == 0)
    {
	/* An entry for a new-born file; ts_rcs is dummy */

	if (vers->ts_user == NULL)
	{
	    /*
	     * There is no user file, but there should be one; remove the
	     * entry
	     */
	    if (!really_quiet)
		error (0, 0, "warning: new-born %s has disappeared", fullname);
	    ret = T_REMOVE_ENTRY;
	}
	else
	{
	    /* There is a user file */

	    if (vers->vn_rcs == NULL)
		/* There is no RCS file, added file */
		ret = T_ADDED;
#ifdef DEATH_SUPPORT
	    else if (RCS_isdead (vers->srcfile, vers->vn_rcs))
		/* we are resurrecting. */
		ret = T_ADDED;
#endif /* DEATH_SUPPORT */
	    else
	    {
#ifdef DEATH_SUPPORT
		 if (vers->srcfile->flags & INATTIC
		     && vers->srcfile->flags & VALID)
		 {
		     /* This file has been added on some branch other than
			the one we are looking at.  In the branch we are
			looking at, the file was already valid.  */
		     if (!really_quiet)
			 error (0, 0,
				"conflict: %s has been added, but already exists",
				fullname);
		 }
		 else
		 {
#endif /* DEATH_SUPPORT */
		/*
		 * There is an RCS file, so someone else must have checked
		 * one in behind our back; conflict
		 */
		if (!really_quiet)
		    error (0, 0,
			"conflict: %s created independently by second party",
			   fullname);
#ifdef DEATH_SUPPORT
		 }
#endif
		ret = T_CONFLICT;
	    }
	}
    }
    else if (vers->vn_user[0] == '-')
    {
	/* An entry for a removed file, ts_rcs is invalid */

	if (vers->ts_user == NULL)
	{
	    char tmp[PATH_MAX];

	    /* There is no user file (as it should be) */

	    (void) sprintf (tmp, "-%s", vers->vn_rcs ? vers->vn_rcs : "");

	    if (vers->vn_rcs == NULL)
	    {

		/*
		 * There is no RCS file; this is all-right, but it has been
		 * removed independently by a second party; remove the entry
		 */
		ret = T_REMOVE_ENTRY;
	    }
	    else if (strcmp (tmp, vers->vn_user) == 0)

		/*
		 * The RCS file is the same version as the user file was, and
		 * that's OK; remove it
		 */
		ret = T_REMOVED;
	    else
	    {

		/*
		 * The RCS file is a newer version than the removed user file
		 * and this is definitely not OK; make it a conflict.
		 */
		if (!really_quiet)
		    error (0, 0,
			   "conflict: removed %s was modified by second party",
			   fullname);
		ret = T_CONFLICT;
	    }
	}
	else
	{
	    /* The user file shouldn't be there */
	    if (!really_quiet)
		error (0, 0, "%s should be removed and is still there",
		       fullname);
	    ret = T_REMOVED;
	}
    }
    else
    {
	/* A normal entry, TS_Rcs is valid */
	if (vers->vn_rcs == NULL)
	{
	    /* There is no RCS file */

	    if (vers->ts_user == NULL)
	    {
		/* There is no user file, so just remove the entry */
		if (!really_quiet)
		    error (0, 0, "warning: %s is not (any longer) pertinent",
			   fullname);
		ret = T_REMOVE_ENTRY;
	    }
	    else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
	    {

		/*
		 * The user file is still unmodified, so just remove it from
		 * the entry list
		 */
		if (!really_quiet)
		    error (0, 0, "%s is no longer in the repository",
			   fullname);
		ret = T_REMOVE_ENTRY;
	    }
	    else
	    {
		/*
		 * The user file has been modified and since it is no longer
		 * in the repository, a conflict is raised
		 */
		if (No_Difference (file, vers, entries,
				   repository, update_dir))
		{
		    /* they are different -> conflict */
		    if (!really_quiet)
			error (0, 0,
	       "conflict: %s is modified but no longer in the repository",
			   fullname);
		    ret = T_CONFLICT;
		}
		else
		{
		    /* they weren't really different */
		    if (!really_quiet)
			error (0, 0,
			       "warning: %s is not (any longer) pertinent",
			       fullname);
		    ret = T_REMOVE_ENTRY;
		}
	    }
	}
	else if (strcmp (vers->vn_rcs, vers->vn_user) == 0)
	{
	    /* The RCS file is the same version as the user file */

	    if (vers->ts_user == NULL)
	    {

		/*
		 * There is no user file, so note that it was lost and
		 * extract a new version
		 */
		if (strcmp (command_name, "update") == 0)
		    if (!really_quiet)
			error (0, 0, "warning: %s was lost", fullname);
		ret = T_CHECKOUT;
	    }
	    else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
	    {

		/*
		 * The user file is still unmodified, so nothing special at
		 * all to do -- no lists updated, unless the sticky -k option
		 * has changed.  If the sticky tag has changed, we just need
		 * to re-register the entry
		 */
		if (vers->entdata->options &&
		    strcmp (vers->entdata->options, vers->options) != 0)
		    ret = T_CHECKOUT;
		else
		{
#ifdef SERVER_SUPPORT
		    sticky_ck (file, aflag, vers, entries,
			       repository, update_dir);
#else
		    sticky_ck (file, aflag, vers, entries);
#endif
		    ret = T_UPTODATE;
		}
	    }
	    else
	    {

		/*
		 * The user file appears to have been modified, but we call
		 * No_Difference to verify that it really has been modified
		 */
		if (No_Difference (file, vers, entries,
				   repository, update_dir))
		{

		    /*
		     * they really are different; modified if we aren't
		     * changing any sticky -k options, else needs merge
		     */
#ifdef XXX_FIXME_WHEN_RCSMERGE_IS_FIXED
		    if (strcmp (vers->entdata->options ?
			   vers->entdata->options : "", vers->options) == 0)
			ret = T_MODIFIED;
		    else
			ret = T_NEEDS_MERGE;
#else
		    ret = T_MODIFIED;
#ifdef SERVER_SUPPORT
		    sticky_ck (file, aflag, vers, entries,
			       repository, update_dir);
#else
		    sticky_ck (file, aflag, vers, entries);
#endif /* SERVER_SUPPORT */
#endif
		}
		else
		{
		    /* file has not changed; check out if -k changed */
		    if (strcmp (vers->entdata->options ?
			   vers->entdata->options : "", vers->options) != 0)
		    {
			ret = T_CHECKOUT;
		    }
		    else
		    {

			/*
			 * else -> note that No_Difference will Register the
			 * file already for us, using the new tag/date. This
			 * is the desired behaviour
			 */
			ret = T_UPTODATE;
		    }
		}
	    }
	}
	else
	{
	    /* The RCS file is a newer version than the user file */

	    if (vers->ts_user == NULL)
	    {
		/* There is no user file, so just get it */

		if (strcmp (command_name, "update") == 0)
		    if (!really_quiet)
			error (0, 0, "warning: %s was lost", fullname);
		ret = T_CHECKOUT;
	    }
	    else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
	    {

		/*
		 * The user file is still unmodified, so just get it as well
		 */
#ifdef SERVER_SUPPORT
	        if (strcmp (vers->entdata->options ?
			    vers->entdata->options : "", vers->options) != 0
		    || (vers->srcfile != NULL
			&& (vers->srcfile->flags & INATTIC) != 0))
		    ret = T_CHECKOUT;
		else
		    ret = T_PATCH;
#else
		ret = T_CHECKOUT;
#endif
	    }
	    else
	    {
		if (No_Difference (file, vers, entries,
				   repository, update_dir))
		    /* really modified, needs to merge */
		    ret = T_NEEDS_MERGE;
#ifdef SERVER_SUPPORT
	        else if ((strcmp (vers->entdata->options ?
				  vers->entdata->options : "", vers->options)
			  != 0)
			 || (vers->srcfile != NULL
			     && (vers->srcfile->flags & INATTIC) != 0))
		    /* not really modified, check it out */
		    ret = T_CHECKOUT;
		else
		    ret = T_PATCH;
#else
		else
		    /* not really modified, check it out */
		    ret = T_CHECKOUT;
#endif
	    }
	}
    }

    /* free up the vers struct, or just return it */
    if (versp != (Vers_TS **) NULL)
	*versp = vers;
    else
	freevers_ts (&vers);

    free (fullname);

    /* return the status of the file */
    return (ret);
}

static void
#ifdef SERVER_SUPPORT
sticky_ck (file, aflag, vers, entries, repository, update_dir)
#else
sticky_ck (file, aflag, vers, entries)
#endif
    char *file;
    int aflag;
    Vers_TS *vers;
    List *entries;
#ifdef SERVER_SUPPORT
    char *repository;
    char *update_dir;
#endif
{
    if (aflag || vers->tag || vers->date)
    {
	char *enttag = vers->entdata->tag;
	char *entdate = vers->entdata->date;

	if ((enttag && vers->tag && strcmp (enttag, vers->tag)) ||
	    ((enttag && !vers->tag) || (!enttag && vers->tag)) ||
	    (entdate && vers->date && strcmp (entdate, vers->date)) ||
	    ((entdate && !vers->date) || (!entdate && vers->date)))
	{
	    Register (entries, file, vers->vn_user, vers->ts_rcs,
		      vers->options, vers->tag, vers->date, vers->ts_conflict);

#ifdef SERVER_SUPPORT
	    if (server_active)
	    {
		/* We need to update the entries line on the client side.
		   It is possible we will later update it again via
		   server_updated or some such, but that is OK.  */
		server_update_entries
		  (file, update_dir, repository,
		   strcmp (vers->ts_rcs, vers->ts_user) == 0 ?
		   SERVER_UPDATED : SERVER_MERGED);
	    }
#endif
	}
    }
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.