summaryrefslogtreecommitdiff
path: root/src/status.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/status.c')
-rw-r--r--src/status.c378
1 files changed, 378 insertions, 0 deletions
diff --git a/src/status.c b/src/status.c
new file mode 100644
index 0000000..11ab5ac
--- /dev/null
+++ b/src/status.c
@@ -0,0 +1,378 @@
+/*
+ * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ *
+ * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
+ * and others.
+ *
+ * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
+ * Portions 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 source distribution.
+ *
+ * Status Information
+ */
+
+#include "cvs.h"
+
+static Dtype status_dirproc (void *callerdat, const char *dir,
+ const char *repos, const char *update_dir,
+ List *entries);
+static int status_fileproc (void *callerdat, struct file_info *finfo);
+static int tag_list_proc (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",
+ "(Specify the --help global option for a list of other help options)\n",
+ NULL
+};
+
+int
+cvsstatus (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 (current_parsed_root->isremote)
+ {
+ start_server ();
+
+ ign_setup ();
+
+ if (long_format)
+ send_arg("-v");
+ if (local)
+ send_arg("-l");
+ send_arg ("--");
+
+ /* For a while, we tried setting SEND_NO_CONTENTS here so this
+ could be a fast operation. That prevents the
+ server from updating our timestamp if the timestamp is
+ changed but the file is unmodified. Worse, it is user-visible
+ (shows "locally modified" instead of "up to date" if
+ timestamp is changed but file is not). And there is no good
+ workaround (you might not want to run "cvs update"; "cvs -n
+ update" doesn't update CVS/Entries; "cvs diff --brief" or
+ something perhaps could be made to work but somehow that
+ seems nonintuitive to me even if so). Given that timestamps
+ seem to have the potential to get munged for any number of
+ reasons, it seems better to not rely too much on them. */
+
+ send_files (argc, argv, local, 0, 0);
+
+ send_file_names (argc, argv, SEND_EXPAND_WILD);
+
+ send_to_server ("status\012", 0);
+ err = get_responses_and_close ();
+
+ return err;
+ }
+#endif
+
+ /* start the recursion processor */
+ err = start_recursion (status_fileproc, NULL, status_dirproc,
+ NULL, NULL, argc, argv, local, W_LOCAL,
+ 0, CVS_LOCK_READ, NULL, 1, NULL);
+
+ return (err);
+}
+
+/*
+ * display the status of a file
+ */
+/* ARGSUSED */
+static int
+status_fileproc (void *callerdat, struct file_info *finfo)
+{
+ Ctype status;
+ char *sstat;
+ Vers_TS *vers;
+ Node *node;
+
+ status = Classify_File (finfo, NULL, NULL, NULL, 1, 0, &vers, 0);
+ sstat = "Classify Error";
+ switch (status)
+ {
+ case T_UNKNOWN:
+ sstat = "Unknown";
+ break;
+ case T_CHECKOUT:
+ sstat = "Needs Checkout";
+ break;
+ case T_PATCH:
+ sstat = "Needs Patch";
+ break;
+ case T_CONFLICT:
+ /* FIXME - This message could be clearer. It comes up
+ * when a file exists or has been added in the local sandbox
+ * and a file of the same name has been committed indepenently to
+ * the repository from a different sandbox, as well as when a
+ * timestamp hasn't changed since a merge resulted in conflicts.
+ * It also comes up whether an update has been attempted or not, so
+ * technically, I think the double-add case is not actually a
+ * conflict yet.
+ */
+ sstat = "Unresolved Conflict";
+ break;
+ case T_ADDED:
+ sstat = "Locally Added";
+ break;
+ case T_REMOVED:
+ sstat = "Locally Removed";
+ break;
+ case T_MODIFIED:
+ if (file_has_markers (finfo))
+ sstat = "File had conflicts on merge";
+ else
+ /* Note that we do not re Register() the file when we spot
+ * a resolved conflict like update_fileproc() does on the
+ * premise that status should not alter the sandbox.
+ */
+ 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 = Xasprintf ("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);
+ else
+ {
+ cvs_output (" Working revision:\t", 0);
+ cvs_output (vers->vn_user, 0);
+
+ /* Only add the UTC timezone if there is a time to use. */
+ if (!server_active && strlen (vers->ts_rcs) > 0)
+ {
+ /* Convert from the asctime() format to ISO 8601 */
+ char *buf;
+
+ cvs_output ("\t", 0);
+
+ /* Allow conversion from CVS/Entries asctime() to ISO 8601 */
+ buf = Xasprintf ("%s UTC", vers->ts_rcs);
+ cvs_output_tagged ("date", buf);
+ free (buf);
+ }
+ 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->print_path, 0);
+ cvs_output ("\n", 0);
+
+ node = findnode(vers->srcfile->versions,vers->vn_rcs);
+ if (node)
+ {
+ RCSVers *v;
+ v=(RCSVers*)node->data;
+ node = findnode(v->other_delta,"commitid");
+ cvs_output(" Commit Identifier:\t", 0);
+ if(node && node->data)
+ cvs_output(node->data, 0);
+ else
+ cvs_output("(none)",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 ((unsigned char) 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_nodeisbranch (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 (void *callerdat, const char *dir, const char *repos,
+ const 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 (Node *p, void *closure)
+{
+ char *branch = NULL;
+ char *buf;
+
+ if (RCS_nodeisbranch (xrcsnode, p->key))
+ branch = RCS_whatbranch(xrcsnode, p->key) ;
+
+ buf = Xasprintf ("\t%-25s\t(%s: %s)\n", p->key,
+ branch ? "branch" : "revision",
+ branch ? branch : (char *)p->data);
+ cvs_output (buf, 0);
+ free (buf);
+
+ if (branch)
+ free (branch);
+
+ return (0);
+}