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 && vers->tag && !isdigit (vers->tag[0])
39 && strcmp (vers->entdata->tag, vers->tag))
40 /* ...or there used to be a keyword mode which may be
43 || (strlen (vers->entdata->options)
44 && strcmp (vers->entdata->options, vers->options)
45 && strcmp (vers->entdata->options, "-kkv")
46 && strcmp (vers->entdata->options, "-kb"))))
48 || (/* ...this is not commit... */
49 strcmp (cvs_cmd_name, "commit")
51 && (/* ...the tag is changing in a way that affects Name keys... */
52 (vers->entdata->tag && vers->tag
53 && strcmp (vers->entdata->tag, vers->tag)
54 && !(isdigit (vers->entdata->tag[0])
55 && isdigit (vers->entdata->tag[0])))
56 || (!vers->entdata->tag && vers->tag
57 && !isdigit (vers->tag[0])))))
68 * Classify the state of a file
71 Classify_File (finfo, tag, date, options, force_tag_match, aflag, versp,
73 struct file_info *finfo;
77 /* Keyword expansion options. Can be either NULL or "" to
78 indicate none are specified here. */
89 /* get all kinds of good data about the file */
90 vers = Version_TS (finfo, options, tag, date,
93 if (vers->vn_user == NULL)
95 /* No entry available, ts_rcs is invalid */
96 if (vers->vn_rcs == NULL)
98 /* there is no RCS file either */
99 if (vers->ts_user == NULL)
101 /* there is no user file */
102 /* FIXME: Why do we skip this message if vers->tag or
103 vers->date is set? It causes "cvs update -r tag98 foo"
104 to silently do nothing, which is seriously confusing
105 behavior. "cvs update foo" gives this message, which
106 is what I would expect. */
107 if (!force_tag_match || !(vers->tag || vers->date))
109 error (0, 0, "nothing known about %s", finfo->fullname);
114 /* there is a user file */
115 /* FIXME: Why do we skip this message if vers->tag or
116 vers->date is set? It causes "cvs update -r tag98 foo"
117 to silently do nothing, which is seriously confusing
118 behavior. "cvs update foo" gives this message, which
119 is what I would expect. */
120 if (!force_tag_match || !(vers->tag || vers->date))
122 error (0, 0, "use `%s add' to create an entry for %s",
123 program_name, finfo->fullname);
127 else if (RCS_isdead (vers->srcfile, vers->vn_rcs))
129 /* there is an RCS file, but it's dead */
130 if (vers->ts_user == NULL)
134 error (0, 0, "use `%s add' to create an entry for %s",
135 program_name, finfo->fullname);
139 else if (!pipeout && vers->ts_user && No_Difference (finfo, vers))
141 /* the files were different so it is a conflict */
143 error (0, 0, "move away %s; it is in the way",
148 /* no user file or no difference, just checkout */
151 else if (strcmp (vers->vn_user, "0") == 0)
153 /* An entry for a new-born file; ts_rcs is dummy */
155 if (vers->ts_user == NULL)
164 * There is no user file, but there should be one; remove the
168 error (0, 0, "warning: new-born %s has disappeared",
170 ret = T_REMOVE_ENTRY;
173 else if (vers->vn_rcs == NULL ||
174 RCS_isdead (vers->srcfile, vers->vn_rcs))
175 /* No RCS file or RCS file revision is dead */
185 if (vers->srcfile->flags & INATTIC
186 && vers->srcfile->flags & VALID)
188 /* This file has been added on some branch other than
189 the one we are looking at. In the branch we are
190 looking at, the file was already valid. */
193 "conflict: %s has been added, but already exists",
199 * There is an RCS file, so someone else must have checked
200 * one in behind our back; conflict
204 "conflict: %s created independently by second party",
211 else if (vers->vn_user[0] == '-')
213 /* An entry for a removed file, ts_rcs is invalid */
215 if (vers->ts_user == NULL)
217 /* There is no user file (as it should be) */
219 if (vers->vn_rcs == NULL
220 || RCS_isdead (vers->srcfile, vers->vn_rcs))
224 * There is no RCS file; this is all-right, but it has been
225 * removed independently by a second party; remove the entry
227 ret = T_REMOVE_ENTRY;
229 else if (strcmp (vers->vn_rcs, vers->vn_user + 1) == 0)
231 * The RCS file is the same version as the user file was, and
232 * that's OK; remove it
237 * The RCS file doesn't match the user's file, but it doesn't
238 * matter in this case
245 * The RCS file is a newer version than the removed user file
246 * and this is definitely not OK; make it a conflict.
250 "conflict: removed %s was modified by second party",
257 /* The user file shouldn't be there */
259 error (0, 0, "%s should be removed and is still there",
266 /* A normal entry, TS_Rcs is valid */
267 if (vers->vn_rcs == NULL || RCS_isdead (vers->srcfile, vers->vn_rcs))
269 /* There is no RCS file */
271 if (vers->ts_user == NULL)
273 /* There is no user file, so just remove the entry */
275 error (0, 0, "warning: %s is not (any longer) pertinent",
277 ret = T_REMOVE_ENTRY;
279 else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
283 * The user file is still unmodified, so just remove it from
287 error (0, 0, "%s is no longer in the repository",
289 ret = T_REMOVE_ENTRY;
291 else if (No_Difference (finfo, vers))
293 /* they are different -> conflict */
296 "conflict: %s is modified but no longer in the repository",
302 /* they weren't really different */
305 "warning: %s is not (any longer) pertinent",
307 ret = T_REMOVE_ENTRY;
310 else if (strcmp (vers->vn_rcs, vers->vn_user) == 0)
312 /* The RCS file is the same version as the user file */
314 if (vers->ts_user == NULL)
318 * There is no user file, so note that it was lost and
319 * extract a new version
321 /* Comparing the cvs_cmd_name against "update", in
322 addition to being an ugly way to operate, means
323 that this message does not get printed by the
324 server. That might be considered just a straight
325 bug, although there is one subtlety: that case also
326 gets hit when a patch fails and the client fetches
327 a file. I'm not sure there is currently any way
328 for the server to distinguish those two cases. */
329 if (strcmp (cvs_cmd_name, "update") == 0)
331 error (0, 0, "warning: %s was lost", finfo->fullname);
334 else if (!strcmp (vers->ts_user,
336 ? vers->ts_conflict : vers->ts_rcs))
340 * The user file is still unmodified, so nothing special at
341 * all to do -- no lists updated, unless the sticky -k option
342 * has changed. If the sticky tag has changed, we just need
343 * to re-register the entry
345 /* TODO: decide whether we need to check file permissions
346 for a mismatch, and return T_CONFLICT if so. */
347 if (keywords_may_change (aflag, vers))
349 else if (vers->ts_conflict)
354 sticky_ck (finfo, aflag, vers);
357 else if (No_Difference (finfo, vers))
361 * they really are different; modified if we aren't
362 * changing any sticky -k options, else needs merge
364 #ifdef XXX_FIXME_WHEN_RCSMERGE_IS_FIXED
365 if (strcmp (vers->entdata->options ?
366 vers->entdata->options : "", vers->options) == 0)
371 /* Files with conflict markers and new timestamps fall through
372 * here, but they need to. T_CONFLICT is an error in
373 * commit_fileproc, whereas T_CONFLICT with conflict markers
374 * is caught but only warned about. Similarly, update_fileproc
375 * currently reregisters a file that was conflicted but lost
379 sticky_ck (finfo, aflag, vers);
382 else if (strcmp (vers->entdata->options ?
383 vers->entdata->options : "", vers->options) != 0)
385 /* file has not changed; check out if -k changed */
392 * else -> note that No_Difference will Register the
393 * file already for us, using the new tag/date. This
394 * is the desired behaviour
401 /* The RCS file is a newer version than the user file */
403 if (vers->ts_user == NULL)
405 /* There is no user file, so just get it */
407 /* See comment at other "update" compare, for more
408 thoughts on this comparison. */
409 if (strcmp (cvs_cmd_name, "update") == 0)
411 error (0, 0, "warning: %s was lost", finfo->fullname);
414 else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
417 * The user file is still unmodified, so just get it as well
420 else if (No_Difference (finfo, vers))
421 /* really modified, needs to merge */
428 /* free up the vers struct, or just return it */
429 if (versp != (Vers_TS **) NULL)
434 /* return the status of the file */
439 sticky_ck (finfo, aflag, vers)
440 struct file_info *finfo;
444 if (aflag || vers->tag || vers->date)
446 char *enttag = vers->entdata->tag;
447 char *entdate = vers->entdata->date;
449 if ((enttag && vers->tag && strcmp (enttag, vers->tag)) ||
450 ((enttag && !vers->tag) || (!enttag && vers->tag)) ||
451 (entdate && vers->date && strcmp (entdate, vers->date)) ||
452 ((entdate && !vers->date) || (!entdate && vers->date)))
454 Register (finfo->entries, finfo->file, vers->vn_user, vers->ts_rcs,
455 vers->options, vers->tag, vers->date, vers->ts_conflict);
457 #ifdef SERVER_SUPPORT
460 /* We need to update the entries line on the client side.
461 It is possible we will later update it again via
462 server_updated or some such, but that is OK. */
463 server_update_entries
464 (finfo->file, finfo->update_dir, finfo->repository,
465 strcmp (vers->ts_rcs, vers->ts_user) == 0 ?
466 SERVER_UPDATED : SERVER_MERGED);