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.
15 #include <sys/cdefs.h>
16 __FBSDID("$FreeBSD$");
20 static void sticky_ck PROTO ((struct file_info *finfo, int aflag,
25 static inline int keywords_may_change PROTO ((int aflag, Vers_TS * vers));
27 keywords_may_change (aflag, vers)
33 if (/* Options are different... */
34 strcmp (vers->entdata->options, vers->options)
36 || (/* ...clearing stickies... */
39 && (/* ...there used to be a tag which subs in Name keys... */
40 (vers->entdata->tag && !isdigit (vers->entdata->tag[0])
41 && vers->tag && !isdigit (vers->tag[0])
42 && strcmp (vers->entdata->tag, vers->tag))
43 /* ...or there used to be a keyword mode which may be
46 || (strlen (vers->entdata->options)
47 && strcmp (vers->entdata->options, vers->options)
48 && strcmp (vers->entdata->options, "-kkv")
49 && strcmp (vers->entdata->options, "-kb"))))
51 || (/* ...this is not commit... */
52 strcmp (cvs_cmd_name, "commit")
54 && (/* ...the tag is changing in a way that affects Name keys... */
55 (vers->entdata->tag && vers->tag
56 && strcmp (vers->entdata->tag, vers->tag)
57 && !(isdigit (vers->entdata->tag[0])
58 && isdigit (vers->entdata->tag[0])))
59 || (!vers->entdata->tag && vers->tag
60 && !isdigit (vers->tag[0])))))
71 * Classify the state of a file
74 Classify_File (finfo, tag, date, options, force_tag_match, aflag, versp,
76 struct file_info *finfo;
80 /* Keyword expansion options. Can be either NULL or "" to
81 indicate none are specified here. */
92 /* get all kinds of good data about the file */
93 vers = Version_TS (finfo, options, tag, date,
96 if (vers->vn_user == NULL)
98 /* No entry available, ts_rcs is invalid */
99 if (vers->vn_rcs == NULL)
101 /* there is no RCS file either */
102 if (vers->ts_user == NULL)
104 /* there is no user file */
105 /* FIXME: Why do we skip this message if vers->tag or
106 vers->date is set? It causes "cvs update -r tag98 foo"
107 to silently do nothing, which is seriously confusing
108 behavior. "cvs update foo" gives this message, which
109 is what I would expect. */
110 if (!force_tag_match || !(vers->tag || vers->date))
112 error (0, 0, "nothing known about %s", finfo->fullname);
117 /* there is a user file */
118 /* FIXME: Why do we skip this message if vers->tag or
119 vers->date is set? It causes "cvs update -r tag98 foo"
120 to silently do nothing, which is seriously confusing
121 behavior. "cvs update foo" gives this message, which
122 is what I would expect. */
123 if (!force_tag_match || !(vers->tag || vers->date))
125 error (0, 0, "use `%s add' to create an entry for %s",
126 program_name, finfo->fullname);
130 else if (RCS_isdead (vers->srcfile, vers->vn_rcs))
132 /* there is an RCS file, but it's dead */
133 if (vers->ts_user == NULL)
137 error (0, 0, "use `%s add' to create an entry for %s",
138 program_name, finfo->fullname);
142 else if (!pipeout && vers->ts_user && No_Difference (finfo, vers))
144 /* the files were different so it is a conflict */
146 error (0, 0, "move away %s; it is in the way",
151 /* no user file or no difference, just checkout */
154 else if (strcmp (vers->vn_user, "0") == 0)
156 /* An entry for a new-born file; ts_rcs is dummy */
158 if (vers->ts_user == NULL)
167 * There is no user file, but there should be one; remove the
171 error (0, 0, "warning: new-born %s has disappeared",
173 ret = T_REMOVE_ENTRY;
176 else if (vers->vn_rcs == NULL ||
177 RCS_isdead (vers->srcfile, vers->vn_rcs))
178 /* No RCS file or RCS file revision is dead */
188 if (vers->srcfile->flags & INATTIC
189 && vers->srcfile->flags & VALID)
191 /* This file has been added on some branch other than
192 the one we are looking at. In the branch we are
193 looking at, the file was already valid. */
196 "conflict: %s has been added, but already exists",
202 * There is an RCS file, so someone else must have checked
203 * one in behind our back; conflict
207 "conflict: %s created independently by second party",
214 else if (vers->vn_user[0] == '-')
216 /* An entry for a removed file, ts_rcs is invalid */
218 if (vers->ts_user == NULL)
220 /* There is no user file (as it should be) */
222 if (vers->vn_rcs == NULL
223 || RCS_isdead (vers->srcfile, vers->vn_rcs))
227 * There is no RCS file; this is all-right, but it has been
228 * removed independently by a second party; remove the entry
230 ret = T_REMOVE_ENTRY;
232 else if (strcmp (vers->vn_rcs, vers->vn_user + 1) == 0)
234 * The RCS file is the same version as the user file was, and
235 * that's OK; remove it
240 * The RCS file doesn't match the user's file, but it doesn't
241 * matter in this case
248 * The RCS file is a newer version than the removed user file
249 * and this is definitely not OK; make it a conflict.
253 "conflict: removed %s was modified by second party",
260 /* The user file shouldn't be there */
262 error (0, 0, "%s should be removed and is still there",
269 /* A normal entry, TS_Rcs is valid */
270 if (vers->vn_rcs == NULL || RCS_isdead (vers->srcfile, vers->vn_rcs))
272 /* There is no RCS file */
274 if (vers->ts_user == NULL)
276 /* There is no user file, so just remove the entry */
278 error (0, 0, "warning: %s is not (any longer) pertinent",
280 ret = T_REMOVE_ENTRY;
282 else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
286 * The user file is still unmodified, so just remove it from
290 error (0, 0, "%s is no longer in the repository",
292 ret = T_REMOVE_ENTRY;
294 else if (No_Difference (finfo, vers))
296 /* they are different -> conflict */
299 "conflict: %s is modified but no longer in the repository",
305 /* they weren't really different */
308 "warning: %s is not (any longer) pertinent",
310 ret = T_REMOVE_ENTRY;
313 else if (strcmp (vers->vn_rcs, vers->vn_user) == 0)
315 /* The RCS file is the same version as the user file */
317 if (vers->ts_user == NULL)
321 * There is no user file, so note that it was lost and
322 * extract a new version
324 /* Comparing the cvs_cmd_name against "update", in
325 addition to being an ugly way to operate, means
326 that this message does not get printed by the
327 server. That might be considered just a straight
328 bug, although there is one subtlety: that case also
329 gets hit when a patch fails and the client fetches
330 a file. I'm not sure there is currently any way
331 for the server to distinguish those two cases. */
332 if (strcmp (cvs_cmd_name, "update") == 0)
334 error (0, 0, "warning: %s was lost", finfo->fullname);
337 else if (!strcmp (vers->ts_user,
339 ? vers->ts_conflict : vers->ts_rcs))
343 * The user file is still unmodified, so nothing special at
344 * all to do -- no lists updated, unless the sticky -k option
345 * has changed. If the sticky tag has changed, we just need
346 * to re-register the entry
348 /* TODO: decide whether we need to check file permissions
349 for a mismatch, and return T_CONFLICT if so. */
350 if (keywords_may_change (aflag, vers))
352 else if (vers->ts_conflict)
357 sticky_ck (finfo, aflag, vers);
360 else if (No_Difference (finfo, vers))
364 * they really are different; modified if we aren't
365 * changing any sticky -k options, else needs merge
367 #ifdef XXX_FIXME_WHEN_RCSMERGE_IS_FIXED
368 if (strcmp (vers->entdata->options ?
369 vers->entdata->options : "", vers->options) == 0)
374 /* Files with conflict markers and new timestamps fall through
375 * here, but they need to. T_CONFLICT is an error in
376 * commit_fileproc, whereas T_CONFLICT with conflict markers
377 * is caught but only warned about. Similarly, update_fileproc
378 * currently reregisters a file that was conflicted but lost
382 sticky_ck (finfo, aflag, vers);
385 else if (strcmp (vers->entdata->options ?
386 vers->entdata->options : "", vers->options) != 0)
388 /* file has not changed; check out if -k changed */
395 * else -> note that No_Difference will Register the
396 * file already for us, using the new tag/date. This
397 * is the desired behaviour
404 /* The RCS file is a newer version than the user file */
406 if (vers->ts_user == NULL)
408 /* There is no user file, so just get it */
410 /* See comment at other "update" compare, for more
411 thoughts on this comparison. */
412 if (strcmp (cvs_cmd_name, "update") == 0)
414 error (0, 0, "warning: %s was lost", finfo->fullname);
417 else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
420 * The user file is still unmodified, so just get it as well
423 else if (No_Difference (finfo, vers))
424 /* really modified, needs to merge */
431 /* free up the vers struct, or just return it */
432 if (versp != (Vers_TS **) NULL)
437 /* return the status of the file */
442 sticky_ck (finfo, aflag, vers)
443 struct file_info *finfo;
447 if (aflag || vers->tag || vers->date)
449 char *enttag = vers->entdata->tag;
450 char *entdate = vers->entdata->date;
452 if ((enttag && vers->tag && strcmp (enttag, vers->tag)) ||
453 ((enttag && !vers->tag) || (!enttag && vers->tag)) ||
454 (entdate && vers->date && strcmp (entdate, vers->date)) ||
455 ((entdate && !vers->date) || (!entdate && vers->date)))
457 Register (finfo->entries, finfo->file, vers->vn_user, vers->ts_rcs,
458 vers->options, vers->tag, vers->date, vers->ts_conflict);
460 #ifdef SERVER_SUPPORT
463 /* We need to update the entries line on the client side.
464 It is possible we will later update it again via
465 server_updated or some such, but that is OK. */
466 server_update_entries
467 (finfo->file, finfo->update_dir, finfo->repository,
468 strcmp (vers->ts_rcs, vers->ts_user) == 0 ?
469 SERVER_UPDATED : SERVER_MERGED);