]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/cvs/src/classify.c
This commit was generated by cvs2svn to compensate for changes in r173932,
[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             /* there is an RCS file, but it's dead */
78             if (vers->ts_user == NULL)
79                 ret = T_UPTODATE;
80             else
81             {
82                 error (0, 0, "use `%s add' to create an entry for %s",
83                        program_name, finfo->fullname);
84                 ret = T_UNKNOWN;
85             }
86         }
87         else if (!pipeout && vers->ts_user && No_Difference (finfo, vers))
88         {
89             /* the files were different so it is a conflict */
90             if (!really_quiet)
91                 error (0, 0, "move away %s; it is in the way",
92                        finfo->fullname);
93             ret = T_CONFLICT;
94         }
95         else
96             /* no user file or no difference, just checkout */
97             ret = T_CHECKOUT;
98     }
99     else if (strcmp (vers->vn_user, "0") == 0)
100     {
101         /* An entry for a new-born file; ts_rcs is dummy */
102
103         if (vers->ts_user == NULL)
104         {
105             if (pipeout)
106             {
107                 ret = T_CHECKOUT;
108             }
109             else
110             {
111                 /*
112                  * There is no user file, but there should be one; remove the
113                  * entry
114                  */
115                 if (!really_quiet)
116                     error (0, 0, "warning: new-born %s has disappeared",
117                            finfo->fullname);
118                 ret = T_REMOVE_ENTRY;
119             }
120         }
121         else if (vers->vn_rcs == NULL ||
122                  RCS_isdead (vers->srcfile, vers->vn_rcs))
123             /* No RCS file or RCS file revision is dead  */
124             ret = T_ADDED;
125         else
126         {
127             if (pipeout)
128             {
129                 ret = T_CHECKOUT;
130             }
131             else
132             {
133                 if (vers->srcfile->flags & INATTIC
134                     && vers->srcfile->flags & VALID)
135                 {
136                     /* This file has been added on some branch other than
137                        the one we are looking at.  In the branch we are
138                        looking at, the file was already valid.  */
139                     if (!really_quiet)
140                         error (0, 0,
141                            "conflict: %s has been added, but already exists",
142                                finfo->fullname);
143                 }
144                 else
145                 {
146                     /*
147                      * There is an RCS file, so someone else must have checked
148                      * one in behind our back; conflict
149                      */
150                     if (!really_quiet)
151                         error (0, 0,
152                            "conflict: %s created independently by second party",
153                                finfo->fullname);
154                 }
155                 ret = T_CONFLICT;
156             }
157         }
158     }
159     else if (vers->vn_user[0] == '-')
160     {
161         /* An entry for a removed file, ts_rcs is invalid */
162
163         if (vers->ts_user == NULL)
164         {
165             /* There is no user file (as it should be) */
166
167             if (vers->vn_rcs == NULL
168                 || RCS_isdead (vers->srcfile, vers->vn_rcs))
169             {
170
171                 /*
172                  * There is no RCS file; this is all-right, but it has been
173                  * removed independently by a second party; remove the entry
174                  */
175                 ret = T_REMOVE_ENTRY;
176             }
177             else if (strcmp (vers->vn_rcs, vers->vn_user + 1) == 0)
178                 /*
179                  * The RCS file is the same version as the user file was, and
180                  * that's OK; remove it
181                  */
182                 ret = T_REMOVED;
183             else if (pipeout)
184                 /*
185                  * The RCS file doesn't match the user's file, but it doesn't
186                  * matter in this case
187                  */
188                 ret = T_NEEDS_MERGE;
189             else
190             {
191
192                 /*
193                  * The RCS file is a newer version than the removed user file
194                  * and this is definitely not OK; make it a conflict.
195                  */
196                 if (!really_quiet)
197                     error (0, 0,
198                            "conflict: removed %s was modified by second party",
199                            finfo->fullname);
200                 ret = T_CONFLICT;
201             }
202         }
203         else
204         {
205             /* The user file shouldn't be there */
206             if (!really_quiet)
207                 error (0, 0, "%s should be removed and is still there",
208                        finfo->fullname);
209             ret = T_REMOVED;
210         }
211     }
212     else
213     {
214         /* A normal entry, TS_Rcs is valid */
215         if (vers->vn_rcs == NULL || RCS_isdead (vers->srcfile, vers->vn_rcs))
216         {
217             /* There is no RCS file */
218
219             if (vers->ts_user == NULL)
220             {
221                 /* There is no user file, so just remove the entry */
222                 if (!really_quiet)
223                     error (0, 0, "warning: %s is not (any longer) pertinent",
224                            finfo->fullname);
225                 ret = T_REMOVE_ENTRY;
226             }
227             else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
228             {
229
230                 /*
231                  * The user file is still unmodified, so just remove it from
232                  * the entry list
233                  */
234                 if (!really_quiet)
235                     error (0, 0, "%s is no longer in the repository",
236                            finfo->fullname);
237                 ret = T_REMOVE_ENTRY;
238             }
239             else if (No_Difference (finfo, vers))
240             {
241                 /* they are different -> conflict */
242                 if (!really_quiet)
243                     error (0, 0,
244                "conflict: %s is modified but no longer in the repository",
245                            finfo->fullname);
246                 ret = T_CONFLICT;
247             }
248             else
249             {
250                 /* they weren't really different */
251                 if (!really_quiet)
252                     error (0, 0,
253                            "warning: %s is not (any longer) pertinent",
254                            finfo->fullname);
255                 ret = T_REMOVE_ENTRY;
256             }
257         }
258         else if (strcmp (vers->vn_rcs, vers->vn_user) == 0)
259         {
260             /* The RCS file is the same version as the user file */
261
262             if (vers->ts_user == NULL)
263             {
264
265                 /*
266                  * There is no user file, so note that it was lost and
267                  * extract a new version
268                  */
269                 /* Comparing the cvs_cmd_name against "update", in
270                    addition to being an ugly way to operate, means
271                    that this message does not get printed by the
272                    server.  That might be considered just a straight
273                    bug, although there is one subtlety: that case also
274                    gets hit when a patch fails and the client fetches
275                    a file.  I'm not sure there is currently any way
276                    for the server to distinguish those two cases.  */
277                 if (strcmp (cvs_cmd_name, "update") == 0)
278                     if (!really_quiet)
279                         error (0, 0, "warning: %s was lost", finfo->fullname);
280                 ret = T_CHECKOUT;
281             }
282             else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
283             {
284
285                 /*
286                  * The user file is still unmodified, so nothing special at
287                  * all to do -- no lists updated, unless the sticky -k option
288                  * has changed.  If the sticky tag has changed, we just need
289                  * to re-register the entry
290                  */
291                 /* TODO: decide whether we need to check file permissions
292                    for a mismatch, and return T_CONFLICT if so. */
293                 if (vers->entdata->options &&
294                     strcmp (vers->entdata->options, vers->options) != 0)
295                     ret = T_CHECKOUT;
296                 else
297                 {
298                     sticky_ck (finfo, aflag, vers);
299                     ret = T_UPTODATE;
300                 }
301             }
302             else if (No_Difference (finfo, vers))
303             {
304
305                 /*
306                  * they really are different; modified if we aren't
307                  * changing any sticky -k options, else needs merge
308                  */
309 #ifdef XXX_FIXME_WHEN_RCSMERGE_IS_FIXED
310                 if (strcmp (vers->entdata->options ?
311                        vers->entdata->options : "", vers->options) == 0)
312                     ret = T_MODIFIED;
313                 else
314                     ret = T_NEEDS_MERGE;
315 #else
316                 ret = T_MODIFIED;
317                 sticky_ck (finfo, aflag, vers);
318 #endif
319             }
320             else if (strcmp (vers->entdata->options ?
321                        vers->entdata->options : "", vers->options) != 0)
322             {
323                 /* file has not changed; check out if -k changed */
324                 ret = T_CHECKOUT;
325             }
326             else
327             {
328
329                 /*
330                  * else -> note that No_Difference will Register the
331                  * file already for us, using the new tag/date. This
332                  * is the desired behaviour
333                  */
334                 ret = T_UPTODATE;
335             }
336         }
337         else
338         {
339             /* The RCS file is a newer version than the user file */
340
341             if (vers->ts_user == NULL)
342             {
343                 /* There is no user file, so just get it */
344
345                 /* See comment at other "update" compare, for more
346                    thoughts on this comparison.  */
347                 if (strcmp (cvs_cmd_name, "update") == 0)
348                     if (!really_quiet)
349                         error (0, 0, "warning: %s was lost", finfo->fullname);
350                 ret = T_CHECKOUT;
351             }
352             else if (strcmp (vers->ts_user, vers->ts_rcs) == 0)
353             {
354
355                 /*
356                  * The user file is still unmodified, so just get it as well
357                  */
358                 if (strcmp (vers->entdata->options ?
359                             vers->entdata->options : "", vers->options) != 0
360                     || (vers->srcfile != NULL
361                         && (vers->srcfile->flags & INATTIC) != 0))
362                     ret = T_CHECKOUT;
363                 else
364                     ret = T_PATCH;
365             }
366             else if (No_Difference (finfo, vers))
367                 /* really modified, needs to merge */
368                 ret = T_NEEDS_MERGE;
369             else if ((strcmp (vers->entdata->options ?
370                               vers->entdata->options : "", vers->options)
371                       != 0)
372                      || (vers->srcfile != NULL
373                          && (vers->srcfile->flags & INATTIC) != 0))
374                 /* not really modified, check it out */
375                 ret = T_CHECKOUT;
376             else
377                 ret = T_PATCH;
378         }
379     }
380
381     /* free up the vers struct, or just return it */
382     if (versp != (Vers_TS **) NULL)
383         *versp = vers;
384     else
385         freevers_ts (&vers);
386
387     /* return the status of the file */
388     return (ret);
389 }
390
391 static void
392 sticky_ck (finfo, aflag, vers)
393     struct file_info *finfo;
394     int aflag;
395     Vers_TS *vers;
396 {
397     if (aflag || vers->tag || vers->date)
398     {
399         char *enttag = vers->entdata->tag;
400         char *entdate = vers->entdata->date;
401
402         if ((enttag && vers->tag && strcmp (enttag, vers->tag)) ||
403             ((enttag && !vers->tag) || (!enttag && vers->tag)) ||
404             (entdate && vers->date && strcmp (entdate, vers->date)) ||
405             ((entdate && !vers->date) || (!entdate && vers->date)))
406         {
407             Register (finfo->entries, finfo->file, vers->vn_user, vers->ts_rcs,
408                       vers->options, vers->tag, vers->date, vers->ts_conflict);
409
410 #ifdef SERVER_SUPPORT
411             if (server_active)
412             {
413                 /* We need to update the entries line on the client side.
414                    It is possible we will later update it again via
415                    server_updated or some such, but that is OK.  */
416                 server_update_entries
417                   (finfo->file, finfo->update_dir, finfo->repository,
418                    strcmp (vers->ts_rcs, vers->ts_user) == 0 ?
419                    SERVER_UPDATED : SERVER_MERGED);
420             }
421 #endif
422         }
423     }
424 }