#!/usr/bin/perl
#
# cdlabelgen - a program for making cd jewel box covers and traycards
#
# Created: October, 1998 by B. W. Fitzpatrick <fitz@red-bean.com>
# Maintained by: by Avinash Chopde <avinash@acm.org>  www.aczone.com
# -----------------------------------------------------------------------
# Copyright (C) 1998, 1999 B. W. Fitzpatrick <fitz@red-bean.com>
# Copyright (C) 2001, 2002 Avinash Chopde <avinash@aczone.com>  www.aczone.com
#
# All rights reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, and/or sell copies of the Software, and to permit persons
# to whom the Software is furnished to do so, provided that the above
# copyright notice(s) and this permission notice appear in all copies of
# the Software and that both the above copyright notice(s) and this
# permission notice appear in supporting documentation.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
# OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
# HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
# INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# Except as contained in this notice, the name of a copyright holder
# shall not be used in advertising or otherwise to promote the sale, use
# or other dealings in this Software without prior written authorization
# of the copyright holder.
# ---------------------------------------------------------------------
# Apr 2001 Avinash Chopde <avinash@acm.org> http://www.aczone.com/
# Added -m option to support slim-cd cases 
#          prints front cover insert - folding two page insert
# Added -S 0.0 and -T 0.0 support, to print logo as background image instead
# Minor changes for better handling of Windows NT.
# Jul 2001 Avinash Chopde <avinash@acm.org> http://www.aczone.com/
# Added -p option to enable clipping of item text strings
#   without this option, an item is fit to a column by shrinking it as needed
#   Using -p requires the new template.ps that contains this feature.
# Apr 2002 added CD envelope print option -M
# ---------------------------------------------------------------------

use Getopt::Std;
use Socket qw(:DEFAULT :crlf);
use strict;

# Prepare to slurp up the file
my $template = 'template.ps';
my $directory;

# Modify this if you want to store your template somewhere else
# Perhaps we can make this part of a conf file in the future?
my @where_is_the_template;

if ($^O !~ /^MSWin32/) { # not windows...
  # Unix section -----------------------------------------------------
  @where_is_the_template = (
    '/usr/local/lib/cdlabelgen/',
    '/usr/share/cdlabelgen/',
    '/usr/local/share/cdlabelgen/',
    '/etc/cdlabelgen/',
    './postscript/',
    );
} else { # any MSWindows 32 platform...
  # DOS section -----------------------------------------------------
  @where_is_the_template = ('c:/cdlabelgen/', './postscript/');
}

my $found_template = '';
foreach $directory (@where_is_the_template) {
    if (-e ("$directory$template")) {
        $template = "$directory$template";
        $found_template = 1;
        #Put the template dir at the front of the list for later
        push @where_is_the_template,$directory;
        last;
    }
}

my %flag;
my (@items, @cover_items, @tray_items, $num_items_cover);
my $eps_cover_file;
my $eps_tray_card_file;
my $eps_cover_bounds;
my $eps_tray_card_bounds;
my $eps_cover_scale;
my $eps_tray_card_scale;
my $date;
my    $print_to_file;
my $default_eol = $/;
my $show_plaque = 1;
my $default_bounds = "\n/bound1x 10 def\n/bound1y 10 def\n/bound2x 10 def\n/bound2y 10 def\n/scaleratio 1.0 def\n";
my $normalcdcase = "true";
my $envelopecdcase = "false";
my $enable_item_scaling = "true";
######################################################################
# Argument processing

# mar 01 avinash: add defaults, -c or -s can be omitted
$flag{c} = "";
$flag{'s'} = "";

getopts('v:c:s:f:i:d:S:t:T:e:E:o:DbwhmMp', \%flag);    

if($flag{h}) {
    &show_help();
}

# Do we have enough flags to go on? Bail here if not.
# april 2001: -c -s are both optional now..., so commented out
# &show_help unless $flag{c} || $flag{'s'};

if($flag{t} && -f $flag{t})
{
    $template = $flag{t};
    $found_template = 1; 
}
unless ($found_template) {    &error("Postscript template file not found") }

# Category/title
my $category = &scrub($flag{c});

# Subcategory/subtitle
my $subcategory = &scrub($flag{'s'});

