2002-09-26 23:13:18

by Matthias Andree

[permalink] [raw]
Subject: [SCRIPT] lk-changelog.pl 0.39 released

Hi,

I released the new version 0.39 of my lk-changelog.pl script.

It seems as though it had too many features, because no-one reported
that --multi mode was broken in three months (since 0.26 of early June).
Nevermind, the bug is now fixed and dozens of new mail addresses were
added. Feel free to add more addresses that my lbdb did not provide.

I'm considering splitting this script into an engine (.pl) and address
(.pm) part so the latter could be updated independently. Would this be
useful or rather harmful?

The script is below the signature. It can also be downloaded from
http://mandree.home.pages.de/linux/kernel/ -- this site also carries
GnuPG signatures.

Have fun.

--
Matthias Andree

#! /usr/bin/perl -wT

# This Perl script is meant to simplify/beautify BK ChangeLogs for the linux
# kernel.
#
# (C) Copyright 2002 by Matthias Andree <[email protected]>
# Marcus Alanen <[email protected]>
# Tomas Szepe <[email protected]>
#
# $Id: lk-changelog.pl,v 0.39 2002/09/26 23:07:13 emma Exp $
# ----------------------------------------------------------------------
# Distribution of this script is permitted under the terms of the
# GNU General Public License (GNU GPL) v2.
# ----------------------------------------------------------------------

# This program expects its input in the following format:
# (E-Mail Addresses MUST NOT bear leading whitespace!)
#
# <[email protected]>
# changelog text
# more changelog text
# <[email protected]>
# yet another changelog
# <[email protected]>
# changelog #3
# more lines
#
# and discards all changelog lines but the first after an email address,
# and groups and sorts the entries by email address:
#
# [email protected]:
# changelog #3
# [email protected]
# changelog text
# yet another changelog

require 5.005;
use strict;

use Carp;
use Getopt::Long;
use IO::File;
eval 'use Pod::Usage;';
if ($@) {
eval 'sub pod2usage {
print STDERR "Usage information would be presented here if you had Pod::Usage installed.\n"
. "Try: perl -MCPAN -e \'install Pod::Usage\'\nAbort.\n";
exit 2;
}';
}
use Text::ParseWords;
use Text::Tabs;
use Text::Wrap;

# --------------------------------------------------------------------
# customize the following line to change the indentation of the change
# lines, $indent1 is used for the first line of an entry, $indent for
# all subsequent lines. $indent is auto-generated from $indent1.
my $indent1 = " o ";
my $indent = " " x length($indent1);
# change this to enable some debugging stuff:
my $debug = 0;
# --------------------------------------------------------------------

