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 (client_active) 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 127 status = Classify_File (finfo, (char *) NULL, (char *) NULL, (char *) NULL, 128 1, 0, &vers, 0); 129 sstat = "Classify Error"; 130 switch (status) 131 { 132 case T_UNKNOWN: 133 sstat = "Unknown"; 134 break; 135 case T_CHECKOUT: 136 sstat = "Needs Checkout"; 137 break; 138 #ifdef SERVER_SUPPORT 139 case T_PATCH: 140 sstat = "Needs Patch"; 141 break; 142 #endif 143 case T_CONFLICT: 144 /* I _think_ that "unresolved" is correct; that if it has 145 been resolved then the status will change. But I'm not 146 sure about that. */ 147 sstat = "Unresolved Conflict"; 148 break; 149 case T_ADDED: 150 sstat = "Locally Added"; 151 break; 152 case T_REMOVED: 153 sstat = "Locally Removed"; 154 break; 155 case T_MODIFIED: 156 if (vers->ts_conflict) 157 sstat = "File had conflicts on merge"; 158 else 159 sstat = "Locally Modified"; 160 break; 161 case T_REMOVE_ENTRY: 162 sstat = "Entry Invalid"; 163 break; 164 case T_UPTODATE: 165 sstat = "Up-to-date"; 166 break; 167 case T_NEEDS_MERGE: 168 sstat = "Needs Merge"; 169 break; 170 case T_TITLE: 171 /* I don't think this case can occur here. Just print 172 "Classify Error". */ 173 break; 174 } 175 176 cvs_output ("\ 177 ===================================================================\n", 0); 178 if (vers->ts_user == NULL) 179 { 180 cvs_output ("File: no file ", 0); 181 cvs_output (finfo->file, 0); 182 cvs_output ("\t\tStatus: ", 0); 183 cvs_output (sstat, 0); 184 cvs_output ("\n\n", 0); 185 } 186 else 187 { 188 char *buf; 189 buf = xmalloc (strlen (finfo->file) + strlen (sstat) + 80); 190 sprintf (buf, "File: %-17s\tStatus: %s\n\n", finfo->file, sstat); 191 cvs_output (buf, 0); 192 free (buf); 193 } 194 195 if (vers->vn_user == NULL) 196 { 197 cvs_output (" Working revision:\tNo entry for ", 0); 198 cvs_output (finfo->file, 0); 199 cvs_output ("\n", 0); 200 } 201 else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0') 202 cvs_output (" Working revision:\tNew file!\n", 0); 203 #ifdef SERVER_SUPPORT 204 else if (server_active) 205 { 206 cvs_output (" Working revision:\t", 0); 207 cvs_output (vers->vn_user, 0); 208 cvs_output ("\n", 0); 209 } 210 #endif 211 else 212 { 213 cvs_output (" Working revision:\t", 0); 214 cvs_output (vers->vn_user, 0); 215 cvs_output ("\t", 0); 216 cvs_output (vers->ts_rcs, 0); 217 cvs_output ("\n", 0); 218 } 219 220 if (vers->vn_rcs == NULL) 221 cvs_output (" Repository revision:\tNo revision control file\n", 0); 222 else 223 { 224 cvs_output (" Repository revision:\t", 0); 225 cvs_output (vers->vn_rcs, 0); 226 cvs_output ("\t", 0); 227 cvs_output (vers->srcfile->path, 0); 228 cvs_output ("\n", 0); 229 } 230 231 if (vers->entdata) 232 { 233 Entnode *edata; 234 235 edata = vers->entdata; 236 if (edata->tag) 237 { 238 if (vers->vn_rcs == NULL) 239 { 240 cvs_output (" Sticky Tag:\t\t", 0); 241 cvs_output (edata->tag, 0); 242 cvs_output (" - MISSING from RCS file!\n", 0); 243 } 244 else 245 { 246 if (isdigit ((unsigned char) edata->tag[0])) 247 { 248 cvs_output (" Sticky Tag:\t\t", 0); 249 cvs_output (edata->tag, 0); 250 cvs_output ("\n", 0); 251 } 252 else 253 { 254 char *branch = NULL; 255 256 if (RCS_nodeisbranch (finfo->rcs, edata->tag)) 257 branch = RCS_whatbranch(finfo->rcs, edata->tag); 258 259 cvs_output (" Sticky Tag:\t\t", 0); 260 cvs_output (edata->tag, 0); 261 cvs_output (" (", 0); 262 cvs_output (branch ? "branch" : "revision", 0); 263 cvs_output (": ", 0); 264 cvs_output (branch ? branch : vers->vn_rcs, 0); 265 cvs_output (")\n", 0); 266 267 if (branch) 268 free (branch); 269 } 270 } 271 } 272 else if (!really_quiet) 273 cvs_output (" Sticky Tag:\t\t(none)\n", 0); 274 275 if (edata->date) 276 { 277 cvs_output (" Sticky Date:\t\t", 0); 278 cvs_output (edata->date, 0); 279 cvs_output ("\n", 0); 280 } 281 else if (!really_quiet) 282 cvs_output (" Sticky Date:\t\t(none)\n", 0); 283 284 if (edata->options && edata->options[0]) 285 { 286 cvs_output (" Sticky Options:\t", 0); 287 cvs_output (edata->options, 0); 288 cvs_output ("\n", 0); 289 } 290 else if (!really_quiet) 291 cvs_output (" Sticky Options:\t(none)\n", 0); 292 } 293 294 if (long_format && vers->srcfile) 295 { 296 List *symbols = RCS_symbols(vers->srcfile); 297 298 cvs_output ("\n Existing Tags:\n", 0); 299 if (symbols) 300 { 301 xrcsnode = finfo->rcs; 302 (void) walklist (symbols, tag_list_proc, NULL); 303 } 304 else 305 cvs_output ("\tNo Tags Exist\n", 0); 306 } 307 308 cvs_output ("\n", 0); 309 freevers_ts (&vers); 310 return (0); 311 } 312 313 /* 314 * Print a warm fuzzy message 315 */ 316 /* ARGSUSED */ 317 static Dtype 318 status_dirproc (callerdat, dir, repos, update_dir, entries) 319 void *callerdat; 320 char *dir; 321 char *repos; 322 char *update_dir; 323 List *entries; 324 { 325 if (!quiet) 326 error (0, 0, "Examining %s", update_dir); 327 return (R_PROCESS); 328 } 329 330 /* 331 * Print out a tag and its type 332 */ 333 static int 334 tag_list_proc (p, closure) 335 Node *p; 336 void *closure; 337 { 338 char *branch = NULL; 339 char *buf; 340 341 if (RCS_nodeisbranch (xrcsnode, p->key)) 342 branch = RCS_whatbranch(xrcsnode, p->key) ; 343 344 buf = xmalloc (80 + strlen (p->key) 345 + (branch ? strlen (branch) : strlen (p->data))); 346 sprintf (buf, "\t%-25s\t(%s: %s)\n", p->key, 347 branch ? "branch" : "revision", 348 branch ? branch : p->data); 349 cvs_output (buf, 0); 350 free (buf); 351 352 if (branch) 353 free (branch); 354 355 return (0); 356 } 357