]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/cvs/src/classify.c
This commit was generated by cvs2svn to compensate for changes in r49795,
[FreeBSD/FreeBSD.git] / contrib / cvs / src / classify.c
1 /*
2  * Copyright (c) 1992, Brian Berliner and Jeff Polk
3  * Copyright (c) 1989-1992, Brian Berliner
4  * 
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.
7  * 
8  */
9
10 #include "cvs.h"
11
12 static void sticky_ck PROTO ((struct file_info *finfo, int aflag,
13                               Vers_TS * vers));
14
15 /*
16  * Classify the state of a file
17  */
18 Ctype
19 Classify_File (finfo, tag, date, options, force_tag_match, aflag, versp,
20                pipeout)
21     struct file_info *finfo;
22     char *tag;
23     char *date;
24
25     /* Keyword expansion options.  Can be either NULL or "" to
26        indicate none are specified here.  */
27     char *options;
28
29     int force_tag_match;
30     int aflag;
31     Vers_TS **versp;
32     int pipeout;
33 {
34     Vers_TS *vers;
35     Ctype ret;
36
37     /* get all kinds of good data about the file */
38     vers = Version_TS (finfo, options, tag, date,
39                        force_tag_match, 0);
40
41     if (vers->vn_user == NULL)
42     {
43         /* No entry available, ts_rcs is invalid */
44         if (vers->vn_rcs == NULL)
45         {
46             /* there is no RCS file either */
47             if (vers->ts_user == NULL)
48             {
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))
56                     if (!really_quiet)
57                         error (0, 0, "nothing known about %s", finfo->fullname);
58                 ret = T_UNKNOWN;
59             }
60             else
61             {
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))
69                     if (!really_quiet)
70                         error (0, 0, "use `%s add' to create an entry for %s",
71                                program_name, finfo->fullname);
72                 ret = T_UNKNOWN;
73             }
74         }
75         else if (RCS_isdead (vers->srcfile, vers->vn_rcs))
76         {
77             if (vers->ts_user == NULL)
78                 ret = T_UPTODATE;
79             else
80             {
81                 error (0, 0, "use `%s add' to create an entry for %s",
82                        program_name, finfo->fullname);
83                 ret = T_UNKNOWN;
84             }
85         }
86         else
87         {
88             /* there is an rcs file */
89
90             if (vers->ts_user == NULL)
91             {
92                 /* There is no user file; needs checkout */
93                 ret = T_CHECKOUT;
94             }
95             else
96             {
97                 if (pipeout)
98                 {
99                     /*
100                      * The user file doesn't necessarily have anything
101                      * to do with this.
102                      */
103                     ret = T_CHECKOUT;
104                 }
105                 /*
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
108                  * plan to extract
109                  */
110                 else if (No_Difference (finfo, vers))
111                 {
112                     /* the files were different so it is a conflict */
113                     if (!really_quiet)
114                         error (0, 0, "move away %s; it is in the way",
115                                finfo->fullname);
116                     ret = T_CONFLICT;
117                 }
118                 else
119                     /* since there was no difference, still needs checkout */
120                     ret = T_CHECKOUT;
121             }
122         }
123     }
124     else if (strcmp (vers->vn_user, "0") == 0)
125     {
126         /* An entry for a new-born file; ts_rcs is dummy */
127
128         if (vers->ts_user == NULL)
129         {
130             /*
131              * There is no user file, but there should be one; remove the
132              * entry
133              */
134             if (!really_quiet)
135                 error (0, 0, "warning: new-born %s has disappeared", finfo->fullname);
136             ret = T_REMOVE_ENTRY;
137         }
138         else
139         {
140             /* There is a user file */
141
142             if (vers->vn_rcs == NULL)
143                 /* There is no RCS file, added file */
144                 ret = T_ADDED;
145             else if (RCS_isdead (vers->srcfile, vers->vn_rcs))
146                 /* we are resurrecting. */
147                 ret = T_ADDED;
148             else
149             {
150                 if (vers->srcfile->flags & INATTIC
151                     && vers->srcfile->flags & VALID)
152                 {
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.  */
156                     if (!really_quiet)
157                         error (0, 0,
158                                "\
159 conflict: %s has been added, but already exists",
160                                finfo->fullname);
161                 }
162                 else
163                 {
164                     /*
165                      * There is an RCS file, so someone else must have checked
166                      * one in behind our back; conflict
167                      */
168                     if (!really_quiet)
169                         error (0, 0,
170                                "\
171 conflict: %s created independently by second party",
172                                finfo->fullname);
173                 }
174                 ret = T_CONFLICT;
175             }
176         }
177     }
178     else if (vers->vn_user[0] == '-')
179     {
180         /* An entry for a removed file, ts_rcs is invalid */
181
182         if (vers->ts_user == NULL)
183         {
184             /* There is no user file (as it should be) */
185
186             if (vers->vn_rcs == NULL
187                 || RCS_isdead (vers->srcfile, vers->vn_rcs))
188             {
189
190                 /*
191                  * There is no RCS file; this is all-right, but it has been
192                  * removed independently by a second party; remove the entry
193                  */
194                 ret = T_REMOVE_ENTRY;
195             }
196             else if (vers->vn_rcs == NULL
197                      ? vers->vn_user[1] == '\0'
198                      : strcmp (vers->vn_rcs, vers->vn_user + 1) == 0)
199                 /*
200                  * The RCS file is the same version as the user file was, and
201                  * that's OK; remove it
202                  */
203                 ret = T_REMOVED;
204             else
205             {
206
207                 /*
208                  * The RCS file is a newer version than the removed user file
209                  * and this is definitely not OK; make it a conflict.
210                  */
211                 if (!really_quiet)
212                     error (0, 0,
213                            "conflict: removed %s was modified by second party",
214                            finfo->fullname);
215                 ret = T_CONFLICT;
216             }
217         }
218         else
219         {
220             /* The user file shouldn't be there */
221             if (!really_quiet)
222                 error (0, 0, "%s should be removed and is still there",
223                        finfo->fullname);
224             ret = T_REMOVED;
225         }
226     }
227     else
228     {
229         /* A normal entry, TS_Rcs is valid */
230         if (vers->vn_rcs == NULL)
231         {
232             /* There is no RCS file */
233
234             if (vers->ts_user == NULL)
235             {
236                 /* There is no user file, so just remove the entry */
237                 if (!really_quiet)
238                     error (0, 0, "warning: %s is not (any longer) pertinent",
239                            finfo->fullname);
240                 ret = T_REMOVE_ENTRY;
241             }
242             else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
243             {
244
245                 /*
246                  * The user file is still unmodified, so just remove it from
247                  * the entry list
248                  */
249                 if (!really_quiet)
250                     error (0, 0, "%s is no longer in the repository",
251                            finfo->fullname);
252                 ret = T_REMOVE_ENTRY;
253             }
254             else
255             {
256                 /*
257                  * The user file has been modified and since it is no longer
258                  * in the repository, a conflict is raised
259                  */
260                 if (No_Difference (finfo, vers))
261                 {
262                     /* they are different -> conflict */
263                     if (!really_quiet)
264                         error (0, 0,
265                "conflict: %s is modified but no longer in the repository",
266                            finfo->fullname);
267                     ret = T_CONFLICT;
268                 }
269                 else
270                 {
271                     /* they weren't really different */
272                     if (!really_quiet)
273                         error (0, 0,
274                                "warning: %s is not (any longer) pertinent",
275                                finfo->fullname);
276                     ret = T_REMOVE_ENTRY;
277                 }
278             }
279         }
280         else if (strcmp (vers->vn_rcs, vers->vn_user) == 0)
281         {
282             /* The RCS file is the same version as the user file */
283
284             if (vers->ts_user == NULL)
285             {
286
287                 /*
288                  * There is no user file, so note that it was lost and
289                  * extract a new version
290                  */
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)
300                     if (!really_quiet)
301                         error (0, 0, "warning: %s was lost", finfo->fullname);
302                 ret = T_CHECKOUT;
303             }
304             else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
305             {
306
307                 /*
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
312                  */
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)
317                     ret = T_CHECKOUT;
318                 else
319                 {
320                     sticky_ck (finfo, aflag, vers);
321                     ret = T_UPTODATE;
322                 }
323             }
324             else
325             {
326
327                 /*
328                  * The user file appears to have been modified, but we call
329                  * No_Difference to verify that it really has been modified
330                  */
331                 if (No_Difference (finfo, vers))
332                 {
333
334                     /*
335                      * they really are different; modified if we aren't
336                      * changing any sticky -k options, else needs merge
337                      */
338 #ifdef XXX_FIXME_WHEN_RCSMERGE_IS_FIXED
339                     if (strcmp (vers->entdata->options ?
340                            vers->entdata->options : "", vers->options) == 0)
341                         ret = T_MODIFIED;
342                     else
343                         ret = T_NEEDS_MERGE;
344 #else
345                     ret = T_MODIFIED;
346                     sticky_ck (finfo, aflag, vers);
347 #endif
348                 }
349                 else
350                 {
351                     /* file has not changed; check out if -k changed */
352                     if (strcmp (vers->entdata->options ?
353                            vers->entdata->options : "", vers->options) != 0)
354                     {
355                         ret = T_CHECKOUT;
356                     }
357                     else
358                     {
359
360                         /*
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
364                          */
365                         ret = T_UPTODATE;
366                     }
367                 }
368             }
369         }
370         else
371         {
372             /* The RCS file is a newer version than the user file */
373
374             if (vers->ts_user == NULL)
375             {
376                 /* There is no user file, so just get it */
377
378                 /* See comment at other "update" compare, for more
379                    thoughts on this comparison.  */
380                 if (strcmp (command_name, "update") == 0)
381                     if (!really_quiet)
382                         error (0, 0, "warning: %s was lost", finfo->fullname);
383                 ret = T_CHECKOUT;
384             }
385             else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
386             {
387
388                 /*
389                  * The user file is still unmodified, so just get it as well
390                  */
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))
396                     ret = T_CHECKOUT;
397                 else
398                     ret = T_PATCH;
399 #else
400                 ret = T_CHECKOUT;
401 #endif
402             }
403             else
404             {
405                 if (No_Difference (finfo, vers))
406                     /* really modified, needs to merge */
407                     ret = T_NEEDS_MERGE;
408 #ifdef SERVER_SUPPORT
409                 else if ((strcmp (vers->entdata->options ?
410                                   vers->entdata->options : "", vers->options)
411                           != 0)
412                          || (vers->srcfile != NULL
413                              && (vers->srcfile->flags & INATTIC) != 0))
414                     /* not really modified, check it out */
415                     ret = T_CHECKOUT;
416                 else
417                     ret = T_PATCH;
418 #else
419                 else
420                     /* not really modified, check it out */
421                     ret = T_CHECKOUT;
422 #endif
423             }
424         }
425     }
426
427     /* free up the vers struct, or just return it */
428     if (versp != (Vers_TS **) NULL)
429         *versp = vers;
430     else
431         freevers_ts (&vers);
432
433     /* return the status of the file */
434     return (ret);
435 }
436
437 static void
438 sticky_ck (finfo, aflag, vers)
439     struct file_info *finfo;
440     int aflag;
441     Vers_TS *vers;
442 {
443     if (aflag || vers->tag || vers->date)
444     {
445         char *enttag = vers->entdata->tag;
446         char *entdate = vers->entdata->date;
447
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)))
452         {
453             Register (finfo->entries, finfo->file, vers->vn_user, vers->ts_rcs,
454                       vers->options, vers->tag, vers->date, vers->ts_conflict);
455
456 #ifdef SERVER_SUPPORT
457             if (server_active)
458             {
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);
466             }
467 #endif
468         }
469     }
470 }