# the key is the email address in ALL LOWER CAPS!
# the value is the real name of the person
#
# Unless otherwise noted, the addresses below have been obtained using
# lbdbq.
my %addresses = (
'[email protected]' => 'Abraham van der Merwe',
'[email protected]' => 'Albert Cranford',
'[email protected]' => 'Georg Acher',
'[email protected]' => 'Javier Achirica',
'[email protected]' => 'Arnaldo Carvalho de Melo',
'[email protected]' => 'Arnaldo Carvalho de Melo',
'[email protected]' => 'Adam J. Richter',
'[email protected]' => 'Andreas Dilger',
'agrover@acpi3.(none)' => 'Andy Grover',
'[email protected]' => 'Andy Grover',
'[email protected]' => 'Andy Grover',
'[email protected]' => 'Art Haas',
'[email protected]' => 'Anton Altaparmakov',
'[email protected]' => 'Anton Altaparmakov',
'[email protected]' => 'Anton Altaparmakov',
'[email protected]' => 'Ani Joshi',
'[email protected]' => 'Andi Kleen',
'[email protected]' => 'Andi Kleen',
'[email protected]' => 'Andrew Morton',
'[email protected]' => 'Andrew Morton',
'[email protected]' => 'Alan Cox',
'[email protected]' => 'Alan Cox',
'[email protected]' => 'Alan Cox',
'[email protected]' => 'Alexander Riesen',
'[email protected]' => 'Alfredo Sanju?n',
'[email protected]' => 'Alberto Munoz',
'[email protected]' => 'Erik Andersen',
'[email protected]' => 'Anders Gustafsson',
'[email protected]' => 'Andrea Arcangeli',
'[email protected]' => 'Andries E. Brouwer',
'[email protected]' => 'Andrzej Krzysztofowicz',
'[email protected]' => 'Anton Blanchard',
'[email protected]' => 'Arjan van de Ven',
'[email protected]' => 'Arjan van de Ven',
'[email protected]' => 'Arnd Bergmann',
'[email protected]' => 'Asit K. Mallick', # by Kristian Peters
'[email protected]' => 'Jens Axboe',
'[email protected]' => 'Jens Axboe',
'[email protected]' => 'Brent Baccala',
'[email protected]' => 'D. J. Barrow',
'[email protected]' => 'Bart De Schuymer',
'[email protected]' => 'Ben Collins',
'[email protected]' => 'Benjamin LaHaise',
'[email protected]' => 'Brian Beattie', # from david.nelson
'[email protected]' => 'Benjamin Herrenschmidt',
'[email protected]' => 'Ben Fennema',
'[email protected]' => 'Brian Gerst',
'[email protected]' => 'Brad Hards',
'[email protected]' => 'Bhavesh P. Davda',
'[email protected]' => 'Brad Heilbrun', # by himself
'[email protected]' => 'Bjorn Wesen',
'[email protected]' => 'Bjorn Helgaas',
'[email protected]' => 'Boris Itkis', # by Kristian Peters
'[email protected]' => 'Brett Pemberton',
'[email protected]' => 'Ken Brownfield',
'[email protected]' => 'Adrian Bunk',
'[email protected]' => 'Lennert Buytenhek',
'[email protected]' => 'Carl-Daniel Hailfinger',
'[email protected]' => 'Chris Caputo',
'[email protected]' => 'Chuck Lever',
'[email protected]' => 'Christopher Hoover', # by Kristian Peters
'[email protected]' => 'Charles White',
'[email protected]' => 'Samuel S. Chessman',
'[email protected]' => 'Chris Wright',
'[email protected]' => 'Christopher Leech',
'[email protected]' => 'Craig Kulesa',
'[email protected]' => 'Colin Gibbs',
'[email protected]' => 'Matthew Dobson',
'[email protected]' => 'Chris Hanson',
'[email protected]' => 'Christoph Rohland',
'[email protected]' => 'Charles-Edouard Ruault',
'[email protected]' => 'Chad N. Tindel',
'[email protected]' => 'Christopher Yeoh',
'[email protected]' => 'Dan Aloni',
'[email protected]' => 'Martin Dalecki',
'[email protected]' => 'Martin Dalecki',
'[email protected]' => 'Daniel Jacobowitz',
'[email protected]' => 'Dave Jones',
'[email protected]' => 'David S. Miller',
'[email protected]' => 'David S. Miller',
'[email protected]' => 'David S. Miller',
'[email protected]' => 'David Brownell',
'[email protected]' => 'David Nelson',
'[email protected]' => 'David Gibson',
'[email protected]' => 'Davide Libenzi',
'[email protected]' => 'David Mosberger',
'[email protected]' => 'David Mosberger',
'[email protected]' => 'David Mosberger',
'[email protected]' => 'Dan Streetman',
'[email protected]' => 'Jeff DeFouw',
'[email protected]' => "Thomas 'Dent' Mirlacher",
'[email protected]' => 'Dominik Brodowski',
'[email protected]' => 'Martin Devera',
'[email protected]' => 'David Gibson',
'[email protected]' => 'David Howells',
'[email protected]' => 'Dirk Uffmann',
'[email protected]' => 'Doug Ledford',
'[email protected]' => 'Doug Ledford',
'[email protected]' => 'Dave McCracken',
'[email protected]' => 'Denis Oliver Kropp',
'[email protected]' => 'Douglas Gilbert',
'[email protected]' => 'Daniel Jacobowitz',
'[email protected]' => 'Deepak Saxena',
'[email protected]' => 'David Woodhouse',
'[email protected]' => 'David Woodhouse',
'[email protected]' => 'Massimo Dal Zotto',
'[email protected]' => 'Eric Brower',
'[email protected]' => 'Eric Brower',
'[email protected]' => 'Eddie C. Dost',
'[email protected]' => 'Ed Vance',
'[email protected]' => 'Edward Peng',
'[email protected]' => 'Erich Focht',
'[email protected]' => 'Rolf Eike Beer',
'[email protected]' => 'Steven Cole',
'[email protected]' => 'Dave Engebretsen',
'[email protected]' => 'St?phane Eranian',
'[email protected]' => 'Erik Habbinga',
'[email protected]' => 'Frank Davis',
'[email protected]' => 'Felipe Damasio', # by self (did not ask to include the W.)
'[email protected]' => 'Bakonyi Ferenc',
'[email protected]' => 'J?rgen E. Fischer',
'[email protected]' => 'Martin J. Bligh',
'[email protected]' => 'Florian Lohoff',
'[email protected]' => 'Erich Focht',
'[email protected]' => 'Rolf Fokkens',
'[email protected]' => 'Franz Sirl',
'[email protected]' => 'Franz Sirl',
'[email protected]' => 'Ganesh Varadarajan',
'[email protected]' => 'Ganesh Varadarajan',
'[email protected]' => 'Kurt Garloff',
'[email protected]' => 'Geert Uytterhoeven',
'[email protected]' => 'Geert Uytterhoeven',
'[email protected]' => 'George Anzinger',
'[email protected]' => 'Greg Ungerer',
'[email protected]' => 'Ghozlane Toumi',
'[email protected]' => 'Justin T. Gibbs',
'[email protected]' => 'Justin T. Gibbs',
'[email protected]' => 'Dr. David Alan Gilbert',
'[email protected]' => 'Guennadi Liakhovetski',
'[email protected]' => 'Greg Banks',
'[email protected]' => 'Go Taniguchi',
'[email protected]' => 'Patricia Guaghen',
'[email protected]' => 'Cory Watson',
'[email protected]' => 'Oleg Drokin',
'[email protected]' => 'Oleg Drokin',
'[email protected]' => 'Greg Kroah-Hartman',
'[email protected]' => 'Grant Grundler',
'[email protected]' => 'Guillermo S. Romero',
'[email protected]' => 'Ghozlane Toumi',
'[email protected]' => 'Hanna Linder',
'[email protected]' => 'Dave Hansen',
'[email protected]' => 'Christoph Hellwig',
'[email protected]' => 'Christoph Hellwig',
'[email protected]' => 'Christoph Hellwig',
'[email protected]' => 'Christoph Hellwig',
'[email protected]' => 'Christoph Hellwig', # by Kristian Peters
'[email protected]' => 'Christoph Hellwig',
'[email protected]' => 'Henrique Gobbi',
'[email protected]' => 'David Gibson',
'[email protected]' => 'Hirofumi Ogawa', # corrected by himself
'[email protected]' => 'Colin Slater',
'[email protected]' => 'H. Peter Anvin',
'[email protected]' => 'Hugh Dickins',
'[email protected]' => 'Ivan Kokshaysky',
'[email protected]' => 'Ion Badulescu',
'[email protected]' => 'Ishan O. Jayawardena',
'[email protected]' => 'Ingo Rohlfs',
'[email protected]' => 'Ivan Gyurdiev',
'[email protected]' => 'Jan Kara',
'[email protected]' => 'Jack Hammer',
'[email protected]' => 'Jan Harkes',
'[email protected]' => 'Jakob Kemi',
'[email protected]' => 'J. A. Magallon',
'[email protected]' => 'James Bottomley',
'[email protected]' => 'James Mayer',
'[email protected]' => 'Jamey Hicks',
'[email protected]' => 'Jamey Hicks',
'[email protected]' => 'Jani Monoses',
'[email protected]' => 'Jani Monoses',
'[email protected]' => 'Julien Blache',
'[email protected]' => 'Jan-Benedict Glaw',
'[email protected]' => 'James Blackwell',
'[email protected]' => 'David Ruggiero',
'[email protected]' => 'Jeff Dike',
'[email protected]' => 'David Ruggiero',
'[email protected]' => 'Jes Degn S?rensen',
'[email protected]' => 'Jeff Garzik',
'[email protected]' => 'Jeff Garzik',
'[email protected]' => 'Jeff Garzik',
'[email protected]' => 'Jack Hammer',
'[email protected]' => 'James Morris',
'[email protected]' => 'Jochen Suckfuell',
'[email protected]' => 'Johann Deneux',
'[email protected]' => 'Johannes Erdfelt',
'[email protected]' => 'John Clemens',
'[email protected]' => 'John Kim',
'[email protected]' => 'Evgeniy Polyakov',
'[email protected]' => 'John Stultz',
'[email protected]' => 'Josef Siemes',
'[email protected]' => 'James Simmons',
'[email protected]' => 'James Simmons',
'[email protected]' => 'James Simmons',
'[email protected]' => 'Jean Tourrilhes',
'[email protected]' => 'Jean Tourrilhes',
'[email protected]' => 'Jonathan Woithe',
'[email protected]' => 'Kimio Suganuma',
'[email protected]' => 'Karol Kasprzak', # by Kristian Peters
'[email protected]' => 'Patrick McHardy',
'[email protected]' => 'Kai Germaschewski',
'[email protected]' => 'Kai Makisara',
'[email protected]' => 'Kai Reichert',
'[email protected]' => 'Kai Germaschewski',
'[email protected]' => 'Kai Germaschewski',
'[email protected]' => 'Kanoj Sarcar', # sent by Arnaldo Carvalho de Melo
'[email protected]' => 'Kanoj Sarcar',
'[email protected]' => 'Keith Owens',
'[email protected]' => 'Kasper Dupont',
'[email protected]' => 'Keith Underwood',
'[email protected]' => 'Kenneth W. Chen',
'[email protected]' => 'Kent Yoder',
'[email protected]' => 'Khalid Aziz',
'[email protected]' => 'Khalid Aziz',
'[email protected]' => 'Krzysztof Halasa',
'[email protected]' => 'Ravikiran G. Thirumalai',
'[email protected]' => 'Karsten Keil',
'[email protected]' => 'Kendrick M. Smith',
'[email protected]' => 'Erik Inge Bols?',
'[email protected]' => 'Gerd Knorr',
'[email protected]' => 'Gerd Knorr',
'[email protected]' => 'Robert Kuebel',
'[email protected]' => 'Alexey Kuznetsov',
'[email protected]' => 'Ladislav Michl',
'[email protected]' => 'Harald Welte',
'[email protected]' => 'Laurent Latil',
'[email protected]' => 'Lawrence Walton',
'[email protected]' => 'Luca Barbieri',
'[email protected]' => 'Richard Russon',
'[email protected]' => 'John Levon',
'[email protected]' => 'Lionel Bouton',
'[email protected]' => 'Martin Diehl',
'[email protected]' => 'Liyang Hu',
'[email protected]' => 'Larry McVoy',
'[email protected]' => 'Stephen Lord',
'[email protected]' => 'Marcus Alanen',
'[email protected]' => 'Maciej W. Rozycki',
'[email protected]' => 'Manfred Spraul',
'[email protected]' => 'Manik Raina',
'[email protected]' => 'Keith Mannthey',
'[email protected]' => 'Marc Boucher',
'[email protected]' => 'Marcel Holtmann', # sent by himself
'[email protected]' => 'Marcelo Tosatti',
'[email protected]' => 'Marcelo Tosatti',
'[email protected]' => 'Mark W. McClelland',
'[email protected]' => 'Martin J. Bligh',
'[email protected]' => 'Martin Brulisauer',
'[email protected]' => 'Martin Schwenke',
'[email protected]' => 'Chris Mason',
'[email protected]' => 'Matt Domsch', # sent by himself
'[email protected]' => 'Matthew Wilcox',
'[email protected]' => 'Heinz J. Mauelshagen',
'[email protected]' => 'Maksim Krasnyanskiy',
'[email protected]' => 'Marc-Christian Petersen',
'[email protected]' => 'Matthew Dharm',
'[email protected]' => 'Matthew Dharm',
'[email protected]' => 'Michael Elizabeth Chastain',
'[email protected]' => 'Michal Jaegermann',
'[email protected]' => 'Mike Phillips',
'[email protected]' => 'Mikael Pettersson',
'[email protected]' => 'Mikulas Patocka',
'[email protected]' => 'Miles Lane',
'[email protected]' => 'Milton Miller', # by Kristian Peters
'[email protected]' => 'Ingo Molnar',
'[email protected]' => 'Ingo Molnar',
'[email protected]' => 'Martin Mares',
'[email protected]' => 'Mirko Lindner',
'[email protected]' => 'Mark McClelland',
'[email protected]' => 'Patrick Mochel',
'[email protected]' => 'Patrick Mochel',
'[email protected]' => 'Patrick Mochel',
'[email protected]' => 'Michal Ostrowski',
'[email protected]' => 'Matt Wilson',
'[email protected]' => 'Mufasa Yang', # sent by himself
'[email protected]' => 'Muli Ben-Yehuda', # sent by himself
'[email protected]' => 'Michael Westermann',
'[email protected]' => 'Itai Nahshon',
'[email protected]' => 'Nathan Scott',
'[email protected]' => 'Neil Brown',
'[email protected]' => 'Nemosoft Unv.',
'[email protected]' => 'Nicolas Pitre',
'[email protected]' => 'Nicolas Aspert',
'[email protected]' => 'Niels Kristian Bech Jensen',
'[email protected]' => 'Nicholas Miell',
'[email protected]' => 'Oleg Nesterov',
'[email protected]' => 'Olaf Hering',
'[email protected]' => 'Dave Olien',
'[email protected]' => 'Oliver Neukum',
'[email protected]' => 'Oliver Neukum',
'[email protected]' => 'Oliver Neukum',
'[email protected]' => 'Orjan Friberg',
'[email protected]' => 'Oskar Schirmer', # sent by himself
'[email protected]' => 'Owen Taylor',
'[email protected]' => 'Peter De Shrijver',
'[email protected]' => 'Paul Gortmaker',
'[email protected]' => 'Patrick Mansfield',
'[email protected]' => 'Paul Fulghum',
'[email protected]' => 'Paul Mackerras',
'[email protected]' => 'Paul Mackerras',
'[email protected]' => 'Paul Mackerras',
'[email protected]' => 'Paul Mackerras',
'[email protected]' => 'Pavel Jan?k',
'[email protected]' => 'Pavel Machek',
'[email protected]' => 'Pavel Machek',
'[email protected]' => 'Andrey Panin',
'[email protected]' => 'Badari Pulavarty',
'[email protected]' => 'Pam Delaney',
'[email protected]' => 'Jeroen Vreeken',
'[email protected]' => 'Petr Konecny',
'[email protected]' => 'Jaroslav Kysela',
'[email protected]' => 'Jaroslav Kysela',
'[email protected]' => 'Peter Samuelson',
'[email protected]' => 'Peter Chubb',
'[email protected]' => 'Peter Osterlund',
'[email protected]' => 'Petko Manolov',
'[email protected]' => 'Petr Vandrovec',
'[email protected]' => 'Petri Koistinen',
'[email protected]' => 'Pawel Kot',
'[email protected]' => 'Paul Larson',
'[email protected]' => 'Paul Menage',
'[email protected]' => 'Ingo Albrecht',
'[email protected]' => 'Pavel Roskin',
'[email protected]' => 'Peter W?chtler',
'[email protected]' => 'Daniel Quinlan',
'[email protected]' => 'Juan Quintela',
'[email protected]' => 'Ralf Baechle',
'[email protected]' => 'Ray Lee',
'[email protected]' => 'Robert Cardell',
'[email protected]' => 'Bob Tracy',
'[email protected]' => 'Randy Dunlap',
'[email protected]' => 'Udo A. Steinberg',
'[email protected]' => 'Hans Reiser',
'[email protected]' => 'Bob Miller',
'[email protected]' => 'Richard Gooch',
'[email protected]' => 'Richard Gooch',
'[email protected]' => 'Roberto Gordo Saez',
'[email protected]' => 'Richard Hirst',
'[email protected]' => 'Riley Williams',
'[email protected]' => 'Richard Brunner',
'[email protected]' => 'Rik van Riel',
'[email protected]' => 'Roger Luethi',
'[email protected]' => 'Romain Lievin',
'[email protected]' => 'Russell King',
'[email protected]' => 'Russell King',
'[email protected]' => 'Robert Love',
'[email protected]' => 'Rob Radez',
'[email protected]' => 'Robert Olsson',
'[email protected]' => 'Roland Dreier',
'[email protected]' => 'Fran?ois Romieu',
'[email protected]' => 'Richard Henderson',
'[email protected]' => 'Rui Sousa',
'[email protected]' => 'Rusty Russell',
'[email protected]' => 'Randy Hron',
'[email protected]' => 'Richard Zidlicky',
'[email protected]' => 'Thomas Sailer',
'[email protected]' => 'Sam Ravnborg',
'[email protected]' => 'Sam Ravnborg',
'[email protected]' => 'Samuel Thibault',
'[email protected]' => 'Eric Sandeen',
'[email protected]' => 'Santiago A. Nullo', # sent by self
'[email protected]' => 'sawa',
'[email protected]' => 'Andreas Schwab',
'[email protected]' => 'Martin Schwidefsky',
'[email protected]' => 'Scott Feldman',
'[email protected]' => 'Scott Anderson',
'[email protected]' => 'Scott Murray',
'[email protected]' => 'Stephen C. Tweedie',
'[email protected]' => 'Stephen Smalley',
'[email protected]' => 'Sebastian Dr?ge',
'[email protected]' => 'Stephen Rothwell',
'[email protected]' => 'Dave Kleikamp',
'[email protected]' => 'Dave Kleikamp',
'[email protected]' => 'Shing Chuang',
'[email protected]' => 'Simon Burley',
'[email protected]' => 'Skip Ford',
'[email protected]' => 'Stuart Lynne',
'[email protected]' => 'Nathan Dabney',
'[email protected]' => 'Geoffrey Lee', # by himself
'[email protected]' => 'Solar Designer',
'[email protected]' => 'Simon Evans', # by Kristian Peters
'[email protected]' => 'Jack Steiner',
'[email protected]' => 'Stelian Pop',
'[email protected]' => 'Alan Stern',
'[email protected]' => 'Stephen Cameron',
'[email protected]' => 'Steven Whitehouse',
'[email protected]' => 'Stuart MacDonald',
'[email protected]' => 'Mike Sullivan',
'[email protected]' => 'Sunil Saxena',
'[email protected]' => 'Alan Swanson',
'[email protected]' => 'Tomas Szepe',
'[email protected]' => 'Takayoshi Koshi',
'[email protected]' => 'Taisuke Yamada',
'[email protected]' => 'Hirokazu Takahashi',
'[email protected]' => 'Tom Callaway',
'[email protected]' => 'Tero Pirkkanen', # by Kristian Peters
'[email protected]' => 'Tim Hockin',
'[email protected]' => 'Tim Hockin',
'[email protected]' => 'Tigran Aivazian',
'[email protected]' => 'Tim Schmielau',
'[email protected]' => 'Osamu Tomita',
'[email protected]' => 'Ed Tomlinson',
'[email protected]' => 'Anthony J. Breeds-Taurima',
'[email protected]' => 'Linus Torvalds',
'[email protected]' => 'Linus Torvalds',
'[email protected]' => 'Linus Torvalds',
'[email protected]' => 'Linus Torvalds',
'[email protected]' => 'Tom Rini',
'[email protected]' => 'Tom Rini',
'[email protected]' => 'Trond Myklebust',
'[email protected]' => 'Thierry Vignaud',
'[email protected]' => 'Tim Waugh',
'[email protected]' => 'Urban Widmark',
'[email protected]' => 'Joshua Uziel',
'[email protected]' => 'Petr Vandrovec',
'[email protected]' => 'Alexander Viro',
'[email protected]' => 'Paul Vojta',
'[email protected]' => 'Vojtech Pavlik',
'[email protected]' => 'Vojtech Pavlik',
'[email protected]' => 'Vojtech Pavlik', # added by himself
'[email protected]' => 'Werner Almesberger',
'[email protected]' => 'Wes Schreiner',
'[email protected]' => 'Matthew Wilcox',
'[email protected]' => 'Willy Tarreau',
'[email protected]' => 'Wim Van Sebroeck',
'[email protected]' => 'William Lee Irwin III',
'[email protected]' => 'Wolfgang Fritz', # by Kristian Peters
'[email protected]' => 'Wolfgang Muees',
'[email protected]' => 'William Stinson',
'[email protected]' => 'Tomas Kasparek',
'[email protected]' => 'Pete Zaitcev',
'[email protected]' => 'Roman Zippel',
'[email protected]' => 'Zwane Mwaikambo',
'[email protected]' => 'Zwane Mwaikambo',
'[email protected]' => 'Zwane Mwaikambo',
'~~~~~~thisentrylastforconvenience~~~~~' => 'Cesar Brutus Anonymous'
);

