Format CVS or RCS log entries into ChangeLog format.

This code is an application, probably similar to a Perl thing at [L1 ], but obviously superior, because it is written in Tcl.

NEM 4Feb2003 - I can't seem to get this to work. It just hangs reading the log from stdin. Any ideas? The command I used was:

 cvs log | tclsh log2changelog

Is that correct?

TR - the problem is: 'cvs log' also outputs lines containing '=' characters. So changing the 'string match' line to a suited regexp, will fix the problem of an infinite loop under certain conditions.

    # restart using tclsh \
    exec tclsh "$0" "$@" 

    #  log2changelog.tcl
    #  Create changelog entries from cvs or rcs log listing
    #  Read an rcs/rlog or cvs/log listing, and remap the log
    #  entries into a format like:
    #    2002/07/02 Author
    #       * file1.tcl: 
    #       * file2.tcl: 
    #       Changed contents of files.
    #  Use Tcl arrays to re-map the data into entries per date,
    #  developer, and comment string.  Group date/author
    #  changes together.  Match multiple files with identical
    #  comments.  Reformat comment text.

    #  Read rcs/cvs log data from standard input
    while { ! [eof stdin] } {
        lappend data [gets stdin]

    #  Load several arrays with the log entries
    for {set i 0} {$i<[llength $data]} {incr i} {

        set line [lindex $data $i]
        switch -glob -- $line {

            "*Working file:*" {
                regexp {Working file: (.*)} $line -> filename

            "date:*" {
                scan $line "date: %s %s author: %s" date time author
                set author [string trim $author ";"]

                # read the comment lines following date
                set comment ""
                incr i
                set line [lindex $data $i]
                # [TR]: use regexp here to see if log ends:
                while { ! [regexp "(-----*)|(=====*)" $line] } {
                    append comment $line "\n"
                    incr i
                    set line [lindex $data $i]

                #  Store this date/author/comment
                lappend entries [list $date $author]
                lappend comments($date,$author) $comment
                lappend files($date,$author,$comment) $filename


    #  Now that we've loaded the data into some
    #  arrays, let's print out the changelog

    foreach e [lsort -unique -decreasing $entries] {

        #  print the date/author
        foreach {date author} $e {break}
        puts "$date $author"
        puts ""

        #  Find all the comments submitted this date/author
        foreach c [lsort -unique $comments($date,$author)] {

            set txt ""
            #  Print all files for a given comment
            foreach f [lsort -unique $files($date,$author,$c)] {
                puts "\t* $f:"

            #  Format and print the comment
            #  (note that we saved the newlines, just in case
            #   somebody wants to print the comment without
            #   reformatting.)
            set c [string map {"\n" " "} $c]
            set len 60
            while { [string length $c] > 0 } {
                set brk [string last " " $c $len]
                if { $brk < 0 } {set brk $len}
                puts "\t[string range $c 0 $brk]"
                set c [string range $c [expr {$brk+1}] end]
            puts ""