This is Info file pm.info, produced by Makeinfo version 1.68 from the
input file bigpm.texi.


File: pm.info,  Node: Silly/Werder,  Next: SimpleCDB,  Prev: Silly/StringMaths,  Up: Module List

Meaningless gibberish generator
*******************************

NAME
====

   Werder - Meaningless gibberish generator

SYNOPSIS
========

     use Silly::Werder;

     my $foo = new Silly::Werder;

     # Set the min and max number of werds per line
     $foo->set_werds_num(5, 9);

     # Set the min and max # of syllables per werd
     $foo->set_syllables_num(3, 7);

     # Set the percentage of the time a werd will start with a consonant
     $foo->set_cons_weight(75);
     
     # Return a random sentence, question, or exclaimation
     $line = $foo->line;

     $sentence = $foo->sentence;
     $question = $foo->question;
     $question = $foo->exclaimation;

     # Generate a long random sentence calling as a class method
     Silly::Werder->set_werds_num(10,20);
     print Silly::Werder->line;

     # All of the above methods can be used as either class methods
     # or object methods.

DESCRIPTION
===========

   This module is used to create pronouncable yet completely meaningless
language.  It is good for sending to a text-to-speech program (ala
festival), generating passwords, annoying people on irc, and all kinds of
fun things.

BUGS
====

   The only bug I am aware of is the (intentional) spelling of 'werd'
throughout the souce and documentation =)

AUTHOR
======

   Werder was created and implemented by Dave Olszewski, aka cxreg.  You
can send comments, suggestions, flames, or love letters to
dave.olszewski@osdn.com


File: pm.info,  Node: SimpleCDB,  Next: SimpleConfig,  Prev: Silly/Werder,  Up: Module List

Perl-only Constant Database
***************************

NAME
====

   SimpleCDB - Perl-only Constant Database

SYNOPSIS
========

     use SimpleCDB;

     # writer
     # - tie blocks until DB is available (exclusive), or timeout
     tie %h, 'SimpleCDB', 'db', O_WRONLY
     	 or die "tie failed: $SimpleCDB::ERROR\n";
     $h{$k} = $v;
     die "store: $SimpleCDB::ERROR" if $SimpleCDB::ERROR;
     untie %h;	# release DB (exclusive) lock

     # reader
     # - tie blocks until DB is available (shared), or timeout
     tie %h, 'SimpleCDB', 'db', O_RDONLY
     	 or die "tie failed: $SimpleCDB::ERROR\n";
     $v = $h{$i};
     die "fetch: $SimpleCDB::ERROR" if $SimpleCDB::ERROR;
     untie %h;	# release DB (shared) lock

DESCRIPTION
===========

   This is a simple perl-only DB intended for constant DB applications. A
constant DB is one which, once created, is only ever read from (though
this implementation allows appending of new data). That is, this is an
"append-only DB" - records may only be added and/or extracted.

   Course-grained locking provided to allow multiple users, as per flock
semantics (i.e. write access requires an exclusive lock, read access needs
a shared lock (see notes below re. perl < 5.004)). As (exclusive) updates
may be take some time to complete, shared lock attempts will timeout after
a defined waiting period (returning $! == EWOULDBLOCK).  Concurrent update
attempts will behave similarly, but with a longer timeout.

   The DB files are simple flat files, with one record per line. Records
(both keys and values) may be arbitrary (binary) data. Records are
extracted from these files via a plain linear search. Unsurprisingly, this
search is a relatively inefficient operation. To improve extraction speed,
records are randomly distributed across N files, with the average search
space is reduced by 1/N compared to a single file. (See below for some
example performance times.) One advantage of this flat file based solution
is that the DB is human readable (assuming the data is), and with some
care can be edited with a plain ol' text editor.

   Finally, note that this DB does not support duplicate entries. In
practice, the first record found matching a given key is returned, any
duplicates will be ignored.

PURPOSE
-------

   I needed to extract single records from a 20k-40k record data set,
within at most 5 seconds on an old Sun 4/40, to feed to an interactive
voice response system. Fine, I thought, an easy job for any old DBM.

   Unfortunately, all of the standard "system" DBMs (NBDM, SDBM, ODBM) are
broken when it comes to "large" data sets (though I don't generally call
20,000 records "large") - at least on Solaris 2.5.1 and Solaris 2.6
machines. I found after inserting some 15k records: NDBM dies; SDBM and
ODBM silently "lose" data (you can't extract records which you know you
inserted). On an HPUX machine, it took nearer to 100,000 records to break
[NSO]DBM. All worked flawlessly on a Linux 2.2.16 machine. The program
examples/testdbm.pl can be used to exercise the various DBMs.

   BerkeleyDB (DB_File) and GDBM work well, but they don't come standard
with many boxes. Further, this package was originally written for an old
Solaris 2.5 box which lacked development tools (and the space and
management will to install such tools) to build a "real" DB.

   And besides, I hadn't played with perl's tie mechanism before...

EXPORTS / CONSTRUCTOR
=====================

   This modules uses the tie interface, as for DB_File.

   The default Fcntl exports are re-exported by default, primarily for the
LOCK_ constants.

CLASS METHODS / CLASS VARIABLES
===============================

   There are two public class variables:

     $SimpleCDB::DEBUG  turn on some debugging messages
     $SimpleCDB::ERROR  error message for last operation, empty if no error
                        has ocurred

METHODS
=======

   n/a

NOTES
=====

   It seems not all environments have POSIX::EWOULDBLOCK defined, in which
case this module defines it as a subroutine constant.

   This DB may use a significant number of file descriptors, you may want
to increase the user/system resource limits for better performance (e.g.
`ulimit -S -n 300' on a Solaris box). My test programs on Solaris don't
seem to want to open more than 256 files at a time, that is even with the
ulimit set to 300, I got EMFILE results as soon as I reached 256 open file
descriptors.  This means there is still some file closing/opening going
on... Interestingly, on the non-exhaustive, not-terribly-thorough testing
I did, I noticed that using a smaller number of files gave slightly better
performance wrt. creating the DB. e.g.  with ulimit set as above, over two
runs of each on an old Sparc:       nfiles = 256 : real,user,sys time =
3:20, 2:43, 0:01       nfiles =  16 : real,user,sys time = 3:00, 2:40, 0:00
Perhaps this is due to file caching?

   Speaking of performance, I used Devel::DProf to find that using crypt to
generate the digest is a real bottleneck (75% CPU time was in generating
the digest :-) Using MD5 reduces this to around 6% (only half of which is
in MD5)! My homebrew digest is not nearly as good as MD5 (both in CPU and
quality), but it more or less does the job when MD5 isn't available.

   Here's how it runs:  Records are between 0 and 100 bytes each. Times
are user/sys/real, as either minutes:seconds or just seconds. wr = create
the db with the stated number of records. rd = read one record (next to
last inserted, i.e.  should be about the worst case).

     Sun 4/40 (sun4c), Solaris 2.5
      40,000 records, nfiles =   1: wr =14:48/29/14:03  rd = 26/2.2/28
      40,000 records, nfiles =  16: wr =14:04/30/15:15  rd =  4/1.0/ 6
      40,000 records, nfiles = 256: wr =14:33/34/15:32  rd =  3/0.8/ 4
       i.e. sloooowwwww to build, good enough on extraction.

     Sun Ultra/1 (sun4u), Solaris 2.6 (SCSI disks)
      40,000 records, nfiles =   1: wr = 53/2.8/57  rd = 3.0/0.1/3.4
      40,000 records, nfiles =  16: wr = 53/2.4/57  rd = 0.5/0.0/0.6
      40,000 records, nfiles = 256: wr =196/19/240  rd = 0.3/0.0/0.4

     x86 C433/64MB, IDE ATA/66 disk, Linux 2.2.16
      40,000 records, nfiles =   1: wr = 18/0.7/19  rd = 1.3/0.0/1.4
      40,000 records, nfiles =  16: wr = 18/0.8/19  rd = 0.3/0.0/0.3
      40,000 records, nfiles = 256: wr = 18/0.8/20  rd = 0.2/0.0/0.2
     100,000 records, nfiles =   1: wr = 47/2.0/49  rd = 3.1/0.1/3.2
     100,000 records, nfiles =  16: wr = 47/2.0/49  rd = 0.4/0.0/0.4
     100,000 records, nfiles = 256: wr = 47/2.2/49  rd = 0.2/0.0/0.2
       i.e. I think the o/s is caching the whole bloody lot :-)

   Clearly, other overheads limit the benefit of the distributed file
hashing, however the result is useful for my purposes...

   The important thing is, it works (as opposed to NDBM and friends).
while (each %h) always shows as much data as you put in :-)

"BUGS"
======

   Possibly, though it works for me :-)

   I've noted that on a HP-UX B.10.20 box that ALRMs don't seem to trigger
when I expect they should. For example, in _lock, I set alarm for say 5s
and then call flock, which I expect to block until either the lock is
granted *or* the alarm goes off (as happens for Solaris and Linux).
However, it is as if the HP-UX box's ALRM signal is delayed until the flock
returns. HP-UX doesn't have a flock call, but does support lockf (which
can lock regions of a file), so perhaps this behaviour is an artefact of
perl's flock emulation...

COPYRIGHT
=========

   Copyright (c) 2000 Benjamin Low <b.d.low@ieee.org>.  All rights
reserved.

   This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.

   This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE.  See the Artistic License for more
details.

AUTHORS
=======

   Written as a last resort, and as an excuse to write my first tied
module, by Benjamin Low <b.d.low@ieee.org>, July 2000.

SEE ALSO
========

   Dan Berstein has a nice constant DB implementation, written in C, at

   http://cr.yp.to/cdb.html

   If you've a C compiler handy I recommend this library over SimpleCDB.

   If you want a read+write DB, go for GDBM - it doesn't support
fine-grained locking but does actually work.


File: pm.info,  Node: SimpleConfig,  Next: Simran/DB/Session,  Prev: SimpleCDB,  Up: Module List

Simple configuration file parser
********************************

NAME
====

   SimpleConfig - Simple configuration file parser

SYNOPSIS
========

     use SimpleConfig;

     $config = SimpleConfig->new("configrc", [qw(Foo Bar Baz Quux)]);

     $config->parse();

DESCRIPTION
===========

     C<SimpleConfig> reads and parses simple configuration files.  It's
     designed to be smaller and simpler than the C<ConfigReader> module
     and is more suited to simple configuration files.

CONSTRUCTOR
===========

new ( FILENAME, DIRECTIVES )
     This is the constructor for a new SimpleConfig object.

     FILENAME tells the instance where to look for the configuration file.

     DIRECTIVES is a reference to an array.  Each member of the array
     should contain one valid directive.

     This does the actual work.  No parameters needed.

     Returns the parsed value for that directive.

LIMITATIONS/BUGS
================

   Directives are case-sensitive.

   If a directive is repeated, the first instance will silently be ignored.

   Always die()s on errors instead of reporting them.

   get() doesn't warn if used before parse().

   get() doesn't warn if you try to acces the value of an unknown
directive not know (ie: one that wasn't passed via new()).

   All these will be addressed in future releases.

AUTHOR
======

   Bek Oberin <gossamer@tertius.net.au>

COPYRIGHT
=========

   Copyright (c) 1998 Bek Oberin.  All rights reserved.

   This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.


File: pm.info,  Node: Simran/DB/Session,  Next: Simran/Error/Error,  Prev: SimpleConfig,  Up: Module List

Database Session
****************

NAME
====

   DB_session.pm - Database Session


##################################################################################################################

DESCRIPTION
===========

   Gives a friendlier interface to the DBI module.


##################################################################################################################

SYNOPSIS
========

   Please see DESCRIPTION.


##################################################################################################################

REVISION
========

   $Revision: 1.2 $

   $Date: 2000/04/26 04:28:08 $


##################################################################################################################

AUTHOR
======

   Simran *simran@unsw.edu.au*


##################################################################################################################

BUGS
====

   No known bugs.


##################################################################################################################

PROPERTIES
==========

   DATABASE: the name of the database to connect to.

   HOST:     the name of the host computer for the session.

   PORT:     the port number to connect to the host.

   USERNAME: the user name to use for the connection.

   PASSWORD: the password to use for the connection.

   DSN:      the Data Source Name.

   PROTOCOL: the protocol to use for DBI. Defaults to "mysql"

   DATABASE_HANDLE: the database handle when the connection is made (used
to perform queries etc).


##################################################################################################################

METHODS
=======


##################################################################################################################

new
---

Description
     This is the create method for the DB_session class. The new method
     can be called with parameters, if it is, they ar passed to the set
     method (see below).

          $session = DB_session->new

          or

          $session = DB_session->new($parameters)

     eg.

          $session = DB_session->new("PROTOCOL=mysql;DATABASE=test;HOST=localhost;PORT=3306");

Input
          $parameters -  the parameters string is passed straight to the set method (see below).

Output
          New DB_session object created.

Return Value
          New DB_session object.


##################################################################################################################

set
---

Description
     This method takes strings (one or more) of the form
     "<property1>=<value1>; <property2>=<value2>" (i.e. each value in the
     same string must be separated by a semi colon). And sets the
     coressponding property in the object.

     Example: to set the DATABASE property
     $session->set("DATABASE=MyDataBase")

     set is case insensitive when working out which property to set (eg
     DATABASE or database) would work equally well.

          $session->set(@parameters); # list of parameter strings

          or

          $session->set($parameters); # single parameter string

Input
          @parameters (list of inputs $parameters below)

          $parameters (scalar, string) -  the parameters
          string (or list of strings is a set of paired <property>=<value>,
          with each pair being separated by a semi-colon.

          Note: Dont use semi-colons or equals (; or =) in the values

          eg: $parameters = "DATABASE=MyData;USER=Me;PASSWORD=secret";

Output
          Sets properties within the object

Return Value
          returns 1 if all parameters successfully set.


##################################################################################################################

build_dsn
---------

Description
     This internal method builds the DSN property (needed for the
     connection). There should be no need to call this manually as the
     DB_session object should invoke this method interanlly whenever it
     needs to connect to the DB

     A DSN looks like "DBI:<protocol>:database=<dbname>;host=<hostname>;
     port=portname". The host and the port are optional, but the protocol
     and the database are essential.

Syntax
          $session->set(@parameters); # list of parameter strings

          or

          $session->set($parameters); # single parameter string

Input
          None, uses object properties

Output
          Builds the DSN property

Return Value
          returns 1 if DSN is valid.


##################################################################################################################

connect
-------

Description
     This method connects to the database using the DBI connect method.
     Needs a valid DSN to succeed and invokes the internal "build_dsn"
     method.  This is mostly an internal method called when a conection
     becomes necessary.

Input
          None, uses object properties DSN, USERNAME, PASSWORD

Output
          creates DBI database handle and stores it in the
          DATABASE_HANDLE property.

Return Value
          returns 1 if connection succeeds.


##################################################################################################################

disconnect
----------

Description
     This method disconnects the database handle using the DBI disconnect
     method.  This can be called explicity, but will be called when the
     DB_session object is destroyed. ie. when the object is removed or
     deleted.

          $session->disconnect

Input
          None, uses object property DATABASE_HANDLE

Output
          Disconnects and removes the DATABASE_HANDLE

Return Value
          1 if the disconnection succeeds


##################################################################################################################

query_handle
------------

Description
     Returns a statement handle of a particular query (see DBI and DBD
     documentation for how to use the query handle. The query handle
     should be explictly closed ($handle->finish) to avoid warnings and
     errors.

     eg.

          $handle = $query_handle($query);

Input
          $query - the sql query to use

Output
          $handle - the statement handle

Return Value
          same as output


##################################################################################################################

quote
-----

Description
     Puts escape characters next to charaters for sql strings (queries
     etc).

     The following characters have an escape '\' put in front of them: ",
     ', \, !, \t, \r, \n, \0,

     In addition if a positive second parameter is sent (for stronger
     'literal' escaping) these characters are escaped: %, <, >, =

          $escaped_string = $session->escape($string); or

          $escaped_string = $session->escape($string, 1); (for literal)

Input
          $string - the string to 'quote'

          1 (optional) if positive, stronger escaping used.

Output
          $escaped_string

Return Value
          none


##################################################################################################################

all_values
----------

Description
     Similar to the 'Value' from db_routines.pl function, but returns the
     entire query.

     'all_values' does not keep the statement handle so once called, the
     query returns the results and then is gone.

          $array_ref = $session->all_values($query);

Input
          $query - the sql query to run

Output
          $array_ref - the result of a 'fetchall_arrayref'

Return Value
          output is the return value.


##################################################################################################################

rarh
----

Description
     Used for accessing the data from the database with a special
     output/return value

          $url_data = $dbObject->rarh("table", "id=$id and name='simran'")

Input
          $table - the table name we are to get data from
          	$where_clauses - any where clauses

Output
          $table_data - the output is a "reference to an array of references to hashes"
                        containing information for data associated with the query.
                        eg.
                          $table_data = [
                                         { row1field1 => row1value1, row1field2 => row1value2, ... }
                                         { row2field1 => row2value1, row2field2 => row2value2, ... }
                                        ]

          Note: All the field names will be in lower case.

Return Value
          Same as output.


##################################################################################################################

value
-----

Description
     Equivalent to the 'Value' from db_routines.pl function, but returns
     the entire query.

     'values' does not keep the statement handle so once called, the query
     returns the results and then is gone.

     eg.          @array = $session->value($query);

Input
          $query - the query string...

Output
          @array - the result of a 'fetchrow'

Return Value
          output is the return value.


##################################################################################################################

do
--

Description
     A fairly generic do command for the database. It connects if necessary
     and executes the command. It returns the number of row effected by the
     command.

     eg.         $rows = $session->do($mysql_command);

Input
          $mysql_command (scalar, string) a command to be executed using the
            DBI::do method.

Output
          $rows (scalar, integer) the number of rows affected. If do method
            fails rows will be 'undef' # if the method succeeds but the
            command effects no rows the return value will be 0.

Return Value
          same as output


##################################################################################################################

error
-----

Description
     If called in an array context, returns the complete history of error
     messages thus far. Else, returns the latest error message if set.

          $errmsg = $session->error();

          or

          foreach $_ ($session->error()) {
          	  print "Error: $_\n";
          }

Input
          none

Output
          In array context, returns an array containing all error message set thus far.
          Else, returns the latest error message if set.

Return Value
          same as output


##################################################################################################################

DESTROY
-------

Description
     The automatic destructor method for DB_session. Called automatically
     when a DB_session is destroyed.

Syntax
          not used. method called when object is destroyed

Input
          none

Output
          none

Return Value
          none


File: pm.info,  Node: Simran/Error/Error,  Next: Simran/Log/Log,  Prev: Simran/DB/Session,  Up: Module List


##################################################################################################################

Error Module
************

NAME
====

   Error.pm - Error Module


##################################################################################################################

DESCRIPTION
===========

   Gives a friendly interface for scripts and other modules to maintain
error states


##################################################################################################################

SYNOPSIS
========

   Please see DESCRIPTION.


##################################################################################################################

REVISION
========

   $Revision: 1.2 $

   $Date: 2000/04/26 04:28:08 $


##################################################################################################################

AUTHOR
======

   Simran *simran@unsw.edu.au*


##################################################################################################################

BUGS
====

   No known bugs.


##################################################################################################################

PROPERTIES
==========

   ERROR:    the error message - used internally

   CARP:     should be set to '1' if you want the error module to 'carp'
every time           an error is set.

   HISTORY:  a pointer to an array in which the full history of error
messages is kept.


##################################################################################################################

METHODS
=======


##################################################################################################################

new
---

Description
     This is the create method for the Error class. The new method can be
     called with a reference to a hash, if it is, the reference is used to
     set all properties contained in the hash.

          $error = Error->new();

          or

          $error = Error->new($parameters_ref)

     eg.

          $error = Error->new({CARP => 1});

Input
          $parameters_ref - a reference to a hash

Output
          New Error object created.

Return Value
          New Error object.


##################################################################################################################

clear
-----

Description
     This method resets the error message. It should be called at the
     start of any code that you want to set errors in.

Syntax
          $session->clear();

Input
          None, uses object properties

Output
          none

Return Value
          none


##################################################################################################################

set
---

Description
     Sets the error message to the supplied message.

     eg. $error->set("Could not open file : $!";

Input
          $string - the error message

Output
          none

Return Value
          none


##################################################################################################################

msg
---

Description
     Returns a error message(s) that would have been set earlier.

     eg.          $message = $error->msg();

          @messages = $error->msg();

Input
          None

Output
          In array context, returns all the error messages set thus far.
          In scalar context, returns the lasest set error message.

Return Value
          same as output


File: pm.info,  Node: Simran/Log/Log,  Next: Sirc/Chantrack,  Prev: Simran/Error/Error,  Up: Module List


##################################################################################################################

Log Module
**********

NAME
====

   Log.pm - Log Module


##################################################################################################################

DESCRIPTION
===========

   Gives an interface for logging messages to a file


##################################################################################################################

SYNOPSIS
========

   Please see DESCRIPTION.


##################################################################################################################

REVISION
========

   $Revision: 1.2 $

   $Date: 2000/04/26 04:28:08 $


##################################################################################################################

AUTHOR
======

   Simran *simran@unsw.edu.au*


##################################################################################################################

BUGS
====

   No known bugs.


##################################################################################################################

PROPERTIES
==========

   LOGFILE:     the log file name

   FILE_HANDLE: the FileHandle for the file we are logging to


##################################################################################################################

METHODS
=======


##################################################################################################################

new
---

Description
     This is the create method for the Log class. The new method can be
     called with a reference to a hash, if it is, the reference is used to
     set all properties contained in the hash.

          $log = Log->new("/tmp/program.log");

Input
          $logfile = the logfile for writing to

Output
          New Log object created.

Return Value
          New Log object.


##################################################################################################################

open
----

Description
     This method is used internally from within the new method to open the
     file ready for writing to.

Input
          none - uses properties

Output
          none

Return Value
          none


##################################################################################################################

write
-----

Description
     Writes a message to the logfile

     eg. $log->write("Got data from remote host");

Input
          $string - the log message

Output
          none

Return Value
          none


##################################################################################################################

error
-----

Description
     If called in an array context, returns the complete history of error
     messages thus far. Else, returns the latest error message if set.

          $errmsg = $session->error();

          or

          foreach $_ ($session->error()) {
          	  print "Error: $_\n";
          }

Input
          none

Output
          In array context, returns an array containing all error message set thus far.
          Else, returns the latest error message if set.

Return Value
          same as output


File: pm.info,  Node: Sirc/Chantrack,  Next: Sirc/LimitMan,  Prev: Simran/Log/Log,  Up: Module List

Track information about the channels you're on
**********************************************

NAME
====

   Sirc::Chantrack - Track information about the channels you're on

SYNOPSIS
========

     $Channel{$chan}		# true if you're on $channel

     # These only work for channels you are on:
     $Chan_limit{$chan}		# channel limit, or non-existent
     $Chan_user{$chan}{$who}	# true if $who is on $channel
     $Chan_op{$chan}{$who}	# true if $who is an op on $channel
     $Chan_voice{$chan}{$who}	# true if $who has a voice op on $channel

     # These only work for nicks which are on at least one of
     # the channels you are on:
     $Nick{$nick}		# value is $nick, properly cased
     $User_chan{$nick}{$channel}	# true for all the channels you and
     	    	    	    	# $nick are both on

     # Overridden functions in main:
     main::userhost $user, $have, $have_not;
     main::userhost [@user_list], $have, $have_not;

     # Sirc::Util-style hooks:
     +op		gets ($channel, $nick), $who is originator
     -op		ditto
     +voice	gets ($channel, $nick), $who is originator
     -voice	ditto
     limit	gets ($channel, $old_limit, $new_limit), $who is originator

DESCRIPTION
===========

   This module tracks various data about the channels you are on, and the
nicks who are on them with you.  It also overrides main::userhost with an
enhanced version, and it provides hooks for when people gain and lose ops.

   Nothing is exported by default.

   Most of the data is available in a series of hashes.  These hashes are
tied to a package which downcases the keys.

   All of the hashes only track data about the channels you are on.

*$Channel{channel}*
     The keys of this hash are the names of the channels you're on.  Values
     are always 1.

*$Chan_user{channel}{nick}*
     This hash of hashes tracks the users on the channels you're on.  The
     values are always 1.

*$User_chan{nick}{channel}*
     This hash of hashes contains the same data as %Chan_user, but with the
     keys stacked in the opposite order.

*$Chan_op{channel}{nick}*
     This hash of hashes only contains elements for the operators of the
     given channels.  The values are always 1.

*$Chan_voice{channel}{nick}*
     This hash of hashes only contains elements for the people on the
     channel who have voices.  Due to the way /NAMES works, though, it can
     lack people who were +o when you showed up and got +v before you
     showed up (even if they subsequenty lose the +o).  (It syncs from
     `/names' and `/mode'.)  Note that ops can speak without voices.  The
     values are always 1.

