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