classify.c revision 17721
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 1.4 kit. 7 * 8 */ 9 10#include "cvs.h" 11 12#ifdef SERVER_SUPPORT 13static void sticky_ck PROTO((char *file, int aflag, Vers_TS * vers, 14 List * entries, 15 char *repository, char *update_dir)); 16#else 17static void sticky_ck PROTO((char *file, int aflag, Vers_TS * vers, List * entries)); 18#endif 19 20/* 21 * Classify the state of a file 22 */ 23Ctype 24Classify_File (file, tag, date, options, force_tag_match, aflag, repository, 25 entries, rcsnode, versp, update_dir, pipeout) 26 char *file; 27 char *tag; 28 char *date; 29 char *options; 30 int force_tag_match; 31 int aflag; 32 char *repository; 33 List *entries; 34 RCSNode *rcsnode; 35 Vers_TS **versp; 36 char *update_dir; 37 int pipeout; 38{ 39 Vers_TS *vers; 40 Ctype ret; 41 char *fullname; 42 43 fullname = xmalloc (strlen (update_dir) + strlen (file) + 10); 44 if (update_dir[0] == '\0') 45 strcpy (fullname, file); 46 else 47 sprintf (fullname, "%s/%s", update_dir, file); 48 49 /* get all kinds of good data about the file */ 50 vers = Version_TS (repository, options, tag, date, file, 51 force_tag_match, 0, entries, rcsnode); 52 53 if (vers->vn_user == NULL) 54 { 55 /* No entry available, ts_rcs is invalid */ 56 if (vers->vn_rcs == NULL) 57 { 58 /* there is no RCS file either */ 59 if (vers->ts_user == NULL) 60 { 61 /* there is no user file */ 62 if (!force_tag_match || !(vers->tag || vers->date)) 63 if (!really_quiet) 64 error (0, 0, "nothing known about %s", fullname); 65 ret = T_UNKNOWN; 66 } 67 else 68 { 69 /* there is a user file */ 70 if (!force_tag_match || !(vers->tag || vers->date)) 71 if (!really_quiet) 72 error (0, 0, "use `cvs add' to create an entry for %s", 73 fullname); 74 ret = T_UNKNOWN; 75 } 76 } 77 else if (RCS_isdead (vers->srcfile, vers->vn_rcs)) 78 { 79 if (vers->ts_user == NULL) 80 /* 81 * Logically seems to me this should be T_UPTODATE. 82 * But the joining code in update.c seems to expect 83 * T_CHECKOUT, and that is what has traditionally been 84 * returned for this case. 85 */ 86 ret = T_CHECKOUT; 87 else 88 { 89 error (0, 0, "use `cvs add' to create an entry for %s", 90 fullname); 91 ret = T_UNKNOWN; 92 } 93 } 94 else 95 { 96 /* there is an rcs file */ 97 98 if (vers->ts_user == NULL) 99 { 100 /* There is no user file; needs checkout */ 101 ret = T_CHECKOUT; 102 } 103 else 104 { 105 if (pipeout) 106 { 107 /* 108 * The user file doesn't necessarily have anything 109 * to do with this. 110 */ 111 ret = T_CHECKOUT; 112 } 113 /* 114 * There is a user file; print a warning and add it to the 115 * conflict list, only if it is indeed different from what we 116 * plan to extract 117 */ 118 else if (No_Difference (file, vers, entries, 119 repository, update_dir)) 120 { 121 /* the files were different so it is a conflict */ 122 if (!really_quiet) 123 error (0, 0, "move away %s; it is in the way", 124 fullname); 125 ret = T_CONFLICT; 126 } 127 else 128 /* since there was no difference, still needs checkout */ 129 ret = T_CHECKOUT; 130 } 131 } 132 } 133 else if (strcmp (vers->vn_user, "0") == 0) 134 { 135 /* An entry for a new-born file; ts_rcs is dummy */ 136 137 if (vers->ts_user == NULL) 138 { 139 /* 140 * There is no user file, but there should be one; remove the 141 * entry 142 */ 143 if (!really_quiet) 144 error (0, 0, "warning: new-born %s has disappeared", fullname); 145 ret = T_REMOVE_ENTRY; 146 } 147 else 148 { 149 /* There is a user file */ 150 151 if (vers->vn_rcs == NULL) 152 /* There is no RCS file, added file */ 153 ret = T_ADDED; 154 else if (RCS_isdead (vers->srcfile, vers->vn_rcs)) 155 /* we are resurrecting. */ 156 ret = T_ADDED; 157 else 158 { 159 if (vers->srcfile->flags & INATTIC 160 && vers->srcfile->flags & VALID) 161 { 162 /* This file has been added on some branch other than 163 the one we are looking at. In the branch we are 164 looking at, the file was already valid. */ 165 if (!really_quiet) 166 error (0, 0, 167 "\ 168conflict: %s has been added, but already exists", 169 fullname); 170 } 171 else 172 { 173 /* 174 * There is an RCS file, so someone else must have checked 175 * one in behind our back; conflict 176 */ 177 if (!really_quiet) 178 error (0, 0, 179 "\ 180conflict: %s created independently by second party", 181 fullname); 182 } 183 ret = T_CONFLICT; 184 } 185 } 186 } 187 else if (vers->vn_user[0] == '-') 188 { 189 /* An entry for a removed file, ts_rcs is invalid */ 190 191 if (vers->ts_user == NULL) 192 { 193 char tmp[PATH_MAX]; 194 195 /* There is no user file (as it should be) */ 196 197 (void) sprintf (tmp, "-%s", vers->vn_rcs ? vers->vn_rcs : ""); 198 199 if (vers->vn_rcs == NULL) 200 { 201 202 /* 203 * There is no RCS file; this is all-right, but it has been 204 * removed independently by a second party; remove the entry 205 */ 206 ret = T_REMOVE_ENTRY; 207 } 208 else if (strcmp (tmp, vers->vn_user) == 0) 209 210 /* 211 * The RCS file is the same version as the user file was, and 212 * that's OK; remove it 213 */ 214 ret = T_REMOVED; 215 else 216 { 217 218 /* 219 * The RCS file is a newer version than the removed user file 220 * and this is definitely not OK; make it a conflict. 221 */ 222 if (!really_quiet) 223 error (0, 0, 224 "conflict: removed %s was modified by second party", 225 fullname); 226 ret = T_CONFLICT; 227 } 228 } 229 else 230 { 231 /* The user file shouldn't be there */ 232 if (!really_quiet) 233 error (0, 0, "%s should be removed and is still there", 234 fullname); 235 ret = T_REMOVED; 236 } 237 } 238 else 239 { 240 /* A normal entry, TS_Rcs is valid */ 241 if (vers->vn_rcs == NULL) 242 { 243 /* There is no RCS file */ 244 245 if (vers->ts_user == NULL) 246 { 247 /* There is no user file, so just remove the entry */ 248 if (!really_quiet) 249 error (0, 0, "warning: %s is not (any longer) pertinent", 250 fullname); 251 ret = T_REMOVE_ENTRY; 252 } 253 else if (strcmp (vers->ts_user, vers->ts_rcs) == 0) 254 { 255 256 /* 257 * The user file is still unmodified, so just remove it from 258 * the entry list 259 */ 260 if (!really_quiet) 261 error (0, 0, "%s is no longer in the repository", 262 fullname); 263 ret = T_REMOVE_ENTRY; 264 } 265 else 266 { 267 /* 268 * The user file has been modified and since it is no longer 269 * in the repository, a conflict is raised 270 */ 271 if (No_Difference (file, vers, entries, 272 repository, update_dir)) 273 { 274 /* they are different -> conflict */ 275 if (!really_quiet) 276 error (0, 0, 277 "conflict: %s is modified but no longer in the repository", 278 fullname); 279 ret = T_CONFLICT; 280 } 281 else 282 { 283 /* they weren't really different */ 284 if (!really_quiet) 285 error (0, 0, 286 "warning: %s is not (any longer) pertinent", 287 fullname); 288 ret = T_REMOVE_ENTRY; 289 } 290 } 291 } 292 else if (strcmp (vers->vn_rcs, vers->vn_user) == 0) 293 { 294 /* The RCS file is the same version as the user file */ 295 296 if (vers->ts_user == NULL) 297 { 298 299 /* 300 * There is no user file, so note that it was lost and 301 * extract a new version 302 */ 303 if (strcmp (command_name, "update") == 0) 304 if (!really_quiet) 305 error (0, 0, "warning: %s was lost", fullname); 306 ret = T_CHECKOUT; 307 } 308 else if (strcmp (vers->ts_user, vers->ts_rcs) == 0) 309 { 310 311 /* 312 * The user file is still unmodified, so nothing special at 313 * all to do -- no lists updated, unless the sticky -k option 314 * has changed. If the sticky tag has changed, we just need 315 * to re-register the entry 316 */ 317 if (vers->entdata->options && 318 strcmp (vers->entdata->options, vers->options) != 0) 319 ret = T_CHECKOUT; 320 else 321 { 322#ifdef SERVER_SUPPORT 323 sticky_ck (file, aflag, vers, entries, 324 repository, update_dir); 325#else 326 sticky_ck (file, aflag, vers, entries); 327#endif 328 ret = T_UPTODATE; 329 } 330 } 331 else 332 { 333 334 /* 335 * The user file appears to have been modified, but we call 336 * No_Difference to verify that it really has been modified 337 */ 338 if (No_Difference (file, vers, entries, 339 repository, update_dir)) 340 { 341 342 /* 343 * they really are different; modified if we aren't 344 * changing any sticky -k options, else needs merge 345 */ 346#ifdef XXX_FIXME_WHEN_RCSMERGE_IS_FIXED 347 if (strcmp (vers->entdata->options ? 348 vers->entdata->options : "", vers->options) == 0) 349 ret = T_MODIFIED; 350 else 351 ret = T_NEEDS_MERGE; 352#else 353 ret = T_MODIFIED; 354#ifdef SERVER_SUPPORT 355 sticky_ck (file, aflag, vers, entries, 356 repository, update_dir); 357#else 358 sticky_ck (file, aflag, vers, entries); 359#endif /* SERVER_SUPPORT */ 360#endif 361 } 362 else 363 { 364 /* file has not changed; check out if -k changed */ 365 if (strcmp (vers->entdata->options ? 366 vers->entdata->options : "", vers->options) != 0) 367 { 368 ret = T_CHECKOUT; 369 } 370 else 371 { 372 373 /* 374 * else -> note that No_Difference will Register the 375 * file already for us, using the new tag/date. This 376 * is the desired behaviour 377 */ 378 ret = T_UPTODATE; 379 } 380 } 381 } 382 } 383 else 384 { 385 /* The RCS file is a newer version than the user file */ 386 387 if (vers->ts_user == NULL) 388 { 389 /* There is no user file, so just get it */ 390 391 if (strcmp (command_name, "update") == 0) 392 if (!really_quiet) 393 error (0, 0, "warning: %s was lost", fullname); 394 ret = T_CHECKOUT; 395 } 396 else if (strcmp (vers->ts_user, vers->ts_rcs) == 0) 397 { 398 399 /* 400 * The user file is still unmodified, so just get it as well 401 */ 402#ifdef SERVER_SUPPORT 403 if (strcmp (vers->entdata->options ? 404 vers->entdata->options : "", vers->options) != 0 405 || (vers->srcfile != NULL 406 && (vers->srcfile->flags & INATTIC) != 0)) 407 ret = T_CHECKOUT; 408 else 409 ret = T_PATCH; 410#else 411 ret = T_CHECKOUT; 412#endif 413 } 414 else 415 { 416 if (No_Difference (file, vers, entries, 417 repository, update_dir)) 418 /* really modified, needs to merge */ 419 ret = T_NEEDS_MERGE; 420#ifdef SERVER_SUPPORT 421 else if ((strcmp (vers->entdata->options ? 422 vers->entdata->options : "", vers->options) 423 != 0) 424 || (vers->srcfile != NULL 425 && (vers->srcfile->flags & INATTIC) != 0)) 426 /* not really modified, check it out */ 427 ret = T_CHECKOUT; 428 else 429 ret = T_PATCH; 430#else 431 else 432 /* not really modified, check it out */ 433 ret = T_CHECKOUT; 434#endif 435 } 436 } 437 } 438 439 /* free up the vers struct, or just return it */ 440 if (versp != (Vers_TS **) NULL) 441 *versp = vers; 442 else 443 freevers_ts (&vers); 444 445 free (fullname); 446 447 /* return the status of the file */ 448 return (ret); 449} 450 451static void 452#ifdef SERVER_SUPPORT 453sticky_ck (file, aflag, vers, entries, repository, update_dir) 454#else 455sticky_ck (file, aflag, vers, entries) 456#endif 457 char *file; 458 int aflag; 459 Vers_TS *vers; 460 List *entries; 461#ifdef SERVER_SUPPORT 462 char *repository; 463 char *update_dir; 464#endif 465{ 466 if (aflag || vers->tag || vers->date) 467 { 468 char *enttag = vers->entdata->tag; 469 char *entdate = vers->entdata->date; 470 471 if ((enttag && vers->tag && strcmp (enttag, vers->tag)) || 472 ((enttag && !vers->tag) || (!enttag && vers->tag)) || 473 (entdate && vers->date && strcmp (entdate, vers->date)) || 474 ((entdate && !vers->date) || (!entdate && vers->date))) 475 { 476 Register (entries, file, vers->vn_user, vers->ts_rcs, 477 vers->options, vers->tag, vers->date, vers->ts_conflict); 478 479#ifdef SERVER_SUPPORT 480 if (server_active) 481 { 482 /* We need to update the entries line on the client side. 483 It is possible we will later update it again via 484 server_updated or some such, but that is OK. */ 485 server_update_entries 486 (file, update_dir, repository, 487 strcmp (vers->ts_rcs, vers->ts_user) == 0 ? 488 SERVER_UPDATED : SERVER_MERGED); 489 } 490#endif 491 } 492 } 493} 494