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,
21 * Classify the state of a file
24 Classify_File (finfo, tag, date, options, force_tag_match, aflag, versp,
26 struct file_info *finfo;
30 /* Keyword expansion options. Can be either NULL or "" to
31 indicate none are specified here. */
42 /* get all kinds of good data about the file */
43 vers = Version_TS (finfo, options, tag, date,
46 if (vers->vn_user == NULL)
48 /* No entry available, ts_rcs is invalid */
49 if (vers->vn_rcs == NULL)
51 /* there is no RCS file either */
52 if (vers->ts_user == NULL)
54 /* there is no user file */
55 /* FIXME: Why do we skip this message if vers->tag or
56 vers->date is set? It causes "cvs update -r tag98 foo"
57 to silently do nothing, which is seriously confusing
58 behavior. "cvs update foo" gives this message, which
59 is what I would expect. */
60 if (!force_tag_match || !(vers->tag || vers->date))
62 error (0, 0, "nothing known about %s", finfo->fullname);
67 /* there is a user file */
68 /* FIXME: Why do we skip this message if vers->tag or
69 vers->date is set? It causes "cvs update -r tag98 foo"
70 to silently do nothing, which is seriously confusing
71 behavior. "cvs update foo" gives this message, which
72 is what I would expect. */
73 if (!force_tag_match || !(vers->tag || vers->date))
75 error (0, 0, "use `%s add' to create an entry for %s",
76 program_name, finfo->fullname);
80 else if (RCS_isdead (vers->srcfile, vers->vn_rcs))
82 /* there is an RCS file, but it's dead */
83 if (vers->ts_user == NULL)
87 error (0, 0, "use `%s add' to create an entry for %s",
88 program_name, finfo->fullname);
92 else if (!pipeout && vers->ts_user && No_Difference (finfo, vers))
94 /* the files were different so it is a conflict */
96 error (0, 0, "move away %s; it is in the way",
101 /* no user file or no difference, just checkout */
104 else if (strcmp (vers->vn_user, "0") == 0)
106 /* An entry for a new-born file; ts_rcs is dummy */
108 if (vers->ts_user == NULL)
117 * There is no user file, but there should be one; remove the
121 error (0, 0, "warning: new-born %s has disappeared",
123 ret = T_REMOVE_ENTRY;
126 else if (vers->vn_rcs == NULL ||
127 RCS_isdead (vers->srcfile, vers->vn_rcs))
128 /* No RCS file or RCS file revision is dead */
138 if (vers->srcfile->flags & INATTIC
139 && vers->srcfile->flags & VALID)
141 /* This file has been added on some branch other than
142 the one we are looking at. In the branch we are
143 looking at, the file was already valid. */
146 "conflict: %s has been added, but already exists",
152 * There is an RCS file, so someone else must have checked
153 * one in behind our back; conflict
157 "conflict: %s created independently by second party",
164 else if (vers->vn_user[0] == '-')
166 /* An entry for a removed file, ts_rcs is invalid */
168 if (vers->ts_user == NULL)
170 /* There is no user file (as it should be) */
172 if (vers->vn_rcs == NULL
173 || RCS_isdead (vers->srcfile, vers->vn_rcs))
177 * There is no RCS file; this is all-right, but it has been
178 * removed independently by a second party; remove the entry
180 ret = T_REMOVE_ENTRY;
182 else if (strcmp (vers->vn_rcs, vers->vn_user + 1) == 0)
184 * The RCS file is the same version as the user file was, and
185 * that's OK; remove it
190 * The RCS file doesn't match the user's file, but it doesn't
191 * matter in this case
198 * The RCS file is a newer version than the removed user file
199 * and this is definitely not OK; make it a conflict.
203 "conflict: removed %s was modified by second party",
210 /* The user file shouldn't be there */
212 error (0, 0, "%s should be removed and is still there",
219 /* A normal entry, TS_Rcs is valid */
220 if (vers->vn_rcs == NULL || RCS_isdead (vers->srcfile, vers->vn_rcs))
222 /* There is no RCS file */
224 if (vers->ts_user == NULL)
226 /* There is no user file, so just remove the entry */
228 error (0, 0, "warning: %s is not (any longer) pertinent",
230 ret = T_REMOVE_ENTRY;
232 else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
236 * The user file is still unmodified, so just remove it from
240 error (0, 0, "%s is no longer in the repository",
242 ret = T_REMOVE_ENTRY;
244 else if (No_Difference (finfo, vers))
246 /* they are different -> conflict */
249 "conflict: %s is modified but no longer in the repository",
255 /* they weren't really different */
258 "warning: %s is not (any longer) pertinent",
260 ret = T_REMOVE_ENTRY;
263 else if (strcmp (vers->vn_rcs, vers->vn_user) == 0)
265 /* The RCS file is the same version as the user file */
267 if (vers->ts_user == NULL)
271 * There is no user file, so note that it was lost and
272 * extract a new version
274 /* Comparing the cvs_cmd_name against "update", in
275 addition to being an ugly way to operate, means
276 that this message does not get printed by the
277 server. That might be considered just a straight
278 bug, although there is one subtlety: that case also
279 gets hit when a patch fails and the client fetches
280 a file. I'm not sure there is currently any way
281 for the server to distinguish those two cases. */
282 if (strcmp (cvs_cmd_name, "update") == 0)
284 error (0, 0, "warning: %s was lost", finfo->fullname);
287 else if (!strcmp (vers->ts_user,
289 ? vers->ts_conflict : vers->ts_rcs))
293 * The user file is still unmodified, so nothing special at
294 * all to do -- no lists updated, unless the sticky -k option
295 * has changed. If the sticky tag has changed, we just need
296 * to re-register the entry
298 /* TODO: decide whether we need to check file permissions
299 for a mismatch, and return T_CONFLICT if so. */
300 if (vers->entdata->options &&
301 strcmp (vers->entdata->options, vers->options) != 0)
303 else if (vers->ts_conflict)
307 sticky_ck (finfo, aflag, vers);
311 else if (No_Difference (finfo, vers))
315 * they really are different; modified if we aren't
316 * changing any sticky -k options, else needs merge
318 #ifdef XXX_FIXME_WHEN_RCSMERGE_IS_FIXED
319 if (strcmp (vers->entdata->options ?
320 vers->entdata->options : "", vers->options) == 0)
325 /* Files with conflict markers and new timestamps fall through
326 * here, but they need to. T_CONFLICT is an error in
327 * commit_fileproc, whereas T_CONFLICT with conflict markers
328 * is caught but only warned about. Similarly, update_fileproc
329 * currently reregisters a file that was conflicted but lost
333 sticky_ck (finfo, aflag, vers);
336 else if (strcmp (vers->entdata->options ?
337 vers->entdata->options : "", vers->options) != 0)
339 /* file has not changed; check out if -k changed */
346 * else -> note that No_Difference will Register the
347 * file already for us, using the new tag/date. This
348 * is the desired behaviour
355 /* The RCS file is a newer version than the user file */
357 if (vers->ts_user == NULL)
359 /* There is no user file, so just get it */
361 /* See comment at other "update" compare, for more
362 thoughts on this comparison. */
363 if (strcmp (cvs_cmd_name, "update") == 0)
365 error (0, 0, "warning: %s was lost", finfo->fullname);
368 else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
372 * The user file is still unmodified, so just get it as well
374 if (strcmp (vers->entdata->options ?
375 vers->entdata->options : "", vers->options) != 0
376 || (vers->srcfile != NULL
377 && (vers->srcfile->flags & INATTIC) != 0))
382 else if (No_Difference (finfo, vers))
383 /* really modified, needs to merge */
385 else if ((strcmp (vers->entdata->options ?
386 vers->entdata->options : "", vers->options)
388 || (vers->srcfile != NULL
389 && (vers->srcfile->flags & INATTIC) != 0))
390 /* not really modified, check it out */
397 /* free up the vers struct, or just return it */
398 if (versp != (Vers_TS **) NULL)
403 /* return the status of the file */
408 sticky_ck (finfo, aflag, vers)
409 struct file_info *finfo;
413 if (aflag || vers->tag || vers->date)
415 char *enttag = vers->entdata->tag;
416 char *entdate = vers->entdata->date;
418 if ((enttag && vers->tag && strcmp (enttag, vers->tag)) ||
419 ((enttag && !vers->tag) || (!enttag && vers->tag)) ||
420 (entdate && vers->date && strcmp (entdate, vers->date)) ||
421 ((entdate && !vers->date) || (!entdate && vers->date)))
423 Register (finfo->entries, finfo->file, vers->vn_user, vers->ts_rcs,
424 vers->options, vers->tag, vers->date, vers->ts_conflict);
426 #ifdef SERVER_SUPPORT
429 /* We need to update the entries line on the client side.
430 It is possible we will later update it again via
431 server_updated or some such, but that is OK. */
432 server_update_entries
433 (finfo->file, finfo->update_dir, finfo->repository,
434 strcmp (vers->ts_rcs, vers->ts_user) == 0 ?
435 SERVER_UPDATED : SERVER_MERGED);