sub doprint(\%@ ); # forward declaration

my %address_unknown;

# get name associated to an email address
sub rmap_address {
my @o = map {defined $addresses{$_} ? $addresses{$_} :
scalar (($address_unknown{$_} = 1), $_); }
map { lc; } @_;
return wantarray ? @o : $o[0];
}

# case insensitive string comparison
# FIXME: use locale?
sub caseicmp { uc($a) cmp uc($b) };

# case insensitive string comparison by surname
# Strings are of the form
# "Firstname Surname <mailaddress>"
# or
# "<mailaddress>"
sub caseicmpbysurname {
my $alast = "";
my $blast = "";
if ($a =~ m/([^\s]+)\s+\</) { $alast = $1; }
if ($b =~ m/([^\s]+)\s+\</) { $blast = $1; }
return uc($alast . $a) cmp uc($blast . $b);
}

my ($author, $address, $name);
# * $address is always an email address
# * $author can be the email address or Joe N. Sixpack II <[email protected]>
# (ready formatted to print)
# * $name is the name (Joe N. Sixpack II) or the mail address
# (<[email protected]>)

sub get_name() { return $name; }
sub get_author() { return $author; }

# This table maps MODE => { myhash }
# myhash knows the keys "index" and "print" to choose the respective functions
my %table =
(
'oneline' => { 'index' => \&get_name,
'print' => \&print_oneline },
'terse' => { 'index' => \&get_name,
'print' => \&print_terse },
'grouped' => { 'index' => \&get_author,
'print' => \&print_grouped },
'full' => { 'index' => \&get_author,
'print' => \&print_full }
);

