/* * Copyright (c) 1992, Brian Berliner and Jeff Polk * Copyright (c) 1989-1992, Brian Berliner * * You may distribute under the terms of the GNU General Public License as * specified in the README file that comes with the CVS 1.4 kit. * * Status Information */ #include "cvs.h" static Dtype status_dirproc PROTO ((void *callerdat, char *dir, char *repos, char *update_dir, List *entries)); static int status_fileproc PROTO ((void *callerdat, struct file_info *finfo)); static int tag_list_proc PROTO((Node * p, void *closure)); static int local = 0; static int long_format = 0; static RCSNode *xrcsnode; static const char *const status_usage[] = { "Usage: %s %s [-vlR] [files...]\n", "\t-v\tVerbose format; includes tag information for the file\n", "\t-l\tProcess this directory only (not recursive).\n", "\t-R\tProcess directories recursively.\n", NULL }; int status (argc, argv) int argc; char **argv; { int c; int err = 0; if (argc == -1) usage (status_usage); optind = 0; while ((c = getopt (argc, argv, "+vlR")) != -1) { switch (c) { case 'v': long_format = 1; break; case 'l': local = 1; break; case 'R': local = 0; break; case '?': default: usage (status_usage); break; } } argc -= optind; argv += optind; wrap_setup (); #ifdef CLIENT_SUPPORT if (client_active) { start_server (); ign_setup (); if (long_format) send_arg("-v"); if (local) send_arg("-l"); send_file_names (argc, argv, SEND_EXPAND_WILD); /* Note that by setting SEND_NO_CONTENTS, we do prevent the server from updating our timestamp if the timestamp is unchanged and the file is unmodified. And I think it is a user-visible thing in that case (shows "locally modified" instead of "up to date" I would think). But the speed seems to be worth it. */ send_files (argc, argv, local, 0, SEND_NO_CONTENTS); send_to_server ("status\012", 0); err = get_responses_and_close (); return err; } #endif /* start the recursion processor */ err = start_recursion (status_fileproc, (FILESDONEPROC) NULL, status_dirproc, (DIRLEAVEPROC) NULL, NULL, argc, argv, local, W_LOCAL, 0, 1, (char *) NULL, 1); return (err); } /* * display the status of a file */ /* ARGSUSED */ static int status_fileproc (callerdat, finfo) void *callerdat; struct file_info *finfo; { Ctype status; char *sstat; Vers_TS *vers; status = Classify_File (finfo, (char *) NULL, (char *) NULL, (char *) NULL, 1, 0, &vers, 0); sstat = "Classify Error"; switch (status) { case T_UNKNOWN: sstat = "Unknown"; break; case T_CHECKOUT: sstat = "Needs Checkout"; break; #ifdef SERVER_SUPPORT case T_PATCH: sstat = "Needs Patch"; break; #endif case T_CONFLICT: /* I _think_ that "unresolved" is correct; that if it has been resolved then the status will change. But I'm not sure about that. */ sstat = "Unresolved Conflict"; break; case T_ADDED: sstat = "Locally Added"; break; case T_REMOVED: sstat = "Locally Removed"; break; case T_MODIFIED: if (vers->ts_conflict) sstat = "File had conflicts on merge"; else sstat = "Locally Modified"; break; case T_REMOVE_ENTRY: sstat = "Entry Invalid"; break; case T_UPTODATE: sstat = "Up-to-date"; break; case T_NEEDS_MERGE: sstat = "Needs Merge"; break; case T_TITLE: /* I don't think this case can occur here. Just print "Classify Error". */ break; } cvs_output ("\ ===================================================================\n", 0); if (vers->ts_user == NULL) { cvs_output ("File: no file ", 0); cvs_output (finfo->file, 0); cvs_output ("\t\tStatus: ", 0); cvs_output (sstat, 0); cvs_output ("\n\n", 0); } else { char *buf; buf = xmalloc (strlen (finfo->file) + strlen (sstat) + 80); sprintf (buf, "File: %-17s\tStatus: %s\n\n", finfo->file, sstat); cvs_output (buf, 0); free (buf); } if (vers->vn_user == NULL) { cvs_output (" Working revision:\tNo entry for ", 0); cvs_output (finfo->file, 0); cvs_output ("\n", 0); } else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0') cvs_output (" Working revision:\tNew file!\n", 0); #ifdef SERVER_SUPPORT else if (server_active) { cvs_output (" Working revision:\t", 0); cvs_output (vers->vn_user, 0); cvs_output ("\n", 0); } #endif else { cvs_output (" Working revision:\t", 0); cvs_output (vers->vn_user, 0); cvs_output ("\t", 0); cvs_output (vers->ts_rcs, 0); cvs_output ("\n", 0); } if (vers->vn_rcs == NULL) cvs_output (" Repository revision:\tNo revision control file\n", 0); else { cvs_output (" Repository revision:\t", 0); cvs_output (vers->vn_rcs, 0); cvs_output ("\t", 0); cvs_output (vers->srcfile->path, 0); cvs_output ("\n", 0); } if (vers->entdata) { Entnode *edata; edata = vers->entdata; if (edata->tag) { if (vers->vn_rcs == NULL) { cvs_output (" Sticky Tag:\t\t", 0); cvs_output (edata->tag, 0); cvs_output (" - MISSING from RCS file!\n", 0); } else { if (isdigit (edata->tag[0])) { cvs_output (" Sticky Tag:\t\t", 0); cvs_output (edata->tag, 0); cvs_output ("\n", 0); } else { char *branch = NULL; if (RCS_isbranch (finfo->rcs, edata->tag)) branch = RCS_whatbranch(finfo->rcs, edata->tag); cvs_output (" Sticky Tag:\t\t", 0); cvs_output (edata->tag, 0); cvs_output (" (", 0); cvs_output (branch ? "branch" : "revision", 0); cvs_output (": ", 0); cvs_output (branch ? branch : vers->vn_rcs, 0); cvs_output (")\n", 0); if (branch) free (branch); } } } else if (!really_quiet) cvs_output (" Sticky Tag:\t\t(none)\n", 0); if (edata->date) { cvs_output (" Sticky Date:\t\t", 0); cvs_output (edata->date, 0); cvs_output ("\n", 0); } else if (!really_quiet) cvs_output (" Sticky Date:\t\t(none)\n", 0); if (edata->options && edata->options[0]) { cvs_output (" Sticky Options:\t", 0); cvs_output (edata->options, 0); cvs_output ("\n", 0); } else if (!really_quiet) cvs_output (" Sticky Options:\t(none)\n", 0); if (long_format && vers->srcfile) { List *symbols = RCS_symbols(vers->srcfile); cvs_output ("\n Existing Tags:\n", 0); if (symbols) { xrcsnode = finfo->rcs; (void) walklist (symbols, tag_list_proc, NULL); } else cvs_output ("\tNo Tags Exist\n", 0); } } cvs_output ("\n", 0); freevers_ts (&vers); return (0); } /* * Print a warm fuzzy message */ /* ARGSUSED */ static Dtype status_dirproc (callerdat, dir, repos, update_dir, entries) void *callerdat; char *dir; char *repos; char *update_dir; List *entries; { if (!quiet) error (0, 0, "Examining %s", update_dir); return (R_PROCESS); } /* * Print out a tag and its type */ static int tag_list_proc (p, closure) Node *p; void *closure; { char *branch = NULL; char *buf; if (RCS_isbranch (xrcsnode, p->key)) branch = RCS_whatbranch(xrcsnode, p->key) ; buf = xmalloc (80 + strlen (p->key) + (branch ? strlen (branch) : strlen (p->data))); sprintf (buf, "\t%-25s\t(%s: %s)\n", p->key, branch ? "branch" : "revision", branch ? branch : p->data); cvs_output (buf, 0); free (buf); if (branch) free (branch); return (0); }