The attached patch creates an alternate logmsg format containing 
more useful information in an easier to read format, enabled by 
the LogMsgFancy=yes option (default is old format):

> Modified Files:
>       cat-5.lsp            1.66  1.67  +13 -10
>       cat-6.lsp            1.44  1.45  +10 -9 
>       cat-7.lsp            1.42  1.43  +10 -9 
>       stringing-logic.lsp  1.49  1.50  +2  -1 
> Log Message:
> ......

It also adds a new "t" format specifier for the logmsg script invocation,
expanding to the file's tag.

If you are interested in this feature, let me know if you require any
modifications for inclusion.  I find it useful to know how extensive
the changes being committed to our codebase are, and expect to write
an emacs hook to enable clicking on the message from my mail buffer
for the diff.

I grant permission to distribute this patch under the terms of the GNU
Public License.

Greg

Index: doc/ChangeLog
===================================================================
RCS file: /usr/home/greg/repository/cvs/doc/ChangeLog,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- doc/ChangeLog       2001/03/14 22:37:39     1.1.1.1
+++ doc/ChangeLog       2001/03/16 02:14:38     1.2
@@ -1,3 +1,7 @@
+2001-03-15  Greg Klanderman  <[EMAIL PROTECTED]>
+
+       * cvs.texinfo (config): document LogMsgFancy.
+
 2000-09-07  Larry Jones  <[EMAIL PROTECTED]>
 
        * Makefile.in: Use @bindir@, @libdir@, @infodir@, and @mandir@
Index: doc/cvs.texinfo
===================================================================
RCS file: /usr/home/greg/repository/cvs/doc/cvs.texinfo,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- doc/cvs.texinfo     2001/03/14 22:37:39     1.1.1.1
+++ doc/cvs.texinfo     2001/03/16 02:14:38     1.2
@@ -12089,6 +12089,8 @@
 @table @t
 @item s
 file name
+@item t
+file tag
 @item V
 old version number (pre-checkin)
 @item v
@@ -12606,6 +12608,16 @@
 each command.  It also provides a place for the
 @file{CVS/Template} file (@pxref{Working directory
 storage}).
+
+@cindex LogMsgFancy, in CVSROOT/config
+@item LogMsgFancy=@var{value}
+When set to @samp{yes}, use a fancier format for the
+log messages produced by @samp{cvs commit} when enabled
+in the @file{loginfo} administrative file.  The fancier
+format includes the old and new revisions as well as
+the numbers of added and deleted lines for each file
+being checked in.  The default is @samp{no}.
+
 
 @cindex LockDir, in CVSROOT/config
 @item LockDir=@var{directory}
Index: src/ChangeLog
===================================================================
RCS file: /usr/home/greg/repository/cvs/src/ChangeLog,v
retrieving revision 1.1.1.1
retrieving revision 1.3
diff -u -r1.1.1.1 -r1.3
--- src/ChangeLog       2001/03/14 22:37:37     1.1.1.1
+++ src/ChangeLog       2001/03/16 02:14:38     1.3
@@ -1,3 +1,34 @@
+2001-03-15  Greg Klanderman  <[EMAIL PROTECTED]>
+
+       * logmsg.c (title_proc): add "t" as a new format spec for the
+       loginfo filter invocation: expands to the file's tag.
+
+       * rcs.c (compute_change_stats, RCS_checkin): 
+       * parseinfo.c (parse_config): 
+       * logmsg.c (setup_tmpfile, compute_formatting, fmt_proc_fancy):
+       New fancy logmsg format, which can be enabled via the
+       "LogMsgFancy" option in the "config" file.
+
+       * rcs.h: 
+       * import.c (import, add_rev): 
+       * cvs.h:
+       * commit.c (find_fileproc, check_fileproc, commit_fileproc,
+       remove_file, finaladd, checkaddfile):
+       * checkin.c (Checkin): 
+       * add.c (add_directory): 
+       trivial changes for above "fancy logmsg" feature.
+
 2000-09-19  Larry Jones  <[EMAIL PROTECTED]> 
 
        * version.c: Version 1.11.
Index: src/add.c
===================================================================
RCS file: /usr/home/greg/repository/cvs/src/add.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- src/add.c   2001/03/14 22:37:38     1.1.1.1
+++ src/add.c   2001/03/14 22:48:13     1.2
@@ -792,6 +792,7 @@
        li->type = T_TITLE;
        li->tag = xstrdup (tag);
        li->rev_old = li->rev_new = NULL;
+        li->add = li->del = 0;
        p->data = (char *) li;
        (void) addnode (ulist, p);
        Update_Logfile (rcsdir, message, (FILE *) NULL, ulist);
Index: src/checkin.c
===================================================================
RCS file: /usr/home/greg/repository/cvs/src/checkin.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- src/checkin.c       2001/03/14 22:37:38     1.1.1.1
+++ src/checkin.c       2001/03/14 22:48:13     1.2
@@ -20,7 +20,7 @@
 #include "edit.h"
 
 int
-Checkin (type, finfo, rcs, rev, tag, options, message)
+Checkin (type, finfo, rcs, rev, tag, options, message, add, del)
     int type;
     struct file_info *finfo;
     char *rcs;
@@ -28,6 +28,7 @@
     char *tag;
     char *options;
     char *message;
+    unsigned *add, *del;
 {
     Vers_TS *vers;
     int set_time;
@@ -56,7 +57,8 @@
     if (finfo->rcs == NULL)
        finfo->rcs = RCS_parse (finfo->file, finfo->repository);
 
-    switch (RCS_checkin (finfo->rcs, NULL, message, rev, RCS_FLAGS_KEEPFILE))
+    switch (RCS_checkin (finfo->rcs, NULL, message, rev, RCS_FLAGS_KEEPFILE,
+                         add, del))
     {
        case 0:                 /* everything normal */
 
Index: src/commit.c
===================================================================
RCS file: /usr/home/greg/repository/cvs/src/commit.c,v
retrieving revision 1.1.1.1
retrieving revision 1.4
diff -u -r1.1.1.1 -r1.4
--- src/commit.c        2001/03/14 22:37:38     1.1.1.1
+++ src/commit.c        2001/03/16 02:14:39     1.4
@@ -41,7 +41,7 @@
                                        char *repository, char *update_dir,
                                        List *entries));
 static int finaladd PROTO((struct file_info *finfo, char *revision, char *tag,
-                          char *options));
+                          char *options, unsigned *add, unsigned *del));
 static int findmaxrev PROTO((Node * p, void *closure));
 static int lock_RCS PROTO((char *user, RCSNode *rcs, char *rev,
                           char *repository));
@@ -296,6 +296,7 @@
     data->type = status;
     data->tag = xstrdup (vers->tag);
     data->rev_old = data->rev_new = NULL;
+    data->add = data->del = 0;
 
     node->type = UPDATE;
     node->delproc = update_delproc;
@@ -998,6 +999,7 @@
            li->tag = xstrdup (vers->tag);
            li->rev_old = xstrdup (vers->vn_rcs);
            li->rev_new = NULL;
+            li->add = li->del = 0;
            p->data = (char *) li;
            (void) addnode (ulist, p);
 
@@ -1199,6 +1201,7 @@
     int err = 0;
     List *ulist, *cilist;
     struct commit_info *ci;
+    unsigned add_lines = 0, del_lines = 0;
 
     /* Keep track of whether write_dirtag is a branch tag.
        Note that if it is a branch tag in some files and a nonbranch tag
@@ -1286,7 +1289,8 @@
                free (ci->rev);
            ci->rev = RCS_whatbranch (finfo->rcs, ci->tag);
            err = Checkin ('A', finfo, finfo->rcs->path, ci->rev,
-                          ci->tag, ci->options, saved_message);
+                          ci->tag, ci->options, saved_message,
+                           &add_lines, &del_lines);
            if (err != 0)
            {
                unlockrcs (finfo->rcs);
@@ -1318,7 +1322,8 @@
        }
 
        /* XXX - an added file with symbolic -r should add tag as well */
-       err = finaladd (finfo, ci->rev ? ci->rev : xrev, ci->tag, ci->options);
+       err = finaladd (finfo, ci->rev ? ci->rev : xrev, ci->tag, ci->options,
+                        &add_lines, &del_lines);
        if (xrev)
            free (xrev);
     }
@@ -1326,7 +1331,8 @@
     {
        err = Checkin ('M', finfo,
                       finfo->rcs->path, ci->rev, ci->tag,
-                      ci->options, saved_message);
+                      ci->options, saved_message,
+                       &add_lines, &del_lines);
 
        (void) time (&last_register_time);
 
@@ -1390,6 +1396,8 @@
                (void) classify_file_internal (finfo, &vers);
                li = (struct logfile_info *) p->data;
                li->rev_new = xstrdup (vers->vn_rcs);
+                li->add = add_lines;
+                li->del = del_lines;
                freevers_ts (&vers);
            }
        }
@@ -1742,7 +1750,8 @@
        free (corev);
 
     retcode = RCS_checkin (finfo->rcs, finfo->file, message, rev,
-                          RCS_FLAGS_DEAD | RCS_FLAGS_QUIET);
+                          RCS_FLAGS_DEAD | RCS_FLAGS_QUIET,
+                           NULL, NULL);
     if (retcode        != 0)
     {
        if (!quiet)
@@ -1780,17 +1789,18 @@
  * Do the actual checkin for added files
  */
 static int
-finaladd (finfo, rev, tag, options)
+finaladd (finfo, rev, tag, options, add, del)
     struct file_info *finfo;
     char *rev;
     char *tag;
     char *options;
+    unsigned *add, *del;
 {
     int ret;
     char *rcs;
 
     rcs = locate_rcs (finfo->file, finfo->repository);
-    ret = Checkin ('A', finfo, rcs, rev, tag, options, saved_message);
+    ret = Checkin ('A', finfo, rcs, rev, tag, options, saved_message, add, del);
     if (ret == 0)
     {
        char *tmp = xmalloc (strlen (finfo->file) + sizeof (CVSADM)
@@ -2086,7 +2096,8 @@
            (void) sprintf (tmp, "file %s was initially added on branch %s.",
                            file, tag);
            retcode = RCS_checkin (rcsfile, NULL, tmp, NULL,
-                                  RCS_FLAGS_DEAD | RCS_FLAGS_QUIET);
+                                  RCS_FLAGS_DEAD | RCS_FLAGS_QUIET,
+                                   NULL, NULL);
            free (tmp);
            if (retcode != 0)
            {
Index: src/cvs.h
===================================================================
RCS file: /usr/home/greg/repository/cvs/src/cvs.h,v
retrieving revision 1.1.1.1
retrieving revision 1.3
diff -u -r1.1.1.1 -r1.3
--- src/cvs.h   2001/03/14 22:37:38     1.1.1.1
+++ src/cvs.h   2001/03/16 01:50:25     1.3
@@ -397,6 +397,7 @@
 extern int logoff;             /* Don't write history entry */
 
 extern int top_level_admin;
+extern int logmsg_fancy;
 
 #ifdef CLIENT_SUPPORT
 extern List *dirs_sent_to_server; /* used to decide which "Argument
@@ -748,7 +749,8 @@
    processor (for example, needs struct file_info).  */
 
 int Checkin PROTO ((int type, struct file_info *finfo, char *rcs, char *rev,
-                   char *tag, char *options, char *message));
+                   char *tag, char *options, char *message,
+                    unsigned *add, unsigned *del));
 int No_Difference PROTO ((struct file_info *finfo, Vers_TS *vers));
 /* TODO: can the finfo argument to special_file_mismatch be changed? -twp */
 int special_file_mismatch PROTO ((struct file_info *finfo,
@@ -798,6 +800,8 @@
                                   NULL for add or import */
   char *rev_new;               /* rev number after a commit/modify,
                                   add, or import, NULL for remove */
+
+  unsigned add, del;            /* count of lines added and deleted */
 };
 
 /* Wrappers.  */
Index: src/import.c
===================================================================
RCS file: /usr/home/greg/repository/cvs/src/import.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- src/import.c        2001/03/14 22:37:38     1.1.1.1
+++ src/import.c        2001/03/14 22:48:13     1.2
@@ -376,6 +376,7 @@
     li->type = T_TITLE;
     li->tag = xstrdup (vbranch);
     li->rev_old = li->rev_new = NULL;
+    li->add = li->del = 0;
     p->data = (char *) li;
     (void) addnode (ulist, p);
     Update_Logfile (repository, message, logfp, ulist);
@@ -728,7 +729,8 @@
     status = RCS_checkin (rcs, tocvsPath == NULL ? vfile : tocvsPath,
                          message, vbranch,
                          (RCS_FLAGS_QUIET | RCS_FLAGS_KEEPFILE
-                          | (use_file_modtime ? RCS_FLAGS_MODTIME : 0)));
+                          | (use_file_modtime ? RCS_FLAGS_MODTIME : 0)),
+                          NULL, NULL);
     ierrno = errno;
 
     if ((tocvsPath != NULL) && (unlink_file_dir (tocvsPath) < 0))
Index: src/logmsg.c
===================================================================
RCS file: /usr/home/greg/repository/cvs/src/logmsg.c,v
retrieving revision 1.1.1.1
retrieving revision 1.4
diff -u -r1.1.1.1 -r1.4
--- src/logmsg.c        2001/03/14 22:37:38     1.1.1.1
+++ src/logmsg.c        2001/03/16 02:14:39     1.4
@@ -8,9 +8,11 @@
 
 #include "cvs.h"
 #include "getline.h"
+#include <math.h>
 
 static int find_type PROTO((Node * p, void *closure));
-static int fmt_proc PROTO((Node * p, void *closure));
+static int fmt_proc_old PROTO((Node * p, void *closure));
+static int fmt_proc_fancy PROTO((Node * p, void *closure));
 static int logfile_write PROTO((char *repository, char *filter,
                          char *message, FILE * logfp, List * changes));
 static int rcsinfo_proc PROTO((char *repository, char *template));
@@ -27,6 +29,8 @@
 static char *verifymsg_script;
 static Ctype type;
 
+int logmsg_fancy = 0;
+
 /*
  * Puts a standard header on the output which is either being prepared for an
  * editor session, or being sent to a logfile program.  The modified, added,
@@ -34,16 +38,30 @@
 static char *prefix;
 static int col;
 static char *tag;
+
+static int compute_formatting PROTO ((Node *p, void *closure));
+static int fmt_file, fmt_orev, fmt_nrev, fmt_add, fmt_del;
+
 static void
 setup_tmpfile (xfp, xprefix, changes)
     FILE *xfp;
     char *xprefix;
     List *changes;
 {
+    int (*fmt_proc) PROTO((Node * p, void *closure))
+      = logmsg_fancy ? fmt_proc_fancy : fmt_proc_old;
+  
     /* set up statics */
     fp = xfp;
     prefix = xprefix;
 
+    if (logmsg_fancy)
+    {
+        fmt_file = fmt_orev = fmt_nrev = 0;
+        fmt_add = fmt_del = 1;
+        walklist (changes, compute_formatting, NULL);
+    }
+
     type = T_MODIFIED;
     if (walklist (changes, find_type, NULL) != 0)
     {
@@ -85,6 +103,26 @@
     }
 }
 