# temp store
my $indexby;

# The sort function we will use
my $namesortfunc;

# Global store #############
# We store our options here.
my %opt;

# As we are parsing, the log is accumulated in the @cur array. When
# we are done with one item (end of input or new mail address found),
# stuff a copy of this @cur array into the %log hash.
sub append_item(\%@)
# arguments: reference to hash
# array to push
{
my $log = shift;
my @cur = @_;
return unless @cur;
return unless &$indexby;
$log->{&$indexby} = () unless defined $log->{&$indexby};

# strip trailing blank lines
my $t;
while (($t = pop(@cur)) eq '') { };
push @cur, $t;

# store the array
push @{$log->{&$indexby}}, [@cur];
}

# Remove duplicates from hash, without changing the order.
# Prefix duplicates with the count.
sub countdups(@) {
my %t;
croak "do not call removedups() in scalar context" unless wantarray;
my @u = grep (!$t{lc $_}++, @_);
return map {
$t{lc $_} > 1 ? sprintf("%d x ", $t{lc $_}) . $_ : $_;
} @u;
}

# Remove duplicates from array, without changing the order. The
# duplicates need not follow each other, so A B A is properly
# stripped down to A B
sub removedups(@) {
my %t;
croak "do not call removedups() in scalar context" unless wantarray;
return grep (!$t{lc $_}++, @_);
}