# Items | directories | songs
if($flag{f}) {
   my $infile = $flag{'f'};
   @items = split(/\n/, &scrub(get_file_contents($infile,@where_is_the_template)));
}
elsif ($flag{i}){
   my $clean_items = &scrub($flag{i});
   @items = (split (/%/, $clean_items));
}

# Word wrapping
if($flag{w}) {
   @items = &word_wrap(@items);
}

# how to split the items between tray and cover
if ($flag{v}) {
    unless ( $flag{v} =~ /^([+]?\d+)$/ ) {
       &error("-v num items in cover must be a positive integer");
    }
    $num_items_cover = $flag{v};
    @cover_items = @items;
    if ($num_items_cover < ($#items + 1)) {
       # split items between cover and tray
       @tray_items = splice(@cover_items, $num_items_cover);
    } else {
       # put all items on cover, no items in tray
       @tray_items = (' ');
    }
}
else { # Else, no items to be printed on cover, default
    $num_items_cover = 0;
    @cover_items = (' ');
    @tray_items = @items;
}

# Need to at least have an empty string, 1 min item needed
@cover_items = (' ') if ($#cover_items < 0);
@tray_items = (' ') if ($#tray_items < 0);

# Format for a postscript array of strings now that we've wrapped (or not)
# mar 01 avinash: To try to keep this from exceeding
# DSC line len (255 chars), insert \n after each item
@tray_items = map {"($_)\n"} @tray_items;
@cover_items = map {"($_)\n"} @cover_items;

# Date stuff
if ($flag{d}) {
    $date = &scrub($flag{d});
}
else {
    $date = &get_date();
}
if ($flag{D}) {
    $date = '';
}
# cover espfile scaling
if ($flag{S}) {
    # 0 is a allowed value, but -S 0 returns $flag{S} == false!
    # so, user must input 0.0 instead of 0
    unless ( $flag{S} =~ /^([+]?\d+)|([+]?(\d+\.\d+|\d+\.|\.\d+))$/ ) {
    &error("-S logo scale ratio must be a positive integer or floating point number");
    }
    $eps_cover_scale = $flag{S};
}
else { # Else, no scaling
    $eps_cover_scale = 1;
}
# traycard espfile scaling
if ($flag{T}) {
    # 0 is a allowed value, but -T 0 returns $flag{T} == false!
    # so, user must input 0.0 instead of 0
    unless ( $flag{T} =~ /^(fill1|fill2|([+]?\d+)|([+]?(\d+\.\d+|\d+\.|\.\d+)))$/ ) {
    &error("-T logo scale ratio must be a positive integer or floating point number, or the words fill1 or fill2");
    }
    $eps_tray_card_scale = $flag{T};
}
else { # Else, no scaling
    $eps_tray_card_scale = 1;
}
# cover epsfile
if ($flag{e}) {
    $eps_cover_file = get_file_contents($flag{e},@where_is_the_template);
    $eps_cover_bounds = &get_bounding_box($flag{e}, $eps_cover_scale);
}
else {
    $eps_cover_bounds = $default_bounds;
    $eps_cover_file = '';
}
# traycard epsfile
if ($flag{E}) {
    $eps_tray_card_file = get_file_contents($flag{E},@where_is_the_template);
    $eps_tray_card_bounds = &get_bounding_box($flag{E}, $eps_tray_card_scale);
}
else {
    $eps_tray_card_bounds = $default_bounds;
    $eps_tray_card_file = '';
}
# output file
if ($flag{o}) {
    open (OUT, ">$flag{o}") or &error("Cannot open $flag{o} for writing: $!");
    $print_to_file = 1;
}

# If this flag is set, don't print the plaque on the back (give more room for items).
if ($flag{b}) {
   $show_plaque = 0;
}

if ($flag{m} && $flag{M}) {
    &error("-m (slim cd case) and -M (envelope cd case) are exclusive options, use one only");
}

if ($flag{m}) {
   $normalcdcase = "false";
}

if ($flag{M}) {
   $envelopecdcase = "true";
}

if ($flag{p}) {
   $enable_item_scaling = "false";
}

######################################################################
# Grab the template

my $psout = get_file_contents($template);

$psout =~ s/TOKEN_BAN_STRING/$category/;
$psout =~ s/TOKEN_SUBBAN_STRING/$subcategory/g;
$psout =~ s/TOKEN_DATE/$date/g;
$psout =~ s/TOKEN_ITEMS_TRAY/ @tray_items/g; # space makes first item indented same as following items
$psout =~ s/TOKEN_ITEMS_COVER/ @cover_items/g; # space makes first item indented same as following items
$psout =~ s/TOKEN_EPS_BOUNDS/$eps_cover_bounds/g;
$psout =~ s/TOKEN_COVER_EPS/$eps_cover_file/g;
$psout =~ s/TOKEN_TRAY_CARD_BOUNDS/$eps_tray_card_bounds/g;
$psout =~ s/TOKEN_TRAY_CARD_EPS/$eps_tray_card_file/g;
$psout =~ s/TOKEN_PLAQUE_P/$show_plaque/;
$psout =~ s/TOKEN_NORMAL_CDCASE/$normalcdcase/;
$psout =~ s/TOKEN_ENVELOPE_CDCASE/$envelopecdcase/;
$psout =~ s/TOKEN_ENABLE_ITEM_SCALING_P/$enable_item_scaling/;

if ($print_to_file) { print OUT $psout; }
else { print $psout; }
##################################################################################
# Subroutines

sub get_date {
   my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
   $mon++;
   if ($mon  < 10) { $mon = "0$mon"; }
   if ($mday < 10) { $mday = "0$mday"; }
   $year += 1900; 
   return "$year-$mon-$mday";     # ISO 8601:1988 
}   


sub get_full_filename {
    my $fname = shift @_;
    my ($directory,$realname,$found);
    $found=0;
    $realname=$fname;
    foreach $directory ("",@_) {
        if ( -f "$directory$fname") {
            $realname = "$directory$fname";
            $found = 1;
            last;
        }
    }
    return $realname;
}


sub get_file_contents {
    my $fname = shift @_;
    local $/ = undef;
    my ($directory,$realname,$found);
    $found=0;
    foreach $directory ("",@_) {
        if (open (GET_FILE, "$directory$fname")) {
            $realname = "$directory$fname";
            $found = 1;
            last;
        }
    }
    unless ($found) {    &error("Cannot open $fname") }
    $_ = <GET_FILE>;
    close GET_FILE;

        # check end-of-line delimter, make is \n, which is what
        # input will be split on...
    s/$CR?$LF/\n/g; # variables from Socket package

    $_ .= "\n" unless m/\n$/; # make sure last item is included

    return $_;
}


sub scrub {
    my $string = shift @_;
    $string =~ s?\(?\\050?g;
    $string =~ s?\)?\\051?g;
    return $string;
}


sub get_bounding_box {
    my $file = shift @_;
    my $eps_scale = shift @_;
    my $bounds;
    my $got_bounding_box = 0;
    $/ = $default_eol;
    open (EPS, get_full_filename("$file",@where_is_the_template)) or &error("Cannot open epsfile $file");
    while (<EPS>) {
        chomp;
        if (s/\%\%BoundingBox: //) {
            my ($llx, $lly, $urx, $ury) = split (/\s/, $_);
            $bounds ="\n/bound1x $llx def\n/bound1y $lly def\n/bound2x $urx def\n/bound2y $ury def\n";
	    if ($eps_scale =~ /fill1|0.0/) { # -T option only
              $bounds .="/trayimage_fill_endcaps false def\n";
              $bounds .="/scaleratio 0.0 def\n";
	    } elsif ($eps_scale =~ /fill2/) { # -T option only
              $bounds .="/trayimage_fill_endcaps true def\n";
              $bounds .="/scaleratio 0.0 def\n";
	    } else {
              $bounds .="/scaleratio $eps_scale def\n";
	    }
            $got_bounding_box = 1;
            last;
        }
    }
    unless ($got_bounding_box) {
        &error("Cannot get BoundingBox from $file. Are you sure it's an EPS file?");
    }
undef $/;
    return $bounds;
}

# Ugh. This is nasty and hackish, but it sort of does the trick. If
# anyone can improve the word wrapping capability (either in this
# routine(yuck) or in the postscript (yay!), *please* do and send me
# the diffs.  I'd love to do this in postscript, but I just don't have
# the time right now.
sub word_wrap {
   my @long_items = @_;
   my $long_item;
   my @long_item;
   my $max_chars; 
   my @wrapped_items;

   # Account for the super long possibilities of the single column display
   # Note that by wrapping, it may add a column (or 2), so account for that!
   # Jan 2002: With no wrapping, the current template.ps can handle
   # a minimum of these many items (assuming no title/subtiutle on tray):
   # 1 col -> 61
   # 2 col -> 122
   # 3 col -> 183
   # 4 col -> 244
   # 5 col -> 305

 SWITCH: {
      ($#long_items < 40)  && do { $max_chars = 135; last SWITCH;}; # try 1 cols
      ($#long_items < 100) && do { $max_chars = 107; last SWITCH;}; # try 2 cols
      ($#long_items < 160) && do { $max_chars = 79; last SWITCH;}; # try 3 cols
      ($#long_items < 220) && do { $max_chars = 51; last SWITCH;}; # try 4 cols
      $max_chars = 23;                                             # need 5 cols
   }

   foreach $long_item (@long_items) {

      @long_item = split(/(\s+)/, $long_item);
      my $wrapped = pop(@long_item);
      my $len = length($wrapped);

      foreach (@long_item) {
      $len += length($_);
      if ($len > $max_chars) {
              push (@wrapped_items, $wrapped);
              $wrapped = "   $_"; # indent wrapped lines a bit
          $len = length($wrapped);
      } else {
          $wrapped .= $_;
      }
      }
      push (@wrapped_items, $wrapped) if ($wrapped =~ /\S/);
   }
   return @wrapped_items;
}


sub show_help {
    print <<EOT;
usage: $0 -c <category> -s <subcategory>
       -i <item1%item2%etc> -f <itemsfile>  -v <num_items_cover>
       -e <cover_epsfile> -S <cover_eps_scaleratio> -E <tray_epsfile> 
       -T <tray_eps_scaleratio> -d <date> -D -o <outputfile>
       -t <template> -b -w -h -m -M -p
EOT
exit 255;
}


sub error {
    my $err = shift @_;
    warn "$0: $err\n\n";
    &show_help;
}

__END__

##################################################################################
# Documentation

=head1 NAME

cdlabelgen - CD jewel case inserts creator. Generates frontcards and traycards for CD cases

=head1 SYNOPSIS

cdlabelgen [ B<-c> <category> B<-s> <subcategory>
B<-i> <item1%item2%etc> B<-f> <itemsfile>  B<-v> <num_items_cover>
B<-e> <cover_epsfile> B<-S> <cover_eps_scaleratio> B<-E> <tray_epsfile> 
B<-T> <tray_eps_scaleratio> B<-d> <date> B<-D> B<-o> <outputfile>
B<-t> <template> B<-b> B<-w> B<-h> B<-m> B<-M> B<-p> ]

=head1 VERSION

=over

=item Version 2.3.0

=back

=head1 DESCRIPTION

cdlabelgen's purpose in life is twofold:

=over

=item * To be run automatically and swiftly from a shell script and
automatically generate a frontcard and a traycard for a cd--usually
data archive cd's. The traycard (which goes behind the CD itself) is
U-shaped and the ends of the CD case bear the label of what the CD is.

=item * To have a minimum of dependencies--cdlabelgen only requires perl.

=back

cdlabelgen was designed to simplify the process of generating labels
for CD's. It originated as a program to allow auto generation of
frontcards and traycards for CD's burned via an automated mechanism
(specifically for archiving data), but has now become popular for
labelling CD compilations of mp3's, and copies of CDs. Note that
cdlabelgen does not actually print anything--it just spits out
postscript, which you can then do with as you please.

The latest version of cdlabelgen as well as this document can be
found at http://www.aczone.com/tools/cdinsert/. The software package
includes CGI scripts that can be used to serve cdlabelgen over the
internet.
An older version may be available at:
http://www.red-bean.com/~bwf/software/cdlabelgen/.

Thanks to some really hairy postscript from GNUPlot, cdlabelgen now
supports arbitrary ISOLatin font characters. This means that you can
print out characters like  (ASCII \230, \248, \229, \198, \216
and \197)

cdlabelgen comes with several eps images for you to use on your
labels. These images can be found in /usr/local/lib/cdlabelgen or
/usr/share/cdlabelgen or
/usr/local/share/cdlabelgen, depending on your installation. Included
are a Recycling icon, an mp3 icon, the Compact Disc icon (with and
without 'Digital' on it), Tux the penguin, and the new Debian 'swirl'
logo. Two color background images called Music Notes are also
available.

Note that cdlabelgen now prints a 'tongue' as part of the
traycard. This folds around and is viewable from the front in jewel
boxes that are entirely clear (CD holder piece is not opaque). If you
do not have a clear CD holder in your jewel box, you may find it
easier to just cut the 'tongue' off--it's a bit easier to fold without
it.

cdlabelgen requires Perl Version 5.003 or greater. Ghostscript is not
required, but B<is> recommended so that you can test out your labels
without wasting paper.

=head1 SWITCHES

=over

=item B<-c category>

Set the category (title) for the CD

=item B<-s subcategory>

Set the subcategory (subtitle) for the CD

=item B<-i items>

'items' should be a '%' separated list of items to print on the
traycard of the CD.  Note that if the number of items are too many
to fit on the tray card, cdlabelgen will leave out some items at the end.
cdlabelgen automatically flows the items into 2, 3, 4, or 5 columns
and scales the fontsize accordingly, unless the C<-P> option is used.
You can insert blank lines by
inserting 2 percent signs in a row into the items list.

=item B<-f filename>

Get item names from file named filename. Each item should be on its
own line separated by carriage returns. 
cdlabelgen automatically flows the items into 2, 3, 4, or 5
columns and scales the fontsize or clips the items as needed.
You can insert blank
lines by placing blank lines between items in this file

=item B<-v number_of_items_for_cover>

Normally, all the items are printed on the tray card.
But if you have a large number of items, you may wish to print some items
on the cover, and rest on the tray card.
This option provides a way of specifying how many items should be printed
on the cover. Default is 0 (i.e., print no item on the cover, print all
items on the tray). The items to be printed on the cover are taken from
the list of items, from the top of the list.
Note that if the number of items is too many to fit on the cover,
it will result in items being dropped. As of Jan 2002, around
250-300 items can be fitted on the cover or the tray, depending on
whether a title/subtitle/date is used or not.

=item B<-d date>

Set the date to be used as 'date' if not set or not overridden with
the B<-D> flag, today's date will be used (default is today's
date). Use this option if you don't like cdlabelgen's default format of
YYCC-MM-YY, for example.

=item B<-D> 

Do not print B<any> date (overrides B<-d> as well)

=item B<-e cover_epsfile>

Filename of eps file to print on cover. Note that cdlabelgen requires
that the eps file contain a proper '%%BoundingBox LLx LLy URx URy'
declaration according to the PostScript Document Structuring
Conventions. cdlabelgen uses this line to determine the dimensions of
the eps graphic so that it can position it appropriately on the
cover. Note that cdlabelgen first looks for this file in your working
directory. If it doesn't find it there, it will look in the list of
directories where the default eps files are stored (see
@where_is_the_template). This makes it easy to use the images shipped
with cdlabgelgen without typing miles of pathnames.

=item B<-S cover_eps_scaleratio>

The ratio by which you want to scale the epsfile that appears on the
cover. If you omit this flag, cdlabelgen assumes a scaleratio of
1.0. This flag allows you to squeeze larger graphics into the cover or
expand smaller graphics to fill the cover. Scaleratio must be a number
(int or float). 

If the value passed is 0.0 (note: not 0, but 0.0), then the
logo is used as a background image - it will be scaled as required
to fit the entire cover.

=item B<-E tray_epsfile>

Filename of eps file to print on traycard. Note that cdlabelgen
requires that the eps file contain a proper '%%BoundingBox LLx LLy URx
URy' declaration according to the PostScript Document Structuring
Conventions. cdlabelgen uses this line to determine the dimensions of
the eps graphic so that it can position it appropriately on the
cover. Note that cdlabelgen first looks for this file in your working
directory. If it doesn't find it there, it will look in the list of
directories where the default eps files are stored (see
@where_is_the_template). This makes it easy to use the images shipped
with cdlabgelgen without typing miles of pathnames.


=item B<-T tray_eps_scaleratio>

The ratio by which you want to scale the epsfile that appears on the
traycard. If you omit this flag, cdlabelgen assumes a scaleratio of
1. This flag allows you to squeeze larger graphics into the traycard or
expand smaller graphics to fill the traycard. Scaleratio must be a 
positive number (int or float) specifying the scale.

If the value passed is the word B<fill1>, then the image is used as a
background - it is scaled so that it completely fills the interior tray
card region.  The value B<0.0> (note: not 0, but 0.0) works same as the
B<fill1> argument.

If the value passed is the word B<fill2>, then the image is used as a
background - it is scaled so that it completely fills the tray card region,
including the 'tongue' end-caps.

=item B<-o outputfile>

If the B<-o> flag is used, cdlabelgen prints to outputfile instead of STDOUT. 

=item B<-t template>

Specify explicitly which template to use. This is useful if you need
to debug the PostScript code in the
template, use a different template, or if you have created
your own template to use in lieu of the one provided with
cdlabelgen.

=item B<-b>

Suppresses printing of the Plaque on the traycard, thus allowing you
to either fit even more items on the traycard, or to use a slightly 
larger font size for the items.

=item B<-h>

print out the usage message

=item B<-w>

Enables word wrapping of the items that print on the traycard. Note
that this is *not* extensively tested and may be buggy! Make sure that
you preview your label before printing it if you use this flag.

If there is a problem with C<-w>, the best option right now is to split
lines in the input itself, and to omit the C<-w> option.

=item B<-m>

Creates covers suitable for use in slim cd-cases, this means
no tray card (the tray card is now the inside front cover). 
This creates a two page, folding cover insert. This could also be
used in normal cd cases.

=item B<-M>

Creates covers suitable for use as envelopes for a CD. Guide lines
are printed, to aid in folding the printout correctly.

=item B<-p>

Enables clipping of items; uses fixed font size for all items.
Normally, the template.ps used by cdlabelgen will try to fit an
item in a given column by reducing the font size if needed. This is
ok if done for one or two items, but if done too often, it makes the
tray card look ugly, with text of varying font sizes. 

Use this option to use a fixed width font for all items. If the item
is too large to fit in a column, the text will be clipped instead.

=back

=head1 EXAMPLES

    ./cdlabelgen -c "My Filesystem" -s "/usr/local/foo" -e postscript/recycle.eps > foo.ps

    ./cdlabelgen -c "title of cd" -s "subtitle" -i "Item 1%and Item 2%a third item here perhaps" -e postscript/recycle.eps > bar.ps

    ./cdlabelgen -c "Fitz" -s "home directory" -o qux.ps

=head1 AUTHOR

Currently maintained by Avinash Chopde E<lt>F<avinash@acm.org>E<gt>

Last Updated: December 2001

Original author:
B. W. Fitzpatrick E<lt>F<fitz@red-bean.com>E<gt>

=head1 THANKS

    - Karl Fogel, for general encouragement and that free software vibe
    - Adam Di Carlo, for bug testing, help and making the .deb
    - Greg Gallagher, for bug testing, coding, and tons of suggestions
    - Goran Larsson, for feedback and date fixes
    - Jens Claussen, for the patch to allow arbitrary ISO-Latin1 characters
    - Bernard Quatermass, for contributing several excellent new features
    - Sebastian Wenzler <sick@home.and.drunk.at> for reports, tests, RPM.

=head1 ERRATA

Perhaps one of the most important features that I wanted in a
CD labelling program was the ability to print Title/Subtitle, and date
information on the endcaps of the CD jewel box to allow me to keep
archive disks in a standard CD rack and find a particular one without
yanking them all out and shuffling through them like a deck of cards.

cdlabelgen was inspired by the need for not only a simple cd labelling
program (there are many available), but by the need for a free
labelling program which could be integrated easily with scheduled CD
archiving routines. I did find a program called cdlabel
http://londo.ncl.ac.uk/~npac/cdlabel/, but that one is designed to work
with CDDB.

I searched the net for a suitable program, but found none, so taking
cues from programs that I found that perform similar tasks (like tape
labellers and DAT labellers), I embarked on this venture. Notable
inspiration came from the incredible audio-tape.ps by Jamie Zawinski
(which is indeed, as Jamie notes, completely out of control). Other
ideas were drawn from casslabel.c, and cdlabel.cc (noted above).

People have already pointed out to me that cdlabelgen could be
extended to perform other functions:

=over

=item * Print out the actual label that goes on the disk (I suppose it
is kinda funny that it is named cdB<label>gen and doesn't really
generate any label per se).

=item * Integrate with cdindex or cddb or something like that.

=back

Please report bugs and submit any patches to the Author's email address.

=head1 TODO

In order of importance.

=over

* Add cdindex support

=back

=cut