+
+/*
+ * compute fancy formatting information
+ */
+static int
+compute_formatting (p, closure)
+  Node *p;
+  void *closure;
+{
+    struct logfile_info *li = (struct logfile_info *) p->data;
+
+    if (p->key) fmt_file = MAX (fmt_file, strlen (p->key));
+    if (li->rev_old) fmt_orev = MAX (fmt_orev, strlen (li->rev_old));
+    if (li->rev_new) fmt_nrev = MAX (fmt_nrev, strlen (li->rev_new));
+    fmt_add  = MAX (fmt_add, (int)(ceil (log10 (li->add + 1))));
+    fmt_del  = MAX (fmt_del, (int)(ceil (log10 (li->del + 1))));
+
+    return 1;
+}
+
 /*
  * Looks for nodes of a specified type and returns 1 if found
  */
@@ -108,7 +146,7 @@
  * match the one we're looking for
  */
 static int
-fmt_proc (p, closure)
+fmt_proc_old (p, closure)
     Node *p;
     void *closure;
 {
@@ -160,6 +198,59 @@
     return (0);
 }
 
+static int
+fmt_proc_fancy (p, closure)
+    Node *p;
+    void *closure;
+{
+    struct logfile_info *li;
+
+    li = (struct logfile_info *) p->data;
+    if (li->type == type)
+    {
+        if (li->tag == NULL
+           ? tag != NULL
+           : tag == NULL || strcmp (tag, li->tag) != 0)
+       {
+           (void) fprintf (fp, "%6s", prefix);
+
+           if (li->tag == NULL)
+               (void) fprintf (fp, "No tag\n");
+           else
+               (void) fprintf (fp, "Tag: %s\n", li->tag);
+
+           if (tag != NULL)
+               free (tag);
+           tag = xstrdup (li->tag);
+       }
+
+        switch (type)
+        {
+        case T_ADDED:
+          (void) fprintf (fp, "%s\t%-*s  %-*s\n",
+                          prefix, fmt_file, p->key,
+                          fmt_orev, li->rev_new);
+          break;
+
+        case T_REMOVED:
+          (void) fprintf (fp, "%s\t%-*s  %-*s\n",
+                          prefix, fmt_file, p->key,
+                          fmt_orev, li->rev_old);
+          break;
+
+        default:
+        case T_MODIFIED:
+          (void) fprintf (fp, "%s\t%-*s  %-*s  %-*s  +%-*d -%-*d\n",
+                          prefix, fmt_file, p->key,
+                          fmt_orev, li->rev_old,
+                          fmt_nrev, li->rev_new,
+                          fmt_add, li->add, fmt_del, li->del);
+          break;
+        }
+    }
+    return (0);
+}
+
 /*
  * Builds a temporary file using setup_tmpfile() and invokes the user's
  * editor on the file.  The header garbage in the resultant file is then
@@ -611,6 +702,16 @@
                    (void) strcat (str_list, (li->rev_new
                                              ? li->rev_new : "NONE"));
                    break;
+               case 't':
+                   str_list =
+                       xrealloc (str_list,
+                                 (strlen (str_list)
+                                  + (li->tag ? strlen (li->tag) : 0)
+                                  + 10)
+                                 );
+                   (void) strcat (str_list, (li->tag
+                                             ? li->tag : "NONE"));
+                   break;
                /* All other characters, we insert an empty field (but
                   we do put in the comma separating it from other
                   fields).  This way if future CVS versions add formatting
@@ -672,6 +773,7 @@
          s = file name
         V = old version number (pre-checkin)
         v = new version number (post-checkin)
+         t = file tag
 
        For example, valid format strings are:
 
Index: src/parseinfo.c
===================================================================
RCS file: /usr/home/greg/repository/cvs/src/parseinfo.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- src/parseinfo.c     2001/03/14 22:37:38     1.1.1.1
+++ src/parseinfo.c     2001/03/16 01:50:25     1.2
@@ -367,6 +367,18 @@
                goto error_return;
            }
        }
+       else if (strcmp (line, "LogMsgFancy") == 0)
+       {
+           if (strcmp (p, "no") == 0)
+               logmsg_fancy = 0;
+           else if (strcmp (p, "yes") == 0)
+               logmsg_fancy = 1;
+           else
+           {
+               error (0, 0, "unrecognized value '%s' for LogMsgFancy", p);
+               goto error_return;
+           }
+       }
        else if (strcmp (line, "LockDir") == 0)
        {
            if (lock_dir != NULL)
Index: src/rcs.c
===================================================================
RCS file: /usr/home/greg/repository/cvs/src/rcs.c,v
retrieving revision 1.1.1.1
retrieving revision 1.3
diff -u -r1.1.1.1 -r1.3
--- src/rcs.c   2001/03/14 22:37:39     1.1.1.1
+++ src/rcs.c   2001/03/16 01:50:25     1.3
@@ -4772,6 +4772,69 @@
     return newrevnum;
 }
 
+
+static void compute_change_stats PROTO ((char *, int, unsigned *, unsigned *));
+
+static void
+compute_change_stats(text, len, addp, delp)
+  char *text;
+  int len;
+  unsigned *addp;
+  unsigned *delp;
+{
+    unsigned add=0, del=0;
+    char *cp;
+
+    if (addp == NULL || delp == NULL)
+        return;
+
+    *addp = 0;
+    *delp = 0;
+
+    if (text == NULL)
+        return;
+
+    cp = text;
+    while (cp < text + len) {
+        char op;
+        unsigned long count;
+
+        op = *cp++;
+        if (op != 'a' && op  != 'd')
+            return;
+
+        (void) strtoul (cp, &cp, 10);
+        if (*cp++ != ' ')
+            return;
+
+        count = strtoul (cp, &cp, 10);
+        if (*cp++ != '\012')
+            return;
+
+        if (op == 'd')
+            del += count;
+        else {
+            add += count;
+            while (count != 0)
+            {
+                if (*cp == '\012')
+                    --count;
+                else if (cp == text + len)
+                {
+                    if (count != 1)
+                        return;
+                    else
+                        break;
+                }
+                ++cp;
+            }
+        }
+    }
+
+    *addp = add;
+    *delp = del;
+}
+
 /* Check in to RCSFILE with revision REV (which must be greater than
    the largest revision) and message MESSAGE (which is checked for
    legality).  If FLAGS & RCS_FLAGS_DEAD, check in a dead revision.
@@ -4794,12 +4857,13 @@
    or zero for success.  */
 
 int