# Compress the hash passed in, depending on the --compress and --count
# options in the %opt hash.
sub compress(@) {
croak "do not call compress() in scalar context" unless wantarray;
if ($opt{compress}) {
if ($opt{count}) {
return countdups(@_);
} else {
return removedups(@_);
}
} else {
return @_;
}
}

# report write error, exit
# do not return
sub write_error() {
croak "Write error: $!\nAborting";
exit (1);
}

# implementation of "grouped" output:
# author:
# first line of log1
# first line of log2
sub print_grouped(\%) {
my $log = shift;
for (sort $namesortfunc keys %$log) {
my @lines = compress(map { $_->[0] . "\n"; } @{$log->{$_}});
if ($opt{width}) {
@lines = map { expand(wrap($indent1, $indent, ($_))); } @lines;
} else {
@lines = map { "$indent1$_" } @lines;
}
printtag($_) or write_error();
print join("", @lines), "\n" or write_error();
}
}

# implementation of "full" output
# author:
# o log1
# more information on changeset1
# o log2
# more information on changeset2
sub print_full(\%) {
my $log = shift;
for (sort $namesortfunc keys %$log) {
printtag($_) or write_error();
foreach (compress(@{$log->{$_}})) {
my @lines = map { s/^\t//; "$_\n"; } @$_;
if ($opt{width}) {
@lines = expand(wrap($indent1, $indent, @lines));
} else {
@lines = map { "$indent$_"; } @lines;
substr($lines[0], $[, length($indent1)) = $indent1;
}
print join("", @lines), "\n" or write_error();
}
}
print "\n" or write_error();
}

# implementation of "terse" output
# with --swap without --swap
# author1: log1 log1 (author1)
# author1: log2 log2 (author2)
# author2: log3 log3 (author3)
sub print_terse(\%) {
my $log = shift;
for (sort $namesortfunc keys %$log) {
my $a = $_;
if ($opt{width}) {
if ($opt{swap}) {
foreach (compress(map { $_->[0]; } @{$log->{$_}})) {
my @lines = expand(wrap($indent1, $indent, ("$a: $_")));
print join("\n", @lines), "\n" or write_error();
}
} else {
# width, but not swap set
foreach (compress(map { $_->[0]; } @{$log->{$_}})) {
my @addr = expand(split(/\n/, wrap('', $indent, " ($a)")));
my @lines = expand(split(/\n/, wrap($indent1, $indent, ($_))));

if (length($lines[$#lines]) + length($addr[0]) > $opt{width}) {
push @lines, '';
}
$lines[$#lines] .= sprintf("%*s", $opt{width}
- length($lines[$#lines]), $addr[0]);
shift @addr;
print join("\n", @lines), "\n" or write_error();
foreach (@addr) {
printf "%*s\n", $opt{width}, $_ or write_error();
}
}
}
} else {
# using the ?: operator within the map is more maintainable, but
# less efficient.
if ($opt{swap}) {
print join("\n", map { "$indent1$a: $_" }
compress(map { $_->[0]; } @{$log->{$_}})), "\n"
or write_error();
} else {
print join("\n", map { "$indent1$_ ($a)" }
compress(map { $_->[0]; } @{$log->{$_}})), "\n"
or write_error();
}
}
}
}

# implementation of "oneline" output
# which is similar to terse but reformats to one line exactly
# with --swap without --swap
# author1: log1 log1 (author1)
# author1: log2 log2 (author2)
# author2: log3 log3 (author3)
sub print_oneline(\%) {
my $log = shift;
for (sort $namesortfunc keys %$log) {
my $a = $_;
if ($opt{width}) {
if ($opt{swap}) {
foreach (compress(map { $_->[0]; } @{$log->{$_}})) {
my $str = "$a: $_";
if (length($str) > $opt{width}) {
printf "%-.*s...\n", $opt{width}-3, $indent1 . "$a: $_"
or write_error();
} else {
printf "%-.*s\n", $opt{width}, $indent1 . "$a: $_"
or write_error();
}
}
} else { # not swapping
foreach (compress(map { $_->[0]; } @{$log->{$_}})) {
my $l = $opt{width} - length($indent1) - length($a) - 3;
if (length($_) > $l) {
$l -= 3;
printf "%s%-*.*s... (%s)\n", $indent1, $l, $l, $_, $a;
} else {
printf "%s%-*.*s (%s)\n", $indent1, $l, $l, $_, $a;
}
}
}
} else {
# not $opt{width} -> same as print_terse
print_terse(%$log);
}
}
}

# Abbreviate all components of the name except the last. If capital
# Roman numerals form the last component, leave that and the previous
# component alone.
sub abbreviate_name($ ) {
my @a = split /\s+/, $_[0];

# treat Roman numerals as last part of name
my $off = 0;
$off = 1 if ($a[$#a] =~ /^[IVXLCMD]+$/);

for (my $i = 0; $i < $#a - $off; $i++) {
$a[$i] =~ s/^(.).*/$1./;
}
return join(" ", @a);
}

# Read a file and parse it into the %log hash.
sub parse_file(\%$$ ) {
# arguments: %log hash
# file name
# file handle (IO::Handle or IO::File)
croak unless wantarray;
my $log = shift;
my $fn = shift;
my $fh = shift;
my @prolog;
local $_;

# initialize
my @cur = ();
my $first = 0;
my $firstpar = 0;
undef $address;

# now go!

# NOTE: the first @cur item can consist of multiple lines in the
# source file which are joined together. This happens when the first
# paragraph is longer than a single line.
while($_ = $fh -> getline) {
chomp;
s/^ (\S)/\t$1/;
# expand all tabs but the first
$_ = expand($_);
s/^ /\t/;

if (defined $address and $opt{multi}
and m{^[^<[:space:]]} and not m{^ChangeSet@}) {
# if we are in multi mode, if we encounter a non-address
# left-justified line, flush all data and print the header. The
# defined $address trick lets this only trigger to switch back
# from "log entry" to "prolog" mode
append_item(%$log, @cur); @cur = ();
doprint(%$log, @prolog);
print "\n" or write_error(); # print blank line between changelogs
@prolog = ($_);
undef %$log;
undef $address;
} elsif (m{^<([^>]+)>} or m{^ChangeSet@[0-9.]+,\s*[-0-9:+ ]+,\s*(.*)}) {
# go figure if a line starts with an address, if so, take it
# resolve the address to a name if possible
append_item(%$log, @cur); @cur = ();
$address = $1;
$name = rmap_address($address);
if ($name ne $address) {
if ($opt{'abbreviate-names'}) {
$name = abbreviate_name($name);
}
$author = $name . ' <' . $address . '>';
} else {
$author = '<' . $address . '>';
}
$first = 1;
$firstpar = 1;
} elsif ($first) {
# we have a "first" line after an address, take it,
# strip common redundant tags

# kill "PATCH" tag
s/^\s*\[PATCH\]//;
s/^\s*PATCH//;
s/^\s*[-:]+\s*//;

# strip trailing colon or period, and if we strip one,
# we don't parse further lines as part of the first paragraph
if (s/[:.]+\s*$//) { $firstpar = 0; }

# kill leading and trailing whitespace for consistent indentation
s/^\s+//; s/\s+$//;

push @cur, $_;
$first = 0;
} elsif (defined $address) {
# second or subsequent lines -- if in first paragraph,
# append this line to the first log line.
if (m/^\s*$/) { $firstpar = 0; }
elsif (m/^\s*[-*o\#]/) { $firstpar = 0; }
if ($firstpar) {
s/^\s*/ /;
$cur[0] .= $_;
} else {
push @cur, $_;
}
# we don't parse further lines as part of the first paragraph
if (s/[:.]+\s*$//) { $firstpar = 0; }
} else {
# store header before a changelog
push @prolog, $_;
}
}

if ($fh -> error) {
die "Error while reading from \"$fn\": $!";
}

# at file end, flush @cur array to %log.
append_item(%$log, @cur);

return @prolog;
}

# print a word-wrapped name or mail address, followed by a trailing colon.
# used by print_grouped and print_full
# passes the return value of print back up
sub printtag($ ) {
my $a = shift;
$a .= ':';
return print $opt{width} ? expand(wrap("", "", ($a))) : $a, "\n";
}

# === MAIN PROGRAM ===============================================
# Command line arguments
# What options do we support?
my @opts = ("help|?|h", "man", "mode=s", "compress!", "count!", "width:i",
"swap!", "merge!", "warn!", "multi!", "abbreviate-names!",
"by-surname!");
# "bitkeeper|bk!");

# How do we parse them?
if ($Getopt::Long::VERSION gt '2.24') {
Getopt::Long::Configure("gnu_getopt");
}

# set default options
$opt{mode} = 'grouped';
$opt{warn} = 1;

# Parse from environment, temporarily storing the original @ARGV.
if (defined $ENV{LINUXKERNEL_BK_FMT}) {
my @savedargs = @ARGV;
@ARGV = parse_line('\s+', 0, $ENV{LINUXKERNEL_BK_FMT});
GetOptions(\%opt, @opts)
or pod2usage(-verbose => 0,
-message => $0 . ': error in $LINUXKERNEL_BK_FMT');
push @ARGV, @savedargs;
}

# Parse command line. Handle help, check for errors.
GetOptions(\%opt, @opts) or pod2usage(-verbose => 0);
pod2usage(-verbose => 1) if $opt{help};
pod2usage(-verbose => 2) if $opt{man};
pod2usage(-verbose => 0,
-message => ("$0: Unknown mode specified.\nValid modes are:\n "
. join(" ", sort keys %table) . "\n"))
unless defined $table{$opt{mode}};
pod2usage(-verbose => 0,
-message => "$0: No files given, refusing to read from a TTY.")
if (not $opt{bitkeeper} and (@ARGV == 0) and (-t STDIN));
pod2usage(-verbose => 0,
-message => "$0: Must have one or two arguments in --bitkeeper mode.")
if ($opt{bitkeeper} && (@ARGV < 1 || @ARGV > 2));
pod2usage(-verbose => 0,
-message => "$0: You cannot use --merge and --multi at the same time.")
if ($opt{merge} and $opt{multi});

# Shortcut for programmer convenience :-)
$indexby = $table{$opt{mode}}->{'index'};

# --count implies --compress
if ($opt{count}) { $opt{compress} = 1; }

# Set the sort function
$namesortfunc = \&caseicmp;
if ($opt{'by-surname'}) { $namesortfunc = \&caseicmpbysurname; }

# if --width is without argument or the argument is zero,
# try to figure $COLUMNS or fall back to 80.
if (exists $opt{width} and not $opt{width}) {
$opt{width} = $ENV{COLUMNS} ? $ENV{COLUMNS} : 80;
}

# Print the passed-in array linewise, checking for write errors
# Then call the configured function to print %log formatted
sub doprint(\%@ ) {
my $log = shift;
print join("\n", @_), "\n" or write_error();
$table{$opt{mode}}->{print}->($log);
}

# --------------------------------------------------------------------
# Global initializations
$Text::Tabs::tabstop = 8;
$Text::Wrap::huge = 'wrap';
if ($opt{width}) {
$Text::Wrap::columns = $opt{width};
}

if ($debug) {
print STDERR "DEBUG: Options summary:\n";
while (my ($k, $v) = each %opt) { print STDERR "DEBUG: '$k' => '$v'\n"; }
print STDERR "DEBUG: Arguments summary:\n";
foreach (@ARGV) { print STDERR "DEBUG: '$_'\n"; }
}

# Main program
my @prolog;
my %log;

if($opt{bitkeeper}) {
# in Bitkeeper mode, try to figure the change set, and connect the
# bk program to our stdin.
die "not yet implemented";
} elsif (@ARGV) {
# file names
foreach my $fn (@ARGV) {
my $fh = new IO::File;
$fh->open($fn, "r")
or die "cannot open \"$fn\": $!\nAborting";
push @prolog, parse_file(%log, $fn, $fh);
if (not $opt{merge}) {
doprint(%log, @prolog);
undef %log;
}
undef @prolog;
}

if ($opt{merge}) {
doprint(%log, ());
}
} else {
# stdin
my @prolog;
my $fh = new IO::Handle;
$fh->fdopen(fileno(STDIN), "r")
or die "cannot open stdin: $!\nAborting";
@prolog = parse_file(%log, "stdin", $fh);
doprint(%log, @prolog);
}

# Flush STDOUT to prevent clobbering STDOUT with 2>&1-style redirections.
$| = 1;

# Warn about unknown addresses
if ($opt{warn}) {
foreach (sort caseicmp keys %address_unknown) {
print STDERR "Warning: unknown address \"$_\"\n" or write_error();
}
}

__END__
# --------------------------------------------------------------------
# $Log: lk-changelog.pl,v $
# Revision 0.39 2002/09/26 23:07:13 emma
# 46 new addresses from lbdb
#
# Revision 0.38 2002/09/26 22:37:29 emma
# 23 new addresses
#
# Revision 0.37 2002/09/26 22:27:37 emma
# Fix --multi mode.
#
# Revision 0.36 2002/08/29 09:13:40 emma
# Correct Vojtech Pavlik's addresses after mail from him.
#
# Revision 0.35 2002/08/21 13:49:46 emma
# Many new addresses and one correction by Vitezslav 'Vita' Samel <[email protected]>
#
# Revision 0.34 2002/08/21 13:45:53 emma
# 2 new names
#
# Revision 0.33 2002/08/20 01:29:34 emma
# The usual set of new addresses.
#
# Revision 0.32 2002/08/20 01:14:40 emma
# Add Marcel Holtmann, who sent a patch.
#
# Revision 0.31 2002/08/12 22:34:41 emma
# Patch by Marcus Alanen <[email protected]>:
# Hi, patch to sort by developer surname, and a couple of more
# developers. Use if you want to.
#
# Revision 0.30 2002/07/20 17:18:28 emma
# Add one new address
#
# Revision 0.29 2002/07/17 23:10:13 emma
# 23 new addresses.
#
# Revision 0.28 2002/06/25 09:46:57 emma
# New mail addresses.
#
# Revision 0.27 2002/06/14 17:05:23 emma
# three new addresses
#
# Revision 0.26 2002/06/06 10:26:51 emma
# Get rid of global %log, pass it to sub functions by reference.
# Move IO::Handle/IO::File treatment back into main program.
# Prepare for integrating Bitkeeper.
#
# Revision 0.25 2002/06/04 00:01:23 emma
# Recognize "bk changes" output format (that is: "[email protected],
# date, programmer" tag line and body indented by two spaces). Reported
# by Marcelo Tosatti <[email protected]>. Former versions would
# only recognize the BK-kernel-tools/changelog format (see
# http://gkernel.bkbits.net:8080/BK-kernel-tools/anno/[email protected]?nav=index.html|src/).
#
# Revision 0.24 2002/06/03 13:33:00 emma
# * Fix 'grouped', 'terse', 'oneline' modes (change to parse_file()). We
# now take the first paragraph instead of the first line as log
# entry. We also guess where the paragraph ends, it ends at a line with
# trailing dot or colon, or if the next line is empty or starts with a
# "bullet" (that is -, *, o or #).
# * New option --abbreviate-names.
# * Fix 'full' mode indentation, broken in v0.21 by expanding the tabs.
# Now, the first tab is unexpanded again.
# * Enhance 'online' mode: if the log is truncated, append an ellipsis ("...").
# * Add more mail addresses.
# * Fix Brian Beattie's name (was "Michael Beattie").
#
# Revision 0.23 2002/06/03 12:36:01 emma
# More e-mail addresses.
#
# Revision 0.22 2002/05/29 20:28:20 emma
# Mail addresses added.
#
# Revision 0.21 2002/05/29 11:45:48 emma
# * Implement --mode=oneline.
# * Expand tabs in input lines (tab stops are spaced 8 columns away from each other).
# * Bugfix --multi mode: all append_item to flush @cur before printing.
# * Restore prolog detection in --multi mode for efficiency.
# * Undo the "unexpand()" that Text::Wrap does, it breaks our line width
# calculation. In the long run, a replacement for Text::Wrap must be
# found that does not unexpand().
#
# Revision 0.20 2002/05/29 10:44:35 emma
# New --multi option that states multiple changelogs are in the same file.
#
# Revision 0.19 2002/05/29 10:27:21 emma
# New option: --[no]warn: Warn about unknown addresses. By default
# enabled, use --nowarn to suppress.
#
# Revision 0.18 2002/05/29 10:17:00 emma
# New addresses.
#
# Revision 0.17 2002/05/25 23:32:49 emma
# Four new addresses.
#
# Revision 0.16 2002/05/22 15:52:26 emma
# Fix deliberate typo in use Pod::Usage that was left over from debugging.
#
# Revision 0.15 2002/05/22 14:05:13 emma
# Sort addresses/names case insensitively (not locale aware).
# Heed quotes when parsing $ENV{LINUXKERNEL_BK_FMT}. As I don't
# currently have Perl 5.004 to test the older Text::ParseWords
# implementation, script now requires Perl 5.005.
# Do not require Pod::Usage, but warn if it's missing.
#
# Revision 0.14 2002/05/22 12:39:59 emma
# Fold the print function dispatcher into %table.
# Parse files on command line individually, but allow to treat them as
# one with a new --merge option.
# Make @cur local to the parse function.
# Die on read errors on input files. Use IO::Handle to read files.
#
# Revision 0.13 2002/05/21 12:42:46 emma
# Add 3 mail addresses.
# Add commentary to the code.
# Check for write errors on STDOUT and die if one happens.
#
# Revision 0.12 2002/05/18 16:54:50 emma
# Make --compress work in terse mode.
# New feature: --swap in terse mode swaps address and log entry.
#
# Revision 0.11 2002/05/18 16:43:30 emma
# Support 'terse' mode.
#
# Revision 0.10 2002/05/18 16:15:10 emma
# Another set of addresses.
#
# Revision 0.9 2002/05/18 16:06:43 emma
# Dozens of new addresses.
#
# Revision 0.8 2002/05/18 15:46:01 emma
# 21 new addresses.
#
# Revision 0.7 2002/05/16 13:57:37 emma
# Add some documentation.
#
# Revision 0.6 2002/05/16 13:55:24 emma
# Fix shift ambiguity in printtag().
#
# Revision 0.5 2002/05/16 13:51:43 emma
# Implement grouped and full modes.
#
# Revision 0.4 2002/05/16 12:07:17 emma
# Add some POD.
# Do options and environment parsing.
# Prepare multiple output modes (only grouped supported at the moment.)
#
# Revision 0.3 2002/05/13 16:11:34 emma
# Compress identical ChangeLog lines (they need not be subsequent, note
# this feature has O(n^2) behaviour, where n is the number of stored
# ChangeLog lines per respective author):
# Soft-fp fix:
# Soft-fp fix:
# becomes:
# 2 x Soft-fp fix:
#
# Revision 0.2 2002/05/13 10:40:32 emma
# Only consider e-mail addresses that are left-justified.
# Suggested by Greg Kroah-Hartman <[email protected]>.
#
=head1 NAME

lk-changelog.pl - Reformat BitKeeper ChangeLog for Linux Kernel

=head1 SYNOPSIS

lk-changelog.pl [options] [file [...]]

Try lk-changelog.pl --help or lk-changelog.pl --man for more information.

=head1 OPTIONS

-h, --help print this short help
--man print the manual page for this program

--[no]compress if true, suppress duplicate entries
--[no]count if true, fold duplicate entries into one,
prefixing it with the count. Implies --compress.
--[no]swap in terse and oneline mode, swap address and log entry.
--[no]merge treat all files on command line as one big file
and suppress the prolog
--[no]multi states that multiple changelogs are in one file
--[no]warn warn about unknown addresses. Default: set!
--[no]abbreviate-names
abbreviate all but the last name
--[no]by-surname
sort entries by surname

--mode=MODE specify the output format (use --man to find out more)
--width[=WIDTH] specify the line length, if omitted: $COLUMNS or 80.
text lines will not exceed this length.

Warning: Neither --compress nor --count are currently functional with
--mode=full.

=head1 DESCRIPTION

Summarizes or reformats BitKeeper ChangeLogs for Linux Kernel 2.X.

=head1 ENVIRONMENT

=over

=item LINUXKERNEL_BK_FMT

Default options. These have the same meaning and syntax as the command
line options and are parsed before them, so you can override defaults
set in this variable on the command line. B<Example:> If you put
--swap here and --noswap on your command line, --noswap takes
precedence.

=back



=head1 EXAMPLES

=over

=item Reformat ChangeLog-2.5.17, displaying all changes grouped by
their author (that is the default mode, but we specify it anyways),
with 76 character wide lines:

lk-changelog.pl --mode=grouped --width=76 ChangeLog-2.5.17

=item Reformat ChangeLog-2.5.18, displaying all changes and their
author on in "-ac changelog style", with 80 character wide lines:

lk-changelog.pl --mode=terse --width=80 ChangeLog-2.5.18

=item Reformat 2.4.19-pre ChangeLogs (several in one file) from your mailer:

Use the pipe command to pipe the mail into:

lk-changelog.pl --multi --mode=terse --width=80

=back

=head1 AUTHOR

=over

=item * Matthias Andree <[email protected]>

Main developer

=item * Marcus Alanen <[email protected]>

=item * Tomas Szepe <[email protected]>

=item * Further help from:

Albert D. Cahalan <[email protected]>, Robinson Maureira Castillo
<[email protected]>, Greg Kroah-Hartman <[email protected]>.

=back

=head1 BUGS

=over

=item * The header is not wrapped for --width character wide lines.

=item * The implementation is not yet finished.

=item * This manual page is incomplete.

=item * --compress does not currently work with --mode=full.

=item * does not detect if the changelog is already summarized (as in Marcelo's 2.4.19-pre9 announcement on the list)

=back

=head1 TODO

=over

=item * --compress-me-harder

To merge
o iget_locked [1/6]
o iget_locked [2/6]
...
o iget_locked [6/6]
into
o iget_locked [1..6/6]

=item * Integrate Bitkeeper

=back

=cut


2002-09-29 10:00:37

by Geert Uytterhoeven

[permalink] [raw]
Subject: Re: [SCRIPT] lk-changelog.pl 0.39 released

On Fri, 27 Sep 2002, Matthias Andree wrote:
> '[email protected]' => 'Geert Uytterhoeven',
> '[email protected]' => 'Geert Uytterhoeven',

Where did you find the second form? It's bogus.

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds