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 PROTO ((struct file_info *finfo, int aflag,
16 * Classify the state of a file
19 Classify_File (finfo, tag, date, options, force_tag_match, aflag, versp,
21 struct file_info *finfo;
25 /* Keyword expansion options. Can be either NULL or "" to
26 indicate none are specified here. */
37 /* get all kinds of good data about the file */
38 vers = Version_TS (finfo, options, tag, date,
41 if (vers->vn_user == NULL)
43 /* No entry available, ts_rcs is invalid */
44 if (vers->vn_rcs == NULL)
46 /* there is no RCS file either */
47 if (vers->ts_user == NULL)
49 /* there is no user file */
50 /* FIXME: Why do we skip this message if vers->tag or
51 vers->date is set? It causes "cvs update -r tag98 foo"
52 to silently do nothing, which is seriously confusing
53 behavior. "cvs update foo" gives this message, which
54 is what I would expect. */
55 if (!force_tag_match || !(vers->tag || vers->date))
57 error (0, 0, "nothing known about %s", finfo->fullname);
62 /* there is a user file */
63 /* FIXME: Why do we skip this message if vers->tag or
64 vers->date is set? It causes "cvs update -r tag98 foo"
65 to silently do nothing, which is seriously confusing
66 behavior. "cvs update foo" gives this message, which
67 is what I would expect. */
68 if (!force_tag_match || !(vers->tag || vers->date))
70 error (0, 0, "use `%s add' to create an entry for %s",
71 program_name, finfo->fullname);
75 else if (RCS_isdead (vers->srcfile, vers->vn_rcs))
77 if (vers->ts_user == NULL)
81 error (0, 0, "use `%s add' to create an entry for %s",
82 program_name, finfo->fullname);
88 /* there is an rcs file */
90 if (vers->ts_user == NULL)
92 /* There is no user file; needs checkout */
100 * The user file doesn't necessarily have anything
106 * There is a user file; print a warning and add it to the
107 * conflict list, only if it is indeed different from what we
110 else if (No_Difference (finfo, vers))
112 /* the files were different so it is a conflict */
114 error (0, 0, "move away %s; it is in the way",
119 /* since there was no difference, still needs checkout */
124 else if (strcmp (vers->vn_user, "0") == 0)
126 /* An entry for a new-born file; ts_rcs is dummy */
128 if (vers->ts_user == NULL)
131 * There is no user file, but there should be one; remove the
135 error (0, 0, "warning: new-born %s has disappeared", finfo->fullname);
136 ret = T_REMOVE_ENTRY;
140 /* There is a user file */
142 if (vers->vn_rcs == NULL)
143 /* There is no RCS file, added file */
145 else if (RCS_isdead (vers->srcfile, vers->vn_rcs))
146 /* we are resurrecting. */
150 if (vers->srcfile->flags & INATTIC
151 && vers->srcfile->flags & VALID)
153 /* This file has been added on some branch other than
154 the one we are looking at. In the branch we are
155 looking at, the file was already valid. */
159 conflict: %s has been added, but already exists",
165 * There is an RCS file, so someone else must have checked
166 * one in behind our back; conflict
171 conflict: %s created independently by second party",
178 else if (vers->vn_user[0] == '-')
180 /* An entry for a removed file, ts_rcs is invalid */
182 if (vers->ts_user == NULL)
184 /* There is no user file (as it should be) */
186 if (vers->vn_rcs == NULL
187 || RCS_isdead (vers->srcfile, vers->vn_rcs))
191 * There is no RCS file; this is all-right, but it has been
192 * removed independently by a second party; remove the entry
194 ret = T_REMOVE_ENTRY;
196 else if (vers->vn_rcs == NULL
197 ? vers->vn_user[1] == '\0'
198 : strcmp (vers->vn_rcs, vers->vn_user + 1) == 0)
200 * The RCS file is the same version as the user file was, and
201 * that's OK; remove it
208 * The RCS file is a newer version than the removed user file
209 * and this is definitely not OK; make it a conflict.
213 "conflict: removed %s was modified by second party",
220 /* The user file shouldn't be there */
222 error (0, 0, "%s should be removed and is still there",
229 /* A normal entry, TS_Rcs is valid */
230 if (vers->vn_rcs == NULL)
232 /* There is no RCS file */
234 if (vers->ts_user == NULL)
236 /* There is no user file, so just remove the entry */
238 error (0, 0, "warning: %s is not (any longer) pertinent",
240 ret = T_REMOVE_ENTRY;
242 else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
246 * The user file is still unmodified, so just remove it from
250 error (0, 0, "%s is no longer in the repository",
252 ret = T_REMOVE_ENTRY;
257 * The user file has been modified and since it is no longer
258 * in the repository, a conflict is raised
260 if (No_Difference (finfo, vers))
262 /* they are different -> conflict */
265 "conflict: %s is modified but no longer in the repository",
271 /* they weren't really different */
274 "warning: %s is not (any longer) pertinent",
276 ret = T_REMOVE_ENTRY;
280 else if (strcmp (vers->vn_rcs, vers->vn_user) == 0)
282 /* The RCS file is the same version as the user file */
284 if (vers->ts_user == NULL)
288 * There is no user file, so note that it was lost and
289 * extract a new version
291 /* Comparing the command_name against "update", in
292 addition to being an ugly way to operate, means
293 that this message does not get printed by the
294 server. That might be considered just a straight
295 bug, although there is one subtlety: that case also
296 gets hit when a patch fails and the client fetches
297 a file. I'm not sure there is currently any way
298 for the server to distinguish those two cases. */
299 if (strcmp (command_name, "update") == 0)
301 error (0, 0, "warning: %s was lost", finfo->fullname);
304 else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
308 * The user file is still unmodified, so nothing special at
309 * all to do -- no lists updated, unless the sticky -k option
310 * has changed. If the sticky tag has changed, we just need
311 * to re-register the entry
313 /* TODO: decide whether we need to check file permissions
314 for a mismatch, and return T_CONFLICT if so. */
315 if (vers->entdata->options &&
316 strcmp (vers->entdata->options, vers->options) != 0)
320 sticky_ck (finfo, aflag, vers);
328 * The user file appears to have been modified, but we call
329 * No_Difference to verify that it really has been modified
331 if (No_Difference (finfo, vers))
335 * they really are different; modified if we aren't
336 * changing any sticky -k options, else needs merge
338 #ifdef XXX_FIXME_WHEN_RCSMERGE_IS_FIXED
339 if (strcmp (vers->entdata->options ?
340 vers->entdata->options : "", vers->options) == 0)
346 sticky_ck (finfo, aflag, vers);
351 /* file has not changed; check out if -k changed */
352 if (strcmp (vers->entdata->options ?
353 vers->entdata->options : "", vers->options) != 0)
361 * else -> note that No_Difference will Register the
362 * file already for us, using the new tag/date. This
363 * is the desired behaviour
372 /* The RCS file is a newer version than the user file */
374 if (vers->ts_user == NULL)
376 /* There is no user file, so just get it */
378 /* See comment at other "update" compare, for more
379 thoughts on this comparison. */
380 if (strcmp (command_name, "update") == 0)
382 error (0, 0, "warning: %s was lost", finfo->fullname);
385 else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
389 * The user file is still unmodified, so just get it as well
391 #ifdef SERVER_SUPPORT
392 if (strcmp (vers->entdata->options ?
393 vers->entdata->options : "", vers->options) != 0
394 || (vers->srcfile != NULL
395 && (vers->srcfile->flags & INATTIC) != 0))
405 if (No_Difference (finfo, vers))
406 /* really modified, needs to merge */
408 #ifdef SERVER_SUPPORT
409 else if ((strcmp (vers->entdata->options ?
410 vers->entdata->options : "", vers->options)
412 || (vers->srcfile != NULL
413 && (vers->srcfile->flags & INATTIC) != 0))
414 /* not really modified, check it out */
420 /* not really modified, check it out */
427 /* free up the vers struct, or just return it */
428 if (versp != (Vers_TS **) NULL)
433 /* return the status of the file */
438 sticky_ck (finfo, aflag, vers)
439 struct file_info *finfo;
443 if (aflag || vers->tag || vers->date)
445 char *enttag = vers->entdata->tag;
446 char *entdate = vers->entdata->date;
448 if ((enttag && vers->tag && strcmp (enttag, vers->tag)) ||
449 ((enttag && !vers->tag) || (!enttag && vers->tag)) ||
450 (entdate && vers->date && strcmp (entdate, vers->date)) ||
451 ((entdate && !vers->date) || (!entdate && vers->date)))
453 Register (finfo->entries, finfo->file, vers->vn_user, vers->ts_rcs,
454 vers->options, vers->tag, vers->date, vers->ts_conflict);
456 #ifdef SERVER_SUPPORT
459 /* We need to update the entries line on the client side.
460 It is possible we will later update it again via
461 server_updated or some such, but that is OK. */
462 server_update_entries
463 (finfo->file, finfo->update_dir, finfo->repository,
464 strcmp (vers->ts_rcs, vers->ts_user) == 0 ?
465 SERVER_UPDATED : SERVER_MERGED);