On the 16th of last month, Peter Bowen posted a patch on the
info-cvs-request list that provided a new command, "cvs list".
Unfortunately, that patch has a bug (try "cvs ls -a CVSROOT"
on a new repository).

"cvs list" is a very useful command, but you still can't see all
of the information that might be useful; therefore I created
"cvs rlog" (replacing the old deprecated synonym for "log"), which
displays log entries without a working directory. Doubtless a flame
war will now ensue over whether this is an appropriate name (I think
it is, because it goes with the convention already established for
"rtag" - on the other hand, "rlog" used to mean something slightly
different, but the warning has been around at least since 1.10 so
no-one should be using "rlog" now).

Note that:

  1. I'm not on the development list, nor do I intend to
     subscribe to it; so any replies had better go to my mail
     address...

  2. I haven't tested the client/server functionality; I *think*
     it does the right thing, but as I'm on WinNT it's harder
     to test this than it would be e.g. on UNIX.

Hope this proves useful,

Alastair.

p.s. The following things are attached:

1. cvs-rlog.diff; this patch provides the "cvs rlog" command.

2. list.diff/list.c; a fixed version of Peter Bowen's "cvs list".

list.c

Index: cvs.h
===================================================================
RCS file: /home2/cvsroot/ccvs/src/cvs.h,v
retrieving revision 1.206
diff -u -r1.206 cvs.h
--- cvs.h       2000/10/12 15:33:21     1.206
+++ cvs.h       2000/10/16 21:40:41
@@ -314,7 +314,7 @@
 /* The type of request that is being done in do_module() */
 enum mtype
 {
-    CHECKOUT, TAG, PATCH, EXPORT
+    CHECKOUT, TAG, PATCH, EXPORT, CVSLIST
 };
 
 /*
@@ -856,6 +856,7 @@
 extern int cvsstatus PROTO((int argc, char **argv));
 extern int cvstag PROTO((int argc, char **argv));
 extern int version PROTO((int argc, char **argv));
+extern int cvslist PROTO((int argc, char **argv));
 
 extern unsigned long int lookup_command_attribute PROTO((char *));
 
Index: main.c
===================================================================
RCS file: /home2/cvsroot/ccvs/src/main.c,v
retrieving revision 1.154
diff -u -r1.154 main.c
--- main.c      2000/10/11 16:17:53     1.154
+++ main.c      2000/10/16 21:40:41
@@ -114,6 +114,7 @@
 #if defined (HAVE_KERBEROS) && defined (SERVER_SUPPORT)
     { "kserver",  NULL,       NULL,        server }, /* placeholder */
 #endif
+    { "list",    "ls",       NULL,        cvslist },
     { "log",      "lo",       "rlog",      cvslog },
 #ifdef AUTH_CLIENT_SUPPORT
     { "login",    "logon",    "lgn",       login },
@@ -329,6 +330,7 @@
        something doesn't use the WD. */
     if ((strcmp (cmd_name, "checkout") != 0) &&
         (strcmp (cmd_name, "init") != 0) &&
+        (strcmp (cmd_name, "list") != 0) &&
         (strcmp (cmd_name, "login") != 0) &&
        (strcmp (cmd_name, "logout") != 0) &&
         (strcmp (cmd_name, "rdiff") != 0) &&
@@ -350,6 +352,7 @@
         (strcmp (cmd_name, "editors") != 0) &&
         (strcmp (cmd_name, "export") != 0) &&
         (strcmp (cmd_name, "history") != 0) &&
+        (strcmp (cmd_name, "list") != 0) &&
         (strcmp (cmd_name, "log") != 0) &&
         (strcmp (cmd_name, "noop") != 0) &&
         (strcmp (cmd_name, "watchers") != 0) &&
diff -w -r -u orig/cvs-1.11/src/cvs.h cvs-1.11/src/cvs.h
--- orig/cvs-1.11/src/cvs.h     Sat Jul  8 21:57:22 2000
+++ cvs-1.11/src/cvs.h  Sun Nov 12 17:39:25 2000
@@ -314,7 +314,7 @@
 /* The type of request that is being done in do_module() */
 enum mtype
 {
-    CHECKOUT, TAG, PATCH, EXPORT
+    CHECKOUT, TAG, PATCH, EXPORT, CVSRLOG
 };
 
 /*
@@ -857,6 +857,7 @@
 extern int cvsstatus PROTO((int argc, char **argv));
 extern int cvstag PROTO((int argc, char **argv));
 extern int version PROTO((int argc, char **argv));
+extern int cvsrlog PROTO((int argc, char **argv));
 
 extern unsigned long int lookup_command_attribute PROTO((char *));
 
diff -w -r -u orig/cvs-1.11/src/log.c cvs-1.11/src/log.c
--- orig/cvs-1.11/src/log.c     Thu Jun 22 00:28:38 2000
+++ cvs-1.11/src/log.c  Sun Nov 12 17:15:05 2000
@@ -105,6 +105,10 @@
     RCSNode *rcs;
 };
 
+static int rlog_list_proc PROTO ((int argc, char **argv, char *xwhere,
+                                 char *mwhere, char *mfile, int shorten,
+                                 int local_specified, char *mname,
+                                 char *msg));
 static Dtype log_dirproc PROTO ((void *callerdat, char *dir,
                                 char *repository, char *update_dir,
                                 List *entries));
@@ -149,6 +153,25 @@
     NULL
 };
 
+static const char *const rlog_usage[] =
+{
+    "Usage: %s %s [-RhtNb] [-r[revisions]] [-d dates] [-s states]\n",
+    "    [-w[logins]] modules...\n",
+    "\t-R\tOnly print name of RCS file.\n",
+    "\t-h\tOnly print header.\n",
+    "\t-t\tOnly print header and descriptive text.\n",
+    "\t-N\tDo not list tags.\n",
+    "\t-b\tOnly list revisions on the default branch.\n",
+    "\t-r[revisions]\tSpecify revision(s)s to list.\n",
+    "\t-d dates\tSpecify dates (D1<D2 for range, D for latest before).\n",
+    "\t-s states\tOnly list revisions with specified states.\n",
+    "\t-w[logins]\tOnly list revisions checked in by specified logins.\n",
+    "(Specify the --help global option for a list of other help options)\n",
+    NULL
+};
+
+static struct log_data         rlog_data;
+
 #ifdef CLIENT_SUPPORT
 
 /* Helper function for send_arg_list.  */
@@ -190,6 +213,9 @@
 
 #endif
 
+/*
+ * Entry point for standard "cvs log" command
+ */
 int
 cvslog (argc, argv)
     int argc;
@@ -399,6 +425,324 @@
     }
     dellist (&log_data.statelist);
     dellist (&log_data.authorlist);
+
+    return (err);
+}
+
+/*
+ * Entry point for repository-only "cvs rlog" command
+ */
+int
+cvsrlog (argc, argv)
+    int argc;
+    char **argv;
+{
+    int                                i, c;
+    int                                err = 0;
+    struct option_revlist      **prl;
+    DBM                                *db;
+    
+    /* Display usage if we have no arguments */
+    if (argc < 1)
+       usage (rlog_usage);
+
+    /* Initialise */
+    memset (&rlog_data, 0, sizeof (rlog_data));
+    prl = &rlog_data.revlist;
+    
+    /* Parse options */
+    optind = 0;
+
+    while ((c = getopt (argc, argv, "+bd:hNRr::s:tw::")) != -1)
+    {
+       switch (c)
+       {
+           case 'b':
+               rlog_data.default_branch = 1;
+               break;
+           case 'd':
+               log_parse_date (&rlog_data, optarg);
+               break;
+           case 'h':
+               rlog_data.header = 1;
+               break;
+           case 'N':
+               rlog_data.notags = 1;
+               break;
+           case 'R':
+               rlog_data.nameonly = 1;
+               break;
+           case 'r':
+               *prl = log_parse_revlist (optarg);
+               prl = &(*prl)->next;
+               break;
+           case 's':
+               log_parse_list (&rlog_data.statelist, optarg);
+               break;
+           case 't':
+               rlog_data.long_header = 1;
+               break;
+           case 'w':
+               if (optarg != NULL)
+                   log_parse_list (&rlog_data.authorlist, optarg);
+               else
+                   log_parse_list (&rlog_data.authorlist, "@@MYSELF");
+               break;
+           case '?':
+           default:
+               usage (rlog_usage);
+               break;
+       }
+    }
+
+    /* Adjust argv */
+    argc -= optind;
+    argv += optind;
+
+    if (argc == 0)
+       usage (rlog_usage);
+    
+    /* Initialise wrapper support */
+    wrap_setup ();
+
+#ifdef CLIENT_SUPPORT
+    if (client_active)
+    {
+       struct datelist *p;
+       struct option_revlist *rp;
+       char datetmp[MAXDATELEN];
+       
+       /* We're the local client.  Fire-up the remote server. */
+       start_server ();
+
+       ign_setup ();
+
+       /* Send arguments to server */
+       if (rlog_data.default_branch)
+           send_arg ("-b");
+
+       while (rlog_data.datelist != NULL)
+       {
+           p = rlog_data.datelist;
+           rlog_data.datelist = p->next;
+           send_to_server ("Argument -d\012", 0);
+           send_to_server ("Argument ", 0);
+           date_to_internet (datetmp, p->start);
+           send_to_server (datetmp, 0);
+           if (p->inclusive)
+               send_to_server ("<=", 0);
+           else
+               send_to_server ("<", 0);
+           date_to_internet (datetmp, p->end);
+           send_to_server (datetmp, 0);
+           send_to_server ("\012", 0);
+           if (p->start)
+               free (p->start);
+           if (p->end)
+               free (p->end);
+           free (p);
+       }
+       while (rlog_data.singledatelist != NULL)
+       {
+           p = rlog_data.singledatelist;
+           rlog_data.singledatelist = p->next;
+           send_to_server ("Argument -d\012", 0);
+           send_to_server ("Argument ", 0);
+           date_to_internet (datetmp, p->end);
+           send_to_server (datetmp, 0);
+           send_to_server ("\012", 0);
+           if (p->end)
+               free (p->end);
+           free (p);
+       }
+           
+       if (rlog_data.header)
+           send_arg ("-h");
+       if (rlog_data.notags)
+           send_arg("-N");
+       if (rlog_data.nameonly)
+           send_arg("-R");
+       if (rlog_data.long_header)
+           send_arg("-t");
+
+       while (rlog_data.revlist != NULL)
+       {
+           rp = rlog_data.revlist;
+           rlog_data.revlist = rp->next;
+           send_to_server ("Argument -r", 0);
+           if (rp->branchhead)
+           {
+               if (rp->first != NULL)
+                   send_to_server (rp->first, 0);
+               send_to_server (".", 1);
+           }
+           else
+           {
+               if (rp->first != NULL)
+                   send_to_server (rp->first, 0);
+               send_to_server (":", 1);
+               if (rp->last != NULL)
+                   send_to_server (rp->last, 0);
+           }
+           send_to_server ("\012", 0);
+           if (rp->first)
+               free (rp->first);
+           if (rp->last)
+               free (rp->last);
+           free (rp);
+       }
+       send_arg_list ("-s", rlog_data.statelist);
+       dellist (&rlog_data.statelist);
+       send_arg_list ("-w", rlog_data.authorlist);
+       dellist (&rlog_data.authorlist);
+
+       /* Send the rest of the arguments */
+       {
+           int i;
+
+           for (i = 0; i < argc; i++)
+               send_arg (argv[i]);
+       }
+
+       send_to_server ("rlog\012", 0);
+       err = get_responses_and_close ();
+
+       return err;
+    }
+#endif
+
+    /* We're the server or we're local.  Do each module. */
+    db = open_module ();
+
+    for (i = 0; i < argc; i++)
+       err += do_module (db, argv[i], CVSRLOG, "Logging", rlog_list_proc,
+                         (char *) NULL, 0, 0, 0, (char *) NULL);
+
+    close_module (db);
+
+    while (rlog_data.revlist)
+    {
+       struct option_revlist *rl = rlog_data.revlist->next;
+       if (rlog_data.revlist->first)
+           free (rlog_data.revlist->first);
+       if (rlog_data.revlist->last)
+           free (rlog_data.revlist->last);
+       free (rlog_data.revlist);
+       rlog_data.revlist = rl;
+    }
+    while (rlog_data.datelist)
+    {
+       struct datelist *nd = rlog_data.datelist->next;
+       if (rlog_data.datelist->start)
+           free (rlog_data.datelist->start);
+       if (rlog_data.datelist->end)
+           free (rlog_data.datelist->end);
+       free (rlog_data.datelist);
+       rlog_data.datelist = nd;
+    }
+    while (rlog_data.singledatelist)
+    {
+       struct datelist *nd = rlog_data.singledatelist->next;
+       if (rlog_data.singledatelist->start)
+           free (rlog_data.singledatelist->start);
+       if (rlog_data.singledatelist->end)
+           free (rlog_data.singledatelist->end);
+       free (rlog_data.singledatelist);
+       rlog_data.singledatelist = nd;
+    }
+    dellist (&rlog_data.statelist);
+    dellist (&rlog_data.authorlist);
+
+    return (err);
+}
+
+/*
+ * Callback proc. for doing the actual work for cvsrlog
+ */
+/* ARGSUSED */
+static int
+rlog_list_proc (argc, argv, xwhere, mwhere, mfile, shorten, local_specified,
+               mname, msg)
+    int argc;
+    char **argv;
+    char *xwhere;
+    char *mwhere;
+    char *mfile;
+    int shorten;
+    int local_specified;
+    char *mname;
+    char *msg;
+{
+    /* Begin section which is identical to patch_proc */
+    char *myargv[2];
+    int err = 0;
+    char *repository;
+    char *where;
+
+    /* Get the repository path */
+    repository = xmalloc (strlen (CVSroot_directory) + strlen (argv[0])
+                         + (mfile ? strlen (mfile) : 0) + 30);
+    sprintf (repository, "%s/%s", CVSroot_directory, argv[0]);
+
+    /* Get the module path */
+    where = xmalloc (strlen (argv[0]) + (mfile ? strlen (mfile) : 0)
+                    + 10);
+    strcpy (where, argv[0]);
+
+    /* If mfile is non-null, we're only supposed to work on part of this
+       module. */
+    if (mfile)
+    {
+       char *cp;
+       char *path;
+
+       /* if the portion of the module is a path, put the dir part on repos */
+       if ((cp = strrchr (mfile, '/')) != NULL)
+       {
+           *cp = '\0';
+           (void) strcat (repository, "/");
+           (void) strcat (repository, mfile);
+           (void) strcat (where, "/");
+           (void) strcat (where, mfile);
+           mfile = cp + 1;
+       }
+
+       /* take care of the rest */
+       path = xmalloc (strlen (repository) + strlen (mfile) + 5);
+       (void) sprintf (path, "%s/%s", repository, mfile);
+       if (isdir (path))
+       {
+           /* directory means repository gets the dir tacked on */
+           (void) strcpy (repository, path);
+           (void) strcat (where, "/");
+           (void) strcat (where, mfile);
+       }
+       else
+       {
+           myargv[0] = argv[0];
+           myargv[1] = mfile;
+           argc = 2;
+           argv = myargv;
+       }
+       free (path);
+    }
+
+    /* cd to the starting repository */
+    if (CVS_CHDIR (repository) < 0)
+    {
+       error (0, errno, "cannot chdir to %s", repository);
+       free (repository);
+       return (1);
+    }
+    free (repository);
+    /* End section which is identical to patch_proc. */
+
+    err = start_recursion (log_fileproc, (FILESDONEPROC) NULL, log_dirproc,
+                          (DIRLEAVEPROC) NULL, (void *) &rlog_data,
+                          argc - 1, argv + 1, 0, W_REPOS | W_ATTIC, 0, 1,
+                          (char *) NULL, 1);
+
+    free (where);
 
     return (err);
 }
