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 * Status Information 9 */ 10 11 #include "cvs.h" 12 13 static Dtype status_dirproc PROTO ((void *callerdat, char *dir, 14 char *repos, char *update_dir, 15 List *entries)); 16 static int status_fileproc PROTO ((void *callerdat, struct file_info *finfo)); 17 static int tag_list_proc PROTO((Node * p, void *closure)); 18 19 static int local = 0; 20 static int long_format = 0; 21 static RCSNode *xrcsnode; 22 23 static const char *const status_usage[] = 24 { 25 "Usage: %s %s [-vlR] [files...]\n", 26 "\t-v\tVerbose format; includes tag information for the file\n", 27 "\t-l\tProcess this directory only (not recursive).\n", 28 "\t-R\tProcess directories recursively.\n", 29 "(Specify the --help global option for a list of other help options)\n", 30 NULL 31 }; 32 33 int 34 cvsstatus (argc, argv) 35 int argc; 36 char **argv; 37 { 38 int c; 39 int err = 0; 40 41 if (argc == -1) 42 usage (status_usage); 43 44 optind = 0; 45 while ((c = getopt (argc, argv, "+vlR")) != -1) 46 { 47 switch (c) 48 { 49 case 'v': 50 long_format = 1; 51 break; 52 case 'l': 53 local = 1; 54 break; 55 case 'R': 56 local = 0; 57 break; 58 case '?': 59 default: 60 usage (status_usage); 61 break; 62 } 63 } 64 argc -= optind; 65 argv += optind; 66 67 wrap_setup (); 68 69 #ifdef CLIENT_SUPPORT 70 if (current_parsed_root->isremote) 71 { 72 start_server (); 73 74 ign_setup (); 75 76 if (long_format) 77 send_arg("-v"); 78 if (local) 79 send_arg("-l"); 80 81 /* For a while, we tried setting SEND_NO_CONTENTS here so this 82 could be a fast operation. That prevents the 83 server from updating our timestamp if the timestamp is 84 changed but the file is unmodified. Worse, it is user-visible 85 (shows "locally modified" instead of "up to date" if 86 timestamp is changed but file is not). And there is no good 87 workaround (you might not want to run "cvs update"; "cvs -n 88 update" doesn't update CVS/Entries; "cvs diff --brief" or 89 something perhaps could be made to work but somehow that 90 seems nonintuitive to me even if so). Given that timestamps 91 seem to have the potential to get munged for any number of 92 reasons, it seems better to not rely too much on them. */ 93 94 send_files (argc, argv, local, 0, 0); 95 96 send_file_names (argc, argv, SEND_EXPAND_WILD); 97 98 send_to_server ("status\012", 0); 99 err = get_responses_and_close (); 100 101 return err; 102 } 103 #endif 104 105 /* start the recursion processor */ 106 err = start_recursion (status_fileproc, (FILESDONEPROC) NULL, 107 status_dirproc, (DIRLEAVEPROC) NULL, NULL, 108 argc, argv, local, 109 W_LOCAL, 0, 1, (char *) NULL, 1); 110 111 return (err); 112 } 113 114 /* 115 * display the status of a file 116 */ 117 /* ARGSUSED */ 118 static int 119 status_fileproc (callerdat, finfo) 120 void *callerdat; 121 struct file_info *finfo; 122 { 123 Ctype status; 124 char *sstat; 125 Vers_TS *vers; 126 Node *node; 127 128 status = Classify_File (finfo, (char *) NULL, (char *) NULL, (char *) NULL, 129 1, 0, &vers, 0); 130 sstat = "Classify Error"; 131 switch (status) 132 { 133 case T_UNKNOWN: 134 sstat = "Unknown"; 135 break; 136 case T_CHECKOUT: 137 sstat = "Needs Checkout"; 138 break; 139 case T_PATCH: 140 sstat = "Needs Patch"; 141 break; 142 case T_CONFLICT: 143 /* I _think_ that "unresolved" is correct; that if it has 144 been resolved then the status will change. But I'm not 145 sure about that. */ 146 sstat = "Unresolved Conflict"; 147 break; 148 case T_ADDED: 149 sstat = "Locally Added"; 150 break; 151 case T_REMOVED: 152 sstat = "Locally Removed"; 153 break; 154 case T_MODIFIED: 155 if (vers->ts_conflict) 156 sstat = "File had conflicts on merge"; 157 else 158 sstat = "Locally Modified"; 159 break; 160 case T_REMOVE_ENTRY: 161 sstat = "Entry Invalid"; 162 break; 163 case T_UPTODATE: 164 sstat = "Up-to-date"; 165 break; 166 case T_NEEDS_MERGE: 167 sstat = "Needs Merge"; 168 break; 169 case T_TITLE: 170 /* I don't think this case can occur here. Just print 171 "Classify Error". */ 172 break; 173 } 174 175 cvs_output ("\ 176 ===================================================================\n", 0); 177 if (vers->ts_user == NULL) 178 { 179 cvs_output ("File: no file ", 0); 180 cvs_output (finfo->file, 0); 181 cvs_output ("\t\tStatus: ", 0); 182 cvs_output (sstat, 0); 183 cvs_output ("\n\n", 0); 184 } 185 else 186 { 187 char *buf; 188 buf = xmalloc (strlen (finfo->file) + strlen (sstat) + 80); 189 sprintf (buf, "File: %-17s\tStatus: %s\n\n", finfo->file, sstat); 190 cvs_output (buf, 0); 191 free (buf); 192 } 193 194 if (vers->vn_user == NULL) 195 { 196 cvs_output (" Working revision:\tNo entry for ", 0); 197 cvs_output (finfo->file, 0); 198 cvs_output ("\n", 0); 199 } 200 else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0') 201 cvs_output (" Working revision:\tNew file!\n", 0); 202 #ifdef SERVER_SUPPORT 203 else if (server_active) 204 { 205 cvs_output (" Working revision:\t", 0); 206 cvs_output (vers->vn_user, 0); 207 cvs_output ("\n", 0); 208 } 209 #endif 210 else 211 { 212 cvs_output (" Working revision:\t", 0); 213 cvs_output (vers->vn_user, 0); 214 cvs_output ("\t", 0); 215 cvs_output (vers->ts_rcs, 0); 216 cvs_output ("\n", 0); 217 } 218 219 if (vers->vn_rcs == NULL) 220 cvs_output (" Repository revision:\tNo revision control file\n", 0); 221 else 222 { 223 cvs_output (" Repository revision:\t", 0); 224 cvs_output (vers->vn_rcs, 0); 225 cvs_output ("\t", 0); 226 cvs_output (vers->srcfile->path, 0); 227 cvs_output ("\n", 0); 228 229 node = findnode(vers->srcfile->versions,vers->vn_rcs); 230 if (node) 231 { 232 RCSVers *v; 233 v=(RCSVers*)node->data; 234 node = findnode(v->other_delta,"commitid"); 235 cvs_output(" Commit Identifier:\t", 0); 236 if(node && node->data) 237 cvs_output(node->data, 0); 238 else 239 cvs_output("(none)",0); 240 cvs_output("\n",0); 241 } 242 } 243 244 if (vers->entdata) 245 { 246 Entnode *edata; 247 248 edata = vers->entdata; 249 if (edata->tag) 250 { 251 if (vers->vn_rcs == NULL) 252 { 253 cvs_output (" Sticky Tag:\t\t", 0); 254 cvs_output (edata->tag, 0); 255 cvs_output (" - MISSING from RCS file!\n", 0); 256 } 257 else 258 { 259 if (isdigit ((unsigned char) edata->tag[0])) 260 { 261 cvs_output (" Sticky Tag:\t\t", 0); 262 cvs_output (edata->tag, 0); 263 cvs_output ("\n", 0); 264 } 265 else 266 { 267 char *branch = NULL; 268 269 if (RCS_nodeisbranch (finfo->rcs, edata->tag)) 270 branch = RCS_whatbranch(finfo->rcs, edata->tag); 271 272 cvs_output (" Sticky Tag:\t\t", 0); 273 cvs_output (edata->tag, 0); 274 cvs_output (" (", 0); 275 cvs_output (branch ? "branch" : "revision", 0); 276 cvs_output (": ", 0); 277 cvs_output (branch ? branch : vers->vn_rcs, 0); 278 cvs_output (")\n", 0); 279 280 if (branch) 281 free (branch); 282 } 283 } 284 } 285 else if (!really_quiet) 286 cvs_output (" Sticky Tag:\t\t(none)\n", 0); 287 288 if (edata->date) 289 { 290 cvs_output (" Sticky Date:\t\t", 0); 291 cvs_output (edata->date, 0); 292 cvs_output ("\n", 0); 293 } 294 else if (!really_quiet) 295 cvs_output (" Sticky Date:\t\t(none)\n", 0); 296 297 if (edata->options && edata->options[0]) 298 { 299 cvs_output (" Sticky Options:\t", 0); 300 cvs_output (edata->options, 0); 301 cvs_output ("\n", 0); 302 } 303 else if (!really_quiet) 304 cvs_output (" Sticky Options:\t(none)\n", 0); 305 } 306 307 if (long_format && vers->srcfile) 308 { 309 List *symbols = RCS_symbols(vers->srcfile); 310 311 cvs_output ("\n Existing Tags:\n", 0); 312 if (symbols) 313 { 314 xrcsnode = finfo->rcs; 315 (void) walklist (symbols, tag_list_proc, NULL); 316 } 317 else 318 cvs_output ("\tNo Tags Exist\n", 0); 319 } 320 321 cvs_output ("\n", 0); 322 freevers_ts (&vers); 323 return (0); 324 } 325 326 /* 327 * Print a warm fuzzy message 328 */ 329 /* ARGSUSED */ 330 static Dtype 331 status_dirproc (callerdat, dir, repos, update_dir, entries) 332 void *callerdat; 333 char *dir; 334 char *repos; 335 char *update_dir; 336 List *entries; 337 { 338 if (!quiet) 339 error (0, 0, "Examining %s", update_dir); 340 return (R_PROCESS); 341 } 342 343 /* 344 * Print out a tag and its type 345 */ 346 static int 347 tag_list_proc (p, closure) 348 Node *p; 349 void *closure; 350 { 351 char *branch = NULL; 352 char *buf; 353 354 if (RCS_nodeisbranch (xrcsnode, p->key)) 355 branch = RCS_whatbranch(xrcsnode, p->key) ; 356 357 buf = xmalloc (80 + strlen (p->key) 358 + (branch ? strlen (branch) : strlen (p->data))); 359 sprintf (buf, "\t%-25s\t(%s: %s)\n", p->key, 360 branch ? "branch" : "revision", 361 branch ? branch : p->data); 362 cvs_output (buf, 0); 363 free (buf); 364 365 if (branch) 366 free (branch); 367 368 return (0); 369 } 370