*$Nick{nick}*
     This hash maps from any case of nick to the proper case.

*main::userhost *nick-or-array-ref*, *have-code* [, *havenot-code*]*
     This is an overridden version of *main::userhost*.  It uses the cached
     data to avoid going to the server for information.  Additionally, the
     first arg can be a reference to an array of nicks to check on.  If you
     query multiple users this way they're sent to the server in lots of 5.
     Lastly, the two code arguments can be either strings or code refs.
     The data will be in $::who, $::user and $::host when the code runs.

     Eg, here's how to run a command which uses userhost info for every
     user on a channel:

          userhost [keys %{ $Chan_user{$c} }], sub {
          	autoop_try $c, "$who!$user\@$host";
          };

*+op*, *-op*, *+voice*, and *-voice* hooks
     These are *Sirc::Util*-style hooks which are called when people gain
     and lose ops and voices.  They are only called for people who are
     still in the channel after the gain/loss.  That is, an operator
     leaving the channel does not trigger the *-op* hook.

     The hooks are called with the channel as the first arg and the nick as
     the second.  The originator is in $::who.  Eg, here's a trigger which
     activates when you are given ops:

          use Sirc::Util qw(add_hook ieq);

          add_hook '+op', sub {
          	my ($c, $n) = @_;
          	timer 10, qq{ main::cmd_autoop "\Q$c\E" }
          	    if ieq $n, $::nick;
          };

