--- cvs2cl.pl-ORIG	2002-12-18 10:47:10.000000000 -0800
+++ cvs2cl.pl	2002-12-18 12:29:22.000000000 -0800
@@ -131,6 +131,9 @@ my $XML_Encoding = '';
 # Format more for programs than for humans.
 my $XML_Output = 0;
 
+# Format for gods.
+my $Lisp_Output = 0;
+
 # Do some special tweaks for log data that was written in FSF
 # ChangeLog style.
 my $FSF_Style = 0;
@@ -761,7 +764,10 @@ sub derive_change_log ()
 
     print LOG_OUT $ChangeLog_Header;
 
-    if ($XML_Output) {
+    if ($Lisp_Output) {
+      print LOG_OUT "(:cvs2cl-changelog (:version 1)\n";
+    } 
+    elsif ($XML_Output) {
       my $encoding    = 
         length $XML_Encoding ? qq'encoding="$XML_Encoding"' : '';
       my $version     = 'version="1.0"';
@@ -786,7 +792,7 @@ sub derive_change_log ()
 
       # XML output includes everything else, we might as well make
       # it always include Day Of Week too, for consistency.
-      if ($Show_Day_Of_Week or $XML_Output) {
+      if ($Show_Day_Of_Week or $XML_Output or $Lisp_Output) {
         $wday = ("Sunday", "Monday", "Tuesday", "Wednesday",
                  "Thursday", "Friday", "Saturday")[$wday];
         $wday = ($XML_Output) ? "<weekday>${wday}</weekday>\n" : " $wday";
@@ -812,7 +818,13 @@ sub derive_change_log ()
         foreach my $tag (keys %tags) {
           if (!defined $tag_date_printed{$tag}) {
             $tag_date_printed{$tag} = $time;
-            if ($XML_Output) {
+            if ($Lisp_Output) {
+              printf LOG_OUT ("(:tag \"%s\" :date (%u %u %u) :time (%u %u) " .
+                              ":weekday %s)\n",
+                              $tag, $year+1900, $mon+1, $mday, $hour, 
+                              $min, $wday);
+            } 
+            elsif ($XML_Output) {
               # NOT YET DONE
             }
             else {
@@ -824,8 +836,12 @@ sub derive_change_log ()
       }
       while (my ($author,$mesghash) = each %$authorhash)
       {
-        # If XML, escape in outer loop to avoid compound quoting:
-        if ($XML_Output) {
+        # If Lisp or XML, escape in outer loop to avoid compound quoting:
+
+        if ($Lisp_Output) {
+          $author = &lisp_escape ($author);
+        } 
+        elsif ($XML_Output) {
           $author = &xml_escape ($author);
         }
 
@@ -846,7 +862,12 @@ sub derive_change_log ()
           my $body;                 # see below
           my $wholething;           # $header_line + $body
 
-          if ($XML_Output) {
+          if ($Lisp_Output) {
+            $header_line =
+                sprintf (":date (%u %u %u) :time (%u %u) :author \"%s\"\n",
+                         $year+1900, $mon+1, $mday, $hour, $min, $author);
+          }
+          elsif ($XML_Output) {
             $header_line =
                 sprintf ("<date>%4u-%02u-%02u</date>\n"
                          . "${wday}"
@@ -863,7 +884,7 @@ sub derive_change_log ()
           $Text::Wrap::huge = 'overflow'
             if $Text::Wrap::VERSION >= 2001.0130;
           # Reshape the body according to user preferences.
-          if ($XML_Output)
+          if ($Lisp_Output || $XML_Output)
           {
             $msg = &preprocess_msg_text ($msg);
             $body = $files . $msg;
@@ -905,7 +926,10 @@ sub derive_change_log ()
 
           $wholething = $header_line . $body;
 
-          if ($XML_Output) {
+          if ($Lisp_Output) {
+            $wholething = "  (:entry ${wholething})\n";
+          }
+          elsif ($XML_Output) {
             $wholething = "<entry>\n${wholething}</entry>\n";
           }
 
@@ -931,7 +955,10 @@ sub derive_change_log ()
       }
     }
 
-    if ($XML_Output) {
+    if ($Lisp_Output) {
+      print LOG_OUT ")\n";
+    }
+    elsif ($XML_Output) {
       print LOG_OUT "</changelog>\n";
     }
 
@@ -1006,7 +1033,7 @@ sub parse_date_and_author ()
 # summary that will include all the information the user asked for.
 sub pretty_file_list ()
 {
-  if ($Hide_Filenames and (! $XML_Output)) {
+  if ($Hide_Filenames and (! $XML_Output) and (! $Lisp_Output)) {
     return "";
   }
 
@@ -1094,7 +1121,70 @@ sub pretty_file_list ()
     }
   }
 
-  if ($XML_Output)
+  if ($Lisp_Output)
+  {
+    $beauty = "   :files (";
+    my $first = 1;
+
+    foreach my $qunkref (@qunkrefs)
+    {
+      my $filename    = $$qunkref{'filename'};
+      my $revision    = $$qunkref{'revision'};
+      my $tags        = $$qunkref{'tags'};
+      my $branch      = $$qunkref{'branch'};
+      my $branchroots = $$qunkref{'branchroots'};
+
+      $filename = &lisp_escape ($filename);
+      $revision = &lisp_escape ($revision);
+
+      unless ($first) {
+        $beauty .= "\n           ";
+      } 
+
+      $first = 0;
+
+      $revision = &lisp_convert_revision ($revision);
+      $beauty .= "(:name \"${filename}\" :revision ${revision}";
+      if ($branch) {
+        $branch   = &lisp_escape ($branch);
+        $beauty .= "            :branch \"${branch}\"\n";
+      }
+
+      $beauty .= "\n            :tags (";
+      foreach my $tag (@$tags) {
+        $tag = &lisp_escape ($tag);
+        $beauty .= "\"${tag}\" ";
+      }
+      $beauty .= ")";
+
+
+      $beauty .= "\n            :branchroots (";
+      foreach my $root (@$branchroots) {
+        $root = &lisp_escape ($root);
+        $beauty .= "\"${root}\" ";
+      }
+      $beauty .= "))";
+    }
+
+    $beauty .= ")";
+
+    if ((scalar (keys (%unanimous_tags))) > 1) {
+      $beauty .= "\n   :utags (";
+      foreach my $utag ((keys (%unanimous_tags))) {
+        $utag = &lisp_escape ($utag);
+        $beauty .= "\"${utag}\" ";
+      }
+      $beauty .= ")";
+    }
+    if ($common_dir) {
+      $common_dir = &xml_escape ($common_dir);
+      $beauty .= "\n   :commondir \"${common_dir}\"";
+    }
+
+    $beauty .= "\n";
+    return $beauty;
+  }
+  elsif ($XML_Output)
   {
     # If outputting XML, then our task is pretty simple, because we
     # don't have to detect common dir, common tags, branch prefixing,
@@ -1328,6 +1418,11 @@ sub preprocess_msg_text ()
   # If it *looks* like two newlines, make it *be* two newlines:
   $text =~ s/\n\s*\n/\n\n/g;
 
+  if ($Lisp_Output)
+  {
+    $text = &lisp_escape ($text);
+    $text = "   :message \"${text}\"";
+  }
   if ($XML_Output)
   {
     $text = &xml_escape ($text);
@@ -1552,6 +1647,30 @@ sub xml_escape ()
   return $txt;
 }
 
+#
+# Prepare text for embedding into Lisp string literal
+# This means escaping double quotes and backslashes
+#
+
+sub lisp_escape ()
+{
+  my $txt = shift;
+  $txt =~ s/"/\"/g;
+  $txt =~ s/\\/\\\\/g;
+  return $txt;
+}
+
+#
+# Turn CVS revision into a better Lisp representation.
+# E.g. "1.1.2.3" => "(1 1 2 3)"
+#
+
+sub lisp_convert_revision ()
+{
+  my $rev = shift;
+  $rev =~ s/\./ /g;
+  return "(${rev})";
+}
 
 sub maybe_read_user_map_file ()
 {
@@ -1723,6 +1842,9 @@ sub parse_options ()
     elsif ($arg =~ /^--xml$/) {
       $XML_Output = 1;
     }
+    elsif ($arg =~ /^--lisp$/) {
+      $Lisp_Output = 1;
+    }
     elsif ($arg =~ /^--hide-filenames$/) {
       $Hide_Filenames = 1;
       $After_Header = "";
@@ -1755,6 +1877,11 @@ sub parse_options ()
     $exit_with_admonishment = 1;
   }
 
+  if ($XML_Output && $Lisp_Output) {
+    print STDERR "cannot pass both --lisp and --xml\n";
+    $exit_with_admonishment = 1;
+  }
+
   # Or if any other error message has already been printed out, we
   # just leave now:
   if ($exit_with_admonishment) {
