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 (struct file_info *finfo, int aflag,
21 * Classify the state of a file.
24 * finfo Information about the file to be classified.
27 * options Keyword expansion options. Can be either NULL or "" to
28 * indicate none are specified here.
32 * pipeout Did the user pass the "pipeout" flag to request that
33 * all output go to STDOUT rather than to a file or files?
36 * A Ctype (defined as an enum) describing the state of the file relative to
37 * the repository. See the definition of Ctype for more.
40 Classify_File (struct file_info *finfo, char *tag, char *date, char *options,
41 int force_tag_match, int aflag, Vers_TS **versp, int pipeout)
46 /* get all kinds of good data about the file */
47 vers = Version_TS (finfo, options, tag, date,
50 if (vers->vn_user == NULL)
52 /* No entry available, ts_rcs is invalid */
53 if (vers->vn_rcs == NULL)
55 /* there is no RCS file either */
56 if (vers->ts_user == NULL)
58 /* there is no user file */
59 /* FIXME: Why do we skip this message if vers->tag or
60 vers->date is set? It causes "cvs update -r tag98 foo"
61 to silently do nothing, which is seriously confusing
62 behavior. "cvs update foo" gives this message, which
63 is what I would expect. */
64 if (!force_tag_match || !(vers->tag || vers->date))
66 error (0, 0, "nothing known about `%s'",
72 /* there is a user file */
73 /* FIXME: Why do we skip this message if vers->tag or
74 vers->date is set? It causes "cvs update -r tag98 foo"
75 to silently do nothing, which is seriously confusing
76 behavior. "cvs update foo" gives this message, which
77 is what I would expect. */
78 if (!force_tag_match || !(vers->tag || vers->date))
80 error (0, 0, "use `%s add' to create an entry for `%s'",
81 program_name, finfo->fullname);
85 else if (RCS_isdead (vers->srcfile, vers->vn_rcs))
87 /* there is an RCS file, but it's dead */
88 if (vers->ts_user == NULL)
92 error (0, 0, "use `%s add' to create an entry for `%s'",
93 program_name, finfo->fullname);
97 else if (!pipeout && vers->ts_user && No_Difference (finfo, vers))
99 /* the files were different so it is a conflict */
101 error (0, 0, "move away `%s'; it is in the way",
106 /* no user file or no difference, just checkout */
109 else if (strcmp (vers->vn_user, "0") == 0)
111 /* An entry for a new-born file; ts_rcs is dummy */
113 if (vers->ts_user == NULL)
122 * There is no user file, but there should be one; remove the
126 error (0, 0, "warning: new-born `%s' has disappeared",
128 ret = T_REMOVE_ENTRY;
131 else if (vers->vn_rcs == NULL ||
132 RCS_isdead (vers->srcfile, vers->vn_rcs))
133 /* No RCS file or RCS file revision is dead */
143 if (vers->srcfile->flags & INATTIC
144 && vers->srcfile->flags & VALID)
146 /* This file has been added on some branch other than
147 the one we are looking at. In the branch we are
148 looking at, the file was already valid. */
151 "conflict: `%s' has been added, but already exists",
157 * There is an RCS file, so someone else must have checked
158 * one in behind our back; conflict
162 "conflict: `%s' created independently by"
170 else if (vers->vn_user[0] == '-')
172 /* An entry for a removed file, ts_rcs is invalid */
174 if (vers->ts_user == NULL)
176 /* There is no user file (as it should be) */
178 if (vers->vn_rcs == NULL
179 || RCS_isdead (vers->srcfile, vers->vn_rcs))
183 * There is no RCS file; this is all-right, but it has been
184 * removed independently by a second party; remove the entry
186 ret = T_REMOVE_ENTRY;
188 else if (strcmp (vers->vn_rcs, vers->vn_user + 1) == 0)
190 * The RCS file is the same version as the user file was, and
191 * that's OK; remove it
196 * The RCS file doesn't match the user's file, but it doesn't
197 * matter in this case
204 * The RCS file is a newer version than the removed user file
205 * and this is definitely not OK; make it a conflict.
209 "conflict: removed `%s' was modified by"
217 /* The user file shouldn't be there */
219 error (0, 0, "`%s' should be removed and is still there",
226 /* A normal entry, TS_Rcs is valid */
227 if (vers->vn_rcs == NULL || RCS_isdead (vers->srcfile, vers->vn_rcs))
229 /* There is no RCS file */
231 if (vers->ts_user == NULL)
233 /* There is no user file, so just remove the entry */
235 error (0, 0, "warning: `%s' is not (any longer) pertinent",
237 ret = T_REMOVE_ENTRY;
239 else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
243 * The user file is still unmodified, so just remove it from
247 error (0, 0, "`%s' is no longer in the repository",
249 ret = T_REMOVE_ENTRY;
251 else if (No_Difference (finfo, vers))
253 /* they are different -> conflict */
256 "conflict: `%s' is modified but no longer in the"
263 /* they weren't really different */
266 "warning: `%s' is not (any longer) pertinent",
268 ret = T_REMOVE_ENTRY;
271 else if (strcmp (vers->vn_rcs, vers->vn_user) == 0)
273 /* The RCS file is the same version as the user file */
275 if (vers->ts_user == NULL)
279 * There is no user file, so note that it was lost and
280 * extract a new version
282 /* Comparing the cvs_cmd_name against "update", in
283 addition to being an ugly way to operate, means
284 that this message does not get printed by the
285 server. That might be considered just a straight
286 bug, although there is one subtlety: that case also
287 gets hit when a patch fails and the client fetches
288 a file. I'm not sure there is currently any way
289 for the server to distinguish those two cases. */
290 if (strcmp (cvs_cmd_name, "update") == 0)
292 error (0, 0, "warning: `%s' was lost", finfo->fullname);
295 else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
299 * The user file is still unmodified, so nothing special at
300 * all to do -- no lists updated, unless the sticky -k option
301 * has changed. If the sticky tag has changed, we just need
302 * to re-register the entry
304 /* TODO: decide whether we need to check file permissions
305 for a mismatch, and return T_CONFLICT if so. */
306 if (vers->entdata->options &&
307 strcmp (vers->entdata->options, vers->options) != 0)
311 sticky_ck (finfo, aflag, vers);
315 else if (No_Difference (finfo, vers))
319 * they really are different; modified if we aren't
320 * changing any sticky -k options, else needs merge
322 #ifdef XXX_FIXME_WHEN_RCSMERGE_IS_FIXED
323 if (strcmp (vers->entdata->options ?
324 vers->entdata->options : "", vers->options) == 0)
330 sticky_ck (finfo, aflag, vers);
333 else if (strcmp (vers->entdata->options ?
334 vers->entdata->options : "", vers->options) != 0)
336 /* file has not changed; check out if -k changed */
343 * else -> note that No_Difference will Register the
344 * file already for us, using the new tag/date. This
345 * is the desired behaviour
352 /* The RCS file is a newer version than the user file */
354 if (vers->ts_user == NULL)
356 /* There is no user file, so just get it */
358 /* See comment at other "update" compare, for more
359 thoughts on this comparison. */
360 if (strcmp (cvs_cmd_name, "update") == 0)
362 error (0, 0, "warning: `%s' was lost", finfo->fullname);
365 else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
369 * The user file is still unmodified, so just get it as well
371 if (strcmp (vers->entdata->options ?
372 vers->entdata->options : "", vers->options) != 0
373 || (vers->srcfile != NULL
374 && (vers->srcfile->flags & INATTIC) != 0))
379 else if (No_Difference (finfo, vers))
380 /* really modified, needs to merge */
382 else if ((strcmp (vers->entdata->options ?
383 vers->entdata->options : "", vers->options)
385 || (vers->srcfile != NULL
386 && (vers->srcfile->flags & INATTIC) != 0))
387 /* not really modified, check it out */
394 /* free up the vers struct, or just return it */
400 /* return the status of the file */
405 sticky_ck (struct file_info *finfo, int aflag, Vers_TS *vers)
407 if (aflag || vers->tag || vers->date)
409 char *enttag = vers->entdata->tag;
410 char *entdate = vers->entdata->date;
412 if ((enttag && vers->tag && strcmp (enttag, vers->tag)) ||
413 ((enttag && !vers->tag) || (!enttag && vers->tag)) ||
414 (entdate && vers->date && strcmp (entdate, vers->date)) ||
415 ((entdate && !vers->date) || (!entdate && vers->date)))
417 Register (finfo->entries, finfo->file, vers->vn_user, vers->ts_rcs,
418 vers->options, vers->tag, vers->date, vers->ts_conflict);
420 #ifdef SERVER_SUPPORT
423 /* We need to update the entries line on the client side.
424 It is possible we will later update it again via
425 server_updated or some such, but that is OK. */
426 server_update_entries
427 (finfo->file, finfo->update_dir, finfo->repository,
428 strcmp (vers->ts_rcs, vers->ts_user) == 0 ?
429 SERVER_UPDATED : SERVER_MERGED);