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