limit hook
     This is a Sirc::Util-style hook for channel limit changes.  It gets as
     args the channel name, the old limit, and the new limit.  $::who
     contains the originator.

AVAILABILITY
============

   Check CPAN or http://www.argon.org/~roderick/ for the latest version.

AUTHOR
======

   Roderick Schertler <`roderick@argon.org'>

SEE ALSO
========

   sirc(1), perl(1), Sirc::Util(3pm).


File: pm.info,  Node: Sirc/LimitMan,  Next: Sirc/Util,  Prev: Sirc/Chantrack,  Up: Module List

simple channel limit management
*******************************

NAME
====

   Sirc::LimitMan - simple channel limit management

SYNOPSIS
========

     /eval use Sirc::LimitMan

     /limitman			# toggles management on current channel
     /limitman #mychan		# toggles management on #mychan

DESCRIPTION
===========

   This module provides a command which will do simple channel limit
management.  When invoked for a channel you will occasionally modify the
channel's limit to keep it within a certain distance of the actual number
of users.  The channel can become full while limit management is in place.
This is intentional, if the limit were always upped in order to allow
somebody else to join, it would be pointless.

   This code tries to keep the noise down by limiting the number of +l
changes.  A client running it considers itself the master if it's the last
one who made a change to the limit.  Normally the clients try to schedule
themselves so that only the master keeps changing the limit, but somebody
else will step in if he falls down on the job.

Settable Options
================

   You can set these values with *sirc*'s /set command.  Most of them
should really be specifiable per-channel, but they aren't.  Sorry.

limitman *on*|*off*
     If disabled then no limit management is done.  The channels you want
     limit management for are still remembered, so if you enable it again
     later they'll kick in again.  The default is *on*.

limitman_debug *on*|*off*
     Turning this on causes the module to let you in on its cogitations.
     It defaults to *off*.

limitman_tween seconds
     This is the base number of seconds between checks to see if the limit
     should be adjusted.  The default is 60.

limitman_skew seconds
     Non-masters have an additional delay between checks.  Part of it is a
     random delay of up to limitman_skew seconds, default 30.

limitman_skew_offset seconds
     An additional part of the delay for non-masters is a constant
     limitman_skew_offset seconds, default 15.

limitman_low count
     The limit will raised if there are fewer than limitman_low free slots
     on the channel, default 2.

limitman_high count
     The limit will lowered if there are more than limitman_high free
     slots on the channel, default 5.

limitman_reset count
     When the limit is reset, it's set to the current number of users plus
     limitman_reset, default 4.

AVAILABILITY
============

   Check CPAN or http://www.argon.org/~roderick/ for the latest version.

AUTHOR
======

   Roderick Schertler <`roderick@argon.org'>