diff -w -r -u orig/cvs-1.11/src/main.c cvs-1.11/src/main.c
--- orig/cvs-1.11/src/main.c    Thu Sep  7 01:35:04 2000
+++ cvs-1.11/src/main.c Sun Nov 12 17:39:02 2000
@@ -114,7 +114,7 @@
 #if defined (HAVE_KERBEROS) && defined (SERVER_SUPPORT)
     { "kserver",  NULL,       NULL,        server }, /* placeholder */
 #endif
-    { "log",      "lo",       "rlog",      cvslog },
+    { "log",      "lo",       NULL,       cvslog },
 #ifdef AUTH_CLIENT_SUPPORT
     { "login",    "logon",    "lgn",       login },
     { "logout",   NULL,       NULL,        logout },
@@ -125,6 +125,7 @@
     { "rdiff",    "patch",    "pa",        patch },
     { "release",  "re",       "rel",       release },
     { "remove",   "rm",       "delete",    cvsremove },
+    { "rlog",    "rl",       NULL,        cvsrlog },
     { "rtag",     "rt",       "rfreeze",   rtag },
 #ifdef SERVER_SUPPORT
     { "server",   NULL,       NULL,        server },
@@ -214,6 +215,7 @@
     "        rdiff        Create 'patch' format diffs between releases\n",
     "        release      Indicate that a Module is no longer in use\n",
     "        remove       Remove an entry from the repository\n",
