2 * Copyright (c) 1992, Brian Berliner and Jeff Polk
3 * Copyright (c) 1989-1992, Brian Berliner
5 * You may distribute under the terms of the GNU General Public License as
6 * specified in the README file that comes with the CVS source distribution.
12 static void sticky_ck (struct file_info *finfo, int aflag,
16 * Classify the state of a file.
19 * finfo Information about the file to be classified.
22 * options Keyword expansion options. Can be either NULL or "" to
23 * indicate none are specified here.
27 * pipeout Did the user pass the "pipeout" flag to request that
28 * all output go to STDOUT rather than to a file or files?
31 * A Ctype (defined as an enum) describing the state of the file relative to
32 * the repository. See the definition of Ctype for more.
35 Classify_File (struct file_info *finfo, char *tag, char *date, char *options,
36 int force_tag_match, int aflag, Vers_TS **versp, int pipeout)
41 /* get all kinds of good data about the file */
42 vers = Version_TS (finfo, options, tag, date,
45 if (vers->vn_user == NULL)
47 /* No entry available, ts_rcs is invalid */
48 if (vers->vn_rcs == NULL)
50 /* there is no RCS file either */
51 if (vers->ts_user == NULL)
53 /* there is no user file */
54 /* FIXME: Why do we skip this message if vers->tag or
55 vers->date is set? It causes "cvs update -r tag98 foo"
56 to silently do nothing, which is seriously confusing
57 behavior. "cvs update foo" gives this message, which
58 is what I would expect. */
59 if (!force_tag_match || !(vers->tag || vers->date))
61 error (0, 0, "nothing known about `%s'",
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"
165 else if (vers->vn_user[0] == '-')
167 /* An entry for a removed file, ts_rcs is invalid */
169 if (vers->ts_user == NULL)
171 /* There is no user file (as it should be) */
173 if (vers->vn_rcs == NULL
174 || RCS_isdead (vers->srcfile, vers->vn_rcs))
178 * There is no RCS file; this is all-right, but it has been
179 * removed independently by a second party; remove the entry
181 ret = T_REMOVE_ENTRY;
183 else if (strcmp (vers->vn_rcs, vers->vn_user + 1) == 0)
185 * The RCS file is the same version as the user file was, and
186 * that's OK; remove it
191 * The RCS file doesn't match the user's file, but it doesn't
192 * matter in this case
199 * The RCS file is a newer version than the removed user file
200 * and this is definitely not OK; make it a conflict.
204 "conflict: removed `%s' was modified by"
212 /* The user file shouldn't be there */
214 error (0, 0, "`%s' should be removed and is still there",
221 /* A normal entry, TS_Rcs is valid */
222 if (vers->vn_rcs == NULL || RCS_isdead (vers->srcfile, vers->vn_rcs))
224 /* There is no RCS file */
226 if (vers->ts_user == NULL)
228 /* There is no user file, so just remove the entry */
230 error (0, 0, "warning: `%s' is not (any longer) pertinent",
232 ret = T_REMOVE_ENTRY;
234 else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
238 * The user file is still unmodified, so just remove it from
242 error (0, 0, "`%s' is no longer in the repository",
244 ret = T_REMOVE_ENTRY;
246 else if (No_Difference (finfo, vers))
248 /* they are different -> conflict */
251 "conflict: `%s' is modified but no longer in the"
258 /* they weren't really different */
261 "warning: `%s' is not (any longer) pertinent",
263 ret = T_REMOVE_ENTRY;
266 else if (strcmp (vers->vn_rcs, vers->vn_user) == 0)
268 /* The RCS file is the same version as the user file */
270 if (vers->ts_user == NULL)
274 * There is no user file, so note that it was lost and
275 * extract a new version
277 /* Comparing the cvs_cmd_name against "update", in
278 addition to being an ugly way to operate, means
279 that this message does not get printed by the
280 server. That might be considered just a straight
281 bug, although there is one subtlety: that case also
282 gets hit when a patch fails and the client fetches
283 a file. I'm not sure there is currently any way
284 for the server to distinguish those two cases. */
285 if (strcmp (cvs_cmd_name, "update") == 0)
287 error (0, 0, "warning: `%s' was lost", finfo->fullname);
290 else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
294 * The user file is still unmodified, so nothing special at
295 * all to do -- no lists updated, unless the sticky -k option
296 * has changed. If the sticky tag has changed, we just need
297 * to re-register the entry
299 /* TODO: decide whether we need to check file permissions
300 for a mismatch, and return T_CONFLICT if so. */
301 if (vers->entdata->options &&
302 strcmp (vers->entdata->options, vers->options) != 0)
306 sticky_ck (finfo, aflag, vers);
310 else if (No_Difference (finfo, vers))
314 * they really are different; modified if we aren't
315 * changing any sticky -k options, else needs merge
317 #ifdef XXX_FIXME_WHEN_RCSMERGE_IS_FIXED
318 if (strcmp (vers->entdata->options ?
319 vers->entdata->options : "", vers->options) == 0)
325 sticky_ck (finfo, aflag, vers);
328 else if (strcmp (vers->entdata->options ?
329 vers->entdata->options : "", vers->options) != 0)
331 /* file has not changed; check out if -k changed */
338 * else -> note that No_Difference will Register the
339 * file already for us, using the new tag/date. This
340 * is the desired behaviour
347 /* The RCS file is a newer version than the user file */
349 if (vers->ts_user == NULL)
351 /* There is no user file, so just get it */
353 /* See comment at other "update" compare, for more
354 thoughts on this comparison. */
355 if (strcmp (cvs_cmd_name, "update") == 0)
357 error (0, 0, "warning: `%s' was lost", finfo->fullname);
360 else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
364 * The user file is still unmodified, so just get it as well
366 if (strcmp (vers->entdata->options ?
367 vers->entdata->options : "", vers->options) != 0
368 || (vers->srcfile != NULL
369 && (vers->srcfile->flags & INATTIC) != 0))
374 else if (No_Difference (finfo, vers))
375 /* really modified, needs to merge */
377 else if ((strcmp (vers->entdata->options ?
378 vers->entdata->options : "", vers->options)
380 || (vers->srcfile != NULL
381 && (vers->srcfile->flags & INATTIC) != 0))
382 /* not really modified, check it out */
389 /* free up the vers struct, or just return it */
390 if (versp != (Vers_TS **) NULL)
395 /* return the status of the file */
400 sticky_ck (struct file_info *finfo, int aflag, Vers_TS *vers)
402 if (aflag || vers->tag || vers->date)
404 char *enttag = vers->entdata->tag;
405 char *entdate = vers->entdata->date;
407 if ((enttag && vers->tag && strcmp (enttag, vers->tag)) ||
408 ((enttag && !vers->tag) || (!enttag && vers->tag)) ||
409 (entdate && vers->date && strcmp (entdate, vers->date)) ||
410 ((entdate && !vers->date) || (!entdate && vers->date)))
412 Register (finfo->entries, finfo->file, vers->vn_user, vers->ts_rcs,
413 vers->options, vers->tag, vers->date, vers->ts_conflict);
415 #ifdef SERVER_SUPPORT
418 /* We need to update the entries line on the client side.
419 It is possible we will later update it again via
420 server_updated or some such, but that is OK. */
421 server_update_entries
422 (finfo->file, finfo->update_dir, finfo->repository,
423 strcmp (vers->ts_rcs, vers->ts_user) == 0 ?
424 SERVER_UPDATED : SERVER_MERGED);