SEE ALSO
========

   sirc(1), perl(1), Sirc::Chantrack(3pm), Sirc::Util(3pm).


File: pm.info,  Node: Sirc/Util,  Next: Slay/Maker,  Prev: Sirc/LimitMan,  Up: Module List

Utility sirc functions
**********************

NAME
====

   Sirc::Util - Utility sirc functions

SYNOPSIS
========

     # sirc functions
     use Sirc::Util ':sirc';
     # overrides:
     timer $delay, $code_string_or_ref, [$reference];

     # user messages
     arg_count_error $name, $want, [@arg];
     tell_error $msg;
     tell_question $msg;
     xtell $msg;

     # miscellaneous
     $pattern = ban_pattern $nick, $user, $host;
     $boolean = by_server [$who, $user, $host];
     eval_this $code, [@arg];
     eval_verbose $name, code$, [@arg];
     $boolean = have_ops $channel;
     $boolean = have_ops_q $channel;
     $boolean = ieq $a, $b;
     $re = mask_to_re $mask;
     $unused_timer = newtimer;
     optional_channel or return;
     $boolean = plausible_channel $channel;
     $boolean = plausible_nick $nick;
     $arg = xgetarg;
     $restricted = xrestrict;

     # /settables
     settable name, $var_ref, $validate_ref;
     settable_boolean $name, $var_ref;
     settable_int $name, $var_ref, [$validate_ref];

     # hooks
     add_hook_type $name;
     add_hook $name, $code;
     run_hook $name, [@arg];

DESCRIPTION
===========

   This module provides a bunch of utility functions for *sirc*.

   It also allows you to import from it all of the standard sirc API
functions, so that you can more simply write your script as a module.

   Nothing is exported by default.

STANDARD SIRC FUNCTIONS
=======================

   You can import the standard SIRC API functions individually or, using
the tag *:sirc*, as a group.  The available functions are:


     accept addcmd addhelp addhook addset connect deltimer describe
     docommand doset dosplat dostatus eq getarg getuserline getuserpass
     listen load me msg newfh notice print remhook remsel resolve say sl
     tell timer userhost yetonearg

   Some of these are actually enhanced versions of the routines that *sirc*
provides, see below for information about them.

STANDARD MESSAGE FORMS
======================

   These functions provide for a few standard message forms which are shown
to the user via main::tell().

arg_count_error name, *want*, [*arg*...]
     This prints an error appropriate to an incorrect number of arguments.
     name is the name of the invoking sub, *want* is how many arguments
     were desired and the remaining *arg* arguments are the arguments which
     were actually received.

tell_error msg
     This formats msg as an error message and passes it to main::tell.
     It's appropriate for errors caused by the system or an invalid
     invocation of your code.

tell_question msg
     This formats msg as an error message for something the user did
     wrong.  The message is passed to main::tell.

