classify.c revision 32785
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 632785Speter * specified in the README file that comes with the CVS source distribution. 717721Speter * 817721Speter */ 917721Speter 1017721Speter#include "cvs.h" 1117721Speter 1232785Speterstatic void sticky_ck PROTO ((struct file_info *finfo, int aflag, 1332785Speter Vers_TS * vers)); 1417721Speter 1517721Speter/* 1617721Speter * Classify the state of a file 1717721Speter */ 1817721SpeterCtype 1925839SpeterClassify_File (finfo, tag, date, options, force_tag_match, aflag, versp, 2025839Speter pipeout) 2125839Speter struct file_info *finfo; 2217721Speter char *tag; 2317721Speter char *date; 2432785Speter 2532785Speter /* Keyword expansion options. Can be either NULL or "" to 2632785Speter indicate none are specified here. */ 2717721Speter char *options; 2832785Speter 2917721Speter int force_tag_match; 3017721Speter int aflag; 3117721Speter Vers_TS **versp; 3217721Speter int pipeout; 3317721Speter{ 3417721Speter Vers_TS *vers; 3517721Speter Ctype ret; 3617721Speter 3717721Speter /* get all kinds of good data about the file */ 3825839Speter vers = Version_TS (finfo, options, tag, date, 3925839Speter force_tag_match, 0); 4017721Speter 4117721Speter if (vers->vn_user == NULL) 4217721Speter { 4317721Speter /* No entry available, ts_rcs is invalid */ 4417721Speter if (vers->vn_rcs == NULL) 4517721Speter { 4617721Speter /* there is no RCS file either */ 4717721Speter if (vers->ts_user == NULL) 4817721Speter { 4917721Speter /* there is no user file */ 5025839Speter /* FIXME: Why do we skip this message if vers->tag or 5125839Speter vers->date is set? It causes "cvs update -r tag98 foo" 5225839Speter to silently do nothing, which is seriously confusing 5325839Speter behavior. "cvs update foo" gives this message, which 5425839Speter is what I would expect. */ 5517721Speter if (!force_tag_match || !(vers->tag || vers->date)) 5617721Speter if (!really_quiet) 5725839Speter error (0, 0, "nothing known about %s", finfo->fullname); 5817721Speter ret = T_UNKNOWN; 5917721Speter } 6017721Speter else 6117721Speter { 6217721Speter /* there is a user file */ 6325839Speter /* FIXME: Why do we skip this message if vers->tag or 6425839Speter vers->date is set? It causes "cvs update -r tag98 foo" 6525839Speter to silently do nothing, which is seriously confusing 6625839Speter behavior. "cvs update foo" gives this message, which 6725839Speter is what I would expect. */ 6817721Speter if (!force_tag_match || !(vers->tag || vers->date)) 6917721Speter if (!really_quiet) 7032785Speter error (0, 0, "use `%s add' to create an entry for %s", 7132785Speter program_name, finfo->fullname); 7217721Speter ret = T_UNKNOWN; 7317721Speter } 7417721Speter } 7517721Speter else if (RCS_isdead (vers->srcfile, vers->vn_rcs)) 7617721Speter { 7717721Speter if (vers->ts_user == NULL) 7825839Speter ret = T_UPTODATE; 7917721Speter else 8017721Speter { 8132785Speter error (0, 0, "use `%s add' to create an entry for %s", 8232785Speter program_name, finfo->fullname); 8317721Speter ret = T_UNKNOWN; 8417721Speter } 8517721Speter } 8617721Speter else 8717721Speter { 8817721Speter /* there is an rcs file */ 8917721Speter 9017721Speter if (vers->ts_user == NULL) 9117721Speter { 9217721Speter /* There is no user file; needs checkout */ 9317721Speter ret = T_CHECKOUT; 9417721Speter } 9517721Speter else 9617721Speter { 9717721Speter if (pipeout) 9817721Speter { 9917721Speter /* 10017721Speter * The user file doesn't necessarily have anything 10117721Speter * to do with this. 10217721Speter */ 10317721Speter ret = T_CHECKOUT; 10417721Speter } 10517721Speter /* 10617721Speter * There is a user file; print a warning and add it to the 10717721Speter * conflict list, only if it is indeed different from what we 10817721Speter * plan to extract 10917721Speter */ 11025839Speter else if (No_Difference (finfo, vers)) 11117721Speter { 11217721Speter /* the files were different so it is a conflict */ 11317721Speter if (!really_quiet) 11417721Speter error (0, 0, "move away %s; it is in the way", 11525839Speter finfo->fullname); 11617721Speter ret = T_CONFLICT; 11717721Speter } 11817721Speter else 11917721Speter /* since there was no difference, still needs checkout */ 12017721Speter ret = T_CHECKOUT; 12117721Speter } 12217721Speter } 12317721Speter } 12417721Speter else if (strcmp (vers->vn_user, "0") == 0) 12517721Speter { 12617721Speter /* An entry for a new-born file; ts_rcs is dummy */ 12717721Speter 12817721Speter if (vers->ts_user == NULL) 12917721Speter { 13017721Speter /* 13117721Speter * There is no user file, but there should be one; remove the 13217721Speter * entry 13317721Speter */ 13417721Speter if (!really_quiet) 13525839Speter error (0, 0, "warning: new-born %s has disappeared", finfo->fullname); 13617721Speter ret = T_REMOVE_ENTRY; 13717721Speter } 13817721Speter else 13917721Speter { 14017721Speter /* There is a user file */ 14117721Speter 14217721Speter if (vers->vn_rcs == NULL) 14317721Speter /* There is no RCS file, added file */ 14417721Speter ret = T_ADDED; 14517721Speter else if (RCS_isdead (vers->srcfile, vers->vn_rcs)) 14617721Speter /* we are resurrecting. */ 14717721Speter ret = T_ADDED; 14817721Speter else 14917721Speter { 15017721Speter if (vers->srcfile->flags & INATTIC 15117721Speter && vers->srcfile->flags & VALID) 15217721Speter { 15317721Speter /* This file has been added on some branch other than 15417721Speter the one we are looking at. In the branch we are 15517721Speter looking at, the file was already valid. */ 15617721Speter if (!really_quiet) 15717721Speter error (0, 0, 15817721Speter "\ 15917721Speterconflict: %s has been added, but already exists", 16025839Speter finfo->fullname); 16117721Speter } 16217721Speter else 16317721Speter { 16417721Speter /* 16517721Speter * There is an RCS file, so someone else must have checked 16617721Speter * one in behind our back; conflict 16717721Speter */ 16817721Speter if (!really_quiet) 16917721Speter error (0, 0, 17017721Speter "\ 17117721Speterconflict: %s created independently by second party", 17225839Speter finfo->fullname); 17317721Speter } 17417721Speter ret = T_CONFLICT; 17517721Speter } 17617721Speter } 17717721Speter } 17817721Speter else if (vers->vn_user[0] == '-') 17917721Speter { 18017721Speter /* An entry for a removed file, ts_rcs is invalid */ 18117721Speter 18217721Speter if (vers->ts_user == NULL) 18317721Speter { 18417721Speter /* There is no user file (as it should be) */ 18517721Speter 18625839Speter if (vers->vn_rcs == NULL 18725839Speter || RCS_isdead (vers->srcfile, vers->vn_rcs)) 18817721Speter { 18917721Speter 19017721Speter /* 19117721Speter * There is no RCS file; this is all-right, but it has been 19217721Speter * removed independently by a second party; remove the entry 19317721Speter */ 19417721Speter ret = T_REMOVE_ENTRY; 19517721Speter } 19625839Speter else if (vers->vn_rcs == NULL 19725839Speter ? vers->vn_user[1] == '\0' 19825839Speter : strcmp (vers->vn_rcs, vers->vn_user + 1) == 0) 19917721Speter /* 20017721Speter * The RCS file is the same version as the user file was, and 20117721Speter * that's OK; remove it 20217721Speter */ 20317721Speter ret = T_REMOVED; 20417721Speter else 20517721Speter { 20617721Speter 20717721Speter /* 20817721Speter * The RCS file is a newer version than the removed user file 20917721Speter * and this is definitely not OK; make it a conflict. 21017721Speter */ 21117721Speter if (!really_quiet) 21217721Speter error (0, 0, 21317721Speter "conflict: removed %s was modified by second party", 21425839Speter finfo->fullname); 21517721Speter ret = T_CONFLICT; 21617721Speter } 21717721Speter } 21817721Speter else 21917721Speter { 22017721Speter /* The user file shouldn't be there */ 22117721Speter if (!really_quiet) 22217721Speter error (0, 0, "%s should be removed and is still there", 22325839Speter finfo->fullname); 22417721Speter ret = T_REMOVED; 22517721Speter } 22617721Speter } 22717721Speter else 22817721Speter { 22917721Speter /* A normal entry, TS_Rcs is valid */ 23017721Speter if (vers->vn_rcs == NULL) 23117721Speter { 23217721Speter /* There is no RCS file */ 23317721Speter 23417721Speter if (vers->ts_user == NULL) 23517721Speter { 23617721Speter /* There is no user file, so just remove the entry */ 23717721Speter if (!really_quiet) 23817721Speter error (0, 0, "warning: %s is not (any longer) pertinent", 23925839Speter finfo->fullname); 24017721Speter ret = T_REMOVE_ENTRY; 24117721Speter } 24217721Speter else if (strcmp (vers->ts_user, vers->ts_rcs) == 0) 24317721Speter { 24417721Speter 24517721Speter /* 24617721Speter * The user file is still unmodified, so just remove it from 24717721Speter * the entry list 24817721Speter */ 24917721Speter if (!really_quiet) 25017721Speter error (0, 0, "%s is no longer in the repository", 25125839Speter finfo->fullname); 25217721Speter ret = T_REMOVE_ENTRY; 25317721Speter } 25417721Speter else 25517721Speter { 25617721Speter /* 25717721Speter * The user file has been modified and since it is no longer 25817721Speter * in the repository, a conflict is raised 25917721Speter */ 26025839Speter if (No_Difference (finfo, vers)) 26117721Speter { 26217721Speter /* they are different -> conflict */ 26317721Speter if (!really_quiet) 26417721Speter error (0, 0, 26517721Speter "conflict: %s is modified but no longer in the repository", 26625839Speter finfo->fullname); 26717721Speter ret = T_CONFLICT; 26817721Speter } 26917721Speter else 27017721Speter { 27117721Speter /* they weren't really different */ 27217721Speter if (!really_quiet) 27317721Speter error (0, 0, 27417721Speter "warning: %s is not (any longer) pertinent", 27525839Speter finfo->fullname); 27617721Speter ret = T_REMOVE_ENTRY; 27717721Speter } 27817721Speter } 27917721Speter } 28017721Speter else if (strcmp (vers->vn_rcs, vers->vn_user) == 0) 28117721Speter { 28217721Speter /* The RCS file is the same version as the user file */ 28317721Speter 28417721Speter if (vers->ts_user == NULL) 28517721Speter { 28617721Speter 28717721Speter /* 28817721Speter * There is no user file, so note that it was lost and 28917721Speter * extract a new version 29017721Speter */ 29117721Speter if (strcmp (command_name, "update") == 0) 29217721Speter if (!really_quiet) 29325839Speter error (0, 0, "warning: %s was lost", finfo->fullname); 29417721Speter ret = T_CHECKOUT; 29517721Speter } 29617721Speter else if (strcmp (vers->ts_user, vers->ts_rcs) == 0) 29717721Speter { 29817721Speter 29917721Speter /* 30017721Speter * The user file is still unmodified, so nothing special at 30117721Speter * all to do -- no lists updated, unless the sticky -k option 30217721Speter * has changed. If the sticky tag has changed, we just need 30317721Speter * to re-register the entry 30417721Speter */ 30517721Speter if (vers->entdata->options && 30617721Speter strcmp (vers->entdata->options, vers->options) != 0) 30717721Speter ret = T_CHECKOUT; 30817721Speter else 30917721Speter { 31032785Speter sticky_ck (finfo, aflag, vers); 31117721Speter ret = T_UPTODATE; 31217721Speter } 31317721Speter } 31417721Speter else 31517721Speter { 31617721Speter 31717721Speter /* 31817721Speter * The user file appears to have been modified, but we call 31917721Speter * No_Difference to verify that it really has been modified 32017721Speter */ 32125839Speter if (No_Difference (finfo, vers)) 32217721Speter { 32317721Speter 32417721Speter /* 32517721Speter * they really are different; modified if we aren't 32617721Speter * changing any sticky -k options, else needs merge 32717721Speter */ 32817721Speter#ifdef XXX_FIXME_WHEN_RCSMERGE_IS_FIXED 32917721Speter if (strcmp (vers->entdata->options ? 33017721Speter vers->entdata->options : "", vers->options) == 0) 33117721Speter ret = T_MODIFIED; 33217721Speter else 33317721Speter ret = T_NEEDS_MERGE; 33417721Speter#else 33517721Speter ret = T_MODIFIED; 33632785Speter sticky_ck (finfo, aflag, vers); 33717721Speter#endif 33817721Speter } 33917721Speter else 34017721Speter { 34117721Speter /* file has not changed; check out if -k changed */ 34217721Speter if (strcmp (vers->entdata->options ? 34317721Speter vers->entdata->options : "", vers->options) != 0) 34417721Speter { 34517721Speter ret = T_CHECKOUT; 34617721Speter } 34717721Speter else 34817721Speter { 34917721Speter 35017721Speter /* 35117721Speter * else -> note that No_Difference will Register the 35217721Speter * file already for us, using the new tag/date. This 35317721Speter * is the desired behaviour 35417721Speter */ 35517721Speter ret = T_UPTODATE; 35617721Speter } 35717721Speter } 35817721Speter } 35917721Speter } 36017721Speter else 36117721Speter { 36217721Speter /* The RCS file is a newer version than the user file */ 36317721Speter 36417721Speter if (vers->ts_user == NULL) 36517721Speter { 36617721Speter /* There is no user file, so just get it */ 36717721Speter 36817721Speter if (strcmp (command_name, "update") == 0) 36917721Speter if (!really_quiet) 37025839Speter error (0, 0, "warning: %s was lost", finfo->fullname); 37117721Speter ret = T_CHECKOUT; 37217721Speter } 37317721Speter else if (strcmp (vers->ts_user, vers->ts_rcs) == 0) 37417721Speter { 37517721Speter 37617721Speter /* 37717721Speter * The user file is still unmodified, so just get it as well 37817721Speter */ 37917721Speter#ifdef SERVER_SUPPORT 38017721Speter if (strcmp (vers->entdata->options ? 38117721Speter vers->entdata->options : "", vers->options) != 0 38217721Speter || (vers->srcfile != NULL 38317721Speter && (vers->srcfile->flags & INATTIC) != 0)) 38417721Speter ret = T_CHECKOUT; 38517721Speter else 38617721Speter ret = T_PATCH; 38717721Speter#else 38817721Speter ret = T_CHECKOUT; 38917721Speter#endif 39017721Speter } 39117721Speter else 39217721Speter { 39325839Speter if (No_Difference (finfo, vers)) 39417721Speter /* really modified, needs to merge */ 39517721Speter ret = T_NEEDS_MERGE; 39617721Speter#ifdef SERVER_SUPPORT 39717721Speter else if ((strcmp (vers->entdata->options ? 39817721Speter vers->entdata->options : "", vers->options) 39917721Speter != 0) 40017721Speter || (vers->srcfile != NULL 40117721Speter && (vers->srcfile->flags & INATTIC) != 0)) 40217721Speter /* not really modified, check it out */ 40317721Speter ret = T_CHECKOUT; 40417721Speter else 40517721Speter ret = T_PATCH; 40617721Speter#else 40717721Speter else 40817721Speter /* not really modified, check it out */ 40917721Speter ret = T_CHECKOUT; 41017721Speter#endif 41117721Speter } 41217721Speter } 41317721Speter } 41417721Speter 41517721Speter /* free up the vers struct, or just return it */ 41617721Speter if (versp != (Vers_TS **) NULL) 41717721Speter *versp = vers; 41817721Speter else 41917721Speter freevers_ts (&vers); 42017721Speter 42117721Speter /* return the status of the file */ 42217721Speter return (ret); 42317721Speter} 42417721Speter 42517721Speterstatic void 42632785Spetersticky_ck (finfo, aflag, vers) 42732785Speter struct file_info *finfo; 42817721Speter int aflag; 42917721Speter Vers_TS *vers; 43017721Speter{ 43117721Speter if (aflag || vers->tag || vers->date) 43217721Speter { 43317721Speter char *enttag = vers->entdata->tag; 43417721Speter char *entdate = vers->entdata->date; 43517721Speter 43617721Speter if ((enttag && vers->tag && strcmp (enttag, vers->tag)) || 43717721Speter ((enttag && !vers->tag) || (!enttag && vers->tag)) || 43817721Speter (entdate && vers->date && strcmp (entdate, vers->date)) || 43917721Speter ((entdate && !vers->date) || (!entdate && vers->date))) 44017721Speter { 44132785Speter Register (finfo->entries, finfo->file, vers->vn_user, vers->ts_rcs, 44217721Speter vers->options, vers->tag, vers->date, vers->ts_conflict); 44317721Speter 44417721Speter#ifdef SERVER_SUPPORT 44517721Speter if (server_active) 44617721Speter { 44717721Speter /* We need to update the entries line on the client side. 44817721Speter It is possible we will later update it again via 44917721Speter server_updated or some such, but that is OK. */ 45017721Speter server_update_entries 45132785Speter (finfo->file, finfo->update_dir, finfo->repository, 45217721Speter strcmp (vers->ts_rcs, vers->ts_user) == 0 ? 45317721Speter SERVER_UPDATED : SERVER_MERGED); 45417721Speter } 45517721Speter#endif 45617721Speter } 45717721Speter } 45817721Speter} 459