-RCS_checkin (rcs, workfile, message, rev, flags)
+RCS_checkin (rcs, workfile, message, rev, flags, add, del)
     RCSNode *rcs;
     char *workfile;
     char *message;
     char *rev;
     int flags;
+    unsigned *add, *del;
 {
     RCSVers *delta, *commitpt;
     Deltatext *dtext;
@@ -5302,6 +5366,9 @@
            commitpt->text->text = xstrdup ("");
            commitpt->text->len = 0;
        }
+
+        compute_change_stats (commitpt->text->text, commitpt->text->len,
+                              del, add); /* NB: the diff was reversed.. */
     }
     else
     {
@@ -5333,6 +5400,8 @@
            dtext->text = xstrdup ("");
            dtext->len = 0;
        }
+
+        compute_change_stats (dtext->text, dtext->len, add, del);
     }
 
     /* Update DELTA linkage.  It is important not to do this before
Index: src/rcs.h
===================================================================
RCS file: /usr/home/greg/repository/cvs/src/rcs.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- src/rcs.h   2001/03/14 22:37:38     1.1.1.1
+++ src/rcs.h   2001/03/14 22:48:13     1.2
@@ -218,7 +218,7 @@
 int RCS_checkout PROTO ((RCSNode *, char *, char *, char *, char *, char *,
                         RCSCHECKOUTPROC, void *));
 int RCS_checkin PROTO ((RCSNode *rcs, char *workfile, char *message,
-                       char *rev, int flags));
+                       char *rev, int flags, unsigned *add, unsigned *del));
 int RCS_cmp_file PROTO ((RCSNode *, char *, char *, const char *));
 int RCS_settag PROTO ((RCSNode *, const char *, const char *));
 int RCS_deltag PROTO ((RCSNode *, const char *));

Reply via email to