xtell msg
     This is just `main::tell "*** $msg"'.

MISCELLANEOUS FUNCTIONS
=======================

   These are some functions which don't fall nicely into groups like those
following do.

ban_pattern nick, user, host
     This returns a pattern suitable for banning the given nick, user and
     host.

     The current implementation is this:  Any nick is always matched.  If
     the user has a ~ at the start (that is, it didn't come from identd)
     all user names are matched, else just the one given matches.  If the
     host is an IP address, it bans a class C sized chunk of IP space,
     otherwise part of it is wildcarded (how much depends on how many
     parts it has).

     For example:

          qw(Nick  user 1.2.3.4)		*!user@1.2.3.*
          qw(Nick ~user 1.2.3.4)		*!*@1.2.3.*
          qw(Nick  user host.foo.com)		*!user@*.foo.com
          qw(Nick ~user host.foo.com)		*!*@*.foo.com
          qw(Nick  user foo.com)		*!user@*foo.com
          qw(Nick ~user foo.com)		*!*@*foo.com

by_server [who, user, host]
     If the given who, user, host corresponds to a server rather than a
     user, return the server name, else return undef.  If these aren't
     specified the global $::who, $::user, and $::host are used, which is
     what you usually want anyway.

eval_this code, [*arg*...]
     This evals code with *arg* as arguments.  The code can be either a
     code reference or a string.  In either case the *arg*s will be
     available in @_.  The return value is whatever the code returns.  $@
     will be set if an exception was raised.

eval_verbose name, code, [*arg*...]
     This is like eval_this except that if an exception is raised it is
     passed along to tell_error (with a message indicating it's from name).

have_ops channel
     This function returns true if you have ops on the specified channel.
     If you don\'t have ops it prints an error message and returns false.

have_ops_q channel
     This is like have_ops except that no message is printed, it just
     returns true or false depending on whether you have ops on the
     specified channel.

ieq $a, $b
     This sub returns true if its two args are eq, ignoring case.

mask_to_re glob
     Convert the given "mask" (an IRC-style glob pattern) to a regular
     expression.  The only special characters in IRC masks are * and ?
     (there's no way to escape one of these).  The returned pattern always
     matches case insensitively and is anchored at the front and back (as
     IRC does it).

optional_channel
     This sub examines $::args to see if the first word in it looks like a
     channel.  If it doesn't then $::talkchannel is inserted there.  If
     there was no channel present and you're not on a channel then an
     error message is printed and false is returned, otherwise true is
     returned.

     Here's a replacement for /names which runs /names for your current
     channel if you don't provide any args.

          sub main::cmd_names {
          	optional_channel or return;
          	docommand "/names $::args";
          }
          addcmd 'names';

newtimer
     Return an unused timer number.

plausible_channel channel
     This returns true if channel is syntactically valid as a channel name.

plausible_nick nick
     This returns true if nick is syntactically valid as a nick name.
     Originally I used the RFC 1459 definition here, but that turns out to
     be no longer valid.  I don't know what definition modern IRC servers
     are using.  This sub allows characters in the range [!-~].

timer @args
     This is an enhanced version of *sirc*'s timer().  It allows you to use
     a code reference as the code arg.

xgetarg
     This is like main::getarg, but it returns the new argument (in
     addition to setting $::newarg).

xrestrict
     This just returns $::restrict.

/SET COMMANDS
=============

   These commands provide a simplified interface to adding /set variables.

settable name, *var-ref*, *validate-ref*
     This sub adds a user-settable option.  name is its name, *var-ref* is
     a reference to the place it will be stored, and *validate-ref* is a
     reference to code to validate and save new values.  The code will be
     called as `$rvalidate-'($rvar, $name, $value)>.  $name will be in
     upper case.  The code needs to set both $$rvar and $::set{$name}.
     (The values in %set are user-visible.)

settable_boolean name, *var-ref*
     This adds a /settable boolean called name.  *var-ref* is a reference
     to the scalar which will store the value.

settable_int name, *var-ref*, [*validate-ref*]
     This function adds a /settable integer called name.  *var-ref* is a
     reference to the scalar which will store the value.

     *validate-ref*, if provided, will be called to validate the a new
     value is legal.  It will receive both the name and the new value as
     arguments.  Before it is called the new value will have been vetted
     for number-hood.  It should return a boolean to indicate whether the
     value is okay.

HOOKS
=====

   Sirc::Util provides functionality for creating, adding code to and
running hooks.

add_hook_type name
     This creates a new hook called name.

add_hook name, code
     Add code to the name hook.  The name must already have been created
     with add_hook_type().  The code can be either a string or a code
     reference.

run_hook name, [*arg*...]
     Run the name hook, passing the *arg*s to each hook member via @_.

AVAILABILITY
============

   Check CPAN or http://www.argon.org/~roderick/ for the latest version.

AUTHOR
======

   Roderick Schertler <`roderick@argon.org'>

SEE ALSO
========

   sirc(1), perl(1), Sirc::Chantrack(3pm).


File: pm.info,  Node: Slay/Maker,  Next: Slay/MakerRule,  Prev: Sirc/Util,  Up: Module List

An perl make engine using perl code for rules
*********************************************

NAME
====

   Slay::Maker - An perl make engine using perl code for rules

STATUS
======

   Beta. Pretty stable, though underdocumented.

DESCRIPTION
===========

   Slay::Maker is a make engine that uses perl declaration syntax for
rules, including regular expressions for targets and anonymous subs for
targets, dependancies, and actions.

   This allows you to tightly integrate a make engine in an application
and to excercise a large amount of control over the make process, taking
full advantage of Perl code at any point in the make cycle.

RULE SYNTAX
===========

   The rulebase syntax is:

     [ @targets1, ':', @dependancies1, '=', @actions1, { option => val } ],
     [ @targets2, ':', @dependancies2, '=', @actions2, { option => val } ],
     [ @targets3, ':', @dependancies3, '=', @actions3, { option => val } ],
     [ @targets4, ':', @dependancies4, '=', @actions4, { option => val } ],
     ...

   Each item in any of the three arrays may be a literal string or a
subroutine (CODE) reference.  A literal string is pretty much the same as
using a literal string in a regular makefile.  You may also use regular
expression ('Regexp') references (`qr/.../') in @targets and the $1, $2,
... variables inside strings in @dependancies:

     [ qr/(.*).pm/, ':', "$1.pm.in", '=', sub { ... } ],

   Subroutine references are evaluated as lazily as possible when the make
is being run, so any CODE refs in @targets will be called each time a make
is run, CODE refs in @dependancies will only be called if a target
matches, and CODE refs in @actions are only called if the rule is fired.

TARGET SUBS
-----------

   ** NOT IMPLEMENTED QUITE YET **.  It's simple to do, just haven't needed
it yet.

   Aside from strings and Regexps, you will be able to use CODE refs in
the target list.  These are called each time the rule is evaluated, which
will usually happen once per target or dependancy being checked when the
make is run.

   A target sub declaration might look like:

     sub {
        my ( $maker ) = @_ ;
        ...
        return @targets;
     },

   (if target subs were implemented already).

DEPENDANCIES
------------

   Dependancies may be strings or CODE references.  Plain strings have $1,
$2, ... interpolation done on them (remember to \ escape the $1, etc.).

   CODE refs will be called if the target matches and must return a
