2 * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
4 * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
7 * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
8 * Portions Copyright (C) 1989-1992, Brian Berliner
10 * You may distribute under the terms of the GNU General Public License as
11 * specified in the README file that comes with the CVS source distribution.
17 static void sticky_ck PROTO ((struct file_info *finfo, int aflag,
22 static inline int keywords_may_change PROTO ((int aflag, Vers_TS * vers));
24 keywords_may_change (aflag, vers)
30 if (/* Options are different... */
31 strcmp (vers->entdata->options, vers->options)
33 || (/* ...clearing stickies... */
36 && (/* ...there used to be a tag which subs in Name keys... */
37 (vers->entdata->tag && !isdigit (vers->entdata->tag[0]))
38 /* ...or there used to be a keyword mode which may be
41 || (strlen (vers->entdata->options)
42 && strcmp (vers->entdata->options, "-kkv")
43 && strcmp (vers->entdata->options, "-kb"))))
45 || (/* ...this is not commit... */
46 strcmp (cvs_cmd_name, "commit")
48 && (/* ...the tag is changing in a way that affects Name keys... */
49 (vers->entdata->tag && vers->tag
50 && strcmp (vers->entdata->tag, vers->tag)
51 && !(isdigit (vers->entdata->tag[0])
52 && isdigit (vers->entdata->tag[0])))
53 || (!vers->entdata->tag && vers->tag
54 && !isdigit (vers->tag[0])))))
65 * Classify the state of a file
68 Classify_File (finfo, tag, date, options, force_tag_match, aflag, versp,
70 struct file_info *finfo;
74 /* Keyword expansion options. Can be either NULL or "" to
75 indicate none are specified here. */
86 /* get all kinds of good data about the file */
87 vers = Version_TS (finfo, options, tag, date,
90 if (vers->vn_user == NULL)
92 /* No entry available, ts_rcs is invalid */
93 if (vers->vn_rcs == NULL)
95 /* there is no RCS file either */
96 if (vers->ts_user == NULL)
98 /* there is no user file */
99 /* FIXME: Why do we skip this message if vers->tag or
100 vers->date is set? It causes "cvs update -r tag98 foo"
101 to silently do nothing, which is seriously confusing
102 behavior. "cvs update foo" gives this message, which
103 is what I would expect. */
104 if (!force_tag_match || !(vers->tag || vers->date))
106 error (0, 0, "nothing known about %s", finfo->fullname);
111 /* there is a user file */
112 /* FIXME: Why do we skip this message if vers->tag or
113 vers->date is set? It causes "cvs update -r tag98 foo"
114 to silently do nothing, which is seriously confusing
115 behavior. "cvs update foo" gives this message, which
116 is what I would expect. */
117 if (!force_tag_match || !(vers->tag || vers->date))
119 error (0, 0, "use `%s add' to create an entry for %s",
120 program_name, finfo->fullname);
124 else if (RCS_isdead (vers->srcfile, vers->vn_rcs))
126 /* there is an RCS file, but it's dead */
127 if (vers->ts_user == NULL)
131 error (0, 0, "use `%s add' to create an entry for %s",
132 program_name, finfo->fullname);
136 else if (!pipeout && vers->ts_user && No_Difference (finfo, vers))
138 /* the files were different so it is a conflict */
140 error (0, 0, "move away %s; it is in the way",
145 /* no user file or no difference, just checkout */
148 else if (strcmp (vers->vn_user, "0") == 0)
150 /* An entry for a new-born file; ts_rcs is dummy */
152 if (vers->ts_user == NULL)
161 * There is no user file, but there should be one; remove the
165 error (0, 0, "warning: new-born %s has disappeared",
167 ret = T_REMOVE_ENTRY;
170 else if (vers->vn_rcs == NULL ||
171 RCS_isdead (vers->srcfile, vers->vn_rcs))
172 /* No RCS file or RCS file revision is dead */
182 if (vers->srcfile->flags & INATTIC
183 && vers->srcfile->flags & VALID)
185 /* This file has been added on some branch other than
186 the one we are looking at. In the branch we are
187 looking at, the file was already valid. */
190 "conflict: %s has been added, but already exists",
196 * There is an RCS file, so someone else must have checked
197 * one in behind our back; conflict
201 "conflict: %s created independently by second party",
208 else if (vers->vn_user[0] == '-')
210 /* An entry for a removed file, ts_rcs is invalid */
212 if (vers->ts_user == NULL)
214 /* There is no user file (as it should be) */
216 if (vers->vn_rcs == NULL
217 || RCS_isdead (vers->srcfile, vers->vn_rcs))
221 * There is no RCS file; this is all-right, but it has been
222 * removed independently by a second party; remove the entry
224 ret = T_REMOVE_ENTRY;
226 else if (strcmp (vers->vn_rcs, vers->vn_user + 1) == 0)
228 * The RCS file is the same version as the user file was, and
229 * that's OK; remove it
234 * The RCS file doesn't match the user's file, but it doesn't
235 * matter in this case
242 * The RCS file is a newer version than the removed user file
243 * and this is definitely not OK; make it a conflict.
247 "conflict: removed %s was modified by second party",
254 /* The user file shouldn't be there */
256 error (0, 0, "%s should be removed and is still there",
263 /* A normal entry, TS_Rcs is valid */
264 if (vers->vn_rcs == NULL || RCS_isdead (vers->srcfile, vers->vn_rcs))
266 /* There is no RCS file */
268 if (vers->ts_user == NULL)
270 /* There is no user file, so just remove the entry */
272 error (0, 0, "warning: %s is not (any longer) pertinent",
274 ret = T_REMOVE_ENTRY;
276 else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
280 * The user file is still unmodified, so just remove it from
284 error (0, 0, "%s is no longer in the repository",
286 ret = T_REMOVE_ENTRY;
288 else if (No_Difference (finfo, vers))
290 /* they are different -> conflict */
293 "conflict: %s is modified but no longer in the repository",
299 /* they weren't really different */
302 "warning: %s is not (any longer) pertinent",
304 ret = T_REMOVE_ENTRY;
307 else if (strcmp (vers->vn_rcs, vers->vn_user) == 0)
309 /* The RCS file is the same version as the user file */
311 if (vers->ts_user == NULL)
315 * There is no user file, so note that it was lost and
316 * extract a new version
318 /* Comparing the cvs_cmd_name against "update", in
319 addition to being an ugly way to operate, means
320 that this message does not get printed by the
321 server. That might be considered just a straight
322 bug, although there is one subtlety: that case also
323 gets hit when a patch fails and the client fetches
324 a file. I'm not sure there is currently any way
325 for the server to distinguish those two cases. */
326 if (strcmp (cvs_cmd_name, "update") == 0)
328 error (0, 0, "warning: %s was lost", finfo->fullname);
331 else if (!strcmp (vers->ts_user,
333 ? vers->ts_conflict : vers->ts_rcs))
337 * The user file is still unmodified, so nothing special at
338 * all to do -- no lists updated, unless the sticky -k option
339 * has changed. If the sticky tag has changed, we just need
340 * to re-register the entry
342 /* TODO: decide whether we need to check file permissions
343 for a mismatch, and return T_CONFLICT if so. */
344 if (keywords_may_change (aflag, vers))
346 else if (vers->ts_conflict)
351 sticky_ck (finfo, aflag, vers);
354 else if (No_Difference (finfo, vers))
358 * they really are different; modified if we aren't
359 * changing any sticky -k options, else needs merge
361 #ifdef XXX_FIXME_WHEN_RCSMERGE_IS_FIXED
362 if (strcmp (vers->entdata->options ?
363 vers->entdata->options : "", vers->options) == 0)
368 /* Files with conflict markers and new timestamps fall through
369 * here, but they need to. T_CONFLICT is an error in
370 * commit_fileproc, whereas T_CONFLICT with conflict markers
371 * is caught but only warned about. Similarly, update_fileproc
372 * currently reregisters a file that was conflicted but lost
376 sticky_ck (finfo, aflag, vers);
379 else if (strcmp (vers->entdata->options ?
380 vers->entdata->options : "", vers->options) != 0)
382 /* file has not changed; check out if -k changed */
389 * else -> note that No_Difference will Register the
390 * file already for us, using the new tag/date. This
391 * is the desired behaviour
398 /* The RCS file is a newer version than the user file */
400 if (vers->ts_user == NULL)
402 /* There is no user file, so just get it */
404 /* See comment at other "update" compare, for more
405 thoughts on this comparison. */
406 if (strcmp (cvs_cmd_name, "update") == 0)
408 error (0, 0, "warning: %s was lost", finfo->fullname);
411 else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
414 * The user file is still unmodified, so just get it as well
417 else if (No_Difference (finfo, vers))
418 /* really modified, needs to merge */
425 /* free up the vers struct, or just return it */
426 if (versp != (Vers_TS **) NULL)
431 /* return the status of the file */
436 sticky_ck (finfo, aflag, vers)
437 struct file_info *finfo;
441 if (aflag || vers->tag || vers->date)
443 char *enttag = vers->entdata->tag;
444 char *entdate = vers->entdata->date;
446 if ((enttag && vers->tag && strcmp (enttag, vers->tag)) ||
447 ((enttag && !vers->tag) || (!enttag && vers->tag)) ||
448 (entdate && vers->date && strcmp (entdate, vers->date)) ||
449 ((entdate && !vers->date) || (!entdate && vers->date)))
451 Register (finfo->entries, finfo->file, vers->vn_user, vers->ts_rcs,
452 vers->options, vers->tag, vers->date, vers->ts_conflict);
454 #ifdef SERVER_SUPPORT
457 /* We need to update the entries line on the client side.
458 It is possible we will later update it again via
459 server_updated or some such, but that is OK. */
460 server_update_entries
461 (finfo->file, finfo->update_dir, finfo->repository,
462 strcmp (vers->ts_rcs, vers->ts_user) == 0 ?
463 SERVER_UPDATED : SERVER_MERGED);