+    "        rlog         Print out history information for modules\n",
     "        rtag         Add a symbolic tag to a module\n",
 #ifdef SERVER_SUPPORT
     "        server       Server mode\n",
@@ -333,6 +335,7 @@
        (strcmp (cmd_name, "logout") != 0) &&
         (strcmp (cmd_name, "rdiff") != 0) &&
         (strcmp (cmd_name, "release") != 0) &&
+       (strcmp (cmd_name, "rlog") != 0) &&
         (strcmp (cmd_name, "rtag") != 0))
     {
         ret |= CVS_CMD_USES_WORK_DIR;
@@ -354,6 +357,7 @@
         (strcmp (cmd_name, "noop") != 0) &&
         (strcmp (cmd_name, "watchers") != 0) &&
         (strcmp (cmd_name, "release") != 0) &&
+       (strcmp (cmd_name, "rlog") != 0) &&
         (strcmp (cmd_name, "status") != 0))
     {
         ret |= CVS_CMD_MODIFIES_REPOSITORY;
@@ -675,15 +679,6 @@
     }
     else
        command_name = cm->fullname;    /* Global pointer for later use */
-
-    /* This should probably remain a warning, rather than an error,
-       for quite a while.  For one thing the version of VC distributed
-       with GNU emacs 19.34 invokes 'cvs rlog' instead of 'cvs log'.  */
-    if (strcmp (argv[0], "rlog") == 0)
-    {
-       error (0, 0, "warning: the rlog command is deprecated");
-       error (0, 0, "use the synonymous log command instead");
-    }
 
     if (help)
     {

Reply via email to