possibly empty list of strings containing the names of dependancies.
Variable interpolation will not be done on the returned strings.  That
would be obscene.

   A dependancy sub declaration might look like:

     sub {
        my ( $maker, $target, $matches ) = @_ ;
        ...
        return @dependancies ;
     },

   where

     $maker    refers to the Slay::Maker (or subclass) being run
     $target   is the target that matched (in the event of multiple targets)
     $matches  is an ARRAY of the values extracted from $1, $2, etc.

   .

ACTIONS
-------

   If an $action is a plain string, it's passed to "sh -c '$string'".  If
it's an ARRAY ref, it's run without interference from or benefit of a
shell (see `run', *Note IPC/Run: IPC/Run, for details).  If it's a CODE
ref, it's called.

   An action sub declaration might look like:

     sub {
        my ( $maker, $target, $deps, $matches ) = @_ ;
        ...
        return @dependancies ;
     },

   where

     $maker    refers to the Slay::Maker (or subclass) being run
     $target   is the target that matched (in the event of multiple targets)
     $deps     is an ARRAY of the expanded dependancies.  There's no way
               of telling which are freshly rebuilt, but you can track that
     	     yourself in the action rules of the dependancies, if you
     	     like.
     $matches  is an ARRAY of the values extracted from $1, $2, etc.

TARGET BACKUPS
==============

   A target may be moved off to a backup location before it is rebuilt, so
that it may be restored if rebuilding fails.  This is also used for the
optional restoral of modification times described below.

   Restoral needs to be done manually by calling the `' in this node
method, and you can call the `' in this node method, too.

   The `' in this node method will be called automatically if modification
time restoral is enabled for a target.

MODIFICATION TIME RESTORAL
==========================

   One unusual option is that a target file's modification time can be
restored if it is unchanged after being updated.  This can be useful when
checking files out of a repository: the files' mod times won't be affected
if their contents haven't changed.

   This can be done by a (fast but possibly misleading) check for a change
in file size or by executing 'diff -brief' between a target's backup and
it's new version.  Other methods, such as hashing or block-by-block binary
comparison will be implemented in the future if needed.

   This is controled by the `' in this node option passed to the base
class constructor:

     my $self = $class->SUPER::new( ..., { detect_no_diffs => 1 } ) ;

   and can be passed as an option to any rule.

AN EXAMPLE
==========

   Here's a real example, which will have to stand in for documentation
until further notice.  If you need more, mail me (barries@slaysys.com) and
get me to do something productive for a change.

   This is a subclass that compiles a set of builtin rules at module
compilation time.  It declares a method for spawning the cvs command
first, then builds some rules.

     package Safari::Cvs::Make ;

     @ISA = qw( Slay::Maker ) ;

     use strict ;
     use IPC::Run ;

     sub cvs {
        my Safari::Cvs::Make $maker = shift ;

     my $stdout_to ;
     if ( $_[-1] =~ /^\s*>(.*)/ ) {
     	 $stdout_to = $1 ;
     	 pop ;
     }

     my $cvs_out ;
     run [ qw( cvs -q -l -z9 ), @_ ], \undef, \$cvs_out or die $! ;

     return $cvs_out ;
        }

     my $builtin_rules = Safari::Make->compile_rules(
        [  'meta/cvs_modules',
     	 '=', sub {   ## The action that occurs when the rule fires.
     	    ## We could just do the cvs co -c here, but many pservers don't
     	    ## have that implemented.  so, check out the modules file and
     	    ## parse it.
     	    my ( $maker, $target ) = @_ ;
     	    $maker->cvs( qw( checkout -p CVSROOT/modules ), ">$target" ) ;
     	 },
        ],
        [ 'update',
     	 ':' => sub {
     	    my ( $maker ) = @_ ;

     my $context = $maker->{CONTEXT} ;

     my @modules ;

     my %args = $context->request->args ;
     if ( defined $args{modules} ) {
        @modules = split( ',', $args{modules} ) ;
     }
     elsif ( defined $args{module} ) {
        @modules = $args{module} ;
     }
     else {
        eval {
           ## A recursive make
     		  $maker->make( 'meta/cvs_modules', { force => 1 } ) ;
        } ;
        if ( $@ ) {
     		  warn $@ ;
        }

     if ( ! open( F, "<meta/cvs_modules" ) ) {
     		  warn "$!: meta/cvs_modules, globbing" ;
     		  @modules = map {
     		     s{^meta/HEAD/}{}; $_
     		  } grep {
     		     -d $_
     		  } glob( 'meta/HEAD/*' ) ;
     }
     else {
     		  my $line ;
     		  my %modules ;
     		  while (<F>) {
     		     next if /^\s*#|^\s*$/ ;
     		     chomp ;
     		     $line .= $_ ;
     		     redo if $line =~ s{\\$}{} ;
     		     $modules{$1} = 1 if $line =~ m{^\s*(\S+)} ;
     		     $line = '' ;
     		  }
     		  close F ;
     		  @modules = sort keys %modules ;
     }
     	    }

     debug 'modules', \@modules ;
     die "No modules found\n" unless @modules ;
     return map { "source/HEAD/$_/CVS/" } @modules ;
     	 },
     	 '=' => sub {
     my ( $maker, $target, $deps ) = @_ ;

     my @dirs = map { s{/CVS/}{} ; $_ } @$deps ;

     ## We go ahead and update after creating modules for a couple of
     ## reasons:
     ## 1. It's rare that we've just checked out a module
     ## 2. It's simpler this way
     ## 3. If we just created a *big* module, then we might need to
     ## update anyway.

     ## We set $logs{$filename} = 1 if we must replace the current log file,
     ## or = 0 to just ensure that the log file is fetched.
     my %logs ;
     my $force_all ;

     my $cwd = cwd() ;
     for ( @dirs ) {
        chdir $_ or die "$!: $_" ;
        my $module = $_ ;
        $module =~ s{.*/}{} ;
        ## -P: Prune empty dirs
        ## -d: Add new dirs that we don't have
        for ( split /^/m, $maker->cvs( qw( update -d -P ) ) ) {
     		  chomp ;
     		  if ( /^[UP]\s+(.*)/ ) {
     		     $logs{"meta/HEAD/$module/$1.log"} = 1 ;
     		  }
     		  elsif ( /^\?\s+(.*)/ ) {
     		     my $log_file = "meta/HEAD/$module/$1.log" ;
     		     eval {
     			rmtree( [ $log_file ] ) ;
     		     } ;
     		     warn "Error removing ;$log_file'" if $@ ;
     		  }
     		  else {
     		     warn "Unexpected CVS file mode: $_" ;
     		  }
        }
        chdir $cwd or die "$!: $cwd" ;
     }

     for ( sort keys %logs ) {
        $maker->make(
     		  $_,
     		  {
     		     force => $force_all || $logs{$_}
     		  }
        ) ;
     }

     },
     {
        force => 1,   # Always remake this target
     }
           ],
        ) ;

METHODS
=======

new
     Constructor.

          my $rules = [
             # ...
          ] ;
          my $maker = Slay::Maker->new( $rules ) ;
          my $maker = Slay::Maker->new( $rules, { option => 1 } ) ;

     options (which can also be defined on a per-rule basis) are:

    auto_create_dirs
          Creates directories that targets will be created in before
          executing a target's actions.

    detect_no_diffs
          Copy the target before executing a rule, then restore the
          original modification and access times if the contents of the
          target are the same after the rule.

    detect_no_size_change
          Look for changes in the size of a file after executing a rule
          and restore the original modification and access times if it
          changes.

    force
          Always remake target, even if it does not appear to be out of
          date

     Warning: options are not checked for spelling errors.

     Options may be passed to new(), make(), build_queue(), and to rules
     themselves.  Options passed to make() or build_queue() take
     precedence over rules' options, and rules' options take precedence
     over those passed to new().

add_rules
     Add rules (compiled or not) to the rule base.

atime
     This returns the atime of a file, reading from the stat cache if
     possible.

build_queue
     Builds a new queue of rules to be exec()ed to make a target

builtin_rules
     Returns [] by default.  This is provided so that subclasses may
     overload it to provide sets of rules.  This is called by new() before
     adding any rules passed to new().

canonpath
     Cleans up the path, much like File::Spec::Unix::canonpath(), but also
     removes name/.. constructs.

chdir
     Calls sytem's chdir(), die()s on failure, and uses the parameter as
     the current directory.  The last is the main reason for this sub: if
     you chdir() to a symbolic link, then we want to know the symbolic
     directory, not the real one returned by cwd().

check_targets
     Checks targets and adds them to queue if need be.  Does not integrate
     Slay::Maker options: this is left to the caller (usually the original
     build_queue() call).

clear_caches
     Clears the stat cache, so the filesystem must be reexamined.  Only
     needed if Slay::Maker is being called repetetively.

clear_stat
     Clears the stat cache for a given path, so the next stat() on that
     path will read the filesystem.

compile_rules
     Returns a rulebase compiled from the arguments.  Rules that are
     already compiled are passed through unchanged.  This is a class
     method, so

          Slay::Maker->compile_rules(
             [ 'a', [qw( b c )], 'cat b c > a' ],
             ...
          ) ;

     can be used to compile a rulebase once at startup

backup
     Copies a file so that it can be restored later or checked for changes.

     If the target will only ever be replaced by the make, then it will
     not be altered in-place, and the move option may be passed:

          $maker->backup( $target, { move => 1 } ) ;

     If the target is an fiel which always changes size when it's changed,
     you may pass the `stat_only' option:

          $maker->backup( $target, { stat_only => 1 } ) ;

     The return value can be passed to restore(), target_unchanged(), and
     remove_backup().

cwd
     Returns the current working directory, from the cache if that's
     possible.

e
     Returns true if the file exists, but uses the stat_cache if possible.

exec_queue
     Executes the queued commands.

find_rule
     Given a target, finds a rule.

make
     Makes one or more target(s) if it's out of date.  Throws exceptions if
     the make fails.  May partially make targets.

make_level
     Returns 0 if make() has not been called (well, actually, if
     recurse_in() has not been called).  Returns number of recursive calls
     otherwise, so this is equal to 1 when making something but not
     recursing.

mtime
     This returns the mtime of a file, reading from the stat cache if
     possible.

options
     Sets / gets a reference to the options hash.

push
     Adds a ( target, rule ) tuple to the exec queue.  Will not add the
     same target twice.

recurse_in
     Sets up for a recursive make.  Called automatically by make() if
     make() is already running.

recurse_out
     Restored after a recursive make.  Called automatically by make() if
     make() is already running.

queue_size
     Number of rules that need to be made.

remove_backup
          my $backup = $maker->backup( $target ) ;
          ## ...
          $maker->remove_backup(
             $backup,
             {
          	 restore_if_unchanged => 1,
          	 deps                 => \@deps,
             }
          ) ;

     Removes a backup of the target created with backup_target().

replace_rules
     Replaces the rule for a target (or targets).  The targets passed in
     must exactly match those of the rule to be replaced.

restore
          my $backup = $maker->backup( $target, { move => 1 } ) ;
          ## Try to recreate target, setting $error on error
          $maker->restore( $backup )
             if $error ;
          $maker->restore( $backup, { deps => \@deps } )
             if ! $error && $maker->target_unchanged( $backup ) ;
          $maker->remove_backup( $backup ) ;

     Note that you only need this in case of an error.  You can pass the
     restore_if_unchanged => 1 and deps => \@deps options to
     remove_backup().

     When backup() has been called, it's return value can be passed to
     restore_target() to restore the original target, timestamps and all.

     NOTE: restoring a target that's not changed is likely to cuase it to
     be remade every time once a dependancy's timestamp becomes more
     recent.  The `deps' option allows the timestamps to be set to the
     newest of the original timestamps and the dependencies' timestamps.
     This should not be done if there was an error generating the file.

rules
     Gets or replaces the rules list

size
     This returns the size of a file, reading from the stat cache if
     possible.

stat
     Looks in the stat cache for the stat() results for a path.  If not
     found, fills the cache.  The cache is shared between all instances of
     this class, and may be cleared using clear_stat_cache().

target_unchanged
     Takes the result of backup_target() and checks to see if the target
     has been changed or removed.

back
TODO
====

   * Propogate effects of restored timestamps.

     If a target has it's timestamps restored as a result of detecting no
     change (see options detect_no_size_change and detect_no_diffs), then
     there may well be no need to actually execute later rules.

     One way to do this is to re-check the mtime dependencies when
     rebuilding.  Another is to subscribe later items in the queue to
     earlier items and have the earlier items set a flag that tells the
     later items to go ahead and execute.  Items could flag themselves to
     execute regardless, which we might want to do if a dependancy is not
     present when make is run.

   * Don't really call diff(1) for detect_no_diffs

AUTHOR
======

   Barrie Slaymaker <barries@slaysys.com>

LICENSE
=======

   Copyright 2000, R. Barrie Slaymaker, Jr., All Rights Reserved.

   That being said, do what you will with this code, it's completely free.

   Please let me know of any improvements so I can have the option of
folding them back in to the original.


