classify.c revision 25839
117721Speter/*
217721Speter * Copyright (c) 1992, Brian Berliner and Jeff Polk
317721Speter * Copyright (c) 1989-1992, Brian Berliner
417721Speter *
517721Speter * You may distribute under the terms of the GNU General Public License as
617721Speter * specified in the README file that comes with the CVS 1.4 kit.
717721Speter *
817721Speter */
917721Speter
1017721Speter#include "cvs.h"
1117721Speter
1217721Speter#ifdef SERVER_SUPPORT
1317721Speterstatic void sticky_ck PROTO((char *file, int aflag, Vers_TS * vers,
1417721Speter			     List * entries,
1517721Speter			     char *repository, char *update_dir));
1617721Speter#else
1717721Speterstatic void sticky_ck PROTO((char *file, int aflag, Vers_TS * vers, List * entries));
1817721Speter#endif
1917721Speter
2017721Speter/*
2117721Speter * Classify the state of a file
2217721Speter */
2317721SpeterCtype
2425839SpeterClassify_File (finfo, tag, date, options, force_tag_match, aflag, versp,
2525839Speter	       pipeout)
2625839Speter    struct file_info *finfo;
2717721Speter    char *tag;
2817721Speter    char *date;
2917721Speter    char *options;
3017721Speter    int force_tag_match;
3117721Speter    int aflag;
3217721Speter    Vers_TS **versp;
3317721Speter    int pipeout;
3417721Speter{
3517721Speter    Vers_TS *vers;
3617721Speter    Ctype ret;
3717721Speter
3817721Speter    /* get all kinds of good data about the file */
3925839Speter    vers = Version_TS (finfo, options, tag, date,
4025839Speter		       force_tag_match, 0);
4117721Speter
4217721Speter    if (vers->vn_user == NULL)
4317721Speter    {
4417721Speter	/* No entry available, ts_rcs is invalid */
4517721Speter	if (vers->vn_rcs == NULL)
4617721Speter	{
4717721Speter	    /* there is no RCS file either */
4817721Speter	    if (vers->ts_user == NULL)
4917721Speter	    {
5017721Speter		/* there is no user file */
5125839Speter		/* FIXME: Why do we skip this message if vers->tag or
5225839Speter		   vers->date is set?  It causes "cvs update -r tag98 foo"
5325839Speter		   to silently do nothing, which is seriously confusing
5425839Speter		   behavior.  "cvs update foo" gives this message, which
5525839Speter		   is what I would expect.  */
5617721Speter		if (!force_tag_match || !(vers->tag || vers->date))
5717721Speter		    if (!really_quiet)
5825839Speter			error (0, 0, "nothing known about %s", finfo->fullname);
5917721Speter		ret = T_UNKNOWN;
6017721Speter	    }
6117721Speter	    else
6217721Speter	    {
6317721Speter		/* there is a user file */
6425839Speter		/* FIXME: Why do we skip this message if vers->tag or
6525839Speter		   vers->date is set?  It causes "cvs update -r tag98 foo"
6625839Speter		   to silently do nothing, which is seriously confusing
6725839Speter		   behavior.  "cvs update foo" gives this message, which
6825839Speter		   is what I would expect.  */
6917721Speter		if (!force_tag_match || !(vers->tag || vers->date))
7017721Speter		    if (!really_quiet)
7117721Speter			error (0, 0, "use `cvs add' to create an entry for %s",
7225839Speter			       finfo->fullname);
7317721Speter		ret = T_UNKNOWN;
7417721Speter	    }
7517721Speter	}
7617721Speter	else if (RCS_isdead (vers->srcfile, vers->vn_rcs))
7717721Speter	{
7817721Speter	    if (vers->ts_user == NULL)
7925839Speter		ret = T_UPTODATE;
8017721Speter	    else
8117721Speter	    {
8217721Speter		error (0, 0, "use `cvs add' to create an entry for %s",
8325839Speter		       finfo->fullname);
8417721Speter		ret = T_UNKNOWN;
8517721Speter	    }
8617721Speter	}
8717721Speter	else
8817721Speter	{
8917721Speter	    /* there is an rcs file */
9017721Speter
9117721Speter	    if (vers->ts_user == NULL)
9217721Speter	    {
9317721Speter		/* There is no user file; needs checkout */
9417721Speter		ret = T_CHECKOUT;
9517721Speter	    }
9617721Speter	    else
9717721Speter	    {
9817721Speter		if (pipeout)
9917721Speter		{
10017721Speter		    /*
10117721Speter		     * The user file doesn't necessarily have anything
10217721Speter		     * to do with this.
10317721Speter		     */
10417721Speter		    ret = T_CHECKOUT;
10517721Speter		}
10617721Speter		/*
10717721Speter		 * There is a user file; print a warning and add it to the
10817721Speter		 * conflict list, only if it is indeed different from what we
10917721Speter		 * plan to extract
11017721Speter		 */
11125839Speter		else if (No_Difference (finfo, vers))
11217721Speter		{
11317721Speter		    /* the files were different so it is a conflict */
11417721Speter		    if (!really_quiet)
11517721Speter			error (0, 0, "move away %s; it is in the way",
11625839Speter			       finfo->fullname);
11717721Speter		    ret = T_CONFLICT;
11817721Speter		}
11917721Speter		else
12017721Speter		    /* since there was no difference, still needs checkout */
12117721Speter		    ret = T_CHECKOUT;
12217721Speter	    }
12317721Speter	}
12417721Speter    }
12517721Speter    else if (strcmp (vers->vn_user, "0") == 0)
12617721Speter    {
12717721Speter	/* An entry for a new-born file; ts_rcs is dummy */
12817721Speter
12917721Speter	if (vers->ts_user == NULL)
13017721Speter	{
13117721Speter	    /*
13217721Speter	     * There is no user file, but there should be one; remove the
13317721Speter	     * entry
13417721Speter	     */
13517721Speter	    if (!really_quiet)
13625839Speter		error (0, 0, "warning: new-born %s has disappeared", finfo->fullname);
13717721Speter	    ret = T_REMOVE_ENTRY;
13817721Speter	}
13917721Speter	else
14017721Speter	{
14117721Speter	    /* There is a user file */
14217721Speter
14317721Speter	    if (vers->vn_rcs == NULL)
14417721Speter		/* There is no RCS file, added file */
14517721Speter		ret = T_ADDED;
14617721Speter	    else if (RCS_isdead (vers->srcfile, vers->vn_rcs))
14717721Speter		/* we are resurrecting. */
14817721Speter		ret = T_ADDED;
14917721Speter	    else
15017721Speter	    {
15117721Speter		if (vers->srcfile->flags & INATTIC
15217721Speter		    && vers->srcfile->flags & VALID)
15317721Speter		{
15417721Speter		    /* This file has been added on some branch other than
15517721Speter		       the one we are looking at.  In the branch we are
15617721Speter		       looking at, the file was already valid.  */
15717721Speter		    if (!really_quiet)
15817721Speter			error (0, 0,
15917721Speter			       "\
16017721Speterconflict: %s has been added, but already exists",
16125839Speter			       finfo->fullname);
16217721Speter		}
16317721Speter		else
16417721Speter		{
16517721Speter		    /*
16617721Speter		     * There is an RCS file, so someone else must have checked
16717721Speter		     * one in behind our back; conflict
16817721Speter		     */
16917721Speter		    if (!really_quiet)
17017721Speter			error (0, 0,
17117721Speter			       "\
17217721Speterconflict: %s created independently by second party",
17325839Speter			       finfo->fullname);
17417721Speter		}
17517721Speter		ret = T_CONFLICT;
17617721Speter	    }
17717721Speter	}
17817721Speter    }
17917721Speter    else if (vers->vn_user[0] == '-')
18017721Speter    {
18117721Speter	/* An entry for a removed file, ts_rcs is invalid */
18217721Speter
18317721Speter	if (vers->ts_user == NULL)
18417721Speter	{
18517721Speter	    /* There is no user file (as it should be) */
18617721Speter
18725839Speter	    if (vers->vn_rcs == NULL
18825839Speter		|| RCS_isdead (vers->srcfile, vers->vn_rcs))
18917721Speter	    {
19017721Speter
19117721Speter		/*
19217721Speter		 * There is no RCS file; this is all-right, but it has been
19317721Speter		 * removed independently by a second party; remove the entry
19417721Speter		 */
19517721Speter		ret = T_REMOVE_ENTRY;
19617721Speter	    }
19725839Speter	    else if (vers->vn_rcs == NULL
19825839Speter		     ? vers->vn_user[1] == '\0'
19925839Speter		     : strcmp (vers->vn_rcs, vers->vn_user + 1) == 0)
20017721Speter		/*
20117721Speter		 * The RCS file is the same version as the user file was, and
20217721Speter		 * that's OK; remove it
20317721Speter		 */
20417721Speter		ret = T_REMOVED;
20517721Speter	    else
20617721Speter	    {
20717721Speter
20817721Speter		/*
20917721Speter		 * The RCS file is a newer version than the removed user file
21017721Speter		 * and this is definitely not OK; make it a conflict.
21117721Speter		 */
21217721Speter		if (!really_quiet)
21317721Speter		    error (0, 0,
21417721Speter			   "conflict: removed %s was modified by second party",
21525839Speter			   finfo->fullname);
21617721Speter		ret = T_CONFLICT;
21717721Speter	    }
21817721Speter	}
21917721Speter	else
22017721Speter	{
22117721Speter	    /* The user file shouldn't be there */
22217721Speter	    if (!really_quiet)
22317721Speter		error (0, 0, "%s should be removed and is still there",
22425839Speter		       finfo->fullname);
22517721Speter	    ret = T_REMOVED;
22617721Speter	}
22717721Speter    }
22817721Speter    else
22917721Speter    {
23017721Speter	/* A normal entry, TS_Rcs is valid */
23117721Speter	if (vers->vn_rcs == NULL)
23217721Speter	{
23317721Speter	    /* There is no RCS file */
23417721Speter
23517721Speter	    if (vers->ts_user == NULL)
23617721Speter	    {
23717721Speter		/* There is no user file, so just remove the entry */
23817721Speter		if (!really_quiet)
23917721Speter		    error (0, 0, "warning: %s is not (any longer) pertinent",
24025839Speter			   finfo->fullname);
24117721Speter		ret = T_REMOVE_ENTRY;
24217721Speter	    }
24317721Speter	    else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
24417721Speter	    {
24517721Speter
24617721Speter		/*
24717721Speter		 * The user file is still unmodified, so just remove it from
24817721Speter		 * the entry list
24917721Speter		 */
25017721Speter		if (!really_quiet)
25117721Speter		    error (0, 0, "%s is no longer in the repository",
25225839Speter			   finfo->fullname);
25317721Speter		ret = T_REMOVE_ENTRY;
25417721Speter	    }
25517721Speter	    else
25617721Speter	    {
25717721Speter		/*
25817721Speter		 * The user file has been modified and since it is no longer
25917721Speter		 * in the repository, a conflict is raised
26017721Speter		 */
26125839Speter		if (No_Difference (finfo, vers))
26217721Speter		{
26317721Speter		    /* they are different -> conflict */
26417721Speter		    if (!really_quiet)
26517721Speter			error (0, 0,
26617721Speter	       "conflict: %s is modified but no longer in the repository",
26725839Speter			   finfo->fullname);
26817721Speter		    ret = T_CONFLICT;
26917721Speter		}
27017721Speter		else
27117721Speter		{
27217721Speter		    /* they weren't really different */
27317721Speter		    if (!really_quiet)
27417721Speter			error (0, 0,
27517721Speter			       "warning: %s is not (any longer) pertinent",
27625839Speter			       finfo->fullname);
27717721Speter		    ret = T_REMOVE_ENTRY;
27817721Speter		}
27917721Speter	    }
28017721Speter	}
28117721Speter	else if (strcmp (vers->vn_rcs, vers->vn_user) == 0)
28217721Speter	{
28317721Speter	    /* The RCS file is the same version as the user file */
28417721Speter
28517721Speter	    if (vers->ts_user == NULL)
28617721Speter	    {
28717721Speter
28817721Speter		/*
28917721Speter		 * There is no user file, so note that it was lost and
29017721Speter		 * extract a new version
29117721Speter		 */
29217721Speter		if (strcmp (command_name, "update") == 0)
29317721Speter		    if (!really_quiet)
29425839Speter			error (0, 0, "warning: %s was lost", finfo->fullname);
29517721Speter		ret = T_CHECKOUT;
29617721Speter	    }
29717721Speter	    else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
29817721Speter	    {
29917721Speter
30017721Speter		/*
30117721Speter		 * The user file is still unmodified, so nothing special at
30217721Speter		 * all to do -- no lists updated, unless the sticky -k option
30317721Speter		 * has changed.  If the sticky tag has changed, we just need
30417721Speter		 * to re-register the entry
30517721Speter		 */
30617721Speter		if (vers->entdata->options &&
30717721Speter		    strcmp (vers->entdata->options, vers->options) != 0)
30817721Speter		    ret = T_CHECKOUT;
30917721Speter		else
31017721Speter		{
31117721Speter#ifdef SERVER_SUPPORT
31225839Speter		    sticky_ck (finfo->file, aflag, vers, finfo->entries,
31325839Speter			       finfo->repository, finfo->update_dir);
31417721Speter#else
31525839Speter		    sticky_ck (finfo->file, aflag, vers, finfo->entries);
31617721Speter#endif
31717721Speter		    ret = T_UPTODATE;
31817721Speter		}
31917721Speter	    }
32017721Speter	    else
32117721Speter	    {
32217721Speter
32317721Speter		/*
32417721Speter		 * The user file appears to have been modified, but we call
32517721Speter		 * No_Difference to verify that it really has been modified
32617721Speter		 */
32725839Speter		if (No_Difference (finfo, vers))
32817721Speter		{
32917721Speter
33017721Speter		    /*
33117721Speter		     * they really are different; modified if we aren't
33217721Speter		     * changing any sticky -k options, else needs merge
33317721Speter		     */
33417721Speter#ifdef XXX_FIXME_WHEN_RCSMERGE_IS_FIXED
33517721Speter		    if (strcmp (vers->entdata->options ?
33617721Speter			   vers->entdata->options : "", vers->options) == 0)
33717721Speter			ret = T_MODIFIED;
33817721Speter		    else
33917721Speter			ret = T_NEEDS_MERGE;
34017721Speter#else
34117721Speter		    ret = T_MODIFIED;
34217721Speter#ifdef SERVER_SUPPORT
34325839Speter		    sticky_ck (finfo->file, aflag, vers, finfo->entries,
34425839Speter			       finfo->repository, finfo->update_dir);
34517721Speter#else
34625839Speter		    sticky_ck (finfo->file, aflag, vers, finfo->entries);
34717721Speter#endif /* SERVER_SUPPORT */
34817721Speter#endif
34917721Speter		}
35017721Speter		else
35117721Speter		{
35217721Speter		    /* file has not changed; check out if -k changed */
35317721Speter		    if (strcmp (vers->entdata->options ?
35417721Speter			   vers->entdata->options : "", vers->options) != 0)
35517721Speter		    {
35617721Speter			ret = T_CHECKOUT;
35717721Speter		    }
35817721Speter		    else
35917721Speter		    {
36017721Speter
36117721Speter			/*
36217721Speter			 * else -> note that No_Difference will Register the
36317721Speter			 * file already for us, using the new tag/date. This
36417721Speter			 * is the desired behaviour
36517721Speter			 */
36617721Speter			ret = T_UPTODATE;
36717721Speter		    }
36817721Speter		}
36917721Speter	    }
37017721Speter	}
37117721Speter	else
37217721Speter	{
37317721Speter	    /* The RCS file is a newer version than the user file */
37417721Speter
37517721Speter	    if (vers->ts_user == NULL)
37617721Speter	    {
37717721Speter		/* There is no user file, so just get it */
37817721Speter
37917721Speter		if (strcmp (command_name, "update") == 0)
38017721Speter		    if (!really_quiet)
38125839Speter			error (0, 0, "warning: %s was lost", finfo->fullname);
38217721Speter		ret = T_CHECKOUT;
38317721Speter	    }
38417721Speter	    else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
38517721Speter	    {
38617721Speter
38717721Speter		/*
38817721Speter		 * The user file is still unmodified, so just get it as well
38917721Speter		 */
39017721Speter#ifdef SERVER_SUPPORT
39117721Speter	        if (strcmp (vers->entdata->options ?
39217721Speter			    vers->entdata->options : "", vers->options) != 0
39317721Speter		    || (vers->srcfile != NULL
39417721Speter			&& (vers->srcfile->flags & INATTIC) != 0))
39517721Speter		    ret = T_CHECKOUT;
39617721Speter		else
39717721Speter		    ret = T_PATCH;
39817721Speter#else
39917721Speter		ret = T_CHECKOUT;
40017721Speter#endif
40117721Speter	    }
40217721Speter	    else
40317721Speter	    {
40425839Speter		if (No_Difference (finfo, vers))
40517721Speter		    /* really modified, needs to merge */
40617721Speter		    ret = T_NEEDS_MERGE;
40717721Speter#ifdef SERVER_SUPPORT
40817721Speter	        else if ((strcmp (vers->entdata->options ?
40917721Speter				  vers->entdata->options : "", vers->options)
41017721Speter			  != 0)
41117721Speter			 || (vers->srcfile != NULL
41217721Speter			     && (vers->srcfile->flags & INATTIC) != 0))
41317721Speter		    /* not really modified, check it out */
41417721Speter		    ret = T_CHECKOUT;
41517721Speter		else
41617721Speter		    ret = T_PATCH;
41717721Speter#else
41817721Speter		else
41917721Speter		    /* not really modified, check it out */
42017721Speter		    ret = T_CHECKOUT;
42117721Speter#endif
42217721Speter	    }
42317721Speter	}
42417721Speter    }
42517721Speter
42617721Speter    /* free up the vers struct, or just return it */
42717721Speter    if (versp != (Vers_TS **) NULL)
42817721Speter	*versp = vers;
42917721Speter    else
43017721Speter	freevers_ts (&vers);
43117721Speter
43217721Speter    /* return the status of the file */
43317721Speter    return (ret);
43417721Speter}
43517721Speter
43617721Speterstatic void
43717721Speter#ifdef SERVER_SUPPORT
43817721Spetersticky_ck (file, aflag, vers, entries, repository, update_dir)
43917721Speter#else
44017721Spetersticky_ck (file, aflag, vers, entries)
44117721Speter#endif
44217721Speter    char *file;
44317721Speter    int aflag;
44417721Speter    Vers_TS *vers;
44517721Speter    List *entries;
44617721Speter#ifdef SERVER_SUPPORT
44717721Speter    char *repository;
44817721Speter    char *update_dir;
44917721Speter#endif
45017721Speter{
45117721Speter    if (aflag || vers->tag || vers->date)
45217721Speter    {
45317721Speter	char *enttag = vers->entdata->tag;
45417721Speter	char *entdate = vers->entdata->date;
45517721Speter
45617721Speter	if ((enttag && vers->tag && strcmp (enttag, vers->tag)) ||
45717721Speter	    ((enttag && !vers->tag) || (!enttag && vers->tag)) ||
45817721Speter	    (entdate && vers->date && strcmp (entdate, vers->date)) ||
45917721Speter	    ((entdate && !vers->date) || (!entdate && vers->date)))
46017721Speter	{
46117721Speter	    Register (entries, file, vers->vn_user, vers->ts_rcs,
46217721Speter		      vers->options, vers->tag, vers->date, vers->ts_conflict);
46317721Speter
46417721Speter#ifdef SERVER_SUPPORT
46517721Speter	    if (server_active)
46617721Speter	    {
46717721Speter		/* We need to update the entries line on the client side.
46817721Speter		   It is possible we will later update it again via
46917721Speter		   server_updated or some such, but that is OK.  */
47017721Speter		server_update_entries
47117721Speter		  (file, update_dir, repository,
47217721Speter		   strcmp (vers->ts_rcs, vers->ts_user) == 0 ?
47317721Speter		   SERVER_UPDATED : SERVER_MERGED);
47417721Speter	    }
47517721Speter#endif
47617721Speter	}
47717721Speter    }
